From e14d759b7a703a1f3bd706d61774378a141c32dc Mon Sep 17 00:00:00 2001
From: xuekang <914468783@qq.com>
Date: 星期五, 10 五月 2024 20:43:07 +0800
Subject: [PATCH] 初始化
---
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssMapper.java | 13
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java | 174
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteSocialServiceImpl.java | 63
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java | 79
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm | 60
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java | 115
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java | 206
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssBo.java | 49
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/RuoYiSystemApplication.java | 22
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java | 73
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java | 129
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteConfigServiceImpl.java | 29
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml | 7
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm | 116
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java | 75
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysEmailController.java | 60
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java | 59
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java | 123
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java | 61
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java | 29
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java | 35
ruoyi-modules/ruoyi-system/src/main/resources/application.yml | 32
ruoyi-modules/ruoyi-system/src/main/resources/spy.properties | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialBoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java | 51
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java | 67
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysOperLogBoConvert.java | 25
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java | 56
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java | 231
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysClientVoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java | 13
ruoyi-modules/ruoyi-gen/Dockerfile | 16
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java | 51
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java | 203
ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm | 7
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssConfigServiceImpl.java | 175
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/RuoYiJobApplication.java | 24
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssConfigMapper.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java | 80
ruoyi-modules/ruoyi-system/src/main/resources/banner.txt | 10
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java | 54
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java | 183
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssConfigBo.java | 111
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml | 13
ruoyi-modules/pom.xml | 52
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java | 94
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java | 56
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOss.java | 50
ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssConfigMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java | 31
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java | 77
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml | 125
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java | 217
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java | 141
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm | 474 +
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm | 134
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteSmsServiceImpl.java | 46
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java | 115
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java | 107
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java | 83
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java | 25
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java | 57
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java | 147
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java | 372 +
ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm | 63
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java | 45
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java | 125
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java | 115
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm | 53
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java | 125
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java | 14
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/runner/ResourceApplicationRunner.java | 28
ruoyi-modules/ruoyi-gen/src/main/resources/application.yml | 32
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md | 3
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java | 108
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapProcessorDemo.java | 93
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysUserBoConvert.java | 29
ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml | 78
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/RuoYiResourceApplication.java | 23
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java | 144
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java | 85
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java | 88
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java | 186
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java | 137
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml | 7
ruoyi-modules/ruoyi-gen/pom.xml | 94
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java | 14
ruoyi-modules/ruoyi-system/pom.xml | 134
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java | 222
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java | 71
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java | 116
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteClientServiceImpl.java | 33
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java | 38
ruoyi-modules/ruoyi-resource/src/main/resources/logback-plus.xml | 28
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDictServiceImpl.java | 33
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java | 35
ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml | 194
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java | 29
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDictDataVoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java | 29
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java | 191
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssUploadVo.java | 34
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java | 89
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssService.java | 40
ruoyi-modules/ruoyi-gen/src/main/resources/logback-plus.xml | 25
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java | 145
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml | 26
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java | 132
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java | 65
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java | 108
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java | 89
ruoyi-modules/ruoyi-job/src/main/resources/logback-plus.xml | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java | 188
ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm | 507 +
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java | 178
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java | 115
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java | 14
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/workflow/WorkflowStandaloneProcessor.java | 36
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java | 42
ruoyi-modules/ruoyi-resource/src/main/resources/application.yml | 32
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssController.java | 106
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml | 7
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm | 15
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java | 132
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java | 100
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java | 61
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java | 71
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java | 51
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java | 57
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java | 67
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java | 23
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteLogServiceImpl.java | 39
ruoyi-modules/ruoyi-job/src/main/resources/banner.txt | 10
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java | 60
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java | 143
ruoyi-modules/ruoyi-job/src/main/resources/spy.properties | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java | 114
ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java | 94
ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md | 3
ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm | 50
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java | 89
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java | 46
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java | 138
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssVo.java | 72
ruoyi-modules/ruoyi-resource/src/main/resources/mapper/package-info.md | 3
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java | 87
ruoyi-modules/ruoyi-resource/src/main/resources/banner.txt | 10
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java | 106
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java | 87
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/LogTestProcessor.java | 41
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java | 96
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java | 117
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapReduceProcessorDemo.java | 93
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/TimeoutProcessor.java | 25
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java | 28
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityInitializer.java | 35
ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm | 19
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml | 85
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/StandaloneProcessorDemo.java | 51
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/bo.java.vm | 50
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/BroadcastProcessorDemo.java | 56
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java | 79
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java | 114
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java | 70
ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/postgres/sql.vm | 20
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java | 71
ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssMapper.xml | 5
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssConfigController.java | 100
ruoyi-modules/ruoyi-system/Dockerfile | 23
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java | 24
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java | 210
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java | 326
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java | 106
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java | 67
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java | 144
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java | 61
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssConfigVo.java | 96
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/RuoYiGenApplication.java | 22
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java | 79
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java | 32
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java | 80
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java | 31
ruoyi-modules/ruoyi-job/Dockerfile | 23
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java | 548 +
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java | 55
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java | 50
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java | 135
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java | 60
ruoyi-modules/ruoyi-gen/src/main/resources/spy.properties | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java | 47
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java | 285
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java | 136
ruoyi-modules/ruoyi-job/src/main/resources/application.yml | 32
ruoyi-modules/ruoyi-resource/pom.xml | 149
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java | 73
ruoyi-modules/ruoyi-job/pom.xml | 105
ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/SimpleProcessor.java | 35
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java | 228
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysTenantVoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java | 47
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java | 142
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMailServiceImpl.java | 33
ruoyi-modules/ruoyi-resource/Dockerfile | 23
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java | 67
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml | 7
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java | 196
ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm | 59
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java | 56
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java | 14
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml | 67
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysLogininforBoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java | 29
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java | 72
ruoyi-modules/ruoyi-resource/src/main/resources/spy.properties | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java | 99
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteTenantServiceImpl.java | 43
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java | 28
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java | 95
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java | 62
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java | 60
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml | 29
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java | 13
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java | 41
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOssConfig.java | 90
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java | 121
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml | 7
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java | 466 +
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java | 229
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java | 13
ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt | 10
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml | 7
ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/oracle/sql.vm | 19
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java | 365 +
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java | 82
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java | 103
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java | 66
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java | 58
ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java | 336
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java | 123
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java | 127
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java | 29
ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssConfigService.java | 66
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java | 205
ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml | 7
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialVoConvert.java | 17
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java | 114
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java | 486 +
ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java | 119
262 files changed, 21,328 insertions(+), 0 deletions(-)
diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml
new file mode 100644
index 0000000..0980f60
--- /dev/null
+++ b/ruoyi-modules/pom.xml
@@ -0,0 +1,52 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-cloud-plus</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <modules>
+ <module>ruoyi-system</module>
+ <module>ruoyi-gen</module>
+ <module>ruoyi-job</module>
+ <module>ruoyi-resource</module>
+ </modules>
+
+ <artifactId>ruoyi-modules</artifactId>
+ <packaging>pom</packaging>
+
+ <description>
+ ruoyi-modules涓氬姟妯″潡
+ </description>
+
+ <dependencies>
+ <!-- 鑷畾涔夎礋杞藉潎琛�(澶氬洟闃熷紑鍙戜娇鐢�) -->
+<!-- <dependency>-->
+<!-- <groupId>org.dromara</groupId>-->
+<!-- <artifactId>ruoyi-common-loadbalancer</artifactId>-->
+<!-- </dependency>-->
+
+ <!-- ELK 鏃ュ織鏀堕泦 -->
+<!-- <dependency>-->
+<!-- <groupId>org.dromara</groupId>-->
+<!-- <artifactId>ruoyi-common-logstash</artifactId>-->
+<!-- </dependency>-->
+
+ <!-- skywalking 鏃ュ織鏀堕泦 -->
+<!-- <dependency>-->
+<!-- <groupId>org.dromara</groupId>-->
+<!-- <artifactId>ruoyi-common-skylog</artifactId>-->
+<!-- </dependency>-->
+
+ <!-- prometheus 鐩戞帶 -->
+<!-- <dependency>-->
+<!-- <groupId>org.dromara</groupId>-->
+<!-- <artifactId>ruoyi-common-prometheus</artifactId>-->
+<!-- </dependency>-->
+
+ </dependencies>
+
+</project>
diff --git a/ruoyi-modules/ruoyi-gen/Dockerfile b/ruoyi-modules/ruoyi-gen/Dockerfile
new file mode 100644
index 0000000..5b1f972
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/Dockerfile
@@ -0,0 +1,16 @@
+#FROM findepi/graalvm:java17-native
+FROM openjdk:17.0.2-oraclelinux8
+
+MAINTAINER Lion Li
+
+RUN mkdir -p /ruoyi/gen/logs
+
+WORKDIR /ruoyi/gen
+
+ENV SERVER_PORT=9202 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-gen.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} -jar app.jar ${JAVA_OPTS}
diff --git a/ruoyi-modules/ruoyi-gen/pom.xml b/ruoyi-modules/ruoyi-gen/pom.xml
new file mode 100644
index 0000000..f1b388b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/pom.xml
@@ -0,0 +1,94 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-modules</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ruoyi-gen</artifactId>
+
+ <description>
+ ruoyi-gen浠g爜鐢熸垚
+ </description>
+
+ <dependencies>
+
+ <!-- SpringCloud Alibaba Nacos -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+ </dependency>
+
+ <!-- SpringCloud Alibaba Nacos Config -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+ </dependency>
+
+ <!-- Apache Velocity -->
+ <dependency>
+ <groupId>org.apache.velocity</groupId>
+ <artifactId>velocity-engine-core</artifactId>
+ </dependency>
+
+ <!-- RuoYi Common Log -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-log</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-doc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dubbo</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-tenant</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-security</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${project.artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/RuoYiGenApplication.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/RuoYiGenApplication.java
new file mode 100644
index 0000000..d2350df
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/RuoYiGenApplication.java
@@ -0,0 +1,22 @@
+package org.dromara.gen;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 浠g爜鐢熸垚
+ *
+ * @author ruoyi
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiGenApplication {
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(RuoYiGenApplication.class);
+ application.setApplicationStartup(new BufferingApplicationStartup(2048));
+ application.run(args);
+ System.out.println("(鈾モ棤鈥库棤)锞夛緸 浠g爜鐢熸垚妯″潡鍚姩鎴愬姛 醿�(麓凇`醿�)锞� ");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java
new file mode 100644
index 0000000..e973e32
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/config/GenConfig.java
@@ -0,0 +1,65 @@
+package org.dromara.gen.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 浠g爜鐢熸垚鐩稿叧閰嶇疆
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "gen")
+public class GenConfig {
+ /**
+ * 浣滆��
+ */
+ public static String author;
+
+ /**
+ * 鐢熸垚鍖呰矾寰�
+ */
+ public static String packageName;
+
+ /**
+ * 鑷姩鍘婚櫎琛ㄥ墠缂�锛岄粯璁ゆ槸false
+ */
+ public static boolean autoRemovePre;
+
+ /**
+ * 琛ㄥ墠缂�(绫诲悕涓嶄細鍖呭惈琛ㄥ墠缂�)
+ */
+ public static String tablePrefix;
+
+ public static String getAuthor() {
+ return author;
+ }
+
+ public void setAuthor(String author) {
+ GenConfig.author = author;
+ }
+
+ public static String getPackageName() {
+ return packageName;
+ }
+
+ public void setPackageName(String packageName) {
+ GenConfig.packageName = packageName;
+ }
+
+ public static boolean getAutoRemovePre() {
+ return autoRemovePre;
+ }
+
+ public void setAutoRemovePre(boolean autoRemovePre) {
+ GenConfig.autoRemovePre = autoRemovePre;
+ }
+
+ public static String getTablePrefix() {
+ return tablePrefix;
+ }
+
+ public void setTablePrefix(String tablePrefix) {
+ GenConfig.tablePrefix = tablePrefix;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java
new file mode 100644
index 0000000..937869f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/constant/GenConstants.java
@@ -0,0 +1,186 @@
+package org.dromara.gen.constant;
+
+/**
+ * 浠g爜鐢熸垚閫氱敤甯搁噺
+ *
+ * @author Lion Li
+ */
+public interface GenConstants {
+ /**
+ * 鍗曡〃锛堝鍒犳敼鏌ワ級
+ */
+ String TPL_CRUD = "crud";
+
+ /**
+ * 鏍戣〃锛堝鍒犳敼鏌ワ級
+ */
+ String TPL_TREE = "tree";
+
+ /**
+ * 鏍戠紪鐮佸瓧娈�
+ */
+ String TREE_CODE = "treeCode";
+
+ /**
+ * 鏍戠埗缂栫爜瀛楁
+ */
+ String TREE_PARENT_CODE = "treeParentCode";
+
+ /**
+ * 鏍戝悕绉板瓧娈�
+ */
+ String TREE_NAME = "treeName";
+
+ /**
+ * 涓婄骇鑿滃崟ID瀛楁
+ */
+ String PARENT_MENU_ID = "parentMenuId";
+
+ /**
+ * 涓婄骇鑿滃崟鍚嶇О瀛楁
+ */
+ String PARENT_MENU_NAME = "parentMenuName";
+
+ /**
+ * 鏁版嵁搴撳瓧绗︿覆绫诲瀷
+ */
+ String[] COLUMNTYPE_STR = {"char", "varchar", "enum", "set", "nchar", "nvarchar", "varchar2", "nvarchar2"};
+
+ /**
+ * 鏁版嵁搴撴枃鏈被鍨�
+ */
+ String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext", "binary", "varbinary", "blob",
+ "ntext", "image", "bytea"};
+
+ /**
+ * 鏁版嵁搴撴椂闂寸被鍨�
+ */
+ String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp", "year", "interval",
+ "smalldatetime", "datetime2", "datetimeoffset"};
+
+ /**
+ * 鏁版嵁搴撴暟瀛楃被鍨�
+ */
+ String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer",
+ "bit", "bigint", "float", "double", "decimal", "numeric", "real", "double precision",
+ "smallserial", "serial", "bigserial", "money", "smallmoney"};
+
+ /**
+ * BO瀵硅薄 涓嶉渶瑕佹坊鍔犲瓧娈�
+ */
+ String[] COLUMNNAME_NOT_ADD = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version", "tenant_id"};
+
+ /**
+ * BO瀵硅薄 涓嶉渶瑕佺紪杈戝瓧娈�
+ */
+ String[] COLUMNNAME_NOT_EDIT = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version", "tenant_id"};
+
+ /**
+ * VO瀵硅薄 涓嶉渶瑕佽繑鍥炲瓧娈�
+ */
+ String[] COLUMNNAME_NOT_LIST = {"create_dept", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "version", "tenant_id"};
+
+ /**
+ * BO瀵硅薄 涓嶉渶瑕佹煡璇㈠瓧娈�
+ */
+ String[] COLUMNNAME_NOT_QUERY = {"id", "create_dept", "create_by", "create_time", "del_flag", "update_by",
+ "update_time", "remark", "version", "tenant_id"};
+
+ /**
+ * Entity鍩虹被瀛楁
+ */
+ String[] BASE_ENTITY = {"createDept", "createBy", "createTime", "updateBy", "updateTime", "tenantId"};
+
+ /**
+ * 鏂囨湰妗�
+ */
+ String HTML_INPUT = "input";
+
+ /**
+ * 鏂囨湰鍩�
+ */
+ String HTML_TEXTAREA = "textarea";
+
+ /**
+ * 涓嬫媺妗�
+ */
+ String HTML_SELECT = "select";
+
+ /**
+ * 鍗曢�夋
+ */
+ String HTML_RADIO = "radio";
+
+ /**
+ * 澶嶉�夋
+ */
+ String HTML_CHECKBOX = "checkbox";
+
+ /**
+ * 鏃ユ湡鎺т欢
+ */
+ String HTML_DATETIME = "datetime";
+
+ /**
+ * 鍥剧墖涓婁紶鎺т欢
+ */
+ String HTML_IMAGE_UPLOAD = "imageUpload";
+
+ /**
+ * 鏂囦欢涓婁紶鎺т欢
+ */
+ String HTML_FILE_UPLOAD = "fileUpload";
+
+ /**
+ * 瀵屾枃鏈帶浠�
+ */
+ String HTML_EDITOR = "editor";
+
+ /**
+ * 瀛楃涓茬被鍨�
+ */
+ String TYPE_STRING = "String";
+
+ /**
+ * 鏁村瀷
+ */
+ String TYPE_INTEGER = "Integer";
+
+ /**
+ * 闀挎暣鍨�
+ */
+ String TYPE_LONG = "Long";
+
+ /**
+ * 娴偣鍨�
+ */
+ String TYPE_DOUBLE = "Double";
+
+ /**
+ * 楂樼簿搴﹁绠楃被鍨�
+ */
+ String TYPE_BIGDECIMAL = "BigDecimal";
+
+ /**
+ * 鏃堕棿绫诲瀷
+ */
+ String TYPE_DATE = "Date";
+
+ /**
+ * 妯$硦鏌ヨ
+ */
+ String QUERY_LIKE = "LIKE";
+
+ /**
+ * 鐩哥瓑鏌ヨ
+ */
+ String QUERY_EQ = "EQ";
+
+ /**
+ * 闇�瑕�
+ */
+ String REQUIRE = "1";
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java
new file mode 100644
index 0000000..a7c61eb
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/controller/GenController.java
@@ -0,0 +1,217 @@
+package org.dromara.gen.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IoUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.gen.domain.GenTable;
+import org.dromara.gen.domain.GenTableColumn;
+import org.dromara.gen.service.IGenTableService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/gen")
+public class GenController extends BaseController {
+
+ private final IGenTableService genTableService;
+
+ /**
+ * 鏌ヨ浠g爜鐢熸垚鍒楄〃
+ */
+ @SaCheckPermission("tool:gen:list")
+ @GetMapping("/list")
+ public TableDataInfo<GenTable> genList(GenTable genTable, PageQuery pageQuery) {
+ return genTableService.selectPageGenTableList(genTable, pageQuery);
+ }
+
+ /**
+ * 淇敼浠g爜鐢熸垚涓氬姟
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:query")
+ @GetMapping(value = "/{tableId}")
+ public R<Map<String, Object>> getInfo(@PathVariable Long tableId) {
+ GenTable table = genTableService.selectGenTableById(tableId);
+ List<GenTable> tables = genTableService.selectGenTableAll();
+ List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
+ Map<String, Object> map = new HashMap<>();
+ map.put("info", table);
+ map.put("rows", list);
+ map.put("tables", tables);
+ return R.ok(map);
+ }
+
+ /**
+ * 鏌ヨ鏁版嵁搴撳垪琛�
+ */
+ @SaCheckPermission("tool:gen:list")
+ @GetMapping("/db/list")
+ public TableDataInfo<GenTable> dataList(GenTable genTable, PageQuery pageQuery) {
+ return genTableService.selectPageDbTableList(genTable, pageQuery);
+ }
+
+ /**
+ * 鏌ヨ鏁版嵁琛ㄥ瓧娈靛垪琛�
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:list")
+ @GetMapping(value = "/column/{tableId}")
+ public TableDataInfo<GenTableColumn> columnList(@PathVariable("tableId") Long tableId) {
+ TableDataInfo<GenTableColumn> dataInfo = new TableDataInfo<>();
+ List<GenTableColumn> list = genTableService.selectGenTableColumnListByTableId(tableId);
+ dataInfo.setRows(list);
+ dataInfo.setTotal(list.size());
+ return dataInfo;
+ }
+
+ /**
+ * 瀵煎叆琛ㄧ粨鏋勶紙淇濆瓨锛�
+ *
+ * @param tables 琛ㄥ悕涓�
+ */
+ @SaCheckPermission("tool:gen:import")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.IMPORT)
+ @PostMapping("/importTable")
+ public R<Void> importTableSave(String tables, String dataName) {
+ String[] tableNames = Convert.toStrArray(tables);
+ // 鏌ヨ琛ㄤ俊鎭�
+ List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames, dataName);
+ genTableService.importGenTable(tableList, dataName);
+ return R.ok();
+ }
+
+ /**
+ * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+ */
+ @SaCheckPermission("tool:gen:edit")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> editSave(@Validated @RequestBody GenTable genTable) {
+ genTableService.validateEdit(genTable);
+ genTableService.updateGenTable(genTable);
+ return R.ok();
+ }
+
+ /**
+ * 鍒犻櫎浠g爜鐢熸垚
+ *
+ * @param tableIds 琛↖D涓�
+ */
+ @SaCheckPermission("tool:gen:remove")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{tableIds}")
+ public R<Void> remove(@PathVariable Long[] tableIds) {
+ genTableService.deleteGenTableByIds(tableIds);
+ return R.ok();
+ }
+
+ /**
+ * 棰勮浠g爜
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:preview")
+ @GetMapping("/preview/{tableId}")
+ public R<Map<String, String>> preview(@PathVariable("tableId") Long tableId) throws IOException {
+ Map<String, String> dataMap = genTableService.previewCode(tableId);
+ return R.ok(dataMap);
+ }
+
+ /**
+ * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:code")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+ @GetMapping("/download/{tableId}")
+ public void download(HttpServletResponse response, @PathVariable("tableId") Long tableId) throws IOException {
+ byte[] data = genTableService.downloadCode(tableId);
+ genCode(response, data);
+ }
+
+ /**
+ * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:code")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+ @GetMapping("/genCode/{tableId}")
+ public R<Void> genCode(@PathVariable("tableId") Long tableId) {
+ genTableService.generatorCode(tableId);
+ return R.ok();
+ }
+
+ /**
+ * 鍚屾鏁版嵁搴�
+ *
+ * @param tableId 琛↖D
+ */
+ @SaCheckPermission("tool:gen:edit")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+ @GetMapping("/synchDb/{tableId}")
+ public R<Void> synchDb(@PathVariable("tableId") Long tableId) {
+ genTableService.synchDb(tableId);
+ return R.ok();
+ }
+
+ /**
+ * 鎵归噺鐢熸垚浠g爜
+ *
+ * @param tableIdStr 琛↖D涓�
+ */
+ @SaCheckPermission("tool:gen:code")
+ @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.GENCODE)
+ @GetMapping("/batchGenCode")
+ public void batchGenCode(HttpServletResponse response, String tableIdStr) throws IOException {
+ String[] tableIds = Convert.toStrArray(tableIdStr);
+ byte[] data = genTableService.downloadCode(tableIds);
+ genCode(response, data);
+ }
+
+ /**
+ * 鐢熸垚zip鏂囦欢
+ */
+ private void genCode(HttpServletResponse response, byte[] data) throws IOException {
+ response.reset();
+ response.addHeader("Access-Control-Allow-Origin", "*");
+ response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+ response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
+ response.addHeader("Content-Length", "" + data.length);
+ response.setContentType("application/octet-stream; charset=UTF-8");
+ IoUtil.write(response.getOutputStream(), false, data);
+ }
+
+ /**
+ * 鏌ヨ鏁版嵁婧愬悕绉板垪琛�
+ */
+ @SaCheckPermission("tool:gen:list")
+ @GetMapping(value = "/getDataNames")
+ public R<Object> getCurrentDataSourceNameList(){
+ return R.ok(DataBaseHelper.getDataSourceNameList());
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java
new file mode 100644
index 0000000..19f94b0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTable.java
@@ -0,0 +1,196 @@
+package org.dromara.gen.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.gen.constant.GenConstants;
+
+import java.util.List;
+
+/**
+ * 涓氬姟琛� gen_table
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table")
+public class GenTable extends BaseEntity {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId(value = "table_id")
+ private Long tableId;
+
+ /**
+ * 鏁版嵁婧愬悕绉�
+ */
+ @NotBlank(message = "鏁版嵁婧愬悕绉颁笉鑳戒负绌�")
+ private String dataName;
+
+ /**
+ * 琛ㄥ悕绉�
+ */
+ @NotBlank(message = "琛ㄥ悕绉颁笉鑳戒负绌�")
+ private String tableName;
+
+ /**
+ * 琛ㄦ弿杩�
+ */
+ @NotBlank(message = "琛ㄦ弿杩颁笉鑳戒负绌�")
+ private String tableComment;
+
+ /**
+ * 鍏宠仈鐖惰〃鐨勮〃鍚�
+ */
+ private String subTableName;
+
+ /**
+ * 鏈〃鍏宠仈鐖惰〃鐨勫閿悕
+ */
+ private String subTableFkName;
+
+ /**
+ * 瀹炰綋绫诲悕绉�(棣栧瓧姣嶅ぇ鍐�)
+ */
+ @NotBlank(message = "瀹炰綋绫诲悕绉颁笉鑳戒负绌�")
+ private String className;
+
+ /**
+ * 浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔 sub涓诲瓙琛ㄦ搷浣滐級
+ */
+ private String tplCategory;
+
+ /**
+ * 鐢熸垚鍖呰矾寰�
+ */
+ @NotBlank(message = "鐢熸垚鍖呰矾寰勪笉鑳戒负绌�")
+ private String packageName;
+
+ /**
+ * 鐢熸垚妯″潡鍚�
+ */
+ @NotBlank(message = "鐢熸垚妯″潡鍚嶄笉鑳戒负绌�")
+ private String moduleName;
+
+ /**
+ * 鐢熸垚涓氬姟鍚�
+ */
+ @NotBlank(message = "鐢熸垚涓氬姟鍚嶄笉鑳戒负绌�")
+ private String businessName;
+
+ /**
+ * 鐢熸垚鍔熻兘鍚�
+ */
+ @NotBlank(message = "鐢熸垚鍔熻兘鍚嶄笉鑳戒负绌�")
+ private String functionName;
+
+ /**
+ * 鐢熸垚浣滆��
+ */
+ @NotBlank(message = "浣滆�呬笉鑳戒负绌�")
+ private String functionAuthor;
+
+ /**
+ * 鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級
+ */
+ private String genType;
+
+ /**
+ * 鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級
+ */
+ @TableField(updateStrategy = FieldStrategy.NOT_EMPTY)
+ private String genPath;
+
+ /**
+ * 涓婚敭淇℃伅
+ */
+ @TableField(exist = false)
+ private GenTableColumn pkColumn;
+
+ /**
+ * 琛ㄥ垪淇℃伅
+ */
+ @Valid
+ @TableField(exist = false)
+ private List<GenTableColumn> columns;
+
+ /**
+ * 鍏跺畠鐢熸垚閫夐」
+ */
+ private String options;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鏍戠紪鐮佸瓧娈�
+ */
+ @TableField(exist = false)
+ private String treeCode;
+
+ /**
+ * 鏍戠埗缂栫爜瀛楁
+ */
+ @TableField(exist = false)
+ private String treeParentCode;
+
+ /**
+ * 鏍戝悕绉板瓧娈�
+ */
+ @TableField(exist = false)
+ private String treeName;
+
+ /*
+ * 鑿滃崟id鍒楄〃
+ */
+ @TableField(exist = false)
+ private List<Long> menuIds;
+
+ /**
+ * 涓婄骇鑿滃崟ID瀛楁
+ */
+ @TableField(exist = false)
+ private String parentMenuId;
+
+ /**
+ * 涓婄骇鑿滃崟鍚嶇О瀛楁
+ */
+ @TableField(exist = false)
+ private String parentMenuName;
+
+ public boolean isTree() {
+ return isTree(this.tplCategory);
+ }
+
+ public static boolean isTree(String tplCategory) {
+ return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
+ }
+
+ public boolean isCrud() {
+ return isCrud(this.tplCategory);
+ }
+
+ public static boolean isCrud(String tplCategory) {
+ return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
+ }
+
+ public boolean isSuperColumn(String javaField) {
+ return isSuperColumn(this.tplCategory, javaField);
+ }
+
+ public static boolean isSuperColumn(String tplCategory, String javaField) {
+ return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java
new file mode 100644
index 0000000..b3fe7c0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/domain/GenTableColumn.java
@@ -0,0 +1,222 @@
+package org.dromara.gen.domain;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.apache.ibatis.type.JdbcType;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 浠g爜鐢熸垚涓氬姟瀛楁琛� gen_table_column
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("gen_table_column")
+public class GenTableColumn extends BaseEntity {
+
+ /**
+ * 缂栧彿
+ */
+ @TableId(value = "column_id")
+ private Long columnId;
+
+ /**
+ * 褰掑睘琛ㄧ紪鍙�
+ */
+ private Long tableId;
+
+ /**
+ * 鍒楀悕绉�
+ */
+ private String columnName;
+
+ /**
+ * 鍒楁弿杩�
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String columnComment;
+
+ /**
+ * 鍒楃被鍨�
+ */
+ private String columnType;
+
+ /**
+ * JAVA绫诲瀷
+ */
+ private String javaType;
+
+ /**
+ * JAVA瀛楁鍚�
+ */
+ @NotBlank(message = "Java灞炴�т笉鑳戒负绌�")
+ private String javaField;
+
+ /**
+ * 鏄惁涓婚敭锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isPk;
+
+ /**
+ * 鏄惁鑷锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isIncrement;
+
+ /**
+ * 鏄惁蹇呭~锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isRequired;
+
+ /**
+ * 鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isInsert;
+
+ /**
+ * 鏄惁缂栬緫瀛楁锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isEdit;
+
+ /**
+ * 鏄惁鍒楄〃瀛楁锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isList;
+
+ /**
+ * 鏄惁鏌ヨ瀛楁锛�1鏄級
+ */
+ @TableField(updateStrategy = FieldStrategy.IGNORED, jdbcType = JdbcType.VARCHAR)
+ private String isQuery;
+
+ /**
+ * 鏌ヨ鏂瑰紡锛圗Q绛変簬銆丯E涓嶇瓑浜庛�丟T澶т簬銆丩T灏忎簬銆丩IKE妯$硦銆丅ETWEEN鑼冨洿锛�
+ */
+ private String queryType;
+
+ /**
+ * 鏄剧ず绫诲瀷锛坕nput鏂囨湰妗嗐�乼extarea鏂囨湰鍩熴�乻elect涓嬫媺妗嗐�乧heckbox澶嶉�夋銆乺adio鍗曢�夋銆乨atetime鏃ユ湡鎺т欢銆乮mage鍥剧墖涓婁紶鎺т欢銆乽pload鏂囦欢涓婁紶鎺т欢銆乪ditor瀵屾枃鏈帶浠讹級
+ */
+ private String htmlType;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ private String dictType;
+
+ /**
+ * 鎺掑簭
+ */
+ private Integer sort;
+
+ public String getCapJavaField() {
+ return StringUtils.capitalize(javaField);
+ }
+
+ public boolean isPk() {
+ return isPk(this.isPk);
+ }
+
+ public boolean isPk(String isPk) {
+ return isPk != null && StringUtils.equals("1", isPk);
+ }
+
+ public boolean isIncrement() {
+ return isIncrement(this.isIncrement);
+ }
+
+ public boolean isIncrement(String isIncrement) {
+ return isIncrement != null && StringUtils.equals("1", isIncrement);
+ }
+
+ public boolean isRequired() {
+ return isRequired(this.isRequired);
+ }
+
+ public boolean isRequired(String isRequired) {
+ return isRequired != null && StringUtils.equals("1", isRequired);
+ }
+
+ public boolean isInsert() {
+ return isInsert(this.isInsert);
+ }
+
+ public boolean isInsert(String isInsert) {
+ return isInsert != null && StringUtils.equals("1", isInsert);
+ }
+
+ public boolean isEdit() {
+ return isInsert(this.isEdit);
+ }
+
+ public boolean isEdit(String isEdit) {
+ return isEdit != null && StringUtils.equals("1", isEdit);
+ }
+
+ public boolean isList() {
+ return isList(this.isList);
+ }
+
+ public boolean isList(String isList) {
+ return isList != null && StringUtils.equals("1", isList);
+ }
+
+ public boolean isQuery() {
+ return isQuery(this.isQuery);
+ }
+
+ public boolean isQuery(String isQuery) {
+ return isQuery != null && StringUtils.equals("1", isQuery);
+ }
+
+ public boolean isSuperColumn() {
+ return isSuperColumn(this.javaField);
+ }
+
+ public static boolean isSuperColumn(String javaField) {
+ return StringUtils.equalsAnyIgnoreCase(javaField,
+ // BaseEntity
+ "createBy", "createTime", "updateBy", "updateTime",
+ // TreeEntity
+ "parentName", "parentId");
+ }
+
+ public boolean isUsableColumn() {
+ return isUsableColumn(javaField);
+ }
+
+ public static boolean isUsableColumn(String javaField) {
+ // isSuperColumn()涓殑鍚嶅崟鐢ㄤ簬閬垮厤鐢熸垚澶氫綑Domain灞炴�э紝鑻ユ煇浜涘睘鎬у湪鐢熸垚椤甸潰鏃堕渶瑕佺敤鍒颁笉鑳藉拷鐣ワ紝鍒欐斁鍦ㄦ澶勭櫧鍚嶅崟
+ return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+ }
+
+ public String readConverterExp() {
+ String remarks = StringUtils.substringBetween(this.columnComment, "锛�", "锛�");
+ StringBuffer sb = new StringBuffer();
+ if (StringUtils.isNotEmpty(remarks)) {
+ for (String value : remarks.split(" ")) {
+ if (StringUtils.isNotEmpty(value)) {
+ Object startStr = value.subSequence(0, 1);
+ String endStr = value.substring(1);
+ sb.append(StringUtils.EMPTY).append(startStr).append("=").append(endStr).append(StringUtils.SEPARATOR);
+ }
+ }
+ return sb.deleteCharAt(sb.length() - 1).toString();
+ } else {
+ return this.columnComment;
+ }
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java
new file mode 100644
index 0000000..501f0c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableColumnMapper.java
@@ -0,0 +1,28 @@
+package org.dromara.gen.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.gen.domain.GenTableColumn;
+
+import java.util.List;
+
+/**
+ * 涓氬姟瀛楁 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
+public interface GenTableColumnMapper extends BaseMapperPlus<GenTableColumn, GenTableColumn> {
+ /**
+ * 鏍规嵁琛ㄥ悕绉版煡璇㈠垪淇℃伅
+ *
+ * @param tableName 琛ㄥ悕绉�
+ * @param dataName 鏁版嵁婧愬悕绉�
+ * @return 鍒椾俊鎭�
+ */
+ @DS("#dataName")
+ List<GenTableColumn> selectDbTableColumnsByName(@Param("tableName") String tableName, String dataName);
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java
new file mode 100644
index 0000000..2567c89
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/mapper/GenTableMapper.java
@@ -0,0 +1,61 @@
+package org.dromara.gen.mapper;
+
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.annotation.InterceptorIgnore;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.gen.domain.GenTable;
+
+import java.util.List;
+
+/**
+ * 涓氬姟 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+@InterceptorIgnore(dataPermission = "true", tenantLine = "true")
+public interface GenTableMapper extends BaseMapperPlus<GenTable, GenTable> {
+
+ /**
+ * 鏌ヨ鎹簱鍒楄〃
+ *
+ * @param genTable 鏌ヨ鏉′欢
+ * @return 鏁版嵁搴撹〃闆嗗悎
+ */
+ Page<GenTable> selectPageDbTableList(@Param("page") Page<GenTable> page, @Param("genTable") GenTable genTable);
+
+ /**
+ * 鏌ヨ鎹簱鍒楄〃
+ *
+ * @param tableNames 琛ㄥ悕绉扮粍
+ * @return 鏁版嵁搴撹〃闆嗗悎
+ */
+ List<GenTable> selectDbTableListByNames(String[] tableNames);
+
+ /**
+ * 鏌ヨ鎵�鏈夎〃淇℃伅
+ *
+ * @return 琛ㄤ俊鎭泦鍚�
+ */
+ List<GenTable> selectGenTableAll();
+
+ /**
+ * 鏌ヨ琛↖D涓氬姟淇℃伅
+ *
+ * @param id 涓氬姟ID
+ * @return 涓氬姟淇℃伅
+ */
+ GenTable selectGenTableById(Long id);
+
+ /**
+ * 鏌ヨ琛ㄥ悕绉颁笟鍔′俊鎭�
+ *
+ * @param tableName 琛ㄥ悕绉�
+ * @return 涓氬姟淇℃伅
+ */
+ GenTable selectGenTableByName(String tableName);
+
+ @DS("")
+ List<String> selectTableNameList(String dataName);
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java
new file mode 100644
index 0000000..9031760
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/GenTableServiceImpl.java
@@ -0,0 +1,466 @@
+package org.dromara.gen.service;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.lang.Dict;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.dynamic.datasource.annotation.DSTransactional;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.incrementer.IdentifierGenerator;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.gen.constant.GenConstants;
+import org.dromara.gen.domain.GenTable;
+import org.dromara.gen.domain.GenTableColumn;
+import org.dromara.gen.mapper.GenTableColumnMapper;
+import org.dromara.gen.mapper.GenTableMapper;
+import org.dromara.gen.util.GenUtils;
+import org.dromara.gen.util.VelocityInitializer;
+import org.dromara.gen.util.VelocityUtils;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+/**
+ * 涓氬姟 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class GenTableServiceImpl implements IGenTableService {
+
+ private final GenTableMapper baseMapper;
+ private final GenTableColumnMapper genTableColumnMapper;
+ private final IdentifierGenerator identifierGenerator;
+
+ /**
+ * 鏌ヨ涓氬姟瀛楁鍒楄〃
+ *
+ * @param tableId 涓氬姟瀛楁缂栧彿
+ * @return 涓氬姟瀛楁闆嗗悎
+ */
+ @Override
+ public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId) {
+ return genTableColumnMapper.selectList(new LambdaQueryWrapper<GenTableColumn>()
+ .eq(GenTableColumn::getTableId, tableId)
+ .orderByAsc(GenTableColumn::getSort));
+ }
+
+ /**
+ * 鏌ヨ涓氬姟淇℃伅
+ *
+ * @param id 涓氬姟ID
+ * @return 涓氬姟淇℃伅
+ */
+ @Override
+ public GenTable selectGenTableById(Long id) {
+ GenTable genTable = baseMapper.selectGenTableById(id);
+ setTableFromOptions(genTable);
+ return genTable;
+ }
+
+ @Override
+ public TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery) {
+ Page<GenTable> page = baseMapper.selectPage(pageQuery.build(), this.buildGenTableQueryWrapper(genTable));
+ return TableDataInfo.build(page);
+ }
+
+ private QueryWrapper<GenTable> buildGenTableQueryWrapper(GenTable genTable) {
+ Map<String, Object> params = genTable.getParams();
+ QueryWrapper<GenTable> wrapper = Wrappers.query();
+ wrapper
+ .eq(StringUtils.isNotEmpty(genTable.getDataName()),"data_name", genTable.getDataName())
+ .like(StringUtils.isNotBlank(genTable.getTableName()), "lower(table_name)", StringUtils.lowerCase(genTable.getTableName()))
+ .like(StringUtils.isNotBlank(genTable.getTableComment()), "lower(table_comment)", StringUtils.lowerCase(genTable.getTableComment()))
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ "create_time", params.get("beginTime"), params.get("endTime"));
+ return wrapper;
+ }
+
+ @DS("#genTable.dataName")
+ @Override
+ public TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery) {
+ genTable.getParams().put("genTableNames",baseMapper.selectTableNameList(genTable.getDataName()));
+ Page<GenTable> page = baseMapper.selectPageDbTableList(pageQuery.build(), genTable);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏌ヨ鎹簱鍒楄〃
+ *
+ * @param tableNames 琛ㄥ悕绉扮粍
+ * @param dataName 鏁版嵁婧愬悕绉�
+ * @return 鏁版嵁搴撹〃闆嗗悎
+ */
+ @DS("#dataName")
+ @Override
+ public List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName) {
+ return baseMapper.selectDbTableListByNames(tableNames);
+ }
+
+ /**
+ * 鏌ヨ鎵�鏈夎〃淇℃伅
+ *
+ * @return 琛ㄤ俊鎭泦鍚�
+ */
+ @Override
+ public List<GenTable> selectGenTableAll() {
+ return baseMapper.selectGenTableAll();
+ }
+
+ /**
+ * 淇敼涓氬姟
+ *
+ * @param genTable 涓氬姟淇℃伅
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void updateGenTable(GenTable genTable) {
+ String options = JsonUtils.toJsonString(genTable.getParams());
+ genTable.setOptions(options);
+ int row = baseMapper.updateById(genTable);
+ if (row > 0) {
+ for (GenTableColumn cenTableColumn : genTable.getColumns()) {
+ genTableColumnMapper.updateById(cenTableColumn);
+ }
+ }
+ }
+
+ /**
+ * 鍒犻櫎涓氬姟瀵硅薄
+ *
+ * @param tableIds 闇�瑕佸垹闄ょ殑鏁版嵁ID
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public void deleteGenTableByIds(Long[] tableIds) {
+ List<Long> ids = Arrays.asList(tableIds);
+ baseMapper.deleteBatchIds(ids);
+ genTableColumnMapper.delete(new LambdaQueryWrapper<GenTableColumn>().in(GenTableColumn::getTableId, ids));
+ }
+
+ /**
+ * 瀵煎叆琛ㄧ粨鏋�
+ *
+ * @param tableList 瀵煎叆琛ㄥ垪琛�
+ * @param dataName 鏁版嵁婧愬悕绉�
+ */
+ @DSTransactional
+ @Override
+ public void importGenTable(List<GenTable> tableList, String dataName) {
+ Long operId = LoginHelper.getUserId();
+ try {
+ for (GenTable table : tableList) {
+ String tableName = table.getTableName();
+ GenUtils.initTable(table, operId);
+ table.setDataName(dataName);
+ int row = baseMapper.insert(table);
+ if (row > 0) {
+ // 淇濆瓨鍒椾俊鎭�
+ List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName, dataName);
+ List<GenTableColumn> saveColumns = new ArrayList<>();
+ for (GenTableColumn column : genTableColumns) {
+ GenUtils.initColumnField(column, table);
+ saveColumns.add(column);
+ }
+ if (CollUtil.isNotEmpty(saveColumns)) {
+ genTableColumnMapper.insertBatch(saveColumns);
+ }
+ }
+ }
+ } catch (Exception e) {
+ throw new ServiceException("瀵煎叆澶辫触锛�" + e.getMessage());
+ }
+ }
+
+ /**
+ * 棰勮浠g爜
+ *
+ * @param tableId 琛ㄧ紪鍙�
+ * @return 棰勮鏁版嵁鍒楄〃
+ */
+ @Override
+ public Map<String, String> previewCode(Long tableId) {
+ Map<String, String> dataMap = new LinkedHashMap<>();
+ // 鏌ヨ琛ㄤ俊鎭�
+ GenTable table = baseMapper.selectGenTableById(tableId);
+ List<Long> menuIds = new ArrayList<>();
+ for (int i = 0; i < 6; i++) {
+ menuIds.add(identifierGenerator.nextId(null).longValue());
+ }
+ table.setMenuIds(menuIds);
+ // 璁剧疆涓婚敭鍒椾俊鎭�
+ setPkColumn(table);
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 鑾峰彇妯℃澘鍒楄〃
+ List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates) {
+ // 娓叉煋妯℃澘
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ dataMap.put(template, sw.toString());
+ }
+ return dataMap;
+ }
+
+ /**
+ * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+ *
+ * @param tableId 琛ㄥ悕绉�
+ * @return 鏁版嵁
+ */
+ @Override
+ public byte[] downloadCode(Long tableId) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(outputStream);
+ generatorCode(tableId, zip);
+ IoUtil.close(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+ *
+ * @param tableId 琛ㄥ悕绉�
+ */
+ @Override
+ public void generatorCode(Long tableId) {
+ // 鏌ヨ琛ㄤ俊鎭�
+ GenTable table = baseMapper.selectGenTableById(tableId);
+ // 璁剧疆涓婚敭鍒椾俊鎭�
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 鑾峰彇妯℃澘鍒楄〃
+ List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates) {
+ if (!StringUtils.containsAny(template, "sql.vm", "api.ts.vm", "types.ts.vm", "index.vue.vm", "index-tree.vue.vm")) {
+ // 娓叉煋妯℃澘
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ try {
+ String path = getGenPath(table, template);
+ FileUtils.writeUtf8String(sw.toString(), path);
+ } catch (Exception e) {
+ throw new ServiceException("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName());
+ }
+ }
+ }
+ }
+
+ /**
+ * 鍚屾鏁版嵁搴�
+ *
+ * @param tableId 琛ㄥ悕绉�
+ */
+ @DSTransactional
+ @Override
+ public void synchDb(Long tableId) {
+ GenTable table = baseMapper.selectGenTableById(tableId);
+ List<GenTableColumn> tableColumns = table.getColumns();
+ Map<String, GenTableColumn> tableColumnMap = StreamUtils.toIdentityMap(tableColumns, GenTableColumn::getColumnName);
+
+ List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(table.getTableName(), table.getDataName());
+ if (CollUtil.isEmpty(dbTableColumns)) {
+ throw new ServiceException("鍚屾鏁版嵁澶辫触锛屽師琛ㄧ粨鏋勪笉瀛樺湪");
+ }
+ List<String> dbTableColumnNames = StreamUtils.toList(dbTableColumns, GenTableColumn::getColumnName);
+
+ List<GenTableColumn> saveColumns = new ArrayList<>();
+ dbTableColumns.forEach(column -> {
+ GenUtils.initColumnField(column, table);
+ if (tableColumnMap.containsKey(column.getColumnName())) {
+ GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
+ column.setColumnId(prevColumn.getColumnId());
+ if (column.isList()) {
+ // 濡傛灉鏄垪琛紝缁х画淇濈暀鏌ヨ鏂瑰紡/瀛楀吀绫诲瀷閫夐」
+ column.setDictType(prevColumn.getDictType());
+ column.setQueryType(prevColumn.getQueryType());
+ }
+ if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
+ && (column.isInsert() || column.isEdit())
+ && ((column.isUsableColumn()) || (!column.isSuperColumn()))) {
+ // 濡傛灉鏄�(鏂板/淇敼&闈炰富閿�/闈炲拷鐣ュ強鐖跺睘鎬�)锛岀户缁繚鐣欏繀濉�/鏄剧ず绫诲瀷閫夐」
+ column.setIsRequired(prevColumn.getIsRequired());
+ column.setHtmlType(prevColumn.getHtmlType());
+ }
+ }
+ saveColumns.add(column);
+ });
+ if (CollUtil.isNotEmpty(saveColumns)) {
+ genTableColumnMapper.insertOrUpdateBatch(saveColumns);
+ }
+ List<GenTableColumn> delColumns = StreamUtils.filter(tableColumns, column -> !dbTableColumnNames.contains(column.getColumnName()));
+ if (CollUtil.isNotEmpty(delColumns)) {
+ List<Long> ids = StreamUtils.toList(delColumns, GenTableColumn::getColumnId);
+ if (CollUtil.isNotEmpty(ids)) {
+ genTableColumnMapper.deleteBatchIds(ids);
+ }
+ }
+ }
+
+ /**
+ * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+ *
+ * @param tableIds 琛↖D鏁扮粍
+ * @return 鏁版嵁
+ */
+ @Override
+ public byte[] downloadCode(String[] tableIds) {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ ZipOutputStream zip = new ZipOutputStream(outputStream);
+ for (String tableId : tableIds) {
+ generatorCode(Long.parseLong(tableId), zip);
+ }
+ IoUtil.close(zip);
+ return outputStream.toByteArray();
+ }
+
+ /**
+ * 鏌ヨ琛ㄤ俊鎭苟鐢熸垚浠g爜
+ */
+ private void generatorCode(Long tableId, ZipOutputStream zip) {
+ // 鏌ヨ琛ㄤ俊鎭�
+ GenTable table = baseMapper.selectGenTableById(tableId);
+ List<Long> menuIds = new ArrayList<>();
+ for (int i = 0; i < 6; i++) {
+ menuIds.add(identifierGenerator.nextId(null).longValue());
+ }
+ table.setMenuIds(menuIds);
+ // 璁剧疆涓婚敭鍒椾俊鎭�
+ setPkColumn(table);
+
+ VelocityInitializer.initVelocity();
+
+ VelocityContext context = VelocityUtils.prepareContext(table);
+
+ // 鑾峰彇妯℃澘鍒楄〃
+ List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory());
+ for (String template : templates) {
+ // 娓叉煋妯℃澘
+ StringWriter sw = new StringWriter();
+ Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+ tpl.merge(context, sw);
+ try {
+ // 娣诲姞鍒皕ip
+ zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+ IoUtil.write(zip, StandardCharsets.UTF_8, false, sw.toString());
+ IoUtil.close(sw);
+ zip.flush();
+ zip.closeEntry();
+ } catch (IOException e) {
+ log.error("娓叉煋妯℃澘澶辫触锛岃〃鍚嶏細" + table.getTableName(), e);
+ }
+ }
+ }
+
+ /**
+ * 淇敼淇濆瓨鍙傛暟鏍¢獙
+ *
+ * @param genTable 涓氬姟淇℃伅
+ */
+ @Override
+ public void validateEdit(GenTable genTable) {
+ if (GenConstants.TPL_TREE.equals(genTable.getTplCategory())) {
+ String options = JsonUtils.toJsonString(genTable.getParams());
+ Dict paramsObj = JsonUtils.parseMap(options);
+ if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_CODE))) {
+ throw new ServiceException("鏍戠紪鐮佸瓧娈典笉鑳戒负绌�");
+ } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_PARENT_CODE))) {
+ throw new ServiceException("鏍戠埗缂栫爜瀛楁涓嶈兘涓虹┖");
+ } else if (StringUtils.isEmpty(paramsObj.getStr(GenConstants.TREE_NAME))) {
+ throw new ServiceException("鏍戝悕绉板瓧娈典笉鑳戒负绌�");
+ }
+ }
+ }
+
+ /**
+ * 璁剧疆涓婚敭鍒椾俊鎭�
+ *
+ * @param table 涓氬姟琛ㄤ俊鎭�
+ */
+ public void setPkColumn(GenTable table) {
+ for (GenTableColumn column : table.getColumns()) {
+ if (column.isPk()) {
+ table.setPkColumn(column);
+ break;
+ }
+ }
+ if (ObjectUtil.isNull(table.getPkColumn())) {
+ table.setPkColumn(table.getColumns().get(0));
+ }
+
+ }
+
+ /**
+ * 璁剧疆浠g爜鐢熸垚鍏朵粬閫夐」鍊�
+ *
+ * @param genTable 璁剧疆鍚庣殑鐢熸垚瀵硅薄
+ */
+ public void setTableFromOptions(GenTable genTable) {
+ Dict paramsObj = JsonUtils.parseMap(genTable.getOptions());
+ if (ObjectUtil.isNotNull(paramsObj)) {
+ String treeCode = paramsObj.getStr(GenConstants.TREE_CODE);
+ String treeParentCode = paramsObj.getStr(GenConstants.TREE_PARENT_CODE);
+ String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
+ String parentMenuId = paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+ String parentMenuName = paramsObj.getStr(GenConstants.PARENT_MENU_NAME);
+
+ genTable.setTreeCode(treeCode);
+ genTable.setTreeParentCode(treeParentCode);
+ genTable.setTreeName(treeName);
+ genTable.setParentMenuId(parentMenuId);
+ genTable.setParentMenuName(parentMenuName);
+ }
+ }
+
+ /**
+ * 鑾峰彇浠g爜鐢熸垚鍦板潃
+ *
+ * @param table 涓氬姟琛ㄤ俊鎭�
+ * @param template 妯℃澘鏂囦欢璺緞
+ * @return 鐢熸垚鍦板潃
+ */
+ public static String getGenPath(GenTable table, String template) {
+ String genPath = table.getGenPath();
+ if (StringUtils.equals(genPath, "/")) {
+ return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+ }
+ return genPath + File.separator + VelocityUtils.getFileName(template, table);
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java
new file mode 100644
index 0000000..ea23c53
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/service/IGenTableService.java
@@ -0,0 +1,132 @@
+package org.dromara.gen.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.gen.domain.GenTable;
+import org.dromara.gen.domain.GenTableColumn;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 涓氬姟 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface IGenTableService {
+
+ /**
+ * 鏌ヨ涓氬姟瀛楁鍒楄〃
+ *
+ * @param tableId 涓氬姟瀛楁缂栧彿
+ * @return 涓氬姟瀛楁闆嗗悎
+ */
+ List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+ /**
+ * 鏌ヨ涓氬姟鍒楄〃
+ *
+ * @param genTable 涓氬姟淇℃伅
+ * @return 涓氬姟闆嗗悎
+ */
+ TableDataInfo<GenTable> selectPageGenTableList(GenTable genTable, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ鎹簱鍒楄〃
+ *
+ * @param genTable 涓氬姟淇℃伅
+ * @return 鏁版嵁搴撹〃闆嗗悎
+ */
+ TableDataInfo<GenTable> selectPageDbTableList(GenTable genTable, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ鎹簱鍒楄〃
+ *
+ * @param tableNames 琛ㄥ悕绉扮粍
+ * @param dataName 鏁版嵁婧愬悕绉�
+ * @return 鏁版嵁搴撹〃闆嗗悎
+ */
+ List<GenTable> selectDbTableListByNames(String[] tableNames, String dataName);
+
+ /**
+ * 鏌ヨ鎵�鏈夎〃淇℃伅
+ *
+ * @return 琛ㄤ俊鎭泦鍚�
+ */
+ List<GenTable> selectGenTableAll();
+
+ /**
+ * 鏌ヨ涓氬姟淇℃伅
+ *
+ * @param id 涓氬姟ID
+ * @return 涓氬姟淇℃伅
+ */
+ GenTable selectGenTableById(Long id);
+
+ /**
+ * 淇敼涓氬姟
+ *
+ * @param genTable 涓氬姟淇℃伅
+ */
+ void updateGenTable(GenTable genTable);
+
+ /**
+ * 鍒犻櫎涓氬姟淇℃伅
+ *
+ * @param tableIds 闇�瑕佸垹闄ょ殑琛ㄦ暟鎹甀D
+ */
+ void deleteGenTableByIds(Long[] tableIds);
+
+ /**
+ * 瀵煎叆琛ㄧ粨鏋�
+ *
+ * @param tableList 瀵煎叆琛ㄥ垪琛�
+ * @param dataName 鏁版嵁婧愬悕绉�
+ */
+ void importGenTable(List<GenTable> tableList, String dataName);
+
+ /**
+ * 棰勮浠g爜
+ *
+ * @param tableId 琛ㄧ紪鍙�
+ * @return 棰勮鏁版嵁鍒楄〃
+ */
+ Map<String, String> previewCode(Long tableId);
+
+ /**
+ * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+ *
+ * @param tableId 琛ㄥ悕绉�
+ * @return 鏁版嵁
+ */
+ byte[] downloadCode(Long tableId);
+
+ /**
+ * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+ *
+ * @param tableId 琛ㄥ悕绉�
+ */
+ void generatorCode(Long tableId);
+
+ /**
+ * 鍚屾鏁版嵁搴�
+ *
+ * @param tableId 琛ㄥ悕绉�
+ */
+ void synchDb(Long tableId);
+
+ /**
+ * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+ *
+ * @param tableIds 琛↖D鏁扮粍
+ * @return 鏁版嵁
+ */
+ byte[] downloadCode(String[] tableIds);
+
+ /**
+ * 淇敼淇濆瓨鍙傛暟鏍¢獙
+ *
+ * @param genTable 涓氬姟淇℃伅
+ */
+ void validateEdit(GenTable genTable);
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java
new file mode 100644
index 0000000..214b181
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/GenUtils.java
@@ -0,0 +1,231 @@
+package org.dromara.gen.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.RegExUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.gen.config.GenConfig;
+import org.dromara.gen.constant.GenConstants;
+import org.dromara.gen.domain.GenTable;
+import org.dromara.gen.domain.GenTableColumn;
+
+import java.util.Arrays;
+
+/**
+ * 浠g爜鐢熸垚鍣� 宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class GenUtils {
+
+ /**
+ * 鍒濆鍖栬〃淇℃伅
+ */
+ public static void initTable(GenTable genTable, Long operId) {
+ genTable.setClassName(convertClassName(genTable.getTableName()));
+ genTable.setPackageName(GenConfig.getPackageName());
+ genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
+ genTable.setBusinessName(getBusinessName(genTable.getTableName()));
+ genTable.setFunctionName(replaceText(genTable.getTableComment()));
+ genTable.setFunctionAuthor(GenConfig.getAuthor());
+ genTable.setCreateBy(operId);
+ }
+
+ /**
+ * 鍒濆鍖栧垪灞炴�у瓧娈�
+ */
+ public static void initColumnField(GenTableColumn column, GenTable table) {
+ String dataType = getDbType(column.getColumnType());
+ String columnName = column.getColumnName();
+ column.setTableId(table.getTableId());
+ column.setCreateBy(table.getCreateBy());
+ // 璁剧疆java瀛楁鍚�
+ column.setJavaField(StringUtils.toCamelCase(columnName));
+ // 璁剧疆榛樿绫诲瀷
+ column.setJavaType(GenConstants.TYPE_STRING);
+ column.setQueryType(GenConstants.QUERY_EQ);
+
+ if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType)) {
+ // 瀛楃涓查暱搴﹁秴杩�500璁剧疆涓烘枃鏈煙
+ Integer columnLength = getColumnLength(column.getColumnType());
+ String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
+ column.setHtmlType(htmlType);
+ } else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType)) {
+ column.setJavaType(GenConstants.TYPE_DATE);
+ column.setHtmlType(GenConstants.HTML_DATETIME);
+ } else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType)) {
+ column.setHtmlType(GenConstants.HTML_INPUT);
+
+ // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
+ String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), StringUtils.SEPARATOR);
+ if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0) {
+ column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
+ }
+ // 濡傛灉鏄暣褰�
+ else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10) {
+ column.setJavaType(GenConstants.TYPE_INTEGER);
+ }
+ // 闀挎暣褰�
+ else {
+ column.setJavaType(GenConstants.TYPE_LONG);
+ }
+ }
+
+ // BO瀵硅薄 榛樿鎻掑叆鍕鹃��
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_ADD, columnName) && !column.isPk()) {
+ column.setIsInsert(GenConstants.REQUIRE);
+ }
+ // BO瀵硅薄 榛樿缂栬緫鍕鹃��
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+ column.setIsEdit(GenConstants.REQUIRE);
+ }
+ // BO瀵硅薄 榛樿鏄惁蹇呭~鍕鹃��
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName)) {
+ column.setIsRequired(GenConstants.REQUIRE);
+ }
+ // VO瀵硅薄 榛樿杩斿洖鍕鹃��
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName)) {
+ column.setIsList(GenConstants.REQUIRE);
+ }
+ // BO瀵硅薄 榛樿鏌ヨ鍕鹃��
+ if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk()) {
+ column.setIsQuery(GenConstants.REQUIRE);
+ }
+
+ // 鏌ヨ瀛楁绫诲瀷
+ if (StringUtils.endsWithIgnoreCase(columnName, "name")) {
+ column.setQueryType(GenConstants.QUERY_LIKE);
+ }
+ // 鐘舵�佸瓧娈佃缃崟閫夋
+ if (StringUtils.endsWithIgnoreCase(columnName, "status")) {
+ column.setHtmlType(GenConstants.HTML_RADIO);
+ }
+ // 绫诲瀷&鎬у埆瀛楁璁剧疆涓嬫媺妗�
+ else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+ || StringUtils.endsWithIgnoreCase(columnName, "sex")) {
+ column.setHtmlType(GenConstants.HTML_SELECT);
+ }
+ // 鍥剧墖瀛楁璁剧疆鍥剧墖涓婁紶鎺т欢
+ else if (StringUtils.endsWithIgnoreCase(columnName, "image")) {
+ column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
+ }
+ // 鏂囦欢瀛楁璁剧疆鏂囦欢涓婁紶鎺т欢
+ else if (StringUtils.endsWithIgnoreCase(columnName, "file")) {
+ column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
+ }
+ // 鍐呭瀛楁璁剧疆瀵屾枃鏈帶浠�
+ else if (StringUtils.endsWithIgnoreCase(columnName, "content")) {
+ column.setHtmlType(GenConstants.HTML_EDITOR);
+ }
+ }
+
+ /**
+ * 鏍¢獙鏁扮粍鏄惁鍖呭惈鎸囧畾鍊�
+ *
+ * @param arr 鏁扮粍
+ * @param targetValue 鍊�
+ * @return 鏄惁鍖呭惈
+ */
+ public static boolean arraysContains(String[] arr, String targetValue) {
+ return Arrays.asList(arr).contains(targetValue);
+ }
+
+ /**
+ * 鑾峰彇妯″潡鍚�
+ *
+ * @param packageName 鍖呭悕
+ * @return 妯″潡鍚�
+ */
+ public static String getModuleName(String packageName) {
+ int lastIndex = packageName.lastIndexOf(".");
+ int nameLength = packageName.length();
+ return StringUtils.substring(packageName, lastIndex + 1, nameLength);
+ }
+
+ /**
+ * 鑾峰彇涓氬姟鍚�
+ *
+ * @param tableName 琛ㄥ悕
+ * @return 涓氬姟鍚�
+ */
+ public static String getBusinessName(String tableName) {
+ int firstIndex = tableName.indexOf("_");
+ int nameLength = tableName.length();
+ String businessName = StringUtils.substring(tableName, firstIndex + 1, nameLength);
+ businessName = StringUtils.toCamelCase(businessName);
+ return businessName;
+ }
+
+ /**
+ * 琛ㄥ悕杞崲鎴怞ava绫诲悕
+ *
+ * @param tableName 琛ㄥ悕绉�
+ * @return 绫诲悕
+ */
+ public static String convertClassName(String tableName) {
+ boolean autoRemovePre = GenConfig.getAutoRemovePre();
+ String tablePrefix = GenConfig.getTablePrefix();
+ if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix)) {
+ String[] searchList = StringUtils.split(tablePrefix, StringUtils.SEPARATOR);
+ tableName = replaceFirst(tableName, searchList);
+ }
+ return StringUtils.convertToCamelCase(tableName);
+ }
+
+ /**
+ * 鎵归噺鏇挎崲鍓嶇紑
+ *
+ * @param replacementm 鏇挎崲鍊�
+ * @param searchList 鏇挎崲鍒楄〃
+ */
+ public static String replaceFirst(String replacementm, String[] searchList) {
+ String text = replacementm;
+ for (String searchString : searchList) {
+ if (replacementm.startsWith(searchString)) {
+ text = replacementm.replaceFirst(searchString, StringUtils.EMPTY);
+ break;
+ }
+ }
+ return text;
+ }
+
+ /**
+ * 鍏抽敭瀛楁浛鎹�
+ *
+ * @param text 闇�瑕佽鏇挎崲鐨勫悕瀛�
+ * @return 鏇挎崲鍚庣殑鍚嶅瓧
+ */
+ public static String replaceText(String text) {
+ return RegExUtils.replaceAll(text, "(?:琛▅鑻ヤ緷)", "");
+ }
+
+ /**
+ * 鑾峰彇鏁版嵁搴撶被鍨嬪瓧娈�
+ *
+ * @param columnType 鍒楃被鍨�
+ * @return 鎴彇鍚庣殑鍒楃被鍨�
+ */
+ public static String getDbType(String columnType) {
+ if (StringUtils.indexOf(columnType, "(") > 0) {
+ return StringUtils.substringBefore(columnType, "(");
+ } else {
+ return columnType;
+ }
+ }
+
+ /**
+ * 鑾峰彇瀛楁闀垮害
+ *
+ * @param columnType 鍒楃被鍨�
+ * @return 鎴彇鍚庣殑鍒楃被鍨�
+ */
+ public static Integer getColumnLength(String columnType) {
+ if (StringUtils.indexOf(columnType, "(") > 0) {
+ String length = StringUtils.substringBetween(columnType, "(", ")");
+ return Integer.valueOf(length);
+ } else {
+ return 0;
+ }
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityInitializer.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityInitializer.java
new file mode 100644
index 0000000..68773b2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityInitializer.java
@@ -0,0 +1,35 @@
+package org.dromara.gen.util;
+
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.app.Velocity;
+import org.dromara.common.core.constant.Constants;
+
+import java.util.Properties;
+
+/**
+ * VelocityEngine宸ュ巶
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class VelocityInitializer {
+
+ /**
+ * 鍒濆鍖杤m鏂规硶
+ */
+ public static void initVelocity() {
+ Properties p = new Properties();
+ try {
+ // 鍔犺浇classpath鐩綍涓嬬殑vm鏂囦欢
+ p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+ // 瀹氫箟瀛楃闆�
+ p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+ // 鍒濆鍖朧elocity寮曟搸锛屾寚瀹氶厤缃甈roperties
+ Velocity.init(p);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java
new file mode 100644
index 0000000..bdb80e1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/java/org/dromara/gen/util/VelocityUtils.java
@@ -0,0 +1,336 @@
+package org.dromara.gen.util;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.Dict;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.velocity.VelocityContext;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.gen.constant.GenConstants;
+import org.dromara.gen.domain.GenTable;
+import org.dromara.gen.domain.GenTableColumn;
+
+import java.util.*;
+
+/**
+ * 妯℃澘澶勭悊宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public class VelocityUtils {
+
+ /**
+ * 椤圭洰绌洪棿璺緞
+ */
+ private static final String PROJECT_PATH = "main/java";
+
+ /**
+ * mybatis绌洪棿璺緞
+ */
+ private static final String MYBATIS_PATH = "main/resources/mapper";
+
+ /**
+ * 榛樿涓婄骇鑿滃崟锛岀郴缁熷伐鍏�
+ */
+ private static final String DEFAULT_PARENT_MENU_ID = "3";
+
+ /**
+ * 璁剧疆妯℃澘鍙橀噺淇℃伅
+ *
+ * @return 妯℃澘鍒楄〃
+ */
+ public static VelocityContext prepareContext(GenTable genTable) {
+ String moduleName = genTable.getModuleName();
+ String businessName = genTable.getBusinessName();
+ String packageName = genTable.getPackageName();
+ String tplCategory = genTable.getTplCategory();
+ String functionName = genTable.getFunctionName();
+
+ VelocityContext velocityContext = new VelocityContext();
+ velocityContext.put("tplCategory", genTable.getTplCategory());
+ velocityContext.put("tableName", genTable.getTableName());
+ velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "銆愯濉啓鍔熻兘鍚嶇О銆�");
+ velocityContext.put("ClassName", genTable.getClassName());
+ velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
+ velocityContext.put("moduleName", genTable.getModuleName());
+ velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
+ velocityContext.put("businessName", genTable.getBusinessName());
+ velocityContext.put("basePackage", getPackagePrefix(packageName));
+ velocityContext.put("packageName", packageName);
+ velocityContext.put("author", genTable.getFunctionAuthor());
+ velocityContext.put("datetime", DateUtils.getDate());
+ velocityContext.put("pkColumn", genTable.getPkColumn());
+ velocityContext.put("importList", getImportList(genTable));
+ velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
+ velocityContext.put("columns", genTable.getColumns());
+ velocityContext.put("table", genTable);
+ velocityContext.put("dicts", getDicts(genTable));
+ setMenuVelocityContext(velocityContext, genTable);
+ if (GenConstants.TPL_TREE.equals(tplCategory)) {
+ setTreeVelocityContext(velocityContext, genTable);
+ }
+ return velocityContext;
+ }
+
+ public static void setMenuVelocityContext(VelocityContext context, GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(options);
+ String parentMenuId = getParentMenuId(paramsObj);
+ context.put("parentMenuId", parentMenuId);
+ }
+
+ public static void setTreeVelocityContext(VelocityContext context, GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(options);
+ String treeCode = getTreecode(paramsObj);
+ String treeParentCode = getTreeParentCode(paramsObj);
+ String treeName = getTreeName(paramsObj);
+
+ context.put("treeCode", treeCode);
+ context.put("treeParentCode", treeParentCode);
+ context.put("treeName", treeName);
+ context.put("expandColumn", getExpandColumn(genTable));
+ if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
+ context.put("tree_parent_code", paramsObj.get(GenConstants.TREE_PARENT_CODE));
+ }
+ if (paramsObj.containsKey(GenConstants.TREE_NAME)) {
+ context.put("tree_name", paramsObj.get(GenConstants.TREE_NAME));
+ }
+ }
+
+ /**
+ * 鑾峰彇妯℃澘淇℃伅
+ *
+ * @return 妯℃澘鍒楄〃
+ */
+ public static List<String> getTemplateList(String tplCategory) {
+ List<String> templates = new ArrayList<>();
+ templates.add("vm/java/domain.java.vm");
+ templates.add("vm/java/vo.java.vm");
+ templates.add("vm/java/bo.java.vm");
+ templates.add("vm/java/mapper.java.vm");
+ templates.add("vm/java/service.java.vm");
+ templates.add("vm/java/serviceImpl.java.vm");
+ templates.add("vm/java/controller.java.vm");
+ templates.add("vm/xml/mapper.xml.vm");
+ if (DataBaseHelper.isOracle()) {
+ templates.add("vm/sql/oracle/sql.vm");
+ } else if (DataBaseHelper.isPostgerSql()) {
+ templates.add("vm/sql/postgres/sql.vm");
+ } else {
+ templates.add("vm/sql/sql.vm");
+ }
+ templates.add("vm/ts/api.ts.vm");
+ templates.add("vm/ts/types.ts.vm");
+ if (GenConstants.TPL_CRUD.equals(tplCategory)) {
+ templates.add("vm/vue/index.vue.vm");
+ } else if (GenConstants.TPL_TREE.equals(tplCategory)) {
+ templates.add("vm/vue/index-tree.vue.vm");
+ }
+ return templates;
+ }
+
+ /**
+ * 鑾峰彇鏂囦欢鍚�
+ */
+ public static String getFileName(String template, GenTable genTable) {
+ // 鏂囦欢鍚嶇О
+ String fileName = "";
+ // 鍖呰矾寰�
+ String packageName = genTable.getPackageName();
+ // 妯″潡鍚�
+ String moduleName = genTable.getModuleName();
+ // 澶у啓绫诲悕
+ String className = genTable.getClassName();
+ // 涓氬姟鍚嶇О
+ String businessName = genTable.getBusinessName();
+
+ String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
+ String mybatisPath = MYBATIS_PATH + "/" + moduleName;
+ String vuePath = "vue";
+
+ if (template.contains("domain.java.vm")) {
+ fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
+ }
+ if (template.contains("vo.java.vm")) {
+ fileName = StringUtils.format("{}/domain/vo/{}Vo.java", javaPath, className);
+ }
+ if (template.contains("bo.java.vm")) {
+ fileName = StringUtils.format("{}/domain/bo/{}Bo.java", javaPath, className);
+ }
+ if (template.contains("mapper.java.vm")) {
+ fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
+ } else if (template.contains("service.java.vm")) {
+ fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
+ } else if (template.contains("serviceImpl.java.vm")) {
+ fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+ } else if (template.contains("controller.java.vm")) {
+ fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
+ } else if (template.contains("mapper.xml.vm")) {
+ fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
+ } else if (template.contains("sql.vm")) {
+ fileName = businessName + "Menu.sql";
+ } else if (template.contains("api.ts.vm")) {
+ fileName = StringUtils.format("{}/api/{}/{}/index.ts", vuePath, moduleName, businessName);
+ } else if (template.contains("types.ts.vm")) {
+ fileName = StringUtils.format("{}/api/{}/{}/types.ts", vuePath, moduleName, businessName);
+ } else if (template.contains("index.vue.vm")) {
+ fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+ } else if (template.contains("index-tree.vue.vm")) {
+ fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+ }
+ return fileName;
+ }
+
+ /**
+ * 鑾峰彇鍖呭墠缂�
+ *
+ * @param packageName 鍖呭悕绉�
+ * @return 鍖呭墠缂�鍚嶇О
+ */
+ public static String getPackagePrefix(String packageName) {
+ int lastIndex = packageName.lastIndexOf(".");
+ return StringUtils.substring(packageName, 0, lastIndex);
+ }
+
+ /**
+ * 鏍规嵁鍒楃被鍨嬭幏鍙栧鍏ュ寘
+ *
+ * @param genTable 涓氬姟琛ㄥ璞�
+ * @return 杩斿洖闇�瑕佸鍏ョ殑鍖呭垪琛�
+ */
+ public static HashSet<String> getImportList(GenTable genTable) {
+ List<GenTableColumn> columns = genTable.getColumns();
+ HashSet<String> importList = new HashSet<>();
+ for (GenTableColumn column : columns) {
+ if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType())) {
+ importList.add("java.util.Date");
+ importList.add("com.fasterxml.jackson.annotation.JsonFormat");
+ } else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType())) {
+ importList.add("java.math.BigDecimal");
+ }
+ }
+ return importList;
+ }
+
+ /**
+ * 鏍规嵁鍒楃被鍨嬭幏鍙栧瓧鍏哥粍
+ *
+ * @param genTable 涓氬姟琛ㄥ璞�
+ * @return 杩斿洖瀛楀吀缁�
+ */
+ public static String getDicts(GenTable genTable) {
+ List<GenTableColumn> columns = genTable.getColumns();
+ Set<String> dicts = new HashSet<>();
+ addDicts(dicts, columns);
+ return StringUtils.join(dicts, ", ");
+ }
+
+ /**
+ * 娣诲姞瀛楀吀鍒楄〃
+ *
+ * @param dicts 瀛楀吀鍒楄〃
+ * @param columns 鍒楅泦鍚�
+ */
+ public static void addDicts(Set<String> dicts, List<GenTableColumn> columns) {
+ for (GenTableColumn column : columns) {
+ if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
+ column.getHtmlType(),
+ new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX })) {
+ dicts.add("'" + column.getDictType() + "'");
+ }
+ }
+ }
+
+ /**
+ * 鑾峰彇鏉冮檺鍓嶇紑
+ *
+ * @param moduleName 妯″潡鍚嶇О
+ * @param businessName 涓氬姟鍚嶇О
+ * @return 杩斿洖鏉冮檺鍓嶇紑
+ */
+ public static String getPermissionPrefix(String moduleName, String businessName) {
+ return StringUtils.format("{}:{}", moduleName, businessName);
+ }
+
+ /**
+ * 鑾峰彇涓婄骇鑿滃崟ID瀛楁
+ *
+ * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+ * @return 涓婄骇鑿滃崟ID瀛楁
+ */
+ public static String getParentMenuId(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+ && StringUtils.isNotEmpty(paramsObj.getStr(GenConstants.PARENT_MENU_ID))) {
+ return paramsObj.getStr(GenConstants.PARENT_MENU_ID);
+ }
+ return DEFAULT_PARENT_MENU_ID;
+ }
+
+ /**
+ * 鑾峰彇鏍戠紪鐮�
+ *
+ * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+ * @return 鏍戠紪鐮�
+ */
+ public static String getTreecode(Map<String, Object> paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_CODE)) {
+ return StringUtils.toCamelCase(Convert.toStr(paramsObj.get(GenConstants.TREE_CODE)));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 鑾峰彇鏍戠埗缂栫爜
+ *
+ * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+ * @return 鏍戠埗缂栫爜
+ */
+ public static String getTreeParentCode(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_PARENT_CODE)) {
+ return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_PARENT_CODE));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 鑾峰彇鏍戝悕绉�
+ *
+ * @param paramsObj 鐢熸垚鍏朵粬閫夐」
+ * @return 鏍戝悕绉�
+ */
+ public static String getTreeName(Dict paramsObj) {
+ if (CollUtil.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.TREE_NAME)) {
+ return StringUtils.toCamelCase(paramsObj.getStr(GenConstants.TREE_NAME));
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 鑾峰彇闇�瑕佸湪鍝竴鍒椾笂闈㈡樉绀哄睍寮�鎸夐挳
+ *
+ * @param genTable 涓氬姟琛ㄥ璞�
+ * @return 灞曞紑鎸夐挳鍒楀簭鍙�
+ */
+ public static int getExpandColumn(GenTable genTable) {
+ String options = genTable.getOptions();
+ Dict paramsObj = JsonUtils.parseMap(options);
+ String treeName = paramsObj.getStr(GenConstants.TREE_NAME);
+ int num = 0;
+ for (GenTableColumn column : genTable.getColumns()) {
+ if (column.isList()) {
+ num++;
+ String columnName = column.getColumnName();
+ if (columnName.equals(treeName)) {
+ break;
+ }
+ }
+ }
+ return num;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/application.yml b/ruoyi-modules/ruoyi-gen/src/main/resources/application.yml
new file mode 100644
index 0000000..a6761d8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+# Tomcat
+server:
+ port: 9202
+
+# Spring
+spring:
+ application:
+ # 搴旂敤鍚嶇О
+ name: ruoyi-gen
+ profiles:
+ # 鐜閰嶇疆
+ active: @profiles.active@
+
+--- # nacos 閰嶇疆
+spring:
+ cloud:
+ nacos:
+ # nacos 鏈嶅姟鍦板潃
+ server-addr: @nacos.server@
+ discovery:
+ # 娉ㄥ唽缁�
+ group: @nacos.discovery.group@
+ namespace: ${spring.profiles.active}
+ config:
+ # 閰嶇疆缁�
+ group: @nacos.config.group@
+ namespace: ${spring.profiles.active}
+ config:
+ import:
+ - optional:nacos:application-common.yml
+ - optional:nacos:datasource.yml
+ - optional:nacos:${spring.application.name}.yml
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt
new file mode 100644
index 0000000..05f528c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _
+ (_)
+ _ __ _ _ ___ _ _ _ ______ __ _ ___ _ __
+| '__|| | | | / _ \ | | | || ||______| / _` | / _ \| '_ \
+| | | |_| || (_) || |_| || | | (_| || __/| | | |
+|_| \__,_| \___/ \__, ||_| \__, | \___||_| |_|
+ __/ | __/ |
+ |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/logback-plus.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..0ef8ae4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/logback-plus.xml
@@ -0,0 +1,25 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 鏃ュ織瀛樻斁璺緞 -->
+ <property name="log.path" value="logs/${project.artifactId}"/>
+ <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+ <property name="console.log.pattern"
+ value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+ <!-- 鎺у埗鍙拌緭鍑� -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${console.log.pattern}</pattern>
+ <charset>utf-8</charset>
+ </encoder>
+ </appender>
+
+ <include resource="logback-common.xml" />
+
+ <include resource="logback-logstash.xml" />
+
+ <!--绯荤粺鎿嶄綔鏃ュ織-->
+ <root level="info">
+ <appender-ref ref="console"/>
+ </root>
+</configuration>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml
new file mode 100644
index 0000000..8fedeb0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -0,0 +1,78 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.gen.mapper.GenTableColumnMapper">
+
+ <resultMap type="org.dromara.gen.domain.GenTableColumn" id="GenTableColumnResult">
+ </resultMap>
+
+ <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
+ select column_name,
+ (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required,
+ (case when column_key = 'PRI' then '1' else '0' end) as is_pk,
+ ordinal_position as sort,
+ column_comment,
+ (case when extra = 'auto_increment' then '1' else '0' end) as is_increment,
+ column_type
+ from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
+ order by ordinal_position
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
+ select lower(temp.column_name) as column_name,
+ (case when (temp.nullable = 'N' and temp.constraint_type != 'P') then '1' else '0' end) as is_required,
+ (case when temp.constraint_type = 'P' then '1' else '0' end) as is_pk,
+ temp.column_id as sort,
+ temp.comments as column_comment,
+ (case when temp.constraint_type = 'P' then '1' else '0' end) as is_increment,
+ lower(temp.data_type) as column_type
+ from (
+ select col.column_id, col.column_name,col.nullable, col.data_type, colc.comments, uc.constraint_type, row_number()
+ over (partition by col.column_name order by uc.constraint_type desc) as row_flg
+ from user_tab_columns col
+ left join user_col_comments colc on colc.table_name = col.table_name and colc.column_name = col.column_name
+ left join user_cons_columns ucc on ucc.table_name = col.table_name and ucc.column_name = col.column_name
+ left join user_constraints uc on uc.constraint_name = ucc.constraint_name
+ where col.table_name = upper(#{tableName})
+ ) temp
+ WHERE temp.row_flg = 1
+ ORDER BY temp.column_id
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
+ SELECT column_name, is_required, is_pk, sort, column_comment, is_increment, column_type
+ FROM (
+ SELECT c.relname AS table_name,
+ a.attname AS column_name,
+ d.description AS column_comment,
+ CASE WHEN a.attnotnull AND con.conname IS NULL THEN 1 ELSE 0
+ END AS is_required,
+ CASE WHEN con.conname IS NOT NULL THEN 1 ELSE 0
+ END AS is_pk,
+ a.attnum AS sort,
+ CASE WHEN "position"(pg_get_expr(ad.adbin, ad.adrelid),
+ ((c.relname::text || '_'::text) || a.attname::text) || '_seq'::text) > 0 THEN 1 ELSE 0
+ END AS is_increment,
+ btrim(
+ CASE WHEN t.typelem <![CDATA[ <> ]]> 0::oid AND t.typlen = '-1'::integer THEN 'ARRAY'::text ELSE
+ CASE WHEN t.typtype = 'd'::"char" THEN format_type(t.typbasetype, NULL::integer)
+ ELSE format_type(a.atttypid, NULL::integer) END
+ END, '"'::text
+ ) AS column_type
+ FROM pg_attribute a
+ JOIN (pg_class c JOIN pg_namespace n ON c.relnamespace = n.oid) ON a.attrelid = c.oid
+ LEFT JOIN pg_description d ON d.objoid = c.oid AND a.attnum = d.objsubid
+ LEFT JOIN pg_constraint con ON con.conrelid = c.oid AND (a.attnum = ANY (con.conkey))
+ LEFT JOIN pg_attrdef ad ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
+ LEFT JOIN pg_type t ON a.atttypid = t.oid
+ WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
+ AND a.attnum > 0
+ AND n.nspname = 'public'::name
+ ORDER BY c.relname, a.attnum
+ ) temp
+ WHERE table_name = (#{tableName})
+ AND column_type <![CDATA[ <> ]]> '-'
+ </if>
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml
new file mode 100644
index 0000000..3f4f0ce
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -0,0 +1,194 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.gen.mapper.GenTableMapper">
+
+ <!-- 澶氱粨鏋勫祵濂楄嚜鍔ㄦ槧灏勯渶甯︿笂姣忎釜瀹炰綋鐨勪富閿甶d 鍚﹀垯鏄犲皠浼氬け璐� -->
+ <resultMap type="org.dromara.gen.domain.GenTable" id="GenTableResult">
+ <id property="tableId" column="table_id" />
+ <collection property="columns" javaType="java.util.List" resultMap="GenTableColumnResult" />
+ </resultMap>
+
+ <resultMap type="org.dromara.gen.domain.GenTableColumn" id="GenTableColumnResult">
+ <id property="columnId" column="column_id"/>
+ </resultMap>
+
+ <select id="selectPageDbTableList" resultMap="GenTableResult">
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
+ select table_name, table_comment, create_time, update_time
+ from information_schema.tables
+ where table_schema = (select database())
+ AND table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
+ <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
+ AND table_name NOT IN
+ <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
+ #{item}
+ </foreach>
+ </if>
+ <if test="genTable.tableName != null and genTable.tableName != ''">
+ AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
+ </if>
+ <if test="genTable.tableComment != null and genTable.tableComment != ''">
+ AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
+ </if>
+ order by create_time desc
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
+ select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
+ from user_tables dt, user_tab_comments dtc, user_objects uo
+ where dt.table_name = dtc.table_name
+ and dt.table_name = uo.object_name
+ and uo.object_type = 'TABLE'
+ AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
+ <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
+ AND lower(dt.table_name) NOT IN
+ <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
+ #{item}
+ </foreach>
+ </if>
+ <if test="genTable.tableName != null and genTable.tableName != ''">
+ AND lower(dt.table_name) like lower(concat(concat('%', #{genTable.tableName}), '%'))
+ </if>
+ <if test="genTable.tableComment != null and genTable.tableComment != ''">
+ AND lower(dtc.comments) like lower(concat(concat('%', #{genTable.tableComment}), '%'))
+ </if>
+ order by create_time desc
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
+ select table_name, table_comment, create_time, update_time
+ from (
+ SELECT c.relname AS table_name,
+ obj_description(c.oid) AS table_comment,
+ CURRENT_TIMESTAMP AS create_time,
+ CURRENT_TIMESTAMP AS update_time
+ FROM pg_class c
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+ WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
+ AND c.relname != 'spatial_%'::text
+ AND n.nspname = 'public'::name
+ AND n.nspname <![CDATA[ <> ]]> ''::name
+ ) list_table
+ where table_name NOT LIKE 'xxl_job_%' AND table_name NOT LIKE 'gen_%'
+ <if test="genTable.params.genTableNames != null and genTable.params.genTableNames.size > 0">
+ AND table_name NOT IN
+ <foreach collection="genTable.params.genTableNames" open="(" close=")" separator="," item="item">
+ #{item}
+ </foreach>
+ </if>
+ <if test="genTable.tableName != null and genTable.tableName != ''">
+ AND lower(table_name) like lower(concat('%', #{genTable.tableName}, '%'))
+ </if>
+ <if test="genTable.tableComment != null and genTable.tableComment != ''">
+ AND lower(table_comment) like lower(concat('%', #{genTable.tableComment}, '%'))
+ </if>
+ order by create_time desc
+ </if>
+ </select>
+
+ <select id="selectDbTableListByNames" resultMap="GenTableResult">
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
+ select table_name, table_comment, create_time, update_time from information_schema.tables
+ where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
+ and table_name in
+ <foreach collection="array" item="name" open="(" separator="," close=")">
+ #{name}
+ </foreach>
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
+ select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
+ from user_tables dt, user_tab_comments dtc, user_objects uo
+ where dt.table_name = dtc.table_name
+ and dt.table_name = uo.object_name
+ and uo.object_type = 'TABLE'
+ AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
+ and lower(dt.table_name) in
+ <foreach collection="array" item="name" open="(" separator="," close=")">
+ #{name}
+ </foreach>
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
+ select table_name, table_comment, create_time, update_time
+ from (
+ SELECT c.relname AS table_name,
+ obj_description(c.oid) AS table_comment,
+ CURRENT_TIMESTAMP AS create_time,
+ CURRENT_TIMESTAMP AS update_time
+ FROM pg_class c
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+ WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
+ AND c.relname != 'spatial_%'::text
+ AND n.nspname = 'public'::name
+ AND n.nspname <![CDATA[ <> ]]> ''::name
+ ) list_table
+ where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
+ and table_name in
+ <foreach collection="array" item="name" open="(" separator="," close=")">
+ #{name}
+ </foreach>
+ </if>
+ </select>
+
+ <select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isMySql()">
+ select table_name, table_comment, create_time, update_time from information_schema.tables
+ where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%' and table_schema = (select database())
+ and table_name = #{tableName}
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isOracle()">
+ select lower(dt.table_name) as table_name, dtc.comments as table_comment, uo.created as create_time, uo.last_ddl_time as update_time
+ from user_tables dt, user_tab_comments dtc, user_objects uo
+ where dt.table_name = dtc.table_name
+ and dt.table_name = uo.object_name
+ and uo.object_type = 'TABLE'
+ AND dt.table_name NOT LIKE 'XXL_JOB_%' AND dt.table_name NOT LIKE 'GEN_%'
+ AND dt.table_name NOT IN (select table_name from gen_table)
+ and lower(dt.table_name) = #{tableName}
+ </if>
+ <if test="@org.dromara.common.mybatis.helper.DataBaseHelper@isPostgerSql()">
+ select table_name, table_comment, create_time, update_time
+ from (
+ SELECT c.relname AS table_name,
+ obj_description(c.oid) AS table_comment,
+ CURRENT_TIMESTAMP AS create_time,
+ CURRENT_TIMESTAMP AS update_time
+ FROM pg_class c
+ LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
+ WHERE (c.relkind = ANY (ARRAY ['r'::"char", 'p'::"char"]))
+ AND c.relname != 'spatial_%'::text
+ AND n.nspname = 'public'::name
+ AND n.nspname <![CDATA[ <> ]]> ''::name
+ ) list_table
+ where table_name NOT LIKE 'xxl_job_%' and table_name NOT LIKE 'gen_%'
+ and table_name = #{tableName}
+ </if>
+ </select>
+
+ <select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
+ SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
+ c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+ FROM gen_table t
+ LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+ where t.table_id = #{tableId} order by c.sort
+ </select>
+
+ <select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
+ SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
+ c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+ FROM gen_table t
+ LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+ where t.table_name = #{tableName} order by c.sort
+ </select>
+
+ <select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
+ SELECT t.table_id, t.data_name, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
+ c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+ FROM gen_table t
+ LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+ order by c.sort
+ </select>
+
+ <select id="selectTableNameList" resultType="java.lang.String">
+ select table_name from gen_table where data_name = #{dataName,jdbcType=VARCHAR}
+ </select>
+</mapper>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/spy.properties b/ruoyi-modules/ruoyi-gen/src/main/resources/spy.properties
new file mode 100644
index 0000000..abbd893
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/spy.properties
@@ -0,0 +1,28 @@
+# p6spy 鎬ц兘鍒嗘瀽鎻掍欢閰嶇疆鏂囦欢
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 鑷畾涔夋棩蹇楁墦鍗�
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#鏃ュ織杈撳嚭鍒版帶鍒跺彴
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 浣跨敤鏃ュ織绯荤粺璁板綍 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 璁剧疆 p6spy driver 浠g悊
+#deregisterdrivers=true
+# 鍙栨秷JDBC URL鍓嶇紑
+useprefix=true
+# 閰嶇疆璁板綍 Log 渚嬪,鍙幓鎺夌殑缁撴灉闆嗘湁error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 鏃ユ湡鏍煎紡
+dateformat=yyyy-MM-dd HH:mm:ss
+# SQL璇彞鎵撳嵃鏃堕棿鏍煎紡
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
+# 瀹為檯椹卞姩鍙涓�
+#driverlist=org.h2.Driver
+# 鏄惁寮�鍚參SQL璁板綍
+outagedetection=true
+# 鎱QL璁板綍鏍囧噯 2 绉�
+outagedetectioninterval=2
+# 鏄惁杩囨护 Log
+filter=true
+# 杩囨护 Log 鏃舵墍鎺掗櫎鐨� sql 鍏抽敭瀛楋紝浠ラ�楀彿鍒嗛殧
+exclude=SELECT 1
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/bo.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/bo.java.vm
new file mode 100644
index 0000000..511d37c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/bo.java.vm
@@ -0,0 +1,50 @@
+package ${packageName}.domain.bo;
+
+import ${packageName}.domain.${ClassName};
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import jakarta.validation.constraints.*;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+/**
+ * ${functionName}涓氬姟瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = ${ClassName}.class, reverseConvertGenerate = false)
+public class ${ClassName}Bo extends BaseEntity {
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField) && ($column.query || $column.insert || $column.edit))
+ /**
+ * $column.columnComment
+ */
+#if($column.insert && $column.edit)
+#set($Group="AddGroup.class, EditGroup.class")
+#elseif($column.insert)
+#set($Group="AddGroup.class")
+#elseif($column.edit)
+#set($Group="EditGroup.class")
+#end
+#if($column.required)
+#if($column.javaType == 'String')
+ @NotBlank(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
+#else
+ @NotNull(message = "$column.columnComment涓嶈兘涓虹┖", groups = { $Group })
+#end
+#end
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 0000000..a842537
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,116 @@
+package ${packageName}.controller;
+
+import java.util.List;
+
+import lombok.RequiredArgsConstructor;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.*;
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.validation.annotation.Validated;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.excel.utils.ExcelUtil;
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.bo.${ClassName}Bo;
+import ${packageName}.service.I${ClassName}Service;
+#if($table.crud || $table.sub)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}
+ * 鍓嶇璁块棶璺敱鍦板潃涓�:/${moduleName}/${businessName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/${businessName}")
+public class ${ClassName}Controller extends BaseController {
+
+ private final I${ClassName}Service ${className}Service;
+
+ /**
+ * 鏌ヨ${functionName}鍒楄〃
+ */
+ @SaCheckPermission("${permissionPrefix}:list")
+ @GetMapping("/list")
+#if($table.crud || $table.sub)
+ public TableDataInfo<${ClassName}Vo> list(${ClassName}Bo bo, PageQuery pageQuery) {
+ return ${className}Service.queryPageList(bo, pageQuery);
+ }
+#elseif($table.tree)
+ public R<List<${ClassName}Vo>> list(${ClassName}Bo bo) {
+ List<${ClassName}Vo> list = ${className}Service.queryList(bo);
+ return R.ok(list);
+ }
+#end
+
+ /**
+ * 瀵煎嚭${functionName}鍒楄〃
+ */
+ @SaCheckPermission("${permissionPrefix}:export")
+ @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(${ClassName}Bo bo, HttpServletResponse response) {
+ List<${ClassName}Vo> list = ${className}Service.queryList(bo);
+ ExcelUtil.exportExcel(list, "${functionName}", ${ClassName}Vo.class, response);
+ }
+
+ /**
+ * 鑾峰彇${functionName}璇︾粏淇℃伅
+ *
+ * @param ${pkColumn.javaField} 涓婚敭
+ */
+ @SaCheckPermission("${permissionPrefix}:query")
+ @GetMapping("/{${pkColumn.javaField}}")
+ public R<${ClassName}Vo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable ${pkColumn.javaType} ${pkColumn.javaField}) {
+ return R.ok(${className}Service.queryById(${pkColumn.javaField}));
+ }
+
+ /**
+ * 鏂板${functionName}
+ */
+ @SaCheckPermission("${permissionPrefix}:add")
+ @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody ${ClassName}Bo bo) {
+ return toAjax(${className}Service.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼${functionName}
+ */
+ @SaCheckPermission("${permissionPrefix}:edit")
+ @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody ${ClassName}Bo bo) {
+ return toAjax(${className}Service.updateByBo(bo));
+ }
+
+ /**
+ * 鍒犻櫎${functionName}
+ *
+ * @param ${pkColumn.javaField}s 涓婚敭涓�
+ */
+ @SaCheckPermission("${permissionPrefix}:remove")
+ @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{${pkColumn.javaField}s}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s) {
+ return toAjax(${className}Service.deleteWithValidByIds(List.of(${pkColumn.javaField}s), true));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm
new file mode 100644
index 0000000..205fb73
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/domain.java.vm
@@ -0,0 +1,60 @@
+package ${packageName}.domain;
+
+#foreach ($column in $columns)
+#if($column.javaField=='tenantId')
+#set($IsTenant=1)
+#end
+#end
+#if($IsTenant==1)
+import org.dromara.common.tenant.core.TenantEntity;
+#else
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+#end
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+#foreach ($import in $importList)
+import ${import};
+#end
+
+import java.io.Serial;
+
+/**
+ * ${functionName}瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($IsTenant==1)
+#set($Entity="TenantEntity")
+#else
+#set($Entity="BaseEntity")
+#end
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("${tableName}")
+public class ${ClassName} extends ${Entity} {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+ /**
+ * $column.columnComment
+ */
+#if($column.javaField=='delFlag')
+ @TableLogic
+#end
+#if($column.javaField=='version')
+ @Version
+#end
+#if($column.isPk==1)
+ @TableId(value = "$column.columnName")
+#end
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 0000000..0922401
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,15 @@
+package ${packageName}.mapper;
+
+import ${packageName}.domain.${ClassName};
+import ${packageName}.domain.vo.${ClassName}Vo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * ${functionName}Mapper鎺ュ彛
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper extends BaseMapperPlus<${ClassName}, ${ClassName}Vo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..d596a0e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/service.java.vm
@@ -0,0 +1,53 @@
+package ${packageName}.service;
+
+import ${packageName}.domain.${ClassName};
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.bo.${ClassName}Bo;
+#if($table.crud || $table.sub)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+#end
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * ${functionName}Service鎺ュ彛
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service {
+
+ /**
+ * 鏌ヨ${functionName}
+ */
+ ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField});
+
+#if($table.crud || $table.sub)
+ /**
+ * 鏌ヨ${functionName}鍒楄〃
+ */
+ TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery);
+#end
+
+ /**
+ * 鏌ヨ${functionName}鍒楄〃
+ */
+ List<${ClassName}Vo> queryList(${ClassName}Bo bo);
+
+ /**
+ * 鏂板${functionName}
+ */
+ Boolean insertByBo(${ClassName}Bo bo);
+
+ /**
+ * 淇敼${functionName}
+ */
+ Boolean updateByBo(${ClassName}Bo bo);
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄�${functionName}淇℃伅
+ */
+ Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..75a9b83
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +1,134 @@
+package ${packageName}.service.impl;
+
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+#if($table.crud || $table.sub)
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+#end
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.springframework.stereotype.Service;
+import ${packageName}.domain.bo.${ClassName}Bo;
+import ${packageName}.domain.vo.${ClassName}Vo;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.mapper.${ClassName}Mapper;
+import ${packageName}.service.I${ClassName}Service;
+
+import java.util.List;
+import java.util.Map;
+import java.util.Collection;
+
+/**
+ * ${functionName}Service涓氬姟灞傚鐞�
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RequiredArgsConstructor
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service {
+
+ private final ${ClassName}Mapper baseMapper;
+
+ /**
+ * 鏌ヨ${functionName}
+ */
+ @Override
+ public ${ClassName}Vo queryById(${pkColumn.javaType} ${pkColumn.javaField}){
+ return baseMapper.selectVoById(${pkColumn.javaField});
+ }
+
+#if($table.crud || $table.sub)
+ /**
+ * 鏌ヨ${functionName}鍒楄〃
+ */
+ @Override
+ public TableDataInfo<${ClassName}Vo> queryPageList(${ClassName}Bo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
+ Page<${ClassName}Vo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+#end
+
+ /**
+ * 鏌ヨ${functionName}鍒楄〃
+ */
+ @Override
+ public List<${ClassName}Vo> queryList(${ClassName}Bo bo) {
+ LambdaQueryWrapper<${ClassName}> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<${ClassName}> buildQueryWrapper(${ClassName}Bo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<${ClassName}> lqw = Wrappers.lambdaQuery();
+#foreach($column in $columns)
+#if($column.query)
+#set($queryType=$column.queryType)
+#set($javaField=$column.javaField)
+#set($javaType=$column.javaType)
+#set($columnName=$column.columnName)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($mpMethod=$column.queryType.toLowerCase())
+#if($queryType != 'BETWEEN')
+#if($javaType == 'String')
+#set($condition='StringUtils.isNotBlank(bo.get'+$AttrName+'())')
+#else
+#set($condition='bo.get'+$AttrName+'() != null')
+#end
+ lqw.$mpMethod($condition, ${ClassName}::get$AttrName, bo.get$AttrName());
+#else
+ lqw.between(params.get("begin$AttrName") != null && params.get("end$AttrName") != null,
+ ${ClassName}::get$AttrName ,params.get("begin$AttrName"), params.get("end$AttrName"));
+#end
+#end
+#end
+ return lqw;
+ }
+
+ /**
+ * 鏂板${functionName}
+ */
+ @Override
+ public Boolean insertByBo(${ClassName}Bo bo) {
+ ${ClassName} add = MapstructUtils.convert(bo, ${ClassName}.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+#set($pk=$pkColumn.javaField.substring(0,1).toUpperCase() + ${pkColumn.javaField.substring(1)})
+ if (flag) {
+ bo.set$pk(add.get$pk());
+ }
+ return flag;
+ }
+
+ /**
+ * 淇敼${functionName}
+ */
+ @Override
+ public Boolean updateByBo(${ClassName}Bo bo) {
+ ${ClassName} update = MapstructUtils.convert(bo, ${ClassName}.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(${ClassName} entity){
+ //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎${functionName}
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection<${pkColumn.javaType}> ids, Boolean isValid) {
+ if(isValid){
+ //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm
new file mode 100644
index 0000000..f99a2ed
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/java/vo.java.vm
@@ -0,0 +1,59 @@
+package ${packageName}.domain.vo;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import ${packageName}.domain.${ClassName};
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * ${functionName}瑙嗗浘瀵硅薄 ${tableName}
+ *
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = ${ClassName}.class)
+public class ${ClassName}Vo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if($column.list)
+ /**
+ * $column.columnComment
+ */
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if(${column.dictType} && ${column.dictType} != '')
+ @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "${column.dictType}")
+#elseif($parentheseIndex != -1)
+ @ExcelProperty(value = "${comment}", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "$column.readConverterExp()")
+#else
+ @ExcelProperty(value = "${comment}")
+#end
+ private $column.javaType $column.javaField;
+
+#end
+#end
+
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/oracle/sql.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/oracle/sql.vm
new file mode 100644
index 0000000..f6638be
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/oracle/sql.vm
@@ -0,0 +1,19 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate, null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate, null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate, null, null, '');
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/postgres/sql.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/postgres/sql.vm
new file mode 100644
index 0000000..0923392
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/postgres/sql.vm
@@ -0,0 +1,20 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, now(), null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, now(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, now(), null, null, '');
+
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 0000000..01824c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/sql/sql.vm
@@ -0,0 +1,19 @@
+-- 鑿滃崟 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[0]}, '${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 103, 1, sysdate(), null, null, '${functionName}鑿滃崟');
+
+-- 鎸夐挳 SQL
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[1]}, '${functionName}鏌ヨ', ${table.menuIds[0]}, '1', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[2]}, '${functionName}鏂板', ${table.menuIds[0]}, '2', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[3]}, '${functionName}淇敼', ${table.menuIds[0]}, '3', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[4]}, '${functionName}鍒犻櫎', ${table.menuIds[0]}, '4', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove', '#', 103, 1, sysdate(), null, null, '');
+
+insert into sys_menu (menu_id, menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_dept, create_by, create_time, update_by, update_time, remark)
+values(${table.menuIds[5]}, '${functionName}瀵煎嚭', ${table.menuIds[0]}, '5', '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export', '#', 103, 1, sysdate(), null, null, '');
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm
new file mode 100644
index 0000000..3aa4a5f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/api.ts.vm
@@ -0,0 +1,63 @@
+import request from '@/utils/request';
+import { AxiosPromise } from 'axios';
+import { ${BusinessName}VO, ${BusinessName}Form, ${BusinessName}Query } from '@/api/${moduleName}/${businessName}/types';
+
+/**
+ * 鏌ヨ${functionName}鍒楄〃
+ * @param query
+ * @returns {*}
+ */
+
+export const list${BusinessName} = (query?: ${BusinessName}Query): AxiosPromise<${BusinessName}VO[]> => {
+ return request({
+ url: '/${moduleName}/${businessName}/list',
+ method: 'get',
+ params: query
+ });
+};
+
+/**
+ * 鏌ヨ${functionName}璇︾粏
+ * @param ${pkColumn.javaField}
+ */
+export const get${BusinessName} = (${pkColumn.javaField}: string | number): AxiosPromise<${BusinessName}VO> => {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'get'
+ });
+};
+
+/**
+ * 鏂板${functionName}
+ * @param data
+ */
+export const add${BusinessName} = (data: ${BusinessName}Form) => {
+ return request({
+ url: '/${moduleName}/${businessName}',
+ method: 'post',
+ data: data
+ });
+};
+
+/**
+ * 淇敼${functionName}
+ * @param data
+ */
+export const update${BusinessName} = (data: ${BusinessName}Form) => {
+ return request({
+ url: '/${moduleName}/${businessName}',
+ method: 'put',
+ data: data
+ });
+};
+
+/**
+ * 鍒犻櫎${functionName}
+ * @param ${pkColumn.javaField}
+ */
+export const del${BusinessName} = (${pkColumn.javaField}: string | number | Array<string | number>) => {
+ return request({
+ url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+ method: 'delete'
+ });
+};
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm
new file mode 100644
index 0000000..4e0ab5e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/ts/types.ts.vm
@@ -0,0 +1,50 @@
+export interface ${BusinessName}VO {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+#if ($table.tree)
+ /**
+ * 瀛愬璞�
+ */
+ children: ${BusinessName}VO[];
+#end
+}
+
+export interface ${BusinessName}Form extends BaseEntity {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+}
+
+export interface ${BusinessName}Query #if(!${treeCode})extends PageQuery #end{
+#foreach ($column in $columns)
+#if($column.query)
+ /**
+ * $column.columnComment
+ */
+ $column.javaField?:#if($column.javaField.indexOf("id") != -1 || $column.javaField.indexOf("Id") != -1) string | number;
+ #elseif($column.javaType == 'Long' || $column.javaType == 'Integer' || $column.javaType == 'Double' || $column.javaType == 'Float' || $column.javaType == 'BigDecimal') number;
+ #elseif($column.javaType == 'Boolean') boolean;
+ #else string;
+ #end
+#end
+#end
+}
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 0000000..f876f55
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +1,507 @@
+<template>
+ <div class="p-2">
+ <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+ <div class="search" v-show="showSearch">
+ <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-input v-model="queryParams.${column.javaField}" placeholder="璇疯緭鍏�${comment}" clearable style="width: 240px" @keyup.enter="handleQuery" />
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+ <el-option
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+ <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-date-picker clearable
+ v-model="queryParams.${column.javaField}"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="閫夋嫨${comment}"
+ />
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ <el-form-item label="${comment}" style="width: 308px">
+ <el-date-picker
+ v-model="dateRange${AttrName}"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+ />
+ </el-form-item>
+#end
+#end
+#end
+ <el-form-item>
+ <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+ </transition>
+
+ <el-card shadow="never">
+ <template #header>
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button type="primary" plain icon="Plus" @click="handleAdd()" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="info" plain icon="Sort" @click="handleToggleExpandAll">灞曞紑/鎶樺彔</el-button>
+ </el-col>
+ <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+ </template>
+ <el-table
+ v-loading="loading"
+ :data="${businessName}List"
+ row-key="${treeCode}"
+ :default-expand-all="isExpandAll"
+ :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+ ref="${businessName}TableRef"
+ >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+ <template #default="scope">
+ <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+ <el-table-column label="${comment}" align="center" prop="${javaField}">
+ <template #default="scope">
+#if($column.htmlType == "checkbox")
+ <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+ <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+ <el-table-column label="${comment}" prop="${javaField}" />
+#else
+ <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template #default="scope">
+ <el-tooltip content="淇敼" placement="top">
+ <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']" />
+ </el-tooltip>
+ <el-tooltip content="鏂板" placement="top">
+ <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']" />
+ </el-tooltip>
+ <el-tooltip content="鍒犻櫎" placement="top">
+ <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']" />
+ </el-tooltip>
+ </template>
+ </el-table-column>
+ </el-table>
+ </el-card>
+ <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+ <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+ <el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if(($column.insert || $column.edit) && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+ <el-form-item label="${comment}" prop="${treeParentCode}">
+ <el-tree-select
+ v-model="form.${treeParentCode}"
+ :data="${businessName}Options"
+ :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
+ value-key="${treeCode}"
+ placeholder="璇烽�夋嫨${comment}"
+ check-strictly
+ />
+ </el-form-item>
+#elseif($column.htmlType == "input")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+ </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+ <el-form-item label="${comment}" prop="${field}">
+ <image-upload v-model="form.${field}"/>
+ </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+ <el-form-item label="${comment}" prop="${field}">
+ <file-upload v-model="form.${field}"/>
+ </el-form-item>
+#elseif($column.htmlType == "editor")
+ <el-form-item label="${comment}">
+ <editor v-model="form.${field}" :min-height="192"/>
+ </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+ <el-option
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :value="parseInt(dict.value)"
+#else
+ :value="dict.value"
+#end
+ ></el-option>
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+ <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.value">
+ {{dict.label}}
+ </el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :label="parseInt(dict.value)"
+#else
+ :label="dict.value"
+#end
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+ </el-radio-group>
+ </el-form-item>
+#elseif($column.htmlType == "datetime")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-date-picker clearable
+ v-model="form.${field}"
+ type="datetime"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ placeholder="閫夋嫨${comment}"
+ />
+ </el-form-item>
+#elseif($column.htmlType == "textarea")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+ </el-form-item>
+#end
+#end
+#end
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup name="${BusinessName}" lang="ts">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
+
+type ${BusinessName}Option = {
+ ${treeCode}: number;
+ ${treeName}: string;
+ children?: ${BusinessName}Option[];
+}
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;;
+
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
+#end
+
+const ${businessName}List = ref<${BusinessName}VO[]>([]);
+const ${businessName}Options = ref<${BusinessName}Option[]>([]);
+const buttonLoading = ref(false);
+const showSearch = ref(true);
+const isExpandAll = ref(true);
+const loading = ref(false);
+
+const queryFormRef = ref<ElFormInstance>();
+const ${businessName}FormRef = ref<ElFormInstance>();
+const ${businessName}TableRef = ref<ElTableInstance>()
+
+const dialog = reactive<DialogOption>({
+ visible: false,
+ title: ''
+});
+
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
+#end
+#end
+
+const initFormData: ${BusinessName}Form = {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.htmlType == "checkbox")
+ $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+ $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+}
+
+const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
+ form: {...initFormData},
+ queryParams: {
+#foreach ($column in $columns)
+#if($column.query)
+ #if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
+ $column.javaField: undefined,
+ #end
+#end
+#end
+ params: {
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+ }
+ },
+ rules: {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+ $column.javaField: [
+ { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+ ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+ }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+const getList = async () => {
+ loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
+#end
+#end
+ const res = await list${BusinessName}(queryParams.value);
+ const data = proxy?.handleTree<${BusinessName}VO>(res.data, "${treeCode}", "${treeParentCode}");
+ if (data) {
+ ${businessName}List.value = data;
+ loading.value = false;
+ }
+}
+
+/** 鏌ヨ${functionName}涓嬫媺鏍戠粨鏋� */
+const getTreeselect = async () => {
+ const res = await list${BusinessName}();
+ ${businessName}Options.value = [];
+ const data: ${BusinessName}Option = { ${treeCode}: 0, ${treeName}: '椤剁骇鑺傜偣', children: [] };
+ data.children = proxy?.handleTree<${BusinessName}Option>(res.data, "${treeCode}", "${treeParentCode}");
+ ${businessName}Options.value.push(data);
+}
+
+// 鍙栨秷鎸夐挳
+const cancel = () => {
+ reset();
+ dialog.visible = false;
+}
+
+// 琛ㄥ崟閲嶇疆
+const reset = () => {
+ form.value = {...initFormData}
+ ${businessName}FormRef.value?.resetFields();
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ dateRange${AttrName}.value = ['', ''];
+#end
+#end
+ queryFormRef.value?.resetFields();
+ handleQuery();
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+const handleAdd = (row?: ${BusinessName}VO) => {
+ dialog.visible = true;
+ dialog.title = "娣诲姞${functionName}";
+ nextTick(() => {
+ reset();
+ getTreeselect();
+ if (row != null && row.${treeCode}) {
+ form.value.${treeParentCode} = row.${treeParentCode};
+ } else {
+ form.value.${treeParentCode} = 0;
+ }
+ });
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+const handleToggleExpandAll = () => {
+ isExpandAll.value = !isExpandAll.value;
+ toggleExpandAll(${businessName}List.value, isExpandAll.value)
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+const toggleExpandAll = (data: ${BusinessName}VO[], status: boolean) => {
+ data.forEach((item) => {
+ ${businessName}TableRef.value?.toggleRowExpansion(item, status)
+ if (item.children && item.children.length > 0) toggleExpandAll(item.children, status)
+ })
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+const handleUpdate = (row: ${BusinessName}VO) => {
+ loading.value = true;
+ dialog.visible = true;
+ dialog.title = "淇敼${functionName}";
+ nextTick(async () => {
+ reset();
+ await getTreeselect();
+ if (row != null) {
+ form.value.${treeParentCode} = row.${treeCode};
+ }
+ const res = await get${BusinessName}(row.${pkColumn.javaField});
+ loading.value = false;
+ Object.assign(form.value, res.data);
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+ });
+}
+
+/** 鎻愪氦鎸夐挳 */
+const submitForm = () => {
+ ${businessName}FormRef.value?.validate(async (valid: boolean) => {
+ if (valid) {
+ buttonLoading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+ if (form.value.${pkColumn.javaField}) {
+ await update${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+ } else {
+ await add${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+ }
+ proxy?.#[[$modal]]#.msgSuccess("鎿嶄綔鎴愬姛");
+ dialog.visible = false;
+ getList();
+ }
+ });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+const handleDelete = async (row: ${BusinessName}VO) => {
+ await proxy?.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + row.${pkColumn.javaField} + '"鐨勬暟鎹」锛�');
+ loading.value = true;
+ await del${BusinessName}(row.${pkColumn.javaField}).finally(() => loading.value = false);
+ await getList();
+ proxy?.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+}
+
+onMounted(() => {
+ getList();
+});
+</script>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 0000000..6ba61fc
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +1,474 @@
+<template>
+ <div class="p-2">
+ <transition :enter-active-class="proxy?.animate.searchAnimate.enter" :leave-active-class="proxy?.animate.searchAnimate.leave">
+ <div class="search" v-show="showSearch">
+ <el-form :model="queryParams" ref="queryFormRef" :inline="true" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input" || $column.htmlType == "textarea")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-input v-model="queryParams.${column.javaField}" placeholder="璇疯緭鍏�${comment}" clearable style="width: 240px" @keyup.enter="handleQuery" />
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+ <el-option
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+ :value="dict.value"
+ />
+ </el-select>
+ </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+ <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+ <el-form-item label="${comment}" prop="${column.javaField}">
+ <el-date-picker clearable
+ v-model="queryParams.${column.javaField}"
+ type="date"
+ value-format="YYYY-MM-DD"
+ placeholder="璇烽�夋嫨${comment}"
+ />
+ </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ <el-form-item label="${comment}" style="width: 308px">
+ <el-date-picker
+ v-model="dateRange${AttrName}"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ type="daterange"
+ range-separator="-"
+ start-placeholder="寮�濮嬫棩鏈�"
+ end-placeholder="缁撴潫鏃ユ湡"
+ :default-time="[new Date(2000, 1, 1, 0, 0, 0), new Date(2000, 1, 1, 23, 59, 59)]"
+ />
+ </el-form-item>
+#end
+#end
+#end
+ <el-form-item>
+ <el-button type="primary" icon="Search" @click="handleQuery">鎼滅储</el-button>
+ <el-button icon="Refresh" @click="resetQuery">閲嶇疆</el-button>
+ </el-form-item>
+ </el-form>
+ </div>
+ </transition>
+
+ <el-card shadow="never">
+ <template #header>
+ <el-row :gutter="10" class="mb8">
+ <el-col :span="1.5">
+ <el-button type="primary" plain icon="Plus" @click="handleAdd" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="success" plain icon="Edit" :disabled="single" @click="handleUpdate()" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="danger" plain icon="Delete" :disabled="multiple" @click="handleDelete()" v-hasPermi="['${moduleName}:${businessName}:remove']">鍒犻櫎</el-button>
+ </el-col>
+ <el-col :span="1.5">
+ <el-button type="warning" plain icon="Download" @click="handleExport" v-hasPermi="['${moduleName}:${businessName}:export']">瀵煎嚭</el-button>
+ </el-col>
+ <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+ </el-row>
+ </template>
+
+ <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+ <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+ <el-table-column label="${comment}" align="center" prop="${javaField}" v-if="${column.list}" />
+#elseif($column.list && $column.htmlType == "datetime")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+ <template #default="scope">
+ <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+ <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+ <template #default="scope">
+ <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+ </template>
+ </el-table-column>
+#elseif($column.list && $column.dictType && "" != $column.dictType)
+ <el-table-column label="${comment}" align="center" prop="${javaField}">
+ <template #default="scope">
+#if($column.htmlType == "checkbox")
+ <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+ <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+ </template>
+ </el-table-column>
+#elseif($column.list && "" != $javaField)
+ <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+ <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+ <template #default="scope">
+ <el-tooltip content="淇敼" placement="top">
+ <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']"></el-button>
+ </el-tooltip>
+ <el-tooltip content="鍒犻櫎" placement="top">
+ <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']"></el-button>
+ </el-tooltip>
+ </template>
+ </el-table-column>
+ </el-table>
+
+ <pagination
+ v-show="total>0"
+ :total="total"
+ v-model:page="queryParams.pageNum"
+ v-model:limit="queryParams.pageSize"
+ @pagination="getList"
+ />
+ </el-card>
+ <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+ <el-dialog :title="dialog.title" v-model="dialog.visible" width="500px" append-to-body>
+ <el-form ref="${businessName}FormRef" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if(($column.insert || $column.edit) && !$column.pk)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+ </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+ <el-form-item label="${comment}" prop="${field}">
+ <image-upload v-model="form.${field}"/>
+ </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+ <el-form-item label="${comment}" prop="${field}">
+ <file-upload v-model="form.${field}"/>
+ </el-form-item>
+#elseif($column.htmlType == "editor")
+ <el-form-item label="${comment}">
+ <editor v-model="form.${field}" :min-height="192"/>
+ </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+ <el-option
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :value="parseInt(dict.value)"
+#else
+ :value="dict.value"
+#end
+ ></el-option>
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+ <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+ </el-select>
+ </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+ :label="dict.value">
+ {{dict.label}}
+ </el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-checkbox-group v-model="form.${field}">
+ <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+ </el-checkbox-group>
+ </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio
+ v-for="dict in ${dictType}"
+ :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+ :label="parseInt(dict.value)"
+#else
+ :label="dict.value"
+#end
+ >{{dict.label}}</el-radio>
+ </el-radio-group>
+ </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+ <el-form-item label="${comment}" prop="${field}">
+ <el-radio-group v-model="form.${field}">
+ <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+ </el-radio-group>
+ </el-form-item>
+#elseif($column.htmlType == "datetime")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-date-picker clearable
+ v-model="form.${field}"
+ type="datetime"
+ value-format="YYYY-MM-DD HH:mm:ss"
+ placeholder="璇烽�夋嫨${comment}">
+ </el-date-picker>
+ </el-form-item>
+#elseif($column.htmlType == "textarea")
+ <el-form-item label="${comment}" prop="${field}">
+ <el-input v-model="form.${field}" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+ </el-form-item>
+#end
+#end
+#end
+ </el-form>
+ <template #footer>
+ <div class="dialog-footer">
+ <el-button :loading="buttonLoading" type="primary" @click="submitForm">纭� 瀹�</el-button>
+ <el-button @click="cancel">鍙� 娑�</el-button>
+ </div>
+ </template>
+ </el-dialog>
+ </div>
+</template>
+
+<script setup name="${BusinessName}" lang="ts">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from '@/api/${moduleName}/${businessName}';
+import { ${BusinessName}VO, ${BusinessName}Query, ${BusinessName}Form } from '@/api/${moduleName}/${businessName}/types';
+
+const { proxy } = getCurrentInstance() as ComponentInternalInstance;
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = toRefs<any>(proxy?.useDict(${dicts}));
+#end
+
+const ${businessName}List = ref<${BusinessName}VO[]>([]);
+const buttonLoading = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref<Array<string | number>>([]);
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const dateRange${AttrName} = ref<[DateModelType, DateModelType]>(['', '']);
+#end
+#end
+
+const queryFormRef = ref<ElFormInstance>();
+const ${businessName}FormRef = ref<ElFormInstance>();
+
+const dialog = reactive<DialogOption>({
+ visible: false,
+ title: ''
+});
+
+const initFormData: ${BusinessName}Form = {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.htmlType == "checkbox")
+ $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+ $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+}
+const data = reactive<PageData<${BusinessName}Form, ${BusinessName}Query>>({
+ form: {...initFormData},
+ queryParams: {
+ pageNum: 1,
+ pageSize: 10,
+#foreach ($column in $columns)
+#if($column.query)
+ #if($column.htmlType != "datetime" || $column.queryType != "BETWEEN")
+ $column.javaField: undefined,
+ #end
+#end
+#end
+ params: {
+#foreach ($column in $columns)
+#if($column.query)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ $column.javaField: undefined#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+ }
+ },
+ rules: {
+#foreach ($column in $columns)
+#if($column.insert || $column.edit)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("锛�"))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+ $column.javaField: [
+ { required: true, message: "$comment涓嶈兘涓虹┖", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+ ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+#end
+ }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+const getList = async () => {
+ loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+ queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ proxy?.addDateRange(queryParams.value, dateRange${AttrName}.value, '${AttrName}');
+#end
+#end
+ const res = await list${BusinessName}(queryParams.value);
+ ${businessName}List.value = res.rows;
+ total.value = res.total;
+ loading.value = false;
+}
+
+/** 鍙栨秷鎸夐挳 */
+const cancel = () => {
+ reset();
+ dialog.visible = false;
+}
+
+/** 琛ㄥ崟閲嶇疆 */
+const reset = () => {
+ form.value = {...initFormData};
+ ${businessName}FormRef.value?.resetFields();
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+const handleQuery = () => {
+ queryParams.value.pageNum = 1;
+ getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+const resetQuery = () => {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+ dateRange${AttrName}.value = ['', ''];
+#end
+#end
+ queryFormRef.value?.resetFields();
+ handleQuery();
+}
+
+/** 澶氶�夋閫変腑鏁版嵁 */
+const handleSelectionChange = (selection: ${BusinessName}VO[]) => {
+ ids.value = selection.map(item => item.${pkColumn.javaField});
+ single.value = selection.length != 1;
+ multiple.value = !selection.length;
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+const handleAdd = () => {
+ dialog.visible = true;
+ dialog.title = "娣诲姞${functionName}";
+ nextTick(() => {
+ reset();
+ });
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+const handleUpdate = (row?: ${BusinessName}VO) => {
+ loading.value = true
+ dialog.visible = true;
+ dialog.title = "淇敼${functionName}";
+ nextTick(async () => {
+ reset();
+ const _${pkColumn.javaField} = row?.${pkColumn.javaField} || ids.value[0]
+ const res = await get${BusinessName}(_${pkColumn.javaField});
+ loading.value = false;
+ Object.assign(form.value, res.data);
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+ form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+ });
+}
+
+/** 鎻愪氦鎸夐挳 */
+const submitForm = () => {
+ ${businessName}FormRef.value?.validate(async (valid: boolean) => {
+ if (valid) {
+ buttonLoading.value = true;
+ #foreach ($column in $columns)
+ #if($column.htmlType == "checkbox")
+ form.value.$column.javaField = form.value.${column.javaField}.join(",");
+ #end
+ #end
+ if (form.value.${pkColumn.javaField}) {
+ await update${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+ } else {
+ await add${BusinessName}(form.value).finally(() => buttonLoading.value = false);
+ }
+ proxy?.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+ dialog.visible = false;
+ await getList();
+ }
+ });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+const handleDelete = async (row?: ${BusinessName}VO) => {
+ const _${pkColumn.javaField}s = row?.${pkColumn.javaField} || ids.value;
+ await proxy?.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + _${pkColumn.javaField}s + '"鐨勬暟鎹」锛�').finally(() => loading.value = false);
+ await del${BusinessName}(_${pkColumn.javaField}s);
+ proxy?.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+ await getList();
+}
+
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+const handleExport = () => {
+ proxy?.download('${moduleName}/${businessName}/export', {
+ ...queryParams.value
+ }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+}
+
+onMounted(() => {
+ getList();
+});
+</script>
diff --git a/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 0000000..9fb48d9
--- /dev/null
+++ b/ruoyi-modules/ruoyi-gen/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-job/Dockerfile b/ruoyi-modules/ruoyi-job/Dockerfile
new file mode 100644
index 0000000..2922d84
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/Dockerfile
@@ -0,0 +1,23 @@
+#FROM findepi/graalvm:java17-native
+FROM openjdk:17.0.2-oraclelinux8
+
+MAINTAINER Lion Li
+
+RUN mkdir -p /ruoyi/job/logs \
+ /ruoyi/job/temp \
+ /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/job
+
+ENV SERVER_PORT=9203 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-job.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+ #-Dskywalking.agent.service_name=ruoyi-job \
+ #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+ -jar app.jar \
+ -XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
+
diff --git a/ruoyi-modules/ruoyi-job/pom.xml b/ruoyi-modules/ruoyi-job/pom.xml
new file mode 100644
index 0000000..6b92a99
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/pom.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-modules</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ruoyi-job</artifactId>
+
+ <description>
+ ruoyi-job 浠诲姟璋冨害妯″潡
+ </description>
+
+ <dependencies>
+
+ <!-- SpringCloud Alibaba Nacos -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+ </dependency>
+
+ <!-- SpringCloud Alibaba Nacos Config -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+ </dependency>
+
+ <!-- RuoYi Common Log -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-log</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dict</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dubbo</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-job</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-tenant</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mybatis</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-security</artifactId>
+ </dependency>
+
+ <!-- RuoYi Api System -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-api-system</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${project.artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/RuoYiJobApplication.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/RuoYiJobApplication.java
new file mode 100644
index 0000000..ddc03d1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/RuoYiJobApplication.java
@@ -0,0 +1,24 @@
+package org.dromara.job;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 浠诲姟璋冨害妯″潡
+ *
+ * @author Lion Li
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiJobApplication {
+
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(RuoYiJobApplication.class);
+ application.setApplicationStartup(new BufferingApplicationStartup(2048));
+ application.run(args);
+ System.out.println("(鈾モ棤鈥库棤)锞夛緸 浠诲姟璋冨害妯″潡鍚姩鎴愬姛 醿�(麓凇`醿�)锞� ");
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/BroadcastProcessorDemo.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/BroadcastProcessorDemo.java
new file mode 100644
index 0000000..2b4c28a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/BroadcastProcessorDemo.java
@@ -0,0 +1,56 @@
+package org.dromara.job.processors;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import tech.powerjob.common.utils.NetUtils;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.TaskResult;
+import tech.powerjob.worker.core.processor.sdk.BroadcastProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.List;
+
+/**
+ * 骞挎挱澶勭悊鍣� 绀轰緥
+ *
+ * @author tjq
+ * @since 2020/4/17
+ */
+@Slf4j
+@Component
+public class BroadcastProcessorDemo implements BroadcastProcessor {
+
+ @Override
+ public ProcessResult preProcess(TaskContext context) {
+ System.out.println("===== BroadcastProcessorDemo#preProcess ======");
+ context.getOmsLogger().info("BroadcastProcessorDemo#preProcess, current host: {}", NetUtils.getLocalHost());
+ if ("rootFailed".equals(context.getJobParams())) {
+ return new ProcessResult(false, "console need failed");
+ } else {
+ return new ProcessResult(true);
+ }
+ }
+
+ @Override
+ public ProcessResult process(TaskContext taskContext) throws Exception {
+ OmsLogger logger = taskContext.getOmsLogger();
+ System.out.println("===== BroadcastProcessorDemo#process ======");
+ logger.info("BroadcastProcessorDemo#process, current host: {}", NetUtils.getLocalHost());
+ long sleepTime = 1000;
+ try {
+ sleepTime = Long.parseLong(taskContext.getJobParams());
+ } catch (Exception e) {
+ logger.warn("[BroadcastProcessor] parse sleep time failed!", e);
+ }
+ Thread.sleep(Math.max(sleepTime, 1000));
+ return new ProcessResult(true);
+ }
+
+ @Override
+ public ProcessResult postProcess(TaskContext context, List<TaskResult> taskResults) {
+ System.out.println("===== BroadcastProcessorDemo#postProcess ======");
+ context.getOmsLogger().info("BroadcastProcessorDemo#postProcess, current host: {}, taskResult: {}", NetUtils.getLocalHost(), taskResults);
+ return new ProcessResult(true, "success");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/LogTestProcessor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/LogTestProcessor.java
new file mode 100644
index 0000000..2a1000f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/LogTestProcessor.java
@@ -0,0 +1,41 @@
+package org.dromara.job.processors;
+
+import com.alibaba.fastjson.JSONObject;
+import org.springframework.stereotype.Component;
+import tech.powerjob.official.processors.util.CommonUtils;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.Date;
+import java.util.Optional;
+
+/**
+ * LogTestProcessor
+ *
+ * @author tjq
+ * @since 2022/9/18
+ */
+@Component
+public class LogTestProcessor implements BasicProcessor {
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+
+ final OmsLogger omsLogger = context.getOmsLogger();
+ final String parseParams = CommonUtils.parseParams(context);
+ final JSONObject config = Optional.ofNullable(JSONObject.parseObject(parseParams)).orElse(new JSONObject());
+
+ final long loopTimes = Optional.ofNullable(config.getLong("loopTimes")).orElse(1000L);
+
+ for (int i = 0; i < loopTimes; i++) {
+ omsLogger.debug("[DEBUG] one DEBUG log in {}", new Date());
+ omsLogger.info("[INFO] one INFO log in {}", new Date());
+ omsLogger.warn("[WARN] one WARN log in {}", new Date());
+ omsLogger.error("[ERROR] one ERROR log in {}", new Date());
+ }
+
+ return new ProcessResult(true);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapProcessorDemo.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapProcessorDemo.java
new file mode 100644
index 0000000..720d333
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapProcessorDemo.java
@@ -0,0 +1,93 @@
+package org.dromara.job.processors;
+
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import org.dromara.common.json.utils.JsonUtils;
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.MapProcessor;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * Map澶勭悊鍣� 绀轰緥
+ *
+ * @author tjq
+ * @since 2020/4/18
+ */
+@Component
+public class MapProcessorDemo implements MapProcessor {
+
+
+ /**
+ * 姣忎竴鎵瑰彂閫佷换鍔″ぇ灏�
+ */
+ private static final int BATCH_SIZE = 100;
+ /**
+ * 鍙戦�佺殑鎵规
+ */
+ private static final int BATCH_NUM = 5;
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+
+ log.info("============== MapProcessorDemo#process ==============");
+ log.info("isRootTask:{}", isRootTask());
+ log.info("taskContext:{}", JsonUtils.toJsonString(context));
+
+ if (isRootTask()) {
+ log.info("==== MAP ====");
+ List<SubTask> subTasks = Lists.newLinkedList();
+ for (int j = 0; j < BATCH_NUM; j++) {
+ SubTask subTask = new SubTask();
+ subTask.siteId = j;
+ subTask.itemIds = Lists.newLinkedList();
+ subTasks.add(subTask);
+ for (int i = 0; i < BATCH_SIZE; i++) {
+ subTask.itemIds.add(i + j * 100);
+ }
+ }
+ map(subTasks, "MAP_TEST_TASK");
+ return new ProcessResult(true, "map successfully");
+ } else {
+
+ log.info("==== PROCESS ====");
+ SubTask subTask = (SubTask) context.getSubTask();
+ for (Integer itemId : subTask.getItemIds()) {
+ if (Thread.interrupted()) {
+ // 浠诲姟琚腑鏂�
+ log.info("job has been stop! so stop to process subTask: {} => {}", subTask.getSiteId(), itemId);
+ break;
+ }
+ log.info("processing subTask: {} => {}", subTask.getSiteId(), itemId);
+ int max = Integer.MAX_VALUE >> 7;
+ for (int i = 0; ; i++) {
+ // 妯℃嫙鑰楁椂鎿嶄綔
+ if (i > max) {
+ break;
+ }
+ }
+ }
+ // 娴嬭瘯鍦� Map 浠诲姟涓拷鍔犱笂涓嬫枃
+ context.getWorkflowContext().appendData2WfContext("Yasuo", "A sword's poor company for a long road.");
+ boolean b = ThreadLocalRandom.current().nextBoolean();
+ if (context.getCurrentRetryTimes() >= 1) {
+ // 閲嶈瘯鐨勮瘽涓�瀹氫細鎴愬姛
+ b = true;
+ }
+ return new ProcessResult(b, "RESULT:" + b);
+ }
+ }
+
+ @Getter
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class SubTask {
+ private Integer siteId;
+ private List<Integer> itemIds;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapReduceProcessorDemo.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapReduceProcessorDemo.java
new file mode 100644
index 0000000..1498854
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/MapReduceProcessorDemo.java
@@ -0,0 +1,93 @@
+package org.dromara.job.processors;
+
+import cn.hutool.core.lang.Dict;
+import com.google.common.collect.Lists;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.json.utils.JsonUtils;
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.TaskResult;
+import tech.powerjob.worker.core.processor.sdk.MapReduceProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.List;
+import java.util.concurrent.ThreadLocalRandom;
+
+/**
+ * MapReduce 澶勭悊鍣ㄧず渚�
+ * 鎺у埗鍙板弬鏁帮細{"batchSize": 100, "batchNum": 2}
+ *
+ * @author tjq
+ * @since 2020/4/17
+ */
+@Slf4j
+@Component
+public class MapReduceProcessorDemo implements MapReduceProcessor {
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+
+ OmsLogger omsLogger = context.getOmsLogger();
+
+ log.info("============== TestMapReduceProcessor#process ==============");
+ log.info("isRootTask:{}", isRootTask());
+ log.info("taskContext:{}", JsonUtils.toJsonString(context));
+
+ // 鏍规嵁鎺у埗鍙板弬鏁拌幏鍙朚R鎵规鍙婂瓙浠诲姟澶у皬
+ final Dict jobParams = JsonUtils.parseMap(context.getJobParams());
+
+ Integer batchSize = (Integer) jobParams.getOrDefault("batchSize", 100);
+ Integer batchNum = (Integer) jobParams.getOrDefault("batchNum", 10);
+
+ if (isRootTask()) {
+ log.info("==== MAP ====");
+ omsLogger.info("[DemoMRProcessor] start root task~");
+ List<TestSubTask> subTasks = Lists.newLinkedList();
+ for (int j = 0; j < batchNum; j++) {
+ for (int i = 0; i < batchSize; i++) {
+ int x = j * batchSize + i;
+ subTasks.add(new TestSubTask("name" + x, x));
+ }
+ map(subTasks, "MAP_TEST_TASK");
+ subTasks.clear();
+ }
+ omsLogger.info("[DemoMRProcessor] map success~");
+ return new ProcessResult(true, "MAP_SUCCESS");
+ } else {
+ log.info("==== NORMAL_PROCESS ====");
+ omsLogger.info("[DemoMRProcessor] process subTask: {}.", JsonUtils.toJsonString(context.getSubTask()));
+ log.info("subTask: {}", JsonUtils.toJsonString(context.getSubTask()));
+ Thread.sleep(1000);
+ if (context.getCurrentRetryTimes() == 0) {
+ return new ProcessResult(false, "FIRST_FAILED");
+ } else {
+ return new ProcessResult(true, "PROCESS_SUCCESS");
+ }
+ }
+ }
+
+ @Override
+ public ProcessResult reduce(TaskContext context, List<TaskResult> taskResults) {
+ log.info("================ MapReduceProcessorDemo#reduce ================");
+ log.info("TaskContext: {}", JsonUtils.toJsonString(context));
+ log.info("List<TaskResult>: {}", JsonUtils.toJsonString(taskResults));
+ context.getOmsLogger().info("MapReduce job finished, result is {}.", taskResults);
+
+ boolean success = ThreadLocalRandom.current().nextBoolean();
+ return new ProcessResult(success, context + ": " + success);
+ }
+
+ @Getter
+ @ToString
+ @NoArgsConstructor
+ @AllArgsConstructor
+ public static class TestSubTask {
+ private String name;
+ private int age;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/SimpleProcessor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/SimpleProcessor.java
new file mode 100644
index 0000000..3342cfe
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/SimpleProcessor.java
@@ -0,0 +1,35 @@
+package org.dromara.job.processors;
+
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.Optional;
+
+/**
+ * @author Echo009
+ * @since 2022/4/27
+ */
+@Component
+public class SimpleProcessor implements BasicProcessor {
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+
+ OmsLogger logger = context.getOmsLogger();
+
+ String jobParams = Optional.ofNullable(context.getJobParams()).orElse("S");
+ logger.info("Current context:{}", context.getWorkflowContext());
+ logger.info("Current job params:{}", jobParams);
+
+ // 娴嬭瘯涓枃闂 #581
+ if (jobParams.contains("CN")) {
+ return new ProcessResult(true, "浠诲姟鎴愬姛鍟︼紒锛侊紒");
+ }
+
+ return jobParams.contains("F") ? new ProcessResult(false) : new ProcessResult(true, "yeah!");
+
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/StandaloneProcessorDemo.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/StandaloneProcessorDemo.java
new file mode 100644
index 0000000..ea8eff3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/StandaloneProcessorDemo.java
@@ -0,0 +1,51 @@
+package org.dromara.job.processors;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.Collections;
+
+/**
+ * 鍗曟満澶勭悊鍣� 绀轰緥
+ *
+ * @author tjq
+ * @since 2020/4/17
+ */
+@Slf4j
+@Component
+public class StandaloneProcessorDemo implements BasicProcessor {
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+ OmsLogger omsLogger = context.getOmsLogger();
+ omsLogger.info("StandaloneProcessorDemo start process,context is {}.", context);
+ omsLogger.info("Notice! If you want this job process failed, your jobParams need to be 'failed'");
+ omsLogger.info("Let's test the exception~");
+ // 娴嬭瘯寮傚父鏃ュ織
+ try {
+ Collections.emptyList().add("277");
+ } catch (Exception e) {
+ omsLogger.error("oh~it seems that we have an exception~", e);
+ }
+ log.info("================ StandaloneProcessorDemo#process ================");
+ log.info("jobParam:{}", context.getJobParams());
+ log.info("instanceParams:{}", context.getInstanceParams());
+ String param;
+ // 瑙f瀽鍙傛暟锛岄潪澶勪簬宸ヤ綔娴佷腑鏃讹紝浼樺厛鍙栧疄渚嬪弬鏁帮紙鍏佽鍔ㄦ�乕instanceParams]瑕嗙洊闈欐�佸弬鏁癧jobParams]锛�
+ if (context.getWorkflowContext() == null) {
+ param = StringUtils.isBlank(context.getInstanceParams()) ? context.getJobParams() : context.getInstanceParams();
+ } else {
+ param = context.getJobParams();
+ }
+ // 鏍规嵁鍙傛暟鍒ゆ柇鏄惁鎴愬姛
+ boolean success = !"failed".equals(param);
+ omsLogger.info("StandaloneProcessorDemo finished process,success: {}", success);
+ omsLogger.info("anyway, we finished the job successfully~Congratulations!");
+ return new ProcessResult(success, context + ": " + success);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/TimeoutProcessor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/TimeoutProcessor.java
new file mode 100644
index 0000000..4b5899f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/processors/TimeoutProcessor.java
@@ -0,0 +1,25 @@
+package org.dromara.job.processors;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
+
+/**
+ * 娴嬭瘯瓒呮椂浠诲姟锛堝彲涓柇锛�
+ *
+ * @author tjq
+ * @since 2020/4/20
+ */
+@Component
+@Slf4j
+public class TimeoutProcessor implements BasicProcessor {
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+ long sleepTime = Long.parseLong(context.getJobParams());
+ log.info("TaskInstance({}) will sleep {} ms", context.getInstanceId(), sleepTime);
+ Thread.sleep(Long.parseLong(context.getJobParams()));
+ return new ProcessResult(true, "impossible~~~~QAQ~");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/workflow/WorkflowStandaloneProcessor.java b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/workflow/WorkflowStandaloneProcessor.java
new file mode 100644
index 0000000..51187e3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/java/org/dromara/job/workflow/WorkflowStandaloneProcessor.java
@@ -0,0 +1,36 @@
+package org.dromara.job.workflow;
+
+import com.alibaba.fastjson.JSON;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import tech.powerjob.worker.core.processor.ProcessResult;
+import tech.powerjob.worker.core.processor.TaskContext;
+import tech.powerjob.worker.core.processor.sdk.BasicProcessor;
+import tech.powerjob.worker.log.OmsLogger;
+
+import java.util.Map;
+
+/**
+ * 宸ヤ綔娴佹祴璇�
+ *
+ * @author tjq
+ * @since 2020/6/2
+ */
+@Component
+@Slf4j
+public class WorkflowStandaloneProcessor implements BasicProcessor {
+
+ @Override
+ public ProcessResult process(TaskContext context) throws Exception {
+ OmsLogger logger = context.getOmsLogger();
+ logger.info("current jobParams: {}", context.getJobParams());
+ logger.info("current context: {}", context.getWorkflowContext());
+ log.info("jobParams:{}", context.getJobParams());
+ log.info("currentContext:{}", JSON.toJSONString(context));
+
+ // 灏濊瘯鑾峰彇涓婃父浠诲姟
+ Map<String, String> workflowContext = context.getWorkflowContext().fetchWorkflowContext();
+ log.info("宸ヤ綔娴佷笂涓嬫枃鏁版嵁:{}", workflowContext);
+ return new ProcessResult(true, context.getJobId() + " process successfully.");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/application.yml b/ruoyi-modules/ruoyi-job/src/main/resources/application.yml
new file mode 100644
index 0000000..5d5b2d7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+# Tomcat
+server:
+ port: 9203
+
+# Spring
+spring:
+ application:
+ # 搴旂敤鍚嶇О
+ name: ruoyi-job
+ profiles:
+ # 鐜閰嶇疆
+ active: @profiles.active@
+
+--- # nacos 閰嶇疆
+spring:
+ cloud:
+ nacos:
+ # nacos 鏈嶅姟鍦板潃
+ server-addr: @nacos.server@
+ discovery:
+ # 娉ㄥ唽缁�
+ group: @nacos.discovery.group@
+ namespace: ${spring.profiles.active}
+ config:
+ # 閰嶇疆缁�
+ group: @nacos.config.group@
+ namespace: ${spring.profiles.active}
+ config:
+ import:
+ - optional:nacos:application-common.yml
+ - optional:nacos:datasource.yml
+ - optional:nacos:${spring.application.name}.yml
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt
new file mode 100644
index 0000000..683f20c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ _ _
+ (_) (_) | |
+ _ __ _ _ ___ _ _ _ ______ _ ___ | |__
+| '__| | | |/ _ \| | | | |______| |/ _ \| '_ \
+| | | |_| | (_) | |_| | | | | (_) | |_) |
+|_| \__,_|\___/ \__, |_| | |\___/|_.__/
+ __/ | _/ |
+ |___/ |__/
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/logback-plus.xml b/ruoyi-modules/ruoyi-job/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..a2e187f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/resources/logback-plus.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 鏃ュ織瀛樻斁璺緞 -->
+ <property name="log.path" value="logs/${project.artifactId}"/>
+ <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+ <property name="console.log.pattern"
+ value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+ <!-- 鎺у埗鍙拌緭鍑� -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${console.log.pattern}</pattern>
+ <charset>utf-8</charset>
+ </encoder>
+ </appender>
+
+ <include resource="logback-common.xml" />
+
+ <include resource="logback-logstash.xml" />
+
+ <!-- 寮�鍚� skywalking 鏃ュ織鏀堕泦 -->
+ <include resource="logback-skylog.xml" />
+
+ <!--绯荤粺鎿嶄綔鏃ュ織-->
+ <root level="info">
+ <appender-ref ref="console"/>
+ </root>
+</configuration>
diff --git a/ruoyi-modules/ruoyi-job/src/main/resources/spy.properties b/ruoyi-modules/ruoyi-job/src/main/resources/spy.properties
new file mode 100644
index 0000000..abbd893
--- /dev/null
+++ b/ruoyi-modules/ruoyi-job/src/main/resources/spy.properties
@@ -0,0 +1,28 @@
+# p6spy 鎬ц兘鍒嗘瀽鎻掍欢閰嶇疆鏂囦欢
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 鑷畾涔夋棩蹇楁墦鍗�
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#鏃ュ織杈撳嚭鍒版帶鍒跺彴
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 浣跨敤鏃ュ織绯荤粺璁板綍 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 璁剧疆 p6spy driver 浠g悊
+#deregisterdrivers=true
+# 鍙栨秷JDBC URL鍓嶇紑
+useprefix=true
+# 閰嶇疆璁板綍 Log 渚嬪,鍙幓鎺夌殑缁撴灉闆嗘湁error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 鏃ユ湡鏍煎紡
+dateformat=yyyy-MM-dd HH:mm:ss
+# SQL璇彞鎵撳嵃鏃堕棿鏍煎紡
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
+# 瀹為檯椹卞姩鍙涓�
+#driverlist=org.h2.Driver
+# 鏄惁寮�鍚參SQL璁板綍
+outagedetection=true
+# 鎱QL璁板綍鏍囧噯 2 绉�
+outagedetectioninterval=2
+# 鏄惁杩囨护 Log
+filter=true
+# 杩囨护 Log 鏃舵墍鎺掗櫎鐨� sql 鍏抽敭瀛楋紝浠ラ�楀彿鍒嗛殧
+exclude=SELECT 1
diff --git a/ruoyi-modules/ruoyi-resource/Dockerfile b/ruoyi-modules/ruoyi-resource/Dockerfile
new file mode 100644
index 0000000..6e0df4f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/Dockerfile
@@ -0,0 +1,23 @@
+#FROM findepi/graalvm:java17-native
+FROM openjdk:17.0.2-oraclelinux8
+
+MAINTAINER Lion Li
+
+RUN mkdir -p /ruoyi/resource/logs \
+ /ruoyi/resource/temp \
+ /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/resource
+
+ENV SERVER_PORT=9204 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-resource.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+ #-Dskywalking.agent.service_name=ruoyi-resource \
+ #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+ -jar app.jar \
+ -XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
+
diff --git a/ruoyi-modules/ruoyi-resource/pom.xml b/ruoyi-modules/ruoyi-resource/pom.xml
new file mode 100644
index 0000000..6145586
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/pom.xml
@@ -0,0 +1,149 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-modules</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ruoyi-resource</artifactId>
+
+ <description>
+ ruoyi-resource璧勬簮鏈嶅姟
+ </description>
+
+ <dependencies>
+
+ <!-- SpringCloud Alibaba Nacos -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+ </dependency>
+
+ <!-- SpringCloud Alibaba Nacos Config -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-sentinel</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-doc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dubbo</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-seata</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-log</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-oss</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-ratelimiter</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mail</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-sms</artifactId>
+ </dependency>
+
+ <!-- 鐭俊 鐢ㄥ摢涓鍏ュ摢涓緷璧� -->
+<!-- <dependency>-->
+<!-- <groupId>com.aliyun</groupId>-->
+<!-- <artifactId>dysmsapi20170525</artifactId>-->
+<!-- </dependency>-->
+
+<!-- <dependency>-->
+<!-- <groupId>com.tencentcloudapi</groupId>-->
+<!-- <artifactId>tencentcloud-sdk-java-sms</artifactId>-->
+<!-- </dependency>-->
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-tenant</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-security</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-translation</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-websocket</artifactId>
+ </dependency>
+
+ <!-- RuoYi Api System -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-api-system</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-api-resource</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${project.artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/RuoYiResourceApplication.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/RuoYiResourceApplication.java
new file mode 100644
index 0000000..e3d9920
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/RuoYiResourceApplication.java
@@ -0,0 +1,23 @@
+package org.dromara.resource;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 璧勬簮鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@EnableDubbo
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+public class RuoYiResourceApplication {
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(RuoYiResourceApplication.class);
+ application.setApplicationStartup(new BufferingApplicationStartup(2048));
+ application.run(args);
+ System.out.println("(鈾モ棤鈥库棤)锞夛緸 璧勬簮鏈嶅姟妯″潡鍚姩鎴愬姛 醿�(麓凇`醿�)锞� ");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysEmailController.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysEmailController.java
new file mode 100644
index 0000000..19da5ba
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysEmailController.java
@@ -0,0 +1,60 @@
+package org.dromara.resource.controller;
+
+
+import cn.hutool.core.util.RandomUtil;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.mail.config.properties.MailProperties;
+import org.dromara.common.mail.utils.MailUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import jakarta.validation.constraints.NotBlank;
+import java.time.Duration;
+
+/**
+ * 閭欢鍔熻兘
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/email")
+public class SysEmailController extends BaseController {
+
+ private final MailProperties mailProperties;
+
+ /**
+ * 閭楠岃瘉鐮�
+ *
+ * @param email 閭
+ */
+ @RateLimiter(key = "#email", time = 60, count = 1)
+ @GetMapping("/code")
+ public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
+ if (!mailProperties.getEnabled()) {
+ return R.fail("褰撳墠绯荤粺娌℃湁寮�鍚偖绠卞姛鑳斤紒");
+ }
+ String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
+ String code = RandomUtil.randomNumbers(4);
+ RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+ try {
+ MailUtils.sendText(email, "鐧诲綍楠岃瘉鐮�", "鎮ㄦ湰娆¢獙璇佺爜涓猴細" + code + "锛屾湁鏁堟�т负" + Constants.CAPTCHA_EXPIRATION + "鍒嗛挓锛岃灏藉揩濉啓銆�");
+ } catch (Exception e) {
+ log.error("楠岃瘉鐮佺煭淇″彂閫佸紓甯� => {}", e.getMessage());
+ return R.fail(e.getMessage());
+ }
+ return R.ok();
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssConfigController.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssConfigController.java
new file mode 100644
index 0000000..506cdb7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssConfigController.java
@@ -0,0 +1,100 @@
+package org.dromara.resource.controller;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.resource.domain.bo.SysOssConfigBo;
+import org.dromara.resource.domain.vo.SysOssConfigVo;
+import org.dromara.resource.service.ISysOssConfigService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.Arrays;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Controller
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/oss/config")
+public class SysOssConfigController extends BaseController {
+
+ private final ISysOssConfigService iSysOssConfigService;
+
+ /**
+ * 鏌ヨ瀵硅薄瀛樺偍閰嶇疆鍒楄〃
+ */
+ @SaCheckPermission("system:ossConfig:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysOssConfigVo> list(@Validated(QueryGroup.class) SysOssConfigBo bo, PageQuery pageQuery) {
+ return iSysOssConfigService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 鑾峰彇瀵硅薄瀛樺偍閰嶇疆璇︾粏淇℃伅
+ *
+ * @param ossConfigId OSS閰嶇疆ID
+ */
+ @SaCheckPermission("system:ossConfig:list")
+ @GetMapping("/{ossConfigId}")
+ public R<SysOssConfigVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable("ossConfigId") Long ossConfigId) {
+ return R.ok(iSysOssConfigService.queryById(ossConfigId));
+ }
+
+ /**
+ * 鏂板瀵硅薄瀛樺偍閰嶇疆
+ */
+ @SaCheckPermission("system:ossConfig:add")
+ @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.INSERT)
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody SysOssConfigBo bo) {
+ return toAjax(iSysOssConfigService.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼瀵硅薄瀛樺偍閰嶇疆
+ */
+ @SaCheckPermission("system:ossConfig:edit")
+ @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.UPDATE)
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysOssConfigBo bo) {
+ return toAjax(iSysOssConfigService.updateByBo(bo));
+ }
+
+ /**
+ * 鍒犻櫎瀵硅薄瀛樺偍閰嶇疆
+ *
+ * @param ossConfigIds OSS閰嶇疆ID涓�
+ */
+ @SaCheckPermission("system:ossConfig:remove")
+ @Log(title = "瀵硅薄瀛樺偍閰嶇疆", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ossConfigIds}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable Long[] ossConfigIds) {
+ return toAjax(iSysOssConfigService.deleteWithValidByIds(Arrays.asList(ossConfigIds), true));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckPermission("system:ossConfig:edit")
+ @Log(title = "瀵硅薄瀛樺偍鐘舵�佷慨鏀�", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysOssConfigBo bo) {
+ return toAjax(iSysOssConfigService.updateOssConfigStatus(bo));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssController.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssController.java
new file mode 100644
index 0000000..4efe0ab
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysOssController.java
@@ -0,0 +1,106 @@
+package org.dromara.resource.controller;
+
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.QueryGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.resource.domain.bo.SysOssBo;
+import org.dromara.resource.domain.vo.SysOssUploadVo;
+import org.dromara.resource.domain.vo.SysOssVo;
+import org.dromara.resource.service.ISysOssService;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 鏂囦欢涓婁紶 鎺у埗灞�
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/oss")
+public class SysOssController extends BaseController {
+
+ private final ISysOssService iSysOssService;
+
+ /**
+ * 鏌ヨOSS瀵硅薄瀛樺偍鍒楄〃
+ */
+ @SaCheckPermission("system:oss:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysOssVo> list(@Validated(QueryGroup.class) SysOssBo bo, PageQuery pageQuery) {
+ return iSysOssService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 鏌ヨOSS瀵硅薄鍩轰簬id涓�
+ *
+ * @param ossIds OSS瀵硅薄ID涓�
+ */
+ @SaCheckPermission("system:oss:list")
+ @GetMapping("/listByIds/{ossIds}")
+ public R<List<SysOssVo>> listByIds(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable Long[] ossIds) {
+ List<SysOssVo> list = iSysOssService.listByIds(Arrays.asList(ossIds));
+ return R.ok(list);
+ }
+
+ /**
+ * 涓婁紶OSS瀵硅薄瀛樺偍
+ *
+ * @param file 鏂囦欢
+ */
+ @SaCheckPermission("system:oss:upload")
+ @Log(title = "OSS瀵硅薄瀛樺偍", businessType = BusinessType.INSERT)
+ @PostMapping(value = "/upload", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public R<SysOssUploadVo> upload(@RequestPart("file") MultipartFile file) {
+ if (ObjectUtil.isNull(file)) {
+ return R.fail("涓婁紶鏂囦欢涓嶈兘涓虹┖");
+ }
+ SysOssVo oss = iSysOssService.upload(file);
+ SysOssUploadVo uploadVo = new SysOssUploadVo();
+ uploadVo.setUrl(oss.getUrl());
+ uploadVo.setFileName(oss.getOriginalName());
+ uploadVo.setOssId(oss.getOssId().toString());
+ return R.ok(uploadVo);
+ }
+
+ /**
+ * 涓嬭浇OSS瀵硅薄瀛樺偍
+ *
+ * @param ossId OSS瀵硅薄ID
+ */
+ @SaCheckPermission("system:oss:download")
+ @GetMapping("/download/{ossId}")
+ public void download(@PathVariable Long ossId, HttpServletResponse response) throws IOException {
+ iSysOssService.download(ossId, response);
+ }
+
+ /**
+ * 鍒犻櫎OSS瀵硅薄瀛樺偍
+ *
+ * @param ossIds OSS瀵硅薄ID涓�
+ */
+ @SaCheckPermission("system:oss:remove")
+ @Log(title = "OSS瀵硅薄瀛樺偍", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ossIds}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖") @PathVariable Long[] ossIds) {
+ return toAjax(iSysOssService.deleteWithValidByIds(Arrays.asList(ossIds), true));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java
new file mode 100644
index 0000000..1033942
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/controller/SysSmsController.java
@@ -0,0 +1,62 @@
+package org.dromara.resource.controller;
+
+
+import cn.hutool.core.util.RandomUtil;
+import jakarta.validation.constraints.NotBlank;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.ratelimiter.annotation.RateLimiter;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.sms4j.provider.enumerate.SupplierType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.time.Duration;
+import java.util.LinkedHashMap;
+
+/**
+ * 鐭俊鍔熻兘
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/sms")
+public class SysSmsController extends BaseController {
+
+ /**
+ * 鐭俊楠岃瘉鐮�
+ *
+ * @param phonenumber 鐢ㄦ埛鎵嬫満鍙�
+ */
+ @RateLimiter(key = "#phonenumber", time = 60, count = 1)
+ @GetMapping("/code")
+ public R<Void> smsCaptcha(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
+ String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
+ String code = RandomUtil.randomNumbers(4);
+ RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
+ // 楠岃瘉鐮佹ā鏉縤d 鑷澶勭悊 (鏌ユ暟鎹簱鎴栧啓姝诲潎鍙�)
+ String templateId = "";
+ LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
+ map.put("code", code);
+ SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+ SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
+ if (!"OK".equals(smsResponse.getCode())) {
+ log.error("楠岃瘉鐮佺煭淇″彂閫佸紓甯� => {}", smsResponse);
+ return R.fail(smsResponse.getMessage());
+ }
+ return R.ok();
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOss.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOss.java
new file mode 100644
index 0000000..8a1cc4f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOss.java
@@ -0,0 +1,50 @@
+package org.dromara.resource.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * OSS瀵硅薄瀛樺偍瀵硅薄
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_oss")
+public class SysOss extends TenantEntity {
+
+ /**
+ * 瀵硅薄瀛樺偍涓婚敭
+ */
+ @TableId(value = "oss_id")
+ private Long ossId;
+
+ /**
+ * 鏂囦欢鍚�
+ */
+ private String fileName;
+
+ /**
+ * 鍘熷悕
+ */
+ private String originalName;
+
+ /**
+ * 鏂囦欢鍚庣紑鍚�
+ */
+ private String fileSuffix;
+
+ /**
+ * URL鍦板潃
+ */
+ private String url;
+
+ /**
+ * 鏈嶅姟鍟�
+ */
+ private String service;
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOssConfig.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOssConfig.java
new file mode 100644
index 0000000..aebc56e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/SysOssConfig.java
@@ -0,0 +1,90 @@
+package org.dromara.resource.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_oss_config")
+public class SysOssConfig extends BaseEntity {
+
+ /**
+ * 涓诲缓
+ */
+ @TableId(value = "oss_config_id")
+ private Long ossConfigId;
+
+ /**
+ * 閰嶇疆key
+ */
+ private String configKey;
+
+ /**
+ * accessKey
+ */
+ private String accessKey;
+
+ /**
+ * 绉橀挜
+ */
+ private String secretKey;
+
+ /**
+ * 妗跺悕绉�
+ */
+ private String bucketName;
+
+ /**
+ * 鍓嶇紑
+ */
+ private String prefix;
+
+ /**
+ * 璁块棶绔欑偣
+ */
+ private String endpoint;
+
+ /**
+ * 鑷畾涔夊煙鍚�
+ */
+ private String domain;
+
+
+ /**
+ * 鏄惁https锛�0鍚� 1鏄級
+ */
+ private String isHttps;
+
+ /**
+ * 鍩�
+ */
+ private String region;
+
+ /**
+ * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+ */
+ private String status;
+
+ /**
+ * 鎵╁睍瀛楁
+ */
+ private String ext1;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+ */
+ private String accessPolicy;
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssBo.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssBo.java
new file mode 100644
index 0000000..0f399db
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssBo.java
@@ -0,0 +1,49 @@
+package org.dromara.resource.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.resource.domain.SysOss;
+
+/**
+ * OSS瀵硅薄瀛樺偍鍒嗛〉鏌ヨ瀵硅薄 sys_oss
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysOss.class, reverseConvertGenerate = false)
+public class SysOssBo extends BaseEntity {
+
+ /**
+ * ossId
+ */
+ private Long ossId;
+
+ /**
+ * 鏂囦欢鍚�
+ */
+ private String fileName;
+
+ /**
+ * 鍘熷悕
+ */
+ private String originalName;
+
+ /**
+ * 鏂囦欢鍚庣紑鍚�
+ */
+ private String fileSuffix;
+
+ /**
+ * URL鍦板潃
+ */
+ private String url;
+
+ /**
+ * 鏈嶅姟鍟�
+ */
+ private String service;
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssConfigBo.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssConfigBo.java
new file mode 100644
index 0000000..d3aa801
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/bo/SysOssConfigBo.java
@@ -0,0 +1,111 @@
+package org.dromara.resource.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.resource.domain.SysOssConfig;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆涓氬姟瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysOssConfig.class, reverseConvertGenerate = false)
+public class SysOssConfigBo extends BaseEntity {
+
+ /**
+ * 涓诲缓
+ */
+ @NotNull(message = "涓诲缓涓嶈兘涓虹┖", groups = {EditGroup.class})
+ private Long ossConfigId;
+
+ /**
+ * 閰嶇疆key
+ */
+ @NotBlank(message = "閰嶇疆key涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+ @Size(min = 2, max = 100, message = "configKey闀垮害蹇呴』浠嬩簬2鍜�20 涔嬮棿")
+ private String configKey;
+
+ /**
+ * accessKey
+ */
+ @NotBlank(message = "accessKey涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+ @Size(min = 2, max = 100, message = "accessKey闀垮害蹇呴』浠嬩簬2鍜�100 涔嬮棿")
+ private String accessKey;
+
+ /**
+ * 绉橀挜
+ */
+ @NotBlank(message = "secretKey涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+ @Size(min = 2, max = 100, message = "secretKey闀垮害蹇呴』浠嬩簬2鍜�100 涔嬮棿")
+ private String secretKey;
+
+ /**
+ * 妗跺悕绉�
+ */
+ @NotBlank(message = "妗跺悕绉颁笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+ @Size(min = 2, max = 100, message = "bucketName闀垮害蹇呴』浠嬩簬2鍜�100涔嬮棿")
+ private String bucketName;
+
+ /**
+ * 鍓嶇紑
+ */
+ private String prefix;
+
+ /**
+ * 璁块棶绔欑偣
+ */
+ @NotBlank(message = "璁块棶绔欑偣涓嶈兘涓虹┖", groups = {AddGroup.class, EditGroup.class})
+ @Size(min = 2, max = 100, message = "endpoint闀垮害蹇呴』浠嬩簬2鍜�100涔嬮棿")
+ private String endpoint;
+
+ /**
+ * 鑷畾涔夊煙鍚�
+ */
+ private String domain;
+
+ /**
+ * 鏄惁https锛圷=鏄�,N=鍚︼級
+ */
+ private String isHttps;
+
+ /**
+ * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+ */
+ private String status;
+
+ /**
+ * 鍩�
+ */
+ private String region;
+
+ /**
+ * 鎵╁睍瀛楁
+ */
+ private String ext1;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+ */
+ @NotBlank(message = "妗舵潈闄愮被鍨嬩笉鑳戒负绌�", groups = {AddGroup.class, EditGroup.class})
+ private String accessPolicy;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssConfigVo.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssConfigVo.java
new file mode 100644
index 0000000..dc4046f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssConfigVo.java
@@ -0,0 +1,96 @@
+package org.dromara.resource.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.resource.domain.SysOssConfig;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆瑙嗗浘瀵硅薄 sys_oss_config
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Data
+@AutoMapper(target = SysOssConfig.class)
+public class SysOssConfigVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 涓诲缓
+ */
+ private Long ossConfigId;
+
+ /**
+ * 閰嶇疆key
+ */
+ private String configKey;
+
+ /**
+ * accessKey
+ */
+ private String accessKey;
+
+ /**
+ * 绉橀挜
+ */
+ private String secretKey;
+
+ /**
+ * 妗跺悕绉�
+ */
+ private String bucketName;
+
+ /**
+ * 鍓嶇紑
+ */
+ private String prefix;
+
+ /**
+ * 璁块棶绔欑偣
+ */
+ private String endpoint;
+
+ /**
+ * 鑷畾涔夊煙鍚�
+ */
+ private String domain;
+
+ /**
+ * 鏄惁https锛圷=鏄�,N=鍚︼級
+ */
+ private String isHttps;
+
+ /**
+ * 鍩�
+ */
+ private String region;
+
+ /**
+ * 鏄惁榛樿锛�0=鏄�,1=鍚︼級
+ */
+ private String status;
+
+ /**
+ * 鎵╁睍瀛楁
+ */
+ private String ext1;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 妗舵潈闄愮被鍨�(0private 1public 2custom)
+ */
+ private String accessPolicy;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssUploadVo.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssUploadVo.java
new file mode 100644
index 0000000..14d7dc7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssUploadVo.java
@@ -0,0 +1,34 @@
+package org.dromara.resource.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 涓婁紶瀵硅薄淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class SysOssUploadVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * URL鍦板潃
+ */
+ private String url;
+
+ /**
+ * 鏂囦欢鍚�
+ */
+ private String fileName;
+
+ /**
+ * 瀵硅薄瀛樺偍涓婚敭
+ */
+ private String ossId;
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssVo.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssVo.java
new file mode 100644
index 0000000..aa2957b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/domain/vo/SysOssVo.java
@@ -0,0 +1,72 @@
+package org.dromara.resource.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.resource.domain.SysOss;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * OSS瀵硅薄瀛樺偍瑙嗗浘瀵硅薄 sys_oss
+ *
+ * @author Lion Li
+ */
+@Data
+@AutoMapper(target = SysOss.class)
+public class SysOssVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 瀵硅薄瀛樺偍涓婚敭
+ */
+ private Long ossId;
+
+ /**
+ * 鏂囦欢鍚�
+ */
+ private String fileName;
+
+ /**
+ * 鍘熷悕
+ */
+ private String originalName;
+
+ /**
+ * 鏂囦欢鍚庣紑鍚�
+ */
+ private String fileSuffix;
+
+ /**
+ * URL鍦板潃
+ */
+ private String url;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ private Date createTime;
+
+ /**
+ * 涓婁紶浜�
+ */
+ private Long createBy;
+
+ /**
+ * 涓婁紶浜哄悕绉�
+ */
+ @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
+ private String createByName;
+
+ /**
+ * 鏈嶅姟鍟�
+ */
+ private String service;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java
new file mode 100644
index 0000000..0159d45
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteFileServiceImpl.java
@@ -0,0 +1,71 @@
+package org.dromara.resource.dubbo;
+
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.oss.core.OssClient;
+import org.dromara.common.oss.entity.UploadResult;
+import org.dromara.common.oss.factory.OssFactory;
+import org.dromara.resource.api.RemoteFileService;
+import org.dromara.resource.api.domain.RemoteFile;
+import org.dromara.resource.domain.bo.SysOssBo;
+import org.dromara.resource.service.ISysOssService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * 鏂囦欢璇锋眰澶勭悊
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@Service
+@RequiredArgsConstructor
+@DubboService
+public class RemoteFileServiceImpl implements RemoteFileService {
+
+ private final ISysOssService sysOssService;
+
+ /**
+ * 鏂囦欢涓婁紶璇锋眰
+ */
+ @Transactional(rollbackFor = Exception.class)
+ @Override
+ public RemoteFile upload(String name, String originalFilename, String contentType, byte[] file) throws ServiceException {
+ try {
+ String suffix = StringUtils.substring(originalFilename, originalFilename.lastIndexOf("."), originalFilename.length());
+ OssClient storage = OssFactory.instance();
+ UploadResult uploadResult = storage.uploadSuffix(file, suffix, contentType);
+ // 淇濆瓨鏂囦欢淇℃伅
+ SysOssBo oss = new SysOssBo();
+ oss.setUrl(uploadResult.getUrl());
+ oss.setFileSuffix(suffix);
+ oss.setFileName(uploadResult.getFilename());
+ oss.setOriginalName(originalFilename);
+ oss.setService(storage.getConfigKey());
+ sysOssService.insertByBo(oss);
+ RemoteFile sysFile = new RemoteFile();
+ sysFile.setOssId(oss.getOssId());
+ sysFile.setName(uploadResult.getFilename());
+ sysFile.setUrl(uploadResult.getUrl());
+ return sysFile;
+ } catch (Exception e) {
+ log.error("涓婁紶鏂囦欢澶辫触", e);
+ throw new ServiceException("涓婁紶鏂囦欢澶辫触");
+ }
+ }
+
+ /**
+ * 閫氳繃ossId鏌ヨ瀵瑰簲鐨剈rl
+ *
+ * @param ossIds ossId涓查�楀彿鍒嗛殧
+ * @return url涓查�楀彿鍒嗛殧
+ */
+ @Override
+ public String selectUrlByIds(String ossIds) {
+ return sysOssService.selectUrlByIds(ossIds);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMailServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMailServiceImpl.java
new file mode 100644
index 0000000..81badff
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMailServiceImpl.java
@@ -0,0 +1,33 @@
+package org.dromara.resource.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.mail.utils.MailUtils;
+import org.dromara.resource.api.RemoteMailService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 閭欢鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteMailServiceImpl implements RemoteMailService {
+
+ /**
+ * 鍙戦�侀偖浠�
+ *
+ * @param to 鎺ユ敹浜�
+ * @param subject 鏍囬
+ * @param text 鍐呭
+ */
+ public void send(String to, String subject, String text) throws ServiceException {
+ MailUtils.sendText(to, subject, text);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java
new file mode 100644
index 0000000..d8f6def
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteMessageServiceImpl.java
@@ -0,0 +1,42 @@
+package org.dromara.resource.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.websocket.utils.WebSocketUtils;
+import org.dromara.resource.api.RemoteMessageService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鐭俊鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteMessageServiceImpl implements RemoteMessageService {
+
+ /**
+ * 鍙戦�佹秷鎭�
+ *
+ * @param sessionKey session涓婚敭 涓�鑸负鐢ㄦ埛id
+ * @param message 娑堟伅鏂囨湰
+ */
+ @Override
+ public void sendMessage(Long sessionKey, String message) {
+ WebSocketUtils.sendMessage(sessionKey, message);
+ }
+
+ /**
+ * 鍙戝竷璁㈤槄鐨勬秷鎭�(缇ゅ彂)
+ *
+ * @param message 娑堟伅鍐呭
+ */
+ @Override
+ public void publishAll(String message) {
+ WebSocketUtils.publishAll(message);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteSmsServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteSmsServiceImpl.java
new file mode 100644
index 0000000..a8070ee
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/dubbo/RemoteSmsServiceImpl.java
@@ -0,0 +1,46 @@
+package org.dromara.resource.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.resource.api.RemoteSmsService;
+import org.dromara.resource.api.domain.RemoteSms;
+import org.dromara.sms4j.api.SmsBlend;
+import org.dromara.sms4j.api.entity.SmsResponse;
+import org.dromara.sms4j.core.factory.SmsFactory;
+import org.dromara.sms4j.provider.enumerate.SupplierType;
+import org.springframework.stereotype.Service;
+
+import java.util.LinkedHashMap;
+
+/**
+ * 鐭俊鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteSmsServiceImpl implements RemoteSmsService {
+
+ /**
+ * 鍙戦�佺煭淇�
+ *
+ * @param phones 鐢佃瘽鍙�(澶氫釜閫楀彿鍒嗗壊)
+ * @param templateId 妯℃澘id
+ * @param param 妯℃澘瀵瑰簲鍙傛暟
+ */
+ public RemoteSms send(String phones, String templateId, LinkedHashMap<String, String> param) throws ServiceException {
+ SmsBlend smsBlend = SmsFactory.createSmsBlend(SupplierType.ALIBABA);
+ SmsResponse smsResponse = smsBlend.sendMessage(phones, templateId, param);
+ RemoteSms sysSms = new RemoteSms();
+ sysSms.setIsSuccess(smsResponse.isSuccess());
+ sysSms.setMessage(smsResponse.getMessage());
+ sysSms.setResponse(JsonUtils.toJsonString(smsResponse));
+ return sysSms;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssConfigMapper.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssConfigMapper.java
new file mode 100644
index 0000000..aad7d40
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssConfigMapper.java
@@ -0,0 +1,17 @@
+package org.dromara.resource.mapper;
+
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.resource.domain.SysOssConfig;
+import org.dromara.resource.domain.vo.SysOssConfigVo;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Mapper鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface SysOssConfigMapper extends BaseMapperPlus<SysOssConfig, SysOssConfigVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssMapper.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssMapper.java
new file mode 100644
index 0000000..629ad20
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/mapper/SysOssMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.resource.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.resource.domain.SysOss;
+import org.dromara.resource.domain.vo.SysOssVo;
+
+/**
+ * 鏂囦欢涓婁紶 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysOssMapper extends BaseMapperPlus<SysOss, SysOssVo> {
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/runner/ResourceApplicationRunner.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/runner/ResourceApplicationRunner.java
new file mode 100644
index 0000000..8c7484d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/runner/ResourceApplicationRunner.java
@@ -0,0 +1,28 @@
+package org.dromara.resource.runner;
+
+import org.dromara.resource.service.ISysOssConfigService;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+/**
+ * 鍒濆鍖� system 妯″潡瀵瑰簲涓氬姟鏁版嵁
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Component
+public class ResourceApplicationRunner implements ApplicationRunner {
+
+ private final ISysOssConfigService ossConfigService;
+
+ @Override
+ public void run(ApplicationArguments args) throws Exception {
+ ossConfigService.init();
+ log.info("鍒濆鍖朞SS閰嶇疆鎴愬姛");
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssConfigService.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssConfigService.java
new file mode 100644
index 0000000..96b6e29
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssConfigService.java
@@ -0,0 +1,66 @@
+package org.dromara.resource.service;
+
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.resource.domain.bo.SysOssConfigBo;
+import org.dromara.resource.domain.vo.SysOssConfigVo;
+
+import java.util.Collection;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Service鎺ュ彛
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+public interface ISysOssConfigService {
+
+ /**
+ * 鍒濆鍖朞SS閰嶇疆
+ */
+ void init();
+
+ /**
+ * 鏌ヨ鍗曚釜
+ */
+ SysOssConfigVo queryById(Long ossConfigId);
+
+ /**
+ * 鏌ヨ鍒楄〃
+ */
+ TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery);
+
+
+ /**
+ * 鏍规嵁鏂板涓氬姟瀵硅薄鎻掑叆瀵硅薄瀛樺偍閰嶇疆
+ *
+ * @param bo 瀵硅薄瀛樺偍閰嶇疆鏂板涓氬姟瀵硅薄
+ * @return
+ */
+ Boolean insertByBo(SysOssConfigBo bo);
+
+ /**
+ * 鏍规嵁缂栬緫涓氬姟瀵硅薄淇敼瀵硅薄瀛樺偍閰嶇疆
+ *
+ * @param bo 瀵硅薄瀛樺偍閰嶇疆缂栬緫涓氬姟瀵硅薄
+ * @return
+ */
+ Boolean updateByBo(SysOssConfigBo bo);
+
+ /**
+ * 鏍¢獙骞跺垹闄ゆ暟鎹�
+ *
+ * @param ids 涓婚敭闆嗗悎
+ * @param isValid 鏄惁鏍¢獙,true-鍒犻櫎鍓嶆牎楠�,false-涓嶆牎楠�
+ * @return
+ */
+ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+ /**
+ * 鍚敤鍋滅敤鐘舵��
+ */
+ int updateOssConfigStatus(SysOssConfigBo bo);
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssService.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssService.java
new file mode 100644
index 0000000..ce3622a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/ISysOssService.java
@@ -0,0 +1,40 @@
+package org.dromara.resource.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.resource.domain.bo.SysOssBo;
+import org.dromara.resource.domain.vo.SysOssVo;
+import org.springframework.web.multipart.MultipartFile;
+
+import jakarta.servlet.http.HttpServletResponse;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 鏂囦欢涓婁紶 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysOssService {
+
+ TableDataInfo<SysOssVo> queryPageList(SysOssBo sysOss, PageQuery pageQuery);
+
+ List<SysOssVo> listByIds(Collection<Long> ossIds);
+
+ String selectUrlByIds(String ossIds);
+
+ SysOssVo getById(Long ossId);
+
+ SysOssVo upload(MultipartFile file);
+
+ SysOssVo upload(File file);
+
+ Boolean insertByBo(SysOssBo bo);
+
+ void download(Long ossId, HttpServletResponse response) throws IOException;
+
+ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssConfigServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssConfigServiceImpl.java
new file mode 100644
index 0000000..2e7154b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssConfigServiceImpl.java
@@ -0,0 +1,175 @@
+package org.dromara.resource.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.json.utils.JsonUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.oss.constant.OssConstant;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.resource.domain.SysOssConfig;
+import org.dromara.resource.domain.bo.SysOssConfigBo;
+import org.dromara.resource.domain.vo.SysOssConfigVo;
+import org.dromara.resource.mapper.SysOssConfigMapper;
+import org.dromara.resource.service.ISysOssConfigService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀵硅薄瀛樺偍閰嶇疆Service涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ * @author 瀛よ垷鐑熼洦
+ * @date 2021-08-13
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysOssConfigServiceImpl implements ISysOssConfigService {
+
+ private final SysOssConfigMapper baseMapper;
+
+ /**
+ * 椤圭洰鍚姩鏃讹紝鍒濆鍖栧弬鏁板埌缂撳瓨锛屽姞杞介厤缃被
+ */
+ @Override
+ public void init() {
+ List<SysOssConfig> list = baseMapper.selectList();
+ // 鍔犺浇OSS鍒濆鍖栭厤缃�
+ for (SysOssConfig config : list) {
+ String configKey = config.getConfigKey();
+ if ("0".equals(config.getStatus())) {
+ RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, configKey);
+ }
+ CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+ }
+ }
+
+ @Override
+ public SysOssConfigVo queryById(Long ossConfigId) {
+ return baseMapper.selectVoById(ossConfigId);
+ }
+
+ @Override
+ public TableDataInfo<SysOssConfigVo> queryPageList(SysOssConfigBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysOssConfig> lqw = buildQueryWrapper(bo);
+ Page<SysOssConfigVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+
+ private LambdaQueryWrapper<SysOssConfig> buildQueryWrapper(SysOssConfigBo bo) {
+ LambdaQueryWrapper<SysOssConfig> lqw = Wrappers.lambdaQuery();
+ lqw.eq(StringUtils.isNotBlank(bo.getConfigKey()), SysOssConfig::getConfigKey, bo.getConfigKey());
+ lqw.like(StringUtils.isNotBlank(bo.getBucketName()), SysOssConfig::getBucketName, bo.getBucketName());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysOssConfig::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysOssConfig::getOssConfigId);
+ return lqw;
+ }
+
+ @Override
+ public Boolean insertByBo(SysOssConfigBo bo) {
+ SysOssConfig config = BeanUtil.toBean(bo, SysOssConfig.class);
+ validEntityBeforeSave(config);
+ boolean flag = baseMapper.insert(config) > 0;
+ if (flag) {
+ // 浠庢暟鎹簱鏌ヨ瀹屾暣鐨勬暟鎹仛缂撳瓨
+ config = baseMapper.selectById(config.getOssConfigId());
+ CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+ }
+ return flag;
+ }
+
+ @Override
+ public Boolean updateByBo(SysOssConfigBo bo) {
+ SysOssConfig config = BeanUtil.toBean(bo, SysOssConfig.class);
+ validEntityBeforeSave(config);
+ LambdaUpdateWrapper<SysOssConfig> luw = new LambdaUpdateWrapper<>();
+ luw.set(ObjectUtil.isNull(config.getPrefix()), SysOssConfig::getPrefix, "");
+ luw.set(ObjectUtil.isNull(config.getRegion()), SysOssConfig::getRegion, "");
+ luw.set(ObjectUtil.isNull(config.getExt1()), SysOssConfig::getExt1, "");
+ luw.set(ObjectUtil.isNull(config.getRemark()), SysOssConfig::getRemark, "");
+ luw.eq(SysOssConfig::getOssConfigId, config.getOssConfigId());
+ boolean flag = baseMapper.update(config, luw) > 0;
+ if (flag) {
+ // 浠庢暟鎹簱鏌ヨ瀹屾暣鐨勬暟鎹仛缂撳瓨
+ config = baseMapper.selectById(config.getOssConfigId());
+ CacheUtils.put(CacheNames.SYS_OSS_CONFIG, config.getConfigKey(), JsonUtils.toJsonString(config));
+ }
+ return flag;
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(SysOssConfig entity) {
+ if (StringUtils.isNotEmpty(entity.getConfigKey()) && !checkConfigKeyUnique(entity)) {
+ throw new ServiceException("鎿嶄綔閰嶇疆'" + entity.getConfigKey() + "'澶辫触, 閰嶇疆key宸插瓨鍦�!");
+ }
+ }
+
+ @Override
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+ if (isValid) {
+ if (CollUtil.containsAny(ids, OssConstant.SYSTEM_DATA_IDS)) {
+ throw new ServiceException("绯荤粺鍐呯疆, 涓嶅彲鍒犻櫎!");
+ }
+ }
+ List<SysOssConfig> list = CollUtil.newArrayList();
+ for (Long configId : ids) {
+ SysOssConfig config = baseMapper.selectById(configId);
+ list.add(config);
+ }
+ boolean flag = baseMapper.deleteBatchIds(ids) > 0;
+ if (flag) {
+ list.forEach(sysOssConfig ->
+ CacheUtils.evict(CacheNames.SYS_OSS_CONFIG, sysOssConfig.getConfigKey()));
+ }
+ return flag;
+ }
+
+ /**
+ * 鍒ゆ柇configKey鏄惁鍞竴
+ */
+ private boolean checkConfigKeyUnique(SysOssConfig sysOssConfig) {
+ long ossConfigId = ObjectUtil.isNull(sysOssConfig.getOssConfigId()) ? -1L : sysOssConfig.getOssConfigId();
+ SysOssConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysOssConfig>()
+ .select(SysOssConfig::getOssConfigId, SysOssConfig::getConfigKey)
+ .eq(SysOssConfig::getConfigKey, sysOssConfig.getConfigKey()));
+ if (ObjectUtil.isNotNull(info) && info.getOssConfigId() != ossConfigId) {
+ return false;
+ }
+ return true;
+ }
+
+ /**
+ * 鍚敤绂佺敤鐘舵��
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int updateOssConfigStatus(SysOssConfigBo bo) {
+ SysOssConfig sysOssConfig = BeanUtil.toBean(bo, SysOssConfig.class);
+ int row = baseMapper.update(null, new LambdaUpdateWrapper<SysOssConfig>()
+ .set(SysOssConfig::getStatus, "1"));
+ row += baseMapper.updateById(sysOssConfig);
+ if (row > 0) {
+ RedisUtils.setCacheObject(OssConstant.DEFAULT_CONFIG_KEY, sysOssConfig.getConfigKey());
+ }
+ return row;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java
new file mode 100644
index 0000000..41cf223
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/java/org/dromara/resource/service/impl/SysOssServiceImpl.java
@@ -0,0 +1,210 @@
+package org.dromara.resource.service.impl;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.io.IoUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.FileUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.oss.core.OssClient;
+import org.dromara.common.oss.entity.UploadResult;
+import org.dromara.common.oss.enumd.AccessPolicyType;
+import org.dromara.common.oss.factory.OssFactory;
+import org.dromara.resource.domain.SysOss;
+import org.dromara.resource.domain.bo.SysOssBo;
+import org.dromara.resource.domain.vo.SysOssVo;
+import org.dromara.resource.mapper.SysOssMapper;
+import org.dromara.resource.service.ISysOssService;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 鏂囦欢涓婁紶 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysOssServiceImpl implements ISysOssService {
+
+ private final SysOssMapper baseMapper;
+
+ @Override
+ public TableDataInfo<SysOssVo> queryPageList(SysOssBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysOss> lqw = buildQueryWrapper(bo);
+ Page<SysOssVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ List<SysOssVo> filterResult = result.getRecords().stream().map(this::matchingUrl).collect(Collectors.toList());
+ result.setRecords(filterResult);
+ return TableDataInfo.build(result);
+ }
+
+ @Override
+ public List<SysOssVo> listByIds(Collection<Long> ossIds) {
+ List<SysOssVo> list = new ArrayList<>();
+ for (Long id : ossIds) {
+ SysOssVo vo = getById(id);
+ if (ObjectUtil.isNotNull(vo)) {
+ try {
+ list.add(this.matchingUrl(vo));
+ } catch (Exception ignored) {
+ // 濡傛灉oss寮傚父鏃犳硶杩炴帴鍒欏皢鏁版嵁鐩存帴杩斿洖
+ list.add(vo);
+ } }
+ }
+ return list;
+ }
+
+ @Override
+ public String selectUrlByIds(String ossIds) {
+ List<String> list = new ArrayList<>();
+ for (Long id : StringUtils.splitTo(ossIds, Convert::toLong)) {
+ SysOssVo vo = SpringUtils.getAopProxy(this).getById(id);
+ if (ObjectUtil.isNotNull(vo)) {
+ try {
+ list.add(this.matchingUrl(vo).getUrl());
+ } catch (Exception ignored) {
+ // 濡傛灉oss寮傚父鏃犳硶杩炴帴鍒欏皢鏁版嵁鐩存帴杩斿洖
+ list.add(vo.getUrl());
+ }
+ }
+ }
+ return String.join(StringUtils.SEPARATOR, list);
+ }
+
+ private LambdaQueryWrapper<SysOss> buildQueryWrapper(SysOssBo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<SysOss> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getFileName()), SysOss::getFileName, bo.getFileName());
+ lqw.like(StringUtils.isNotBlank(bo.getOriginalName()), SysOss::getOriginalName, bo.getOriginalName());
+ lqw.eq(StringUtils.isNotBlank(bo.getFileSuffix()), SysOss::getFileSuffix, bo.getFileSuffix());
+ lqw.eq(StringUtils.isNotBlank(bo.getUrl()), SysOss::getUrl, bo.getUrl());
+ lqw.between(params.get("beginCreateTime") != null && params.get("endCreateTime") != null,
+ SysOss::getCreateTime, params.get("beginCreateTime"), params.get("endCreateTime"));
+ lqw.eq(ObjectUtil.isNotNull(bo.getCreateBy()), SysOss::getCreateBy, bo.getCreateBy());
+ lqw.eq(StringUtils.isNotBlank(bo.getService()), SysOss::getService, bo.getService());
+ lqw.orderByAsc(SysOss::getOssId);
+ return lqw;
+ }
+
+ @Cacheable(cacheNames = CacheNames.SYS_OSS, key = "#ossId")
+ @Override
+ public SysOssVo getById(Long ossId) {
+ return baseMapper.selectVoById(ossId);
+ }
+
+ @Override
+ public void download(Long ossId, HttpServletResponse response) throws IOException {
+ SysOssVo sysOss = SpringUtils.getAopProxy(this).getById(ossId);
+ if (ObjectUtil.isNull(sysOss)) {
+ throw new ServiceException("鏂囦欢鏁版嵁涓嶅瓨鍦�!");
+ }
+ FileUtils.setAttachmentResponseHeader(response, sysOss.getOriginalName());
+ response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE + "; charset=UTF-8");
+ OssClient storage = OssFactory.instance(sysOss.getService());
+ try(InputStream inputStream = storage.getObjectContent(sysOss.getUrl())) {
+ int available = inputStream.available();
+ IoUtil.copy(inputStream, response.getOutputStream(), available);
+ response.setContentLength(available);
+ } catch (Exception e) {
+ throw new ServiceException(e.getMessage());
+ }
+ }
+
+ @Override
+ public SysOssVo upload(MultipartFile file) {
+ String originalfileName = file.getOriginalFilename();
+ String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+ OssClient storage = OssFactory.instance();
+ UploadResult uploadResult;
+ try {
+ uploadResult = storage.uploadSuffix(file.getBytes(), suffix, file.getContentType());
+ } catch (IOException e) {
+ throw new ServiceException(e.getMessage());
+ }
+ // 淇濆瓨鏂囦欢淇℃伅
+ return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult);
+ }
+
+ @Override
+ public SysOssVo upload(File file) {
+ String originalfileName = file.getName();
+ String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."), originalfileName.length());
+ OssClient storage = OssFactory.instance();
+ UploadResult uploadResult = storage.uploadSuffix(file, suffix);
+ // 淇濆瓨鏂囦欢淇℃伅
+ return buildResultEntity(originalfileName, suffix, storage.getConfigKey(), uploadResult);
+ }
+
+ private SysOssVo buildResultEntity(String originalfileName, String suffix, String configKey, UploadResult uploadResult) {
+ SysOss oss = new SysOss();
+ oss.setUrl(uploadResult.getUrl());
+ oss.setFileSuffix(suffix);
+ oss.setFileName(uploadResult.getFilename());
+ oss.setOriginalName(originalfileName);
+ oss.setService(configKey);
+ baseMapper.insert(oss);
+ SysOssVo sysOssVo = MapstructUtils.convert(oss, SysOssVo.class);
+ return this.matchingUrl(sysOssVo);
+ }
+
+ @Override
+ public Boolean insertByBo(SysOssBo bo) {
+ SysOss oss = BeanUtil.toBean(bo, SysOss.class);
+ boolean flag = baseMapper.insert(oss) > 0;
+ if (flag) {
+ bo.setOssId(oss.getOssId());
+ }
+ return flag;
+ }
+
+ @Override
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+ if (isValid) {
+ // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+ }
+ List<SysOss> list = baseMapper.selectBatchIds(ids);
+ for (SysOss sysOss : list) {
+ OssClient storage = OssFactory.instance(sysOss.getService());
+ storage.delete(sysOss.getUrl());
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+
+ /**
+ * 鍖归厤Url
+ *
+ * @param oss OSS瀵硅薄
+ * @return oss 鍖归厤Url鐨凮SS瀵硅薄
+ */
+ private SysOssVo matchingUrl(SysOssVo oss) {
+ OssClient storage = OssFactory.instance(oss.getService());
+ // 浠呬慨鏀规《绫诲瀷涓� private 鐨刄RL锛屼复鏃禪RL鏃堕暱涓�120s
+ if (AccessPolicyType.PRIVATE == storage.getAccessPolicy()) {
+ oss.setUrl(storage.getPrivateUrl(oss.getFileName(), 120));
+ }
+ return oss;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/application.yml b/ruoyi-modules/ruoyi-resource/src/main/resources/application.yml
new file mode 100644
index 0000000..c86ad8b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+# Tomcat
+server:
+ port: 9204
+
+# Spring
+spring:
+ application:
+ # 搴旂敤鍚嶇О
+ name: ruoyi-resource
+ profiles:
+ # 鐜閰嶇疆
+ active: @profiles.active@
+
+--- # nacos 閰嶇疆
+spring:
+ cloud:
+ nacos:
+ # nacos 鏈嶅姟鍦板潃
+ server-addr: @nacos.server@
+ discovery:
+ # 娉ㄥ唽缁�
+ group: @nacos.discovery.group@
+ namespace: ${spring.profiles.active}
+ config:
+ # 閰嶇疆缁�
+ group: @nacos.config.group@
+ namespace: ${spring.profiles.active}
+ config:
+ import:
+ - optional:nacos:application-common.yml
+ - optional:nacos:datasource.yml
+ - optional:nacos:${spring.application.name}.yml
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-resource/src/main/resources/banner.txt
new file mode 100644
index 0000000..f589ce2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _
+ (_)
+ _ __ _ _ ___ _ _ _ ______ _ __ ___ ___ ___ _ _ _ __ ___ ___
+| '__| | | |/ _ \| | | | |______| '__/ _ \/ __|/ _ \| | | | '__/ __/ _ \
+| | | |_| | (_) | |_| | | | | | __/\__ \ (_) | |_| | | | (_| __/
+|_| \__,_|\___/ \__, |_| |_| \___||___/\___/ \__,_|_| \___\___|
+ __/ |
+ |___/
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/logback-plus.xml b/ruoyi-modules/ruoyi-resource/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..a2e187f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/logback-plus.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 鏃ュ織瀛樻斁璺緞 -->
+ <property name="log.path" value="logs/${project.artifactId}"/>
+ <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+ <property name="console.log.pattern"
+ value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+ <!-- 鎺у埗鍙拌緭鍑� -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${console.log.pattern}</pattern>
+ <charset>utf-8</charset>
+ </encoder>
+ </appender>
+
+ <include resource="logback-common.xml" />
+
+ <include resource="logback-logstash.xml" />
+
+ <!-- 寮�鍚� skywalking 鏃ュ織鏀堕泦 -->
+ <include resource="logback-skylog.xml" />
+
+ <!--绯荤粺鎿嶄綔鏃ュ織-->
+ <root level="info">
+ <appender-ref ref="console"/>
+ </root>
+</configuration>
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssConfigMapper.xml b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssConfigMapper.xml
new file mode 100644
index 0000000..ffad843
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.resource.mapper.SysOssConfigMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssMapper.xml b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssMapper.xml
new file mode 100644
index 0000000..2573ebb
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/mapper/resource/SysOssMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.resource.mapper.SysOssMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-resource/src/main/resources/spy.properties b/ruoyi-modules/ruoyi-resource/src/main/resources/spy.properties
new file mode 100644
index 0000000..abbd893
--- /dev/null
+++ b/ruoyi-modules/ruoyi-resource/src/main/resources/spy.properties
@@ -0,0 +1,28 @@
+# p6spy 鎬ц兘鍒嗘瀽鎻掍欢閰嶇疆鏂囦欢
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 鑷畾涔夋棩蹇楁墦鍗�
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#鏃ュ織杈撳嚭鍒版帶鍒跺彴
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 浣跨敤鏃ュ織绯荤粺璁板綍 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 璁剧疆 p6spy driver 浠g悊
+#deregisterdrivers=true
+# 鍙栨秷JDBC URL鍓嶇紑
+useprefix=true
+# 閰嶇疆璁板綍 Log 渚嬪,鍙幓鎺夌殑缁撴灉闆嗘湁error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 鏃ユ湡鏍煎紡
+dateformat=yyyy-MM-dd HH:mm:ss
+# SQL璇彞鎵撳嵃鏃堕棿鏍煎紡
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
+# 瀹為檯椹卞姩鍙涓�
+#driverlist=org.h2.Driver
+# 鏄惁寮�鍚參SQL璁板綍
+outagedetection=true
+# 鎱QL璁板綍鏍囧噯 2 绉�
+outagedetectioninterval=2
+# 鏄惁杩囨护 Log
+filter=true
+# 杩囨护 Log 鏃舵墍鎺掗櫎鐨� sql 鍏抽敭瀛楋紝浠ラ�楀彿鍒嗛殧
+exclude=SELECT 1
diff --git a/ruoyi-modules/ruoyi-system/Dockerfile b/ruoyi-modules/ruoyi-system/Dockerfile
new file mode 100644
index 0000000..2989fbf
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/Dockerfile
@@ -0,0 +1,23 @@
+#FROM findepi/graalvm:java17-native
+FROM openjdk:17.0.2-oraclelinux8
+
+MAINTAINER Lion Li
+
+RUN mkdir -p /ruoyi/system/logs \
+ /ruoyi/system/temp \
+ /ruoyi/skywalking/agent
+
+WORKDIR /ruoyi/system
+
+ENV SERVER_PORT=9201 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
+
+EXPOSE ${SERVER_PORT}
+
+ADD ./target/ruoyi-system.jar ./app.jar
+
+ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
+ #-Dskywalking.agent.service_name=ruoyi-system \
+ #-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
+ -jar app.jar \
+ -XX:+HeapDumpOnOutOfMemoryError -Xlog:gc*,:time,tags,level -XX:+UseZGC ${JAVA_OPTS}
+
diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml
new file mode 100644
index 0000000..0c1f66a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/pom.xml
@@ -0,0 +1,134 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xmlns="http://maven.apache.org/POM/4.0.0"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <parent>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-modules</artifactId>
+ <version>${revision}</version>
+ </parent>
+ <modelVersion>4.0.0</modelVersion>
+
+ <artifactId>ruoyi-system</artifactId>
+
+ <description>
+ ruoyi-system绯荤粺妯″潡
+ </description>
+
+ <dependencies>
+
+ <!-- SpringCloud Alibaba Nacos -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
+ </dependency>
+
+ <!-- SpringCloud Alibaba Nacos Config -->
+ <dependency>
+ <groupId>com.alibaba.cloud</groupId>
+ <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-sentinel</artifactId>
+ </dependency>
+
+ <!-- RuoYi Common Log -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-log</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dict</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-doc</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-web</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-mybatis</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-dubbo</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-seata</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-idempotent</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-tenant</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-security</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-translation</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-sensitive</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-common-encrypt</artifactId>
+ </dependency>
+
+ <!-- RuoYi Api System -->
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-api-system</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.dromara</groupId>
+ <artifactId>ruoyi-api-resource</artifactId>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <finalName>${project.artifactId}</finalName>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>${spring-boot.version}</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ </plugins>
+ </build>
+
+</project>
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/RuoYiSystemApplication.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/RuoYiSystemApplication.java
new file mode 100644
index 0000000..3359c7d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/RuoYiSystemApplication.java
@@ -0,0 +1,22 @@
+package org.dromara.system;
+
+import org.apache.dubbo.config.spring.context.annotation.EnableDubbo;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
+
+/**
+ * 绯荤粺妯″潡
+ *
+ * @author ruoyi
+ */
+@EnableDubbo
+@SpringBootApplication
+public class RuoYiSystemApplication {
+ public static void main(String[] args) {
+ SpringApplication application = new SpringApplication(RuoYiSystemApplication.class);
+ application.setApplicationStartup(new BufferingApplicationStartup(2048));
+ application.run(args);
+ System.out.println("(鈾モ棤鈥库棤)锞夛緸 绯荤粺妯″潡鍚姩鎴愬姛 醿�(麓凇`醿�)锞� ");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java
new file mode 100644
index 0000000..51ca79d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/CacheController.java
@@ -0,0 +1,55 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.system.domain.vo.CacheListInfoVo;
+import org.redisson.spring.data.connection.RedissonConnectionFactory;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.*;
+
+/**
+ * 缂撳瓨鐩戞帶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/cache")
+public class CacheController {
+
+ private final RedissonConnectionFactory connectionFactory;
+
+ /**
+ * 鑾峰彇缂撳瓨鐩戞帶鍒楄〃
+ */
+ @SaCheckPermission("monitor:cache:list")
+ @GetMapping()
+ public R<CacheListInfoVo> getInfo() throws Exception {
+ RedisConnection connection = connectionFactory.getConnection();
+ Properties commandStats = connection.commands().info("commandstats");
+
+ List<Map<String, String>> pieList = new ArrayList<>();
+ if (commandStats != null) {
+ commandStats.stringPropertyNames().forEach(key -> {
+ Map<String, String> data = new HashMap<>(2);
+ String property = commandStats.getProperty(key);
+ data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+ data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+ pieList.add(data);
+ });
+ }
+
+ CacheListInfoVo infoVo = new CacheListInfoVo();
+ infoVo.setInfo(connection.commands().info());
+ infoVo.setDbSize(connection.commands().dbSize());
+ infoVo.setCommandStats(pieList);
+ return R.ok(infoVo);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
new file mode 100644
index 0000000..0f23e5c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysLogininforController.java
@@ -0,0 +1,89 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.GlobalConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+import org.dromara.system.service.ISysLogininforService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶璁板綍
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/logininfor")
+public class SysLogininforController extends BaseController {
+
+ private final ISysLogininforService logininforService;
+
+ /**
+ * 鑾峰彇绯荤粺璁块棶璁板綍鍒楄〃
+ */
+ @SaCheckPermission("monitor:logininfor:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysLogininforVo> list(SysLogininforBo logininfor, PageQuery pageQuery) {
+ return logininforService.selectPageLogininforList(logininfor, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭绯荤粺璁块棶璁板綍鍒楄〃
+ */
+ @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("monitor:logininfor:export")
+ @PostMapping("/export")
+ public void export(SysLogininforBo logininfor, HttpServletResponse response) {
+ List<SysLogininforVo> list = logininforService.selectLogininforList(logininfor);
+ ExcelUtil.exportExcel(list, "鐧诲綍鏃ュ織", SysLogininforVo.class, response);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎鐧诲綍鏃ュ織
+ * @param infoIds 鏃ュ織ids
+ */
+ @SaCheckPermission("monitor:logininfor:remove")
+ @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{infoIds}")
+ public R<Void> remove(@PathVariable Long[] infoIds) {
+ return toAjax(logininforService.deleteLogininforByIds(infoIds));
+ }
+
+ /**
+ * 娓呯悊绯荤粺璁块棶璁板綍
+ */
+ @SaCheckPermission("monitor:logininfor:remove")
+ @Log(title = "鐧诲綍鏃ュ織", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/clean")
+ public R<Void> clean() {
+ logininforService.cleanLogininfor();
+ return R.ok();
+ }
+
+ @SaCheckPermission("monitor:logininfor:unlock")
+ @Log(title = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
+ @GetMapping("/unlock/{userName}")
+ public R<Void> unlock(@PathVariable("userName") String userName) {
+ String loginName = GlobalConstants.PWD_ERR_CNT_KEY + userName;
+ if (RedisUtils.hasKey(loginName)) {
+ RedisUtils.deleteObject(loginName);
+ }
+ return R.ok();
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java
new file mode 100644
index 0000000..5af1a01
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysOperlogController.java
@@ -0,0 +1,75 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+import org.dromara.system.service.ISysOperLogService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/operlog")
+public class SysOperlogController extends BaseController {
+
+ private final ISysOperLogService operLogService;
+
+ /**
+ * 鑾峰彇鎿嶄綔鏃ュ織璁板綍鍒楄〃
+ */
+ @SaCheckPermission("monitor:operlog:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysOperLogVo> list(SysOperLogBo operLog, PageQuery pageQuery) {
+ return operLogService.selectPageOperLogList(operLog, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭鎿嶄綔鏃ュ織璁板綍鍒楄〃
+ */
+ @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("monitor:operlog:export")
+ @PostMapping("/export")
+ public void export(SysOperLogBo operLog, HttpServletResponse response) {
+ List<SysOperLogVo> list = operLogService.selectOperLogList(operLog);
+ ExcelUtil.exportExcel(list, "鎿嶄綔鏃ュ織", SysOperLogVo.class, response);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎鎿嶄綔鏃ュ織璁板綍
+ * @param operIds 鏃ュ織ids
+ */
+ @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.DELETE)
+ @SaCheckPermission("monitor:operlog:remove")
+ @DeleteMapping("/{operIds}")
+ public R<Void> remove(@PathVariable Long[] operIds) {
+ return toAjax(operLogService.deleteOperLogByIds(operIds));
+ }
+
+ /**
+ * 娓呯悊鎿嶄綔鏃ュ織璁板綍
+ */
+ @SaCheckPermission("monitor:operlog:remove")
+ @Log(title = "鎿嶄綔鏃ュ織", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/clean")
+ public R<Void> clean() {
+ operLogService.cleanOperLog();
+ return R.ok();
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
new file mode 100644
index 0000000..3ea4b91
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/monitor/SysUserOnlineController.java
@@ -0,0 +1,89 @@
+package org.dromara.system.controller.monitor;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.RedisUtils;
+import org.dromara.system.api.domain.SysUserOnline;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 鍦ㄧ嚎鐢ㄦ埛鐩戞帶
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/online")
+public class SysUserOnlineController extends BaseController {
+
+ /**
+ * 鑾峰彇鍦ㄧ嚎鐢ㄦ埛鐩戞帶鍒楄〃
+ *
+ * @param ipaddr IP鍦板潃
+ * @param userName 鐢ㄦ埛鍚�
+ */
+ @SaCheckPermission("monitor:online:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysUserOnline> list(String ipaddr, String userName) {
+ // 鑾峰彇鎵�鏈夋湭杩囨湡鐨� token
+ List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+ List<SysUserOnline> userOnlineDTOList = new ArrayList<>();
+ for (String key : keys) {
+ String token = StringUtils.substringAfterLast(key, ":");
+ // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+ if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+ continue;
+ }
+ userOnlineDTOList.add(RedisUtils.getCacheObject(CacheConstants.ONLINE_TOKEN_KEY + token));
+ }
+ if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName)) {
+ userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+ StringUtils.equals(ipaddr, userOnline.getIpaddr()) &&
+ StringUtils.equals(userName, userOnline.getUserName())
+ );
+ } else if (StringUtils.isNotEmpty(ipaddr)) {
+ userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+ StringUtils.equals(ipaddr, userOnline.getIpaddr())
+ );
+ } else if (StringUtils.isNotEmpty(userName)) {
+ userOnlineDTOList = StreamUtils.filter(userOnlineDTOList, userOnline ->
+ StringUtils.equals(userName, userOnline.getUserName())
+ );
+ }
+ Collections.reverse(userOnlineDTOList);
+ userOnlineDTOList.removeAll(Collections.singleton(null));
+ List<SysUserOnline> userOnlineList = BeanUtil.copyToList(userOnlineDTOList, SysUserOnline.class);
+ return TableDataInfo.build(userOnlineList);
+ }
+
+ /**
+ * 寮洪��鐢ㄦ埛
+ *
+ * @param tokenId token鍊�
+ */
+ @SaCheckPermission("monitor:online:forceLogout")
+ @Log(title = "鍦ㄧ嚎鐢ㄦ埛", businessType = BusinessType.FORCE)
+ @DeleteMapping("/{tokenId}")
+ public R<Void> forceLogout(@PathVariable String tokenId) {
+ try {
+ StpUtil.kickoutByTokenValue(tokenId);
+ } catch (NotLoginException ignored) {
+ }
+ return R.ok();
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
new file mode 100644
index 0000000..c8938e5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysClientController.java
@@ -0,0 +1,115 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.service.ISysClientService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 瀹㈡埛绔鐞�
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/client")
+public class SysClientController extends BaseController {
+
+ private final ISysClientService sysClientService;
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+ */
+ @SaCheckPermission("system:client:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysClientVo> list(SysClientBo bo, PageQuery pageQuery) {
+ return sysClientService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭瀹㈡埛绔鐞嗗垪琛�
+ */
+ @SaCheckPermission("system:client:export")
+ @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(SysClientBo bo, HttpServletResponse response) {
+ List<SysClientVo> list = sysClientService.queryList(bo);
+ ExcelUtil.exportExcel(list, "瀹㈡埛绔鐞�", SysClientVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇瀹㈡埛绔鐞嗚缁嗕俊鎭�
+ *
+ * @param id 涓婚敭
+ */
+ @SaCheckPermission("system:client:query")
+ @GetMapping("/{id}")
+ public R<SysClientVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long id) {
+ return R.ok(sysClientService.queryById(id));
+ }
+
+ /**
+ * 鏂板瀹㈡埛绔鐞�
+ */
+ @SaCheckPermission("system:client:add")
+ @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody SysClientBo bo) {
+ return toAjax(sysClientService.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼瀹㈡埛绔鐞�
+ */
+ @SaCheckPermission("system:client:edit")
+ @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysClientBo bo) {
+ return toAjax(sysClientService.updateByBo(bo));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckPermission("system:client:edit")
+ @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysClientBo bo) {
+ return toAjax(sysClientService.updateUserStatus(bo.getId(), bo.getStatus()));
+ }
+
+ /**
+ * 鍒犻櫎瀹㈡埛绔鐞�
+ *
+ * @param ids 涓婚敭涓�
+ */
+ @SaCheckPermission("system:client:remove")
+ @Log(title = "瀹㈡埛绔鐞�", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long[] ids) {
+ return toAjax(sysClientService.deleteWithValidByIds(List.of(ids), true));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java
new file mode 100644
index 0000000..1d7878b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysConfigController.java
@@ -0,0 +1,137 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+import org.dromara.system.service.ISysConfigService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 鍙傛暟閰嶇疆 淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/config")
+public class SysConfigController extends BaseController {
+
+ private final ISysConfigService configService;
+
+ /**
+ * 鑾峰彇鍙傛暟閰嶇疆鍒楄〃
+ */
+ @SaCheckPermission("system:config:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysConfigVo> list(SysConfigBo config, PageQuery pageQuery) {
+ return configService.selectPageConfigList(config, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭鍙傛暟閰嶇疆鍒楄〃
+ */
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:config:export")
+ @PostMapping("/export")
+ public void export(SysConfigBo config, HttpServletResponse response) {
+ List<SysConfigVo> list = configService.selectConfigList(config);
+ ExcelUtil.exportExcel(list, "鍙傛暟鏁版嵁", SysConfigVo.class, response);
+ }
+
+ /**
+ * 鏍规嵁鍙傛暟缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param configId 鍙傛暟ID
+ */
+ @SaCheckPermission("system:config:query")
+ @GetMapping(value = "/{configId}")
+ public R<SysConfigVo> getInfo(@PathVariable Long configId) {
+ return R.ok(configService.selectConfigById(configId));
+ }
+
+ /**
+ * 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+ *
+ * @param configKey 鍙傛暟Key
+ */
+ @GetMapping(value = "/configKey/{configKey}")
+ public R<String> getConfigKey(@PathVariable String configKey) {
+ return R.ok("鎿嶄綔鎴愬姛", configService.selectConfigByKey(configKey));
+ }
+
+ /**
+ * 鏂板鍙傛暟閰嶇疆
+ */
+ @SaCheckPermission("system:config:add")
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysConfigBo config) {
+ if (!configService.checkConfigKeyUnique(config)) {
+ return R.fail("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+ }
+ configService.insertConfig(config);
+ return R.ok();
+ }
+
+ /**
+ * 淇敼鍙傛暟閰嶇疆
+ */
+ @SaCheckPermission("system:config:edit")
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysConfigBo config) {
+ if (!configService.checkConfigKeyUnique(config)) {
+ return R.fail("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+ }
+ configService.updateConfig(config);
+ return R.ok();
+ }
+
+ /**
+ * 鏍规嵁鍙傛暟閿悕淇敼鍙傛暟閰嶇疆
+ */
+ @SaCheckPermission("system:config:edit")
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping("/updateByKey")
+ public R<Void> updateByKey(@RequestBody SysConfigBo config) {
+ configService.updateConfig(config);
+ return R.ok();
+ }
+
+ /**
+ * 鍒犻櫎鍙傛暟閰嶇疆
+ *
+ * @param configIds 鍙傛暟ID涓�
+ */
+ @SaCheckPermission("system:config:remove")
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{configIds}")
+ public R<Void> remove(@PathVariable Long[] configIds) {
+ configService.deleteConfigByIds(configIds);
+ return R.ok();
+ }
+
+ /**
+ * 鍒锋柊鍙傛暟缂撳瓨
+ */
+ @SaCheckPermission("system:config:remove")
+ @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/refreshCache")
+ public R<Void> refreshCache() {
+ configService.resetConfigCache();
+ return R.ok();
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
new file mode 100644
index 0000000..cf60988
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDeptController.java
@@ -0,0 +1,123 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.convert.Convert;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.service.ISysDeptService;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/dept")
+public class SysDeptController extends BaseController {
+
+ private final ISysDeptService deptService;
+
+ /**
+ * 鑾峰彇閮ㄩ棬鍒楄〃
+ */
+ @SaCheckPermission("system:dept:list")
+ @GetMapping("/list")
+ public R<List<SysDeptVo>> list(SysDeptBo dept) {
+ List<SysDeptVo> depts = deptService.selectDeptList(dept);
+ return R.ok(depts);
+ }
+
+ /**
+ * 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
+ *
+ * @param deptId 閮ㄩ棬ID
+ */
+ @SaCheckPermission("system:dept:list")
+ @GetMapping("/list/exclude/{deptId}")
+ public R<List<SysDeptVo>> excludeChild(@PathVariable(value = "deptId", required = false) Long deptId) {
+ List<SysDeptVo> depts = deptService.selectDeptList(new SysDeptBo());
+ depts.removeIf(d -> d.getDeptId().equals(deptId)
+ || StringUtils.splitList(d.getAncestors()).contains(Convert.toStr(deptId)));
+ return R.ok(depts);
+ }
+
+ /**
+ * 鏍规嵁閮ㄩ棬缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param deptId 閮ㄩ棬ID
+ */
+ @SaCheckPermission("system:dept:query")
+ @GetMapping(value = "/{deptId}")
+ public R<SysDeptVo> getInfo(@PathVariable Long deptId) {
+ deptService.checkDeptDataScope(deptId);
+ return R.ok(deptService.selectDeptById(deptId));
+ }
+
+ /**
+ * 鏂板閮ㄩ棬
+ */
+ @SaCheckPermission("system:dept:add")
+ @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysDeptBo dept) {
+ if (!deptService.checkDeptNameUnique(dept)) {
+ return R.fail("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+ }
+ return toAjax(deptService.insertDept(dept));
+ }
+
+ /**
+ * 淇敼閮ㄩ棬
+ */
+ @SaCheckPermission("system:dept:edit")
+ @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysDeptBo dept) {
+ Long deptId = dept.getDeptId();
+ deptService.checkDeptDataScope(deptId);
+ if (!deptService.checkDeptNameUnique(dept)) {
+ return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+ } else if (dept.getParentId().equals(deptId)) {
+ return R.fail("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
+ } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus())) {
+ if (deptService.selectNormalChildrenDeptById(deptId) > 0) {
+ return R.fail("璇ラ儴闂ㄥ寘鍚湭鍋滅敤鐨勫瓙閮ㄩ棬!");
+ } else if (deptService.checkDeptExistUser(deptId)) {
+ return R.fail("璇ラ儴闂ㄤ笅瀛樺湪宸插垎閰嶇敤鎴凤紝涓嶈兘绂佺敤!");
+ }
+ }
+ return toAjax(deptService.updateDept(dept));
+ }
+
+ /**
+ * 鍒犻櫎閮ㄩ棬
+ *
+ * @param deptId 閮ㄩ棬ID
+ */
+ @SaCheckPermission("system:dept:remove")
+ @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{deptId}")
+ public R<Void> remove(@PathVariable Long deptId) {
+ if (deptService.hasChildByDeptId(deptId)) {
+ return R.warn("瀛樺湪涓嬬骇閮ㄩ棬,涓嶅厑璁稿垹闄�");
+ }
+ if (deptService.checkDeptExistUser(deptId)) {
+ return R.warn("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
+ }
+ deptService.checkDeptDataScope(deptId);
+ return toAjax(deptService.deleteDeptById(deptId));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java
new file mode 100644
index 0000000..f978e91
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictDataController.java
@@ -0,0 +1,117 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.hutool.core.util.ObjectUtil;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.service.ISysDictDataService;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/dict/data")
+public class SysDictDataController extends BaseController {
+
+ private final ISysDictDataService dictDataService;
+ private final ISysDictTypeService dictTypeService;
+
+ /**
+ * 鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+ */
+ @SaCheckPermission("system:dict:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysDictDataVo> list(SysDictDataBo dictData, PageQuery pageQuery) {
+ return dictDataService.selectPageDictDataList(dictData, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭瀛楀吀鏁版嵁鍒楄〃
+ */
+ @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:dict:export")
+ @PostMapping("/export")
+ public void export(SysDictDataBo dictData, HttpServletResponse response) {
+ List<SysDictDataVo> list = dictDataService.selectDictDataList(dictData);
+ ExcelUtil.exportExcel(list, "瀛楀吀鏁版嵁", SysDictDataVo.class, response);
+ }
+
+ /**
+ * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+ *
+ * @param dictCode 瀛楀吀code
+ */
+ @SaCheckPermission("system:dict:query")
+ @GetMapping(value = "/{dictCode}")
+ public R<SysDictDataVo> getInfo(@PathVariable Long dictCode) {
+ return R.ok(dictDataService.selectDictDataById(dictCode));
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ */
+ @GetMapping(value = "/type/{dictType}")
+ public R<List<SysDictDataVo>> dictType(@PathVariable String dictType) {
+ List<SysDictDataVo> data = dictTypeService.selectDictDataByType(dictType);
+ if (ObjectUtil.isNull(data)) {
+ data = new ArrayList<>();
+ }
+ return R.ok(data);
+ }
+
+ /**
+ * 鏂板瀛楀吀绫诲瀷
+ */
+ @SaCheckPermission("system:dict:add")
+ @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysDictDataBo dict) {
+ dictDataService.insertDictData(dict);
+ return R.ok();
+ }
+
+ /**
+ * 淇敼淇濆瓨瀛楀吀绫诲瀷
+ */
+ @SaCheckPermission("system:dict:edit")
+ @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysDictDataBo dict) {
+ dictDataService.updateDictData(dict);
+ return R.ok();
+ }
+
+ /**
+ * 鍒犻櫎瀛楀吀绫诲瀷
+ *
+ * @param dictCodes 瀛楀吀code涓�
+ */
+ @SaCheckPermission("system:dict:remove")
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{dictCodes}")
+ public R<Void> remove(@PathVariable Long[] dictCodes) {
+ dictDataService.deleteDictDataByIds(dictCodes);
+ return R.ok();
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java
new file mode 100644
index 0000000..1e51539
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysDictTypeController.java
@@ -0,0 +1,125 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/dict/type")
+public class SysDictTypeController extends BaseController {
+
+ private final ISysDictTypeService dictTypeService;
+
+ /**
+ * 鏌ヨ瀛楀吀绫诲瀷鍒楄〃
+ */
+ @SaCheckPermission("system:dict:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysDictTypeVo> list(SysDictTypeBo dictType, PageQuery pageQuery) {
+ return dictTypeService.selectPageDictTypeList(dictType, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭瀛楀吀绫诲瀷鍒楄〃
+ */
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:dict:export")
+ @PostMapping("/export")
+ public void export(SysDictTypeBo dictType, HttpServletResponse response) {
+ List<SysDictTypeVo> list = dictTypeService.selectDictTypeList(dictType);
+ ExcelUtil.exportExcel(list, "瀛楀吀绫诲瀷", SysDictTypeVo.class, response);
+ }
+
+ /**
+ * 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+ *
+ * @param dictId 瀛楀吀ID
+ */
+ @SaCheckPermission("system:dict:query")
+ @GetMapping(value = "/{dictId}")
+ public R<SysDictTypeVo> getInfo(@PathVariable Long dictId) {
+ return R.ok(dictTypeService.selectDictTypeById(dictId));
+ }
+
+ /**
+ * 鏂板瀛楀吀绫诲瀷
+ */
+ @SaCheckPermission("system:dict:add")
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysDictTypeBo dict) {
+ if (!dictTypeService.checkDictTypeUnique(dict)) {
+ return R.fail("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+ }
+ dictTypeService.insertDictType(dict);
+ return R.ok();
+ }
+
+ /**
+ * 淇敼瀛楀吀绫诲瀷
+ */
+ @SaCheckPermission("system:dict:edit")
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysDictTypeBo dict) {
+ if (!dictTypeService.checkDictTypeUnique(dict)) {
+ return R.fail("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+ }
+ dictTypeService.updateDictType(dict);
+ return R.ok();
+ }
+
+ /**
+ * 鍒犻櫎瀛楀吀绫诲瀷
+ *
+ * @param dictIds 瀛楀吀ID涓�
+ */
+ @SaCheckPermission("system:dict:remove")
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{dictIds}")
+ public R<Void> remove(@PathVariable Long[] dictIds) {
+ dictTypeService.deleteDictTypeByIds(dictIds);
+ return R.ok();
+ }
+
+ /**
+ * 鍒锋柊瀛楀吀缂撳瓨
+ */
+ @SaCheckPermission("system:dict:remove")
+ @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.CLEAN)
+ @DeleteMapping("/refreshCache")
+ public R<Void> refreshCache() {
+ dictTypeService.resetDictCache();
+ return R.ok();
+ }
+
+ /**
+ * 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
+ */
+ @GetMapping("/optionselect")
+ public R<List<SysDictTypeVo>> optionselect() {
+ List<SysDictTypeVo> dictTypes = dictTypeService.selectDictTypeAll();
+ return R.ok(dictTypes);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
new file mode 100644
index 0000000..5edb6f6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysMenuController.java
@@ -0,0 +1,174 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import cn.dev33.satoken.annotation.SaMode;
+import cn.hutool.core.lang.tree.Tree;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.MenuTreeSelectVo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.dromara.system.service.ISysMenuService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 鑿滃崟淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/menu")
+public class SysMenuController extends BaseController {
+
+ private final ISysMenuService menuService;
+
+ /**
+ * 鑾峰彇璺敱淇℃伅
+ *
+ * @return 璺敱淇℃伅
+ */
+ @GetMapping("/getRouters")
+ public R<List<RouterVo>> getRouters() {
+ List<SysMenu> menus = menuService.selectMenuTreeByUserId(LoginHelper.getUserId());
+ return R.ok(menuService.buildMenus(menus));
+ }
+
+ /**
+ * 鑾峰彇鑿滃崟鍒楄〃
+ */
+ @SaCheckRole(value = {
+ TenantConstants.SUPER_ADMIN_ROLE_KEY,
+ TenantConstants.TENANT_ADMIN_ROLE_KEY
+ }, mode = SaMode.OR)
+ @SaCheckPermission("system:menu:list")
+ @GetMapping("/list")
+ public R<List<SysMenuVo>> list(SysMenuBo menu) {
+ List<SysMenuVo> menus = menuService.selectMenuList(menu, LoginHelper.getUserId());
+ return R.ok(menus);
+ }
+
+ /**
+ * 鏍规嵁鑿滃崟缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param menuId 鑿滃崟ID
+ */
+ @SaCheckRole(value = {
+ TenantConstants.SUPER_ADMIN_ROLE_KEY,
+ TenantConstants.TENANT_ADMIN_ROLE_KEY
+ }, mode = SaMode.OR)
+ @SaCheckPermission("system:menu:query")
+ @GetMapping(value = "/{menuId}")
+ public R<SysMenuVo> getInfo(@PathVariable Long menuId) {
+ return R.ok(menuService.selectMenuById(menuId));
+ }
+
+ /**
+ * 鑾峰彇鑿滃崟涓嬫媺鏍戝垪琛�
+ */
+ @SaCheckPermission("system:menu:query")
+ @GetMapping("/treeselect")
+ public R<List<Tree<Long>>> treeselect(SysMenuBo menu) {
+ List<SysMenuVo> menus = menuService.selectMenuList(menu, LoginHelper.getUserId());
+ return R.ok(menuService.buildMenuTreeSelect(menus));
+ }
+
+ /**
+ * 鍔犺浇瀵瑰簲瑙掕壊鑿滃崟鍒楄〃鏍�
+ *
+ * @param roleId 瑙掕壊ID
+ */
+ @SaCheckPermission("system:menu:query")
+ @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+ public R<MenuTreeSelectVo> roleMenuTreeselect(@PathVariable("roleId") Long roleId) {
+ List<SysMenuVo> menus = menuService.selectMenuList(LoginHelper.getUserId());
+ MenuTreeSelectVo selectVo = new MenuTreeSelectVo();
+ selectVo.setCheckedKeys(menuService.selectMenuListByRoleId(roleId));
+ selectVo.setMenus(menuService.buildMenuTreeSelect(menus));
+ return R.ok(selectVo);
+ }
+
+ /**
+ * 鍔犺浇瀵瑰簲绉熸埛濂楅鑿滃崟鍒楄〃鏍�
+ *
+ * @param packageId 绉熸埛濂楅ID
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:menu:query")
+ @GetMapping(value = "/tenantPackageMenuTreeselect/{packageId}")
+ public R<MenuTreeSelectVo> tenantPackageMenuTreeselect(@PathVariable("packageId") Long packageId) {
+ List<SysMenuVo> menus = menuService.selectMenuList(LoginHelper.getUserId());
+ MenuTreeSelectVo selectVo = new MenuTreeSelectVo();
+ selectVo.setCheckedKeys(menuService.selectMenuListByPackageId(packageId));
+ selectVo.setMenus(menuService.buildMenuTreeSelect(menus));
+ return R.ok(selectVo);
+ }
+
+ /**
+ * 鏂板鑿滃崟
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:menu:add")
+ @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysMenuBo menu) {
+ if (!menuService.checkMenuNameUnique(menu)) {
+ return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+ } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+ return R.fail("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+ }
+ return toAjax(menuService.insertMenu(menu));
+ }
+
+ /**
+ * 淇敼鑿滃崟
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:menu:edit")
+ @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysMenuBo menu) {
+ if (!menuService.checkMenuNameUnique(menu)) {
+ return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+ } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+ return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(s)://寮�澶�");
+ } else if (menu.getMenuId().equals(menu.getParentId())) {
+ return R.fail("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛屼笂绾ц彍鍗曚笉鑳介�夋嫨鑷繁");
+ }
+ return toAjax(menuService.updateMenu(menu));
+ }
+
+ /**
+ * 鍒犻櫎鑿滃崟
+ *
+ * @param menuId 鑿滃崟ID
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:menu:remove")
+ @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{menuId}")
+ public R<Void> remove(@PathVariable("menuId") Long menuId) {
+ if (menuService.hasChildByMenuId(menuId)) {
+ return R.warn("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+ }
+ if (menuService.checkMenuExistRole(menuId)) {
+ return R.warn("鑿滃崟宸插垎閰�,涓嶅厑璁稿垹闄�");
+ }
+ return toAjax(menuService.deleteMenuById(menuId));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
new file mode 100644
index 0000000..6ed291b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysNoticeController.java
@@ -0,0 +1,94 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.service.DictService;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.resource.api.RemoteMessageService;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+import org.dromara.system.service.ISysNoticeService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * 鍏憡 淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/notice")
+public class SysNoticeController extends BaseController {
+
+ private final ISysNoticeService noticeService;
+ private final DictService dictService;
+
+ @DubboReference
+ private final RemoteMessageService remoteMessageService;
+
+ /**
+ * 鑾峰彇閫氱煡鍏憡鍒楄〃
+ */
+ @SaCheckPermission("system:notice:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysNoticeVo> list(SysNoticeBo notice, PageQuery pageQuery) {
+ return noticeService.selectPageNoticeList(notice, pageQuery);
+ }
+
+ /**
+ * 鏍规嵁閫氱煡鍏憡缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param noticeId 鍏憡ID
+ */
+ @SaCheckPermission("system:notice:query")
+ @GetMapping(value = "/{noticeId}")
+ public R<SysNoticeVo> getInfo(@PathVariable Long noticeId) {
+ return R.ok(noticeService.selectNoticeById(noticeId));
+ }
+
+ /**
+ * 鏂板閫氱煡鍏憡
+ */
+ @SaCheckPermission("system:notice:add")
+ @Log(title = "閫氱煡鍏憡", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysNoticeBo notice) {
+ int rows = noticeService.insertNotice(notice);
+ if (rows <= 0) {
+ return R.fail();
+ }
+ String type = dictService.getDictLabel("sys_notice_type", notice.getNoticeType());
+ remoteMessageService.publishAll("[" + type + "] " + notice.getNoticeTitle());
+ return R.ok();
+ }
+
+ /**
+ * 淇敼閫氱煡鍏憡
+ */
+ @SaCheckPermission("system:notice:edit")
+ @Log(title = "閫氱煡鍏憡", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysNoticeBo notice) {
+ return toAjax(noticeService.updateNotice(notice));
+ }
+
+ /**
+ * 鍒犻櫎閫氱煡鍏憡
+ *
+ * @param noticeIds 鍏憡ID涓�
+ */
+ @SaCheckPermission("system:notice:remove")
+ @Log(title = "閫氱煡鍏憡", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{noticeIds}")
+ public R<Void> remove(@PathVariable Long[] noticeIds) {
+ return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
new file mode 100644
index 0000000..9932cb6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysPostController.java
@@ -0,0 +1,121 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.service.ISysPostService;
+import jakarta.servlet.http.HttpServletResponse;
+import lombok.RequiredArgsConstructor;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅鎿嶄綔澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/post")
+public class SysPostController extends BaseController {
+
+ private final ISysPostService postService;
+
+ /**
+ * 鑾峰彇宀椾綅鍒楄〃
+ */
+ @SaCheckPermission("system:post:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysPostVo> list(SysPostBo post, PageQuery pageQuery) {
+ return postService.selectPagePostList(post, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭宀椾綅鍒楄〃
+ */
+ @Log(title = "宀椾綅绠$悊", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:post:export")
+ @PostMapping("/export")
+ public void export(SysPostBo post, HttpServletResponse response) {
+ List<SysPostVo> list = postService.selectPostList(post);
+ ExcelUtil.exportExcel(list, "宀椾綅鏁版嵁", SysPostVo.class, response);
+ }
+
+ /**
+ * 鏍规嵁宀椾綅缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param postId 宀椾綅ID
+ */
+ @SaCheckPermission("system:post:query")
+ @GetMapping(value = "/{postId}")
+ public R<SysPostVo> getInfo(@PathVariable Long postId) {
+ return R.ok(postService.selectPostById(postId));
+ }
+
+ /**
+ * 鏂板宀椾綅
+ */
+ @SaCheckPermission("system:post:add")
+ @Log(title = "宀椾綅绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysPostBo post) {
+ if (!postService.checkPostNameUnique(post)) {
+ return R.fail("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+ } else if (!postService.checkPostCodeUnique(post)) {
+ return R.fail("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+ }
+ return toAjax(postService.insertPost(post));
+ }
+
+ /**
+ * 淇敼宀椾綅
+ */
+ @SaCheckPermission("system:post:edit")
+ @Log(title = "宀椾綅绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysPostBo post) {
+ if (!postService.checkPostNameUnique(post)) {
+ return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+ } else if (!postService.checkPostCodeUnique(post)) {
+ return R.fail("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+ } else if (UserConstants.POST_DISABLE.equals(post.getStatus())
+ && postService.countUserPostById(post.getPostId()) > 0) {
+ return R.fail("璇ュ矖浣嶄笅瀛樺湪宸插垎閰嶇敤鎴凤紝涓嶈兘绂佺敤!");
+ }
+ return toAjax(postService.updatePost(post));
+ }
+
+ /**
+ * 鍒犻櫎宀椾綅
+ *
+ * @param postIds 宀椾綅ID涓�
+ */
+ @SaCheckPermission("system:post:remove")
+ @Log(title = "宀椾綅绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{postIds}")
+ public R<Void> remove(@PathVariable Long[] postIds) {
+ return toAjax(postService.deletePostByIds(postIds));
+ }
+
+ /**
+ * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+ */
+ @GetMapping("/optionselect")
+ public R<List<SysPostVo>> optionselect() {
+ SysPostBo postBo = new SysPostBo();
+ postBo.setStatus(UserConstants.POST_NORMAL);
+ List<SysPostVo> posts = postService.selectPostList(postBo);
+ return R.ok(posts);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
new file mode 100644
index 0000000..5e1a0e7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysProfileController.java
@@ -0,0 +1,132 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.io.FileUtil;
+import io.seata.spring.annotation.GlobalTransactional;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboReference;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.file.MimeTypeUtils;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.resource.api.RemoteFileService;
+import org.dromara.resource.api.domain.RemoteFile;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.bo.SysUserPasswordBo;
+import org.dromara.system.domain.bo.SysUserProfileBo;
+import org.dromara.system.domain.vo.AvatarVo;
+import org.dromara.system.domain.vo.ProfileVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.util.Arrays;
+
+/**
+ * 涓汉淇℃伅 涓氬姟澶勭悊
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/user/profile")
+public class SysProfileController extends BaseController {
+
+ private final ISysUserService userService;
+
+ @DubboReference
+ private RemoteFileService remoteFileService;
+
+ /**
+ * 涓汉淇℃伅
+ */
+ @GetMapping
+ public R<ProfileVo> profile() {
+ SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
+ ProfileVo profileVo = new ProfileVo();
+ profileVo.setUser(user);
+ profileVo.setRoleGroup(userService.selectUserRoleGroup(user.getUserName()));
+ profileVo.setPostGroup(userService.selectUserPostGroup(user.getUserName()));
+ return R.ok(profileVo);
+ }
+
+ /**
+ * 淇敼鐢ㄦ埛
+ */
+ @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> updateProfile(@RequestBody SysUserProfileBo profile) {
+ SysUserBo user = BeanUtil.toBean(profile, SysUserBo.class);
+ String username = LoginHelper.getUsername();
+ if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+ return R.fail("淇敼鐢ㄦ埛'" + username + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+ }
+ if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+ return R.fail("淇敼鐢ㄦ埛'" + username + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+ }
+ user.setUserId(LoginHelper.getUserId());
+ if (userService.updateUserProfile(user) > 0) {
+ return R.ok();
+ }
+ return R.fail("淇敼涓汉淇℃伅寮傚父锛岃鑱旂郴绠$悊鍛�");
+ }
+
+ /**
+ * 閲嶇疆瀵嗙爜
+ *
+ * @param bo 鏂版棫瀵嗙爜
+ */
+ @ApiEncrypt
+ @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+ @PutMapping("/updatePwd")
+ public R<Void> updatePwd(@Validated @RequestBody SysUserPasswordBo bo) {
+ SysUserVo user = userService.selectUserById(LoginHelper.getUserId());
+ String password = user.getPassword();
+ if (!BCrypt.checkpw(bo.getOldPassword(), password)) {
+ return R.fail("淇敼瀵嗙爜澶辫触锛屾棫瀵嗙爜閿欒");
+ }
+ if (BCrypt.checkpw(bo.getNewPassword(), password)) {
+ return R.fail("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
+ }
+
+ if (userService.resetUserPwd(user.getUserId(), BCrypt.hashpw(bo.getNewPassword())) > 0) {
+ return R.ok();
+ }
+ return R.fail("淇敼瀵嗙爜寮傚父锛岃鑱旂郴绠$悊鍛�");
+ }
+
+ /**
+ * 澶村儚涓婁紶
+ *
+ * @param avatarfile 鐢ㄦ埛澶村儚
+ */
+ @GlobalTransactional(rollbackFor = Exception.class)
+ @Log(title = "鐢ㄦ埛澶村儚", businessType = BusinessType.UPDATE)
+ @PostMapping(value = "/avatar", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public R<AvatarVo> avatar(@RequestPart("avatarfile") MultipartFile avatarfile) throws IOException {
+ if (!avatarfile.isEmpty()) {
+ String extension = FileUtil.extName(avatarfile.getOriginalFilename());
+ if (!StringUtils.equalsAnyIgnoreCase(extension, MimeTypeUtils.IMAGE_EXTENSION)) {
+ return R.fail("鏂囦欢鏍煎紡涓嶆纭紝璇蜂笂浼�" + Arrays.toString(MimeTypeUtils.IMAGE_EXTENSION) + "鏍煎紡");
+ }
+ RemoteFile oss = remoteFileService.upload(avatarfile.getName(), avatarfile.getOriginalFilename(), avatarfile.getContentType(), avatarfile.getBytes());
+ String avatar = oss.getUrl();
+ if (userService.updateUserAvatar(LoginHelper.getUserId(), oss.getOssId())) {
+ AvatarVo avatarVo = new AvatarVo();
+ avatarVo.setImgUrl(avatar);
+ return R.ok(avatarVo);
+ }
+ }
+ return R.fail("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛�");
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java
new file mode 100644
index 0000000..2ca7679
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysRoleController.java
@@ -0,0 +1,228 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.DeptTreeSelectVo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysDeptService;
+import org.dromara.system.service.ISysRoleService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 瑙掕壊淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/role")
+public class SysRoleController extends BaseController {
+
+ private final ISysRoleService roleService;
+ private final ISysUserService userService;
+ private final ISysDeptService deptService;
+
+ /**
+ * 鑾峰彇瑙掕壊淇℃伅鍒楄〃
+ */
+ @SaCheckPermission("system:role:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysRoleVo> list(SysRoleBo role, PageQuery pageQuery) {
+ return roleService.selectPageRoleList(role, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭瑙掕壊淇℃伅鍒楄〃
+ */
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:role:export")
+ @PostMapping("/export")
+ public void export(SysRoleBo role, HttpServletResponse response) {
+ List<SysRoleVo> list = roleService.selectRoleList(role);
+ ExcelUtil.exportExcel(list, "瑙掕壊鏁版嵁", SysRoleVo.class, response);
+ }
+
+ /**
+ * 鏍规嵁瑙掕壊缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param roleId 瑙掕壊ID
+ */
+ @SaCheckPermission("system:role:query")
+ @GetMapping(value = "/{roleId}")
+ public R<SysRoleVo> getInfo(@PathVariable Long roleId) {
+ roleService.checkRoleDataScope(roleId);
+ return R.ok(roleService.selectRoleById(roleId));
+ }
+
+ /**
+ * 鏂板瑙掕壊
+ */
+ @SaCheckPermission("system:role:add")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysRoleBo role) {
+ roleService.checkRoleAllowed(role);
+ if (!roleService.checkRoleNameUnique(role)) {
+ return R.fail("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+ } else if (!roleService.checkRoleKeyUnique(role)) {
+ return R.fail("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+ }
+ return toAjax(roleService.insertRole(role));
+
+ }
+
+ /**
+ * 淇敼淇濆瓨瑙掕壊
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysRoleBo role) {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ if (!roleService.checkRoleNameUnique(role)) {
+ return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+ } else if (!roleService.checkRoleKeyUnique(role)) {
+ return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+ }
+
+ if (roleService.updateRole(role) > 0) {
+ roleService.cleanOnlineUserByRole(role.getRoleId());
+ return R.ok();
+ }
+ return R.fail("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑱旂郴绠$悊鍛�");
+ }
+
+ /**
+ * 淇敼淇濆瓨鏁版嵁鏉冮檺
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping("/dataScope")
+ public R<Void> dataScope(@RequestBody SysRoleBo role) {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ return toAjax(roleService.authDataScope(role));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysRoleBo role) {
+ roleService.checkRoleAllowed(role);
+ roleService.checkRoleDataScope(role.getRoleId());
+ return toAjax(roleService.updateRoleStatus(role.getRoleId(), role.getStatus()));
+ }
+
+ /**
+ * 鍒犻櫎瑙掕壊
+ *
+ * @param roleIds 瑙掕壊ID涓�
+ */
+ @SaCheckPermission("system:role:remove")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{roleIds}")
+ public R<Void> remove(@PathVariable Long[] roleIds) {
+ return toAjax(roleService.deleteRoleByIds(roleIds));
+ }
+
+ /**
+ * 鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+ */
+ @SaCheckPermission("system:role:query")
+ @GetMapping("/optionselect")
+ public R<List<SysRoleVo>> optionselect() {
+ return R.ok(roleService.selectRoleAll());
+ }
+
+ /**
+ * 鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+ */
+ @SaCheckPermission("system:role:list")
+ @GetMapping("/authUser/allocatedList")
+ public TableDataInfo<SysUserVo> allocatedList(SysUserBo user, PageQuery pageQuery) {
+ return userService.selectAllocatedList(user, pageQuery);
+ }
+
+ /**
+ * 鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+ */
+ @SaCheckPermission("system:role:list")
+ @GetMapping("/authUser/unallocatedList")
+ public TableDataInfo<SysUserVo> unallocatedList(SysUserBo user, PageQuery pageQuery) {
+ return userService.selectUnallocatedList(user, pageQuery);
+ }
+
+ /**
+ * 鍙栨秷鎺堟潈鐢ㄦ埛
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/cancel")
+ public R<Void> cancelAuthUser(@RequestBody SysUserRole userRole) {
+ return toAjax(roleService.deleteAuthUser(userRole));
+ }
+
+ /**
+ * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 鐢ㄦ埛ID涓�
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/cancelAll")
+ public R<Void> cancelAuthUserAll(Long roleId, Long[] userIds) {
+ return toAjax(roleService.deleteAuthUsers(roleId, userIds));
+ }
+
+ /**
+ * 鎵归噺閫夋嫨鐢ㄦ埛鎺堟潈
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 鐢ㄦ埛ID涓�
+ */
+ @SaCheckPermission("system:role:edit")
+ @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.GRANT)
+ @PutMapping("/authUser/selectAll")
+ public R<Void> selectAuthUserAll(Long roleId, Long[] userIds) {
+ roleService.checkRoleDataScope(roleId);
+ return toAjax(roleService.insertAuthUsers(roleId, userIds));
+ }
+
+ /**
+ * 鑾峰彇瀵瑰簲瑙掕壊閮ㄩ棬鏍戝垪琛�
+ *
+ * @param roleId 瑙掕壊ID
+ */
+ @SaCheckPermission("system:role:list")
+ @GetMapping(value = "/deptTree/{roleId}")
+ public R<DeptTreeSelectVo> roleDeptTreeselect(@PathVariable("roleId") Long roleId) {
+ DeptTreeSelectVo selectVo = new DeptTreeSelectVo();
+ selectVo.setCheckedKeys(deptService.selectDeptListByRoleId(roleId));
+ selectVo.setDepts(deptService.selectDeptTreeList(new SysDeptBo()));
+ return R.ok(selectVo);
+ }
+}
+
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java
new file mode 100644
index 0000000..0d95d0e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysSocialController.java
@@ -0,0 +1,38 @@
+package org.dromara.system.controller.system;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.service.ISysSocialService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯�
+ *
+ * @author thiszhc
+ * @date 2023-06-16
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/social")
+public class SysSocialController extends BaseController {
+
+ private final ISysSocialService socialUserService;
+
+ /**
+ * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+ */
+ @GetMapping("/list")
+ public R<List<SysSocialVo>> list() {
+ return R.ok(socialUserService.queryListByUserId(LoginHelper.getUserId()));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
new file mode 100644
index 0000000..0d43114
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantController.java
@@ -0,0 +1,178 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import com.baomidou.lock.annotation.Lock4j;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.service.ISysTenantService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 绉熸埛绠$悊
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/tenant")
+public class SysTenantController extends BaseController {
+
+ private final ISysTenantService tenantService;
+
+ /**
+ * 鏌ヨ绉熸埛鍒楄〃
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysTenantVo> list(SysTenantBo bo, PageQuery pageQuery) {
+ return tenantService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭绉熸埛鍒楄〃
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:export")
+ @Log(title = "绉熸埛", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(SysTenantBo bo, HttpServletResponse response) {
+ List<SysTenantVo> list = tenantService.queryList(bo);
+ ExcelUtil.exportExcel(list, "绉熸埛", SysTenantVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇绉熸埛璇︾粏淇℃伅
+ *
+ * @param id 涓婚敭
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:query")
+ @GetMapping("/{id}")
+ public R<SysTenantVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long id) {
+ return R.ok(tenantService.queryById(id));
+ }
+
+ /**
+ * 鏂板绉熸埛
+ */
+ @ApiEncrypt
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:add")
+ @Log(title = "绉熸埛", businessType = BusinessType.INSERT)
+ @Lock4j
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantBo bo) {
+ if (!tenantService.checkCompanyNameUnique(bo)) {
+ return R.fail("鏂板绉熸埛'" + bo.getCompanyName() + "'澶辫触锛屼紒涓氬悕绉板凡瀛樺湪");
+ }
+ return toAjax(TenantHelper.ignore(() -> tenantService.insertByBo(bo)));
+ }
+
+ /**
+ * 淇敼绉熸埛
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:edit")
+ @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantBo bo) {
+ tenantService.checkTenantAllowed(bo.getTenantId());
+ if (!tenantService.checkCompanyNameUnique(bo)) {
+ return R.fail("淇敼绉熸埛'" + bo.getCompanyName() + "'澶辫触锛屽叕鍙稿悕绉板凡瀛樺湪");
+ }
+ return toAjax(tenantService.updateByBo(bo));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:edit")
+ @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysTenantBo bo) {
+ tenantService.checkTenantAllowed(bo.getTenantId());
+ return toAjax(tenantService.updateTenantStatus(bo));
+ }
+
+ /**
+ * 鍒犻櫎绉熸埛
+ *
+ * @param ids 涓婚敭涓�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:remove")
+ @Log(title = "绉熸埛", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{ids}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long[] ids) {
+ return toAjax(tenantService.deleteWithValidByIds(Arrays.asList(ids), true));
+ }
+
+ /**
+ * 鍔ㄦ�佸垏鎹㈢鎴�
+ *
+ * @param tenantId 绉熸埛ID
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @GetMapping("/dynamic/{tenantId}")
+ public R<Void> dynamicTenant(@NotBlank(message = "绉熸埛ID涓嶈兘涓虹┖") @PathVariable String tenantId) {
+ TenantHelper.setDynamic(tenantId);
+ return R.ok();
+ }
+
+ /**
+ * 娓呴櫎鍔ㄦ�佺鎴�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @GetMapping("/dynamic/clear")
+ public R<Void> dynamicClear() {
+ TenantHelper.clearDynamic();
+ return R.ok();
+ }
+
+
+ /**
+ * 鍚屾绉熸埛濂楅
+ *
+ * @param tenantId 绉熸埛id
+ * @param packageId 濂楅id
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenant:edit")
+ @Log(title = "绉熸埛", businessType = BusinessType.UPDATE)
+ @GetMapping("/syncTenantPackage")
+ public R<Void> syncTenantPackage(@NotBlank(message = "绉熸埛ID涓嶈兘涓虹┖") String tenantId,
+ @NotNull(message = "濂楅ID涓嶈兘涓虹┖") Long packageId) {
+ return toAjax(TenantHelper.ignore(() -> tenantService.syncTenantPackage(tenantId, packageId)));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
new file mode 100644
index 0000000..d01a4b0
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysTenantPackageController.java
@@ -0,0 +1,135 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.annotation.SaCheckRole;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.idempotent.annotation.RepeatSubmit;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+import org.dromara.system.service.ISysTenantPackageService;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.NotNull;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅绠$悊
+ *
+ * @author Michelle.Chung
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/tenant/package")
+public class SysTenantPackageController extends BaseController {
+
+ private final ISysTenantPackageService tenantPackageService;
+
+ /**
+ * 鏌ヨ绉熸埛濂楅鍒楄〃
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysTenantPackageVo> list(SysTenantPackageBo bo, PageQuery pageQuery) {
+ return tenantPackageService.queryPageList(bo, pageQuery);
+ }
+
+ /**
+ * 鏌ヨ绉熸埛濂楅涓嬫媺閫夊垪琛�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:list")
+ @GetMapping("/selectList")
+ public R<List<SysTenantPackageVo>> selectList() {
+ return R.ok(tenantPackageService.selectList());
+ }
+
+ /**
+ * 瀵煎嚭绉熸埛濂楅鍒楄〃
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:export")
+ @Log(title = "绉熸埛濂楅", businessType = BusinessType.EXPORT)
+ @PostMapping("/export")
+ public void export(SysTenantPackageBo bo, HttpServletResponse response) {
+ List<SysTenantPackageVo> list = tenantPackageService.queryList(bo);
+ ExcelUtil.exportExcel(list, "绉熸埛濂楅", SysTenantPackageVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇绉熸埛濂楅璇︾粏淇℃伅
+ *
+ * @param packageId 涓婚敭
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:query")
+ @GetMapping("/{packageId}")
+ public R<SysTenantPackageVo> getInfo(@NotNull(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long packageId) {
+ return R.ok(tenantPackageService.queryById(packageId));
+ }
+
+ /**
+ * 鏂板绉熸埛濂楅
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:add")
+ @Log(title = "绉熸埛濂楅", businessType = BusinessType.INSERT)
+ @RepeatSubmit()
+ @PostMapping()
+ public R<Void> add(@Validated(AddGroup.class) @RequestBody SysTenantPackageBo bo) {
+ return toAjax(tenantPackageService.insertByBo(bo));
+ }
+
+ /**
+ * 淇敼绉熸埛濂楅
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:edit")
+ @Log(title = "绉熸埛濂楅", businessType = BusinessType.UPDATE)
+ @RepeatSubmit()
+ @PutMapping()
+ public R<Void> edit(@Validated(EditGroup.class) @RequestBody SysTenantPackageBo bo) {
+ return toAjax(tenantPackageService.updateByBo(bo));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:edit")
+ @Log(title = "绉熸埛濂楅", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysTenantPackageBo bo) {
+ return toAjax(tenantPackageService.updatePackageStatus(bo));
+ }
+
+ /**
+ * 鍒犻櫎绉熸埛濂楅
+ *
+ * @param packageIds 涓婚敭涓�
+ */
+ @SaCheckRole(TenantConstants.SUPER_ADMIN_ROLE_KEY)
+ @SaCheckPermission("system:tenantPackage:remove")
+ @Log(title = "绉熸埛濂楅", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{packageIds}")
+ public R<Void> remove(@NotEmpty(message = "涓婚敭涓嶈兘涓虹┖")
+ @PathVariable Long[] packageIds) {
+ return toAjax(tenantPackageService.deleteWithValidByIds(Arrays.asList(packageIds), true));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
new file mode 100644
index 0000000..08dfaea
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/controller/system/SysUserController.java
@@ -0,0 +1,285 @@
+package org.dromara.system.controller.system;
+
+import cn.dev33.satoken.annotation.SaCheckPermission;
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.validation.constraints.NotNull;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.domain.R;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.encrypt.annotation.ApiEncrypt;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.excel.utils.ExcelUtil;
+import org.dromara.common.log.annotation.Log;
+import org.dromara.common.log.enums.BusinessType;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.common.web.core.BaseController;
+import org.dromara.system.api.model.LoginUser;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.*;
+import org.dromara.system.listener.SysUserImportListener;
+import org.dromara.system.service.*;
+import org.springframework.http.MediaType;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ *
+ * @author Lion Li
+ */
+@Validated
+@RequiredArgsConstructor
+@RestController
+@RequestMapping("/user")
+public class SysUserController extends BaseController {
+
+ private final ISysUserService userService;
+ private final ISysRoleService roleService;
+ private final ISysPostService postService;
+ private final ISysDeptService deptService;
+ private final ISysTenantService tenantService;
+
+ /**
+ * 鑾峰彇鐢ㄦ埛鍒楄〃
+ */
+ @SaCheckPermission("system:user:list")
+ @GetMapping("/list")
+ public TableDataInfo<SysUserVo> list(SysUserBo user, PageQuery pageQuery) {
+ return userService.selectPageUserList(user, pageQuery);
+ }
+
+ /**
+ * 瀵煎嚭鐢ㄦ埛鍒楄〃
+ */
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.EXPORT)
+ @SaCheckPermission("system:user:export")
+ @PostMapping("/export")
+ public void export(SysUserBo user, HttpServletResponse response) {
+ List<SysUserVo> list = userService.selectUserList(user);
+ List<SysUserExportVo> listVo = MapstructUtils.convert(list, SysUserExportVo.class);
+ ExcelUtil.exportExcel(listVo, "鐢ㄦ埛鏁版嵁", SysUserExportVo.class, response);
+ }
+
+ /**
+ * 瀵煎叆鏁版嵁
+ *
+ * @param file 瀵煎叆鏂囦欢
+ * @param updateSupport 鏄惁鏇存柊宸插瓨鍦ㄦ暟鎹�
+ */
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.IMPORT)
+ @SaCheckPermission("system:user:import")
+ @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
+ public R<Void> importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception {
+ ExcelResult<SysUserImportVo> result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport));
+ return R.ok(result.getAnalysis());
+ }
+
+ /**
+ * 鑾峰彇瀵煎叆妯℃澘
+ */
+ @PostMapping("/importTemplate")
+ public void importTemplate(HttpServletResponse response) {
+ ExcelUtil.exportExcel(new ArrayList<>(), "鐢ㄦ埛鏁版嵁", SysUserImportVo.class, response);
+ }
+
+ /**
+ * 鑾峰彇鐢ㄦ埛淇℃伅
+ *
+ * @return 鐢ㄦ埛淇℃伅
+ */
+ @GetMapping("/getInfo")
+ public R<UserInfoVo> getInfo() {
+ UserInfoVo userInfoVo = new UserInfoVo();
+ LoginUser loginUser = LoginHelper.getLoginUser();
+ if (TenantHelper.isEnable() && LoginHelper.isSuperAdmin()) {
+ // 瓒呯骇绠$悊鍛� 濡傛灉閲嶆柊鍔犺浇鐢ㄦ埛淇℃伅闇�娓呴櫎鍔ㄦ�佺鎴�
+ TenantHelper.clearDynamic();
+ }
+ SysUserVo user = userService.selectUserById(loginUser.getUserId());
+ if (ObjectUtil.isNull(user)) {
+ return R.fail("娌℃湁鏉冮檺璁块棶鐢ㄦ埛鏁版嵁!");
+ }
+ userInfoVo.setUser(user);
+ userInfoVo.setPermissions(loginUser.getMenuPermission());
+ userInfoVo.setRoles(loginUser.getRolePermission());
+ return R.ok(userInfoVo);
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇璇︾粏淇℃伅
+ *
+ * @param userId 鐢ㄦ埛ID
+ */
+ @SaCheckPermission("system:user:query")
+ @GetMapping(value = {"/", "/{userId}"})
+ public R<SysUserInfoVo> getInfo(@PathVariable(value = "userId", required = false) Long userId) {
+ userService.checkUserDataScope(userId);
+ SysUserInfoVo userInfoVo = new SysUserInfoVo();
+ SysRoleBo roleBo = new SysRoleBo();
+ roleBo.setStatus(UserConstants.ROLE_NORMAL);
+ SysPostBo postBo = new SysPostBo();
+ postBo.setStatus(UserConstants.POST_NORMAL);
+ List<SysRoleVo> roles = roleService.selectRoleList(roleBo);
+ userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
+ userInfoVo.setPosts(postService.selectPostList(postBo));
+ if (ObjectUtil.isNotNull(userId)) {
+ SysUserVo sysUser = userService.selectUserById(userId);
+ userInfoVo.setUser(sysUser);
+ userInfoVo.setRoleIds(StreamUtils.toList(sysUser.getRoles(), SysRoleVo::getRoleId));
+ userInfoVo.setPostIds(postService.selectPostListByUserId(userId));
+ }
+ return R.ok(userInfoVo);
+ }
+
+ /**
+ * 鏂板鐢ㄦ埛
+ */
+ @SaCheckPermission("system:user:add")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.INSERT)
+ @PostMapping
+ public R<Void> add(@Validated @RequestBody SysUserBo user) {
+ deptService.checkDeptDataScope(user.getDeptId());
+ if (!userService.checkUserNameUnique(user)) {
+ return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+ } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+ return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+ } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+ return R.fail("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+ }
+ if (TenantHelper.isEnable()) {
+ if (!tenantService.checkAccountBalance(TenantHelper.getTenantId())) {
+ return R.fail("褰撳墠绉熸埛涓嬬敤鎴峰悕棰濅笉瓒筹紝璇疯仈绯荤鐞嗗憳");
+ }
+ }
+ user.setPassword(BCrypt.hashpw(user.getPassword()));
+ return toAjax(userService.insertUser(user));
+ }
+
+ /**
+ * 淇敼鐢ㄦ埛
+ */
+ @SaCheckPermission("system:user:edit")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping
+ public R<Void> edit(@Validated @RequestBody SysUserBo user) {
+ userService.checkUserAllowed(user.getUserId());
+ userService.checkUserDataScope(user.getUserId());
+ deptService.checkDeptDataScope(user.getDeptId());
+ if (!userService.checkUserNameUnique(user)) {
+ return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+ } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user)) {
+ return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+ } else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user)) {
+ return R.fail("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+ }
+ return toAjax(userService.updateUser(user));
+ }
+
+ /**
+ * 鍒犻櫎鐢ㄦ埛
+ *
+ * @param userIds 瑙掕壊ID涓�
+ */
+ @SaCheckPermission("system:user:remove")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.DELETE)
+ @DeleteMapping("/{userIds}")
+ public R<Void> remove(@PathVariable Long[] userIds) {
+ if (ArrayUtil.contains(userIds, LoginHelper.getUserId())) {
+ return R.fail("褰撳墠鐢ㄦ埛涓嶈兘鍒犻櫎");
+ }
+ return toAjax(userService.deleteUserByIds(userIds));
+ }
+
+ /**
+ * 閲嶇疆瀵嗙爜
+ */
+ @ApiEncrypt
+ @SaCheckPermission("system:user:resetPwd")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping("/resetPwd")
+ public R<Void> resetPwd(@RequestBody SysUserBo user) {
+ userService.checkUserAllowed(user.getUserId());
+ userService.checkUserDataScope(user.getUserId());
+ user.setPassword(BCrypt.hashpw(user.getPassword()));
+ return toAjax(userService.resetUserPwd(user.getUserId(), user.getPassword()));
+ }
+
+ /**
+ * 鐘舵�佷慨鏀�
+ */
+ @SaCheckPermission("system:user:edit")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+ @PutMapping("/changeStatus")
+ public R<Void> changeStatus(@RequestBody SysUserBo user) {
+ userService.checkUserAllowed(user.getUserId());
+ userService.checkUserDataScope(user.getUserId());
+ return toAjax(userService.updateUserStatus(user.getUserId(), user.getStatus()));
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇鎺堟潈瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛ID
+ */
+ @SaCheckPermission("system:user:query")
+ @GetMapping("/authRole/{userId}")
+ public R<SysUserInfoVo> authRole(@PathVariable Long userId) {
+ SysUserVo user = userService.selectUserById(userId);
+ List<SysRoleVo> roles = roleService.selectRolesByUserId(userId);
+ SysUserInfoVo userInfoVo = new SysUserInfoVo();
+ userInfoVo.setUser(user);
+ userInfoVo.setRoles(LoginHelper.isSuperAdmin(userId) ? roles : StreamUtils.filter(roles, r -> !r.isSuperAdmin()));
+ return R.ok(userInfoVo);
+ }
+
+ /**
+ * 鐢ㄦ埛鎺堟潈瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛Id
+ * @param roleIds 瑙掕壊ID涓�
+ */
+ @SaCheckPermission("system:user:edit")
+ @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.GRANT)
+ @PutMapping("/authRole")
+ public R<Void> insertAuthRole(Long userId, Long[] roleIds) {
+ userService.checkUserDataScope(userId);
+ userService.insertUserAuth(userId, roleIds);
+ return R.ok();
+ }
+
+ /**
+ * 鑾峰彇閮ㄩ棬鏍戝垪琛�
+ */
+ @SaCheckPermission("system:user:list")
+ @GetMapping("/deptTree")
+ public R<List<Tree<Long>>> deptTree(SysDeptBo dept) {
+ return R.ok(deptService.selectDeptTreeList(dept));
+ }
+
+ /**
+ * 鑾峰彇閮ㄩ棬涓嬬殑鎵�鏈夌敤鎴蜂俊鎭�
+ */
+ @SaCheckPermission("system:user:list")
+ @GetMapping("/list/dept/{deptId}")
+ public R<List<SysUserVo>> listByDept(@PathVariable @NotNull Long deptId) {
+ return R.ok(userService.selectUserListByDept(deptId));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
new file mode 100644
index 0000000..c659470
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysClient.java
@@ -0,0 +1,79 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+
+/**
+ * 鎺堟潈绠$悊瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ * @date 2023-05-15
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_client")
+public class SysClient extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 瀹㈡埛绔痠d
+ */
+ private String clientId;
+
+ /**
+ * 瀹㈡埛绔痥ey
+ */
+ private String clientKey;
+
+ /**
+ * 瀹㈡埛绔閽�
+ */
+ private String clientSecret;
+
+ /**
+ * 鎺堟潈绫诲瀷
+ */
+ private String grantType;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ private String deviceType;
+
+ /**
+ * token娲昏穬瓒呮椂鏃堕棿
+ */
+ private Long activeTimeout;
+
+ /**
+ * token鍥哄畾瓒呮椂鏃堕棿
+ */
+ private Long timeout;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java
new file mode 100644
index 0000000..df1355c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysConfig.java
@@ -0,0 +1,51 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * 鍙傛暟閰嶇疆琛� sys_config
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_config")
+public class SysConfig extends TenantEntity {
+
+ /**
+ * 鍙傛暟涓婚敭
+ */
+ @TableId(value = "config_id")
+ private Long configId;
+
+ /**
+ * 鍙傛暟鍚嶇О
+ */
+ private String configName;
+
+ /**
+ * 鍙傛暟閿悕
+ */
+ private String configKey;
+
+ /**
+ * 鍙傛暟閿��
+ */
+ private String configValue;
+
+ /**
+ * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+ */
+ private String configType;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
new file mode 100644
index 0000000..9733500
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDept.java
@@ -0,0 +1,79 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+
+/**
+ * 閮ㄩ棬琛� sys_dept
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dept")
+public class SysDept extends TenantEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ @TableId(value = "dept_id")
+ private Long deptId;
+
+ /**
+ * 鐖堕儴闂↖D
+ */
+ private Long parentId;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ private String deptName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ private Integer orderNum;
+
+ /**
+ * 璐熻矗浜�
+ */
+ private Long leader;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ private String phone;
+
+ /**
+ * 閭
+ */
+ private String email;
+
+ /**
+ * 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤
+ */
+ private String status;
+
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+ /**
+ * 绁栫骇鍒楄〃
+ */
+ private String ancestors;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
new file mode 100644
index 0000000..5eb5ca1
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictData.java
@@ -0,0 +1,71 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * 瀛楀吀鏁版嵁琛� sys_dict_data
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dict_data")
+public class SysDictData extends TenantEntity {
+
+ /**
+ * 瀛楀吀缂栫爜
+ */
+ @TableId(value = "dict_code")
+ private Long dictCode;
+
+ /**
+ * 瀛楀吀鎺掑簭
+ */
+ private Integer dictSort;
+
+ /**
+ * 瀛楀吀鏍囩
+ */
+ private String dictLabel;
+
+ /**
+ * 瀛楀吀閿��
+ */
+ private String dictValue;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ private String dictType;
+
+ /**
+ * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+ */
+ private String cssClass;
+
+ /**
+ * 琛ㄦ牸瀛楀吀鏍峰紡
+ */
+ private String listClass;
+
+ /**
+ * 鏄惁榛樿锛圷鏄� N鍚︼級
+ */
+ private String isDefault;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ public boolean getDefault() {
+ return UserConstants.YES.equals(this.isDefault);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java
new file mode 100644
index 0000000..dfd10a7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysDictType.java
@@ -0,0 +1,41 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * 瀛楀吀绫诲瀷琛� sys_dict_type
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_dict_type")
+public class SysDictType extends TenantEntity {
+
+ /**
+ * 瀛楀吀涓婚敭
+ */
+ @TableId(value = "dict_id")
+ private Long dictId;
+
+ /**
+ * 瀛楀吀鍚嶇О
+ */
+ private String dictName;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ private String dictType;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java
new file mode 100644
index 0000000..c57dc0a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysLogininfor.java
@@ -0,0 +1,85 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 绯荤粺璁块棶璁板綍琛� sys_logininfor
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_logininfor")
+public class SysLogininfor implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * ID
+ */
+ @TableId(value = "info_id")
+ private Long infoId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 瀹㈡埛绔�
+ */
+ private String clientKey;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ private String deviceType;
+
+ /**
+ * 鐧诲綍鐘舵�� 0鎴愬姛 1澶辫触
+ */
+ private String status;
+
+ /**
+ * 鐧诲綍IP鍦板潃
+ */
+ private String ipaddr;
+
+ /**
+ * 鐧诲綍鍦扮偣
+ */
+ private String loginLocation;
+
+ /**
+ * 娴忚鍣ㄧ被鍨�
+ */
+ private String browser;
+
+ /**
+ * 鎿嶄綔绯荤粺
+ */
+ private String os;
+
+ /**
+ * 鎻愮ず娑堟伅
+ */
+ private String msg;
+
+ /**
+ * 璁块棶鏃堕棿
+ */
+ private Date loginTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
new file mode 100644
index 0000000..0cdb508
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysMenu.java
@@ -0,0 +1,191 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 鑿滃崟鏉冮檺琛� sys_menu
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_menu")
+public class SysMenu extends BaseEntity {
+
+ /**
+ * 鑿滃崟ID
+ */
+ @TableId(value = "menu_id")
+ private Long menuId;
+
+ /**
+ * 鐖惰彍鍗旾D
+ */
+ private Long parentId;
+
+ /**
+ * 鑿滃崟鍚嶇О
+ */
+ private String menuName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ private Integer orderNum;
+
+ /**
+ * 璺敱鍦板潃
+ */
+ private String path;
+
+ /**
+ * 缁勪欢璺緞
+ */
+ private String component;
+
+ /**
+ * 璺敱鍙傛暟
+ */
+ private String queryParam;
+
+ /**
+ * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+ */
+ private String isFrame;
+
+ /**
+ * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+ */
+ private String isCache;
+
+ /**
+ * 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+ */
+ private String menuType;
+
+ /**
+ * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+ */
+ private String visible;
+
+ /**
+ * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鏉冮檺瀛楃涓�
+ */
+ private String perms;
+
+ /**
+ * 鑿滃崟鍥炬爣
+ */
+ private String icon;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鐖惰彍鍗曞悕绉�
+ */
+ @TableField(exist = false)
+ private String parentName;
+
+ /**
+ * 瀛愯彍鍗�
+ */
+ @TableField(exist = false)
+ private List<SysMenu> children = new ArrayList<>();
+
+ /**
+ * 鑾峰彇璺敱鍚嶇О
+ */
+ public String getRouteName() {
+ String routerName = StringUtils.capitalize(path);
+ // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+ if (isMenuFrame()) {
+ routerName = StringUtils.EMPTY;
+ }
+ return routerName;
+ }
+
+ /**
+ * 鑾峰彇璺敱鍦板潃
+ */
+ public String getRouterPath() {
+ String routerPath = this.path;
+ // 鍐呴摼鎵撳紑澶栫綉鏂瑰紡
+ if (getParentId() != 0L && isInnerLink()) {
+ routerPath = innerLinkReplaceEach(routerPath);
+ }
+ // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+ if (0L == getParentId() && UserConstants.TYPE_DIR.equals(getMenuType())
+ && UserConstants.NO_FRAME.equals(getIsFrame())) {
+ routerPath = "/" + this.path;
+ }
+ // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓鸿彍鍗曪級
+ else if (isMenuFrame()) {
+ routerPath = "/";
+ }
+ return routerPath;
+ }
+
+ /**
+ * 鑾峰彇缁勪欢淇℃伅
+ */
+ public String getComponentInfo() {
+ String component = UserConstants.LAYOUT;
+ if (StringUtils.isNotEmpty(this.component) && !isMenuFrame()) {
+ component = this.component;
+ } else if (StringUtils.isEmpty(this.component) && getParentId() != 0L && isInnerLink()) {
+ component = UserConstants.INNER_LINK;
+ } else if (StringUtils.isEmpty(this.component) && isParentView()) {
+ component = UserConstants.PARENT_VIEW;
+ }
+ return component;
+ }
+
+ /**
+ * 鏄惁涓鸿彍鍗曞唴閮ㄨ烦杞�
+ */
+ public boolean isMenuFrame() {
+ return getParentId() == 0L && UserConstants.TYPE_MENU.equals(menuType) && isFrame.equals(UserConstants.NO_FRAME);
+ }
+
+ /**
+ * 鏄惁涓哄唴閾剧粍浠�
+ */
+ public boolean isInnerLink() {
+ return isFrame.equals(UserConstants.NO_FRAME) && StringUtils.ishttp(path);
+ }
+
+ /**
+ * 鏄惁涓簆arent_view缁勪欢
+ */
+ public boolean isParentView() {
+ return getParentId() != 0L && UserConstants.TYPE_DIR.equals(menuType);
+ }
+
+ /**
+ * 鍐呴摼鍩熷悕鐗规畩瀛楃鏇挎崲
+ */
+ public static String innerLinkReplaceEach(String path) {
+ return StringUtils.replaceEach(path, new String[]{Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":"},
+ new String[]{"", "", "", "/", "/"});
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java
new file mode 100644
index 0000000..fb1df87
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysNotice.java
@@ -0,0 +1,51 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+
+/**
+ * 閫氱煡鍏憡琛� sys_notice
+ *
+ * @author Lion Li
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_notice")
+public class SysNotice extends TenantEntity {
+
+ /**
+ * 鍏憡ID
+ */
+ @TableId(value = "notice_id")
+ private Long noticeId;
+
+ /**
+ * 鍏憡鏍囬
+ */
+ private String noticeTitle;
+
+ /**
+ * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+ */
+ private String noticeType;
+
+ /**
+ * 鍏憡鍐呭
+ */
+ private String noticeContent;
+
+ /**
+ * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java
new file mode 100644
index 0000000..41a8c59
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysOperLog.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍琛� oper_log
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_oper_log")
+public class SysOperLog implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鏃ュ織涓婚敭
+ */
+ @TableId(value = "oper_id")
+ private Long operId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鎿嶄綔妯″潡
+ */
+ private String title;
+
+ /**
+ * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+ */
+ private Integer businessType;
+
+ /**
+ * 璇锋眰鏂规硶
+ */
+ private String method;
+
+ /**
+ * 璇锋眰鏂瑰紡
+ */
+ private String requestMethod;
+
+ /**
+ * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+ */
+ private Integer operatorType;
+
+ /**
+ * 鎿嶄綔浜哄憳
+ */
+ private String operName;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ private String deptName;
+
+ /**
+ * 璇锋眰url
+ */
+ private String operUrl;
+
+ /**
+ * 鎿嶄綔鍦板潃
+ */
+ private String operIp;
+
+ /**
+ * 鎿嶄綔鍦扮偣
+ */
+ private String operLocation;
+
+ /**
+ * 璇锋眰鍙傛暟
+ */
+ private String operParam;
+
+ /**
+ * 杩斿洖鍙傛暟
+ */
+ private String jsonResult;
+
+ /**
+ * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+ */
+ private Integer status;
+
+ /**
+ * 閿欒娑堟伅
+ */
+ private String errorMsg;
+
+ /**
+ * 鎿嶄綔鏃堕棿
+ */
+ private Date operTime;
+
+ /**
+ * 娑堣�楁椂闂�
+ */
+ private Long costTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java
new file mode 100644
index 0000000..7fe7039
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysPost.java
@@ -0,0 +1,51 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import org.dromara.common.tenant.core.TenantEntity;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 宀椾綅琛� sys_post
+ *
+ * @author Lion Li
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_post")
+public class SysPost extends TenantEntity {
+
+ /**
+ * 宀椾綅搴忓彿
+ */
+ @TableId(value = "post_id")
+ private Long postId;
+
+ /**
+ * 宀椾綅缂栫爜
+ */
+ private String postCode;
+
+ /**
+ * 宀椾綅鍚嶇О
+ */
+ private String postName;
+
+ /**
+ * 宀椾綅鎺掑簭
+ */
+ private Integer postSort;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
new file mode 100644
index 0000000..1b262a5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRole.java
@@ -0,0 +1,79 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.tenant.core.TenantEntity;
+
+/**
+ * 瑙掕壊琛� sys_role
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_role")
+public class SysRole extends TenantEntity {
+
+ /**
+ * 瑙掕壊ID
+ */
+ @TableId(value = "role_id")
+ private Long roleId;
+
+ /**
+ * 瑙掕壊鍚嶇О
+ */
+ private String roleName;
+
+ /**
+ * 瑙掕壊鏉冮檺
+ */
+ private String roleKey;
+
+ /**
+ * 瑙掕壊鎺掑簭
+ */
+ private Integer roleSort;
+
+ /**
+ * 鏁版嵁鑼冨洿锛�1锛氭墍鏈夋暟鎹潈闄愶紱2锛氳嚜瀹氫箟鏁版嵁鏉冮檺锛�3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺锛�4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶紱5锛氫粎鏈汉鏁版嵁鏉冮檺锛�
+ */
+ private String dataScope;
+
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
+ */
+ private Boolean menuCheckStrictly;
+
+ /**
+ * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀� 锛�
+ */
+ private Boolean deptCheckStrictly;
+
+ /**
+ * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ public SysRole(Long roleId) {
+ this.roleId = roleId;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java
new file mode 100644
index 0000000..ba77694
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleDept.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 瑙掕壊鍜岄儴闂ㄥ叧鑱� sys_role_dept
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_role_dept")
+public class SysRoleDept {
+
+ /**
+ * 瑙掕壊ID
+ */
+ @TableId(type = IdType.INPUT)
+ private Long roleId;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ private Long deptId;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java
new file mode 100644
index 0000000..ba28f17
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysRoleMenu.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 瑙掕壊鍜岃彍鍗曞叧鑱� sys_role_menu
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_role_menu")
+public class SysRoleMenu {
+
+ /**
+ * 瑙掕壊ID
+ */
+ @TableId(type = IdType.INPUT)
+ private Long roleId;
+
+ /**
+ * 鑿滃崟ID
+ */
+ private Long menuId;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java
new file mode 100644
index 0000000..10f2936
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysSocial.java
@@ -0,0 +1,136 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.io.Serial;
+
+/**
+ * 绀句細鍖栧叧绯诲璞� sys_social
+ *
+ * @author thiszhc
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_social")
+public class SysSocial extends TenantEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 涓婚敭
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ private Long userId;
+
+ /**
+ * 鐨勫敮涓�ID
+ */
+ private String authId;
+
+ /**
+ * 鐢ㄦ埛鏉ユ簮
+ */
+ private String source;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+ */
+ private String accessToken;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private int expireIn;
+
+ /**
+ * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String refreshToken;
+
+ /**
+ * 鐢ㄦ埛鐨� open id
+ */
+ private String openId;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟鏄电О
+ */
+ private String nickName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟閭
+ */
+ private String email;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+ */
+ private String avatar;
+
+ /**
+ * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String accessCode;
+
+ /**
+ * 鐢ㄦ埛鐨� unionid
+ */
+ private String unionId;
+
+ /**
+ * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String scope;
+
+ /**
+ * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String tokenType;
+
+ /**
+ * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String idToken;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macAlgorithm;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macKey;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String code;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthToken;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthTokenSecret;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
new file mode 100644
index 0000000..94e5230
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenant.java
@@ -0,0 +1,103 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+import java.util.Date;
+
+/**
+ * 绉熸埛瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_tenant")
+public class SysTenant extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @TableId(value = "id")
+ private Long id;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鑱旂郴浜�
+ */
+ private String contactUserName;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ private String contactPhone;
+
+ /**
+ * 浼佷笟鍚嶇О
+ */
+ private String companyName;
+
+ /**
+ * 缁熶竴绀句細淇$敤浠g爜
+ */
+ private String licenseNumber;
+
+ /**
+ * 鍦板潃
+ */
+ private String address;
+
+ /**
+ * 鍩熷悕
+ */
+ private String domain;
+
+ /**
+ * 浼佷笟绠�浠�
+ */
+ private String intro;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 绉熸埛濂楅缂栧彿
+ */
+ private Long packageId;
+
+ /**
+ * 杩囨湡鏃堕棿
+ */
+ private Date expireTime;
+
+ /**
+ * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+ */
+ private Long accountCount;
+
+ /**
+ * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
new file mode 100644
index 0000000..5556d9f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysTenantPackage.java
@@ -0,0 +1,56 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+
+import java.io.Serial;
+
+/**
+ * 绉熸埛濂楅瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_tenant_package")
+public class SysTenantPackage extends BaseEntity {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 绉熸埛濂楅id
+ */
+ @TableId(value = "package_id")
+ private Long packageId;
+ /**
+ * 濂楅鍚嶇О
+ */
+ private String packageName;
+ /**
+ * 鍏宠仈鑿滃崟id
+ */
+ private String menuIds;
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀猴紙 0锛氱埗瀛愪笉浜掔浉鍏宠仈鏄剧ず 1锛氱埗瀛愪簰鐩稿叧鑱旀樉绀猴級
+ */
+ private Boolean menuCheckStrictly;
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
new file mode 100644
index 0000000..2a4ddbd
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUser.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.tenant.core.TenantEntity;
+
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄 sys_user
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@TableName("sys_user")
+public class SysUser extends TenantEntity {
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ @TableId(value = "user_id")
+ private Long userId;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ private Long deptId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+ */
+ private String userType;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆
+ */
+ private String sex;
+
+ /**
+ * 鐢ㄦ埛澶村儚
+ */
+ private Long avatar;
+
+ /**
+ * 瀵嗙爜
+ */
+ @TableField(
+ insertStrategy = FieldStrategy.NOT_EMPTY,
+ updateStrategy = FieldStrategy.NOT_EMPTY,
+ whereStrategy = FieldStrategy.NOT_EMPTY
+ )
+ private String password;
+
+ /**
+ * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�
+ */
+ @TableLogic
+ private String delFlag;
+
+ /**
+ * 鏈�鍚庣櫥褰旾P
+ */
+ private String loginIp;
+
+ /**
+ * 鏈�鍚庣櫥褰曟椂闂�
+ */
+ private Date loginDate;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+
+ public SysUser(Long userId) {
+ this.userId = userId;
+ }
+
+ public boolean isSuperAdmin() {
+ return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java
new file mode 100644
index 0000000..119c117
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserPost.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛鍜屽矖浣嶅叧鑱� sys_user_post
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_user_post")
+public class SysUserPost {
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ @TableId(type = IdType.INPUT)
+ private Long userId;
+
+ /**
+ * 宀椾綅ID
+ */
+ private Long postId;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java
new file mode 100644
index 0000000..0a50e80
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/SysUserRole.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 鐢ㄦ埛鍜岃鑹插叧鑱� sys_user_role
+ *
+ * @author Lion Li
+ */
+
+@Data
+@TableName("sys_user_role")
+public class SysUserRole {
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ @TableId(type = IdType.INPUT)
+ private Long userId;
+
+ /**
+ * 瑙掕壊ID
+ */
+ private Long roleId;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java
new file mode 100644
index 0000000..82a9180
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysClientBo.java
@@ -0,0 +1,80 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysClient;
+
+import java.util.List;
+
+/**
+ * 鎺堟潈绠$悊涓氬姟瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysClient.class, reverseConvertGenerate = false)
+public class SysClientBo extends BaseEntity {
+
+ /**
+ * id
+ */
+ @NotNull(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 瀹㈡埛绔痠d
+ */
+ private String clientId;
+
+ /**
+ * 瀹㈡埛绔痥ey
+ */
+ @NotBlank(message = "瀹㈡埛绔痥ey涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String clientKey;
+
+ /**
+ * 瀹㈡埛绔閽�
+ */
+ @NotBlank(message = "瀹㈡埛绔閽ヤ笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+ private String clientSecret;
+
+ /**
+ * 鎺堟潈绫诲瀷
+ */
+ @NotNull(message = "鎺堟潈绫诲瀷涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private List<String> grantTypeList;
+
+ /**
+ * 鎺堟潈绫诲瀷
+ */
+ private String grantType;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ private String deviceType;
+
+ /**
+ * token娲昏穬瓒呮椂鏃堕棿
+ */
+ private Long activeTimeout;
+
+ /**
+ * token鍥哄畾瓒呮椂鏃堕棿
+ */
+ private Long timeout;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java
new file mode 100644
index 0000000..4affa64
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysConfigBo.java
@@ -0,0 +1,60 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysConfig;
+
+/**
+ * 鍙傛暟閰嶇疆涓氬姟瀵硅薄 sys_config
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysConfig.class, reverseConvertGenerate = false)
+public class SysConfigBo extends BaseEntity {
+
+ /**
+ * 鍙傛暟涓婚敭
+ */
+ private Long configId;
+
+ /**
+ * 鍙傛暟鍚嶇О
+ */
+ @NotBlank(message = "鍙傛暟鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "鍙傛暟鍚嶇О涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String configName;
+
+ /**
+ * 鍙傛暟閿悕
+ */
+ @NotBlank(message = "鍙傛暟閿悕涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "鍙傛暟閿悕闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String configKey;
+
+ /**
+ * 鍙傛暟閿��
+ */
+ @NotBlank(message = "鍙傛暟閿�间笉鑳戒负绌�")
+ @Size(min = 0, max = 500, message = "鍙傛暟閿�奸暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+ private String configValue;
+
+ /**
+ * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+ */
+ private String configType;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
new file mode 100644
index 0000000..a5031d7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDeptBo.java
@@ -0,0 +1,70 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDept;
+
+/**
+ * 閮ㄩ棬涓氬姟瀵硅薄 sys_dept
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDept.class, reverseConvertGenerate = false)
+public class SysDeptBo extends BaseEntity {
+
+ /**
+ * 閮ㄩ棬id
+ */
+ private Long deptId;
+
+ /**
+ * 鐖堕儴闂↖D
+ */
+ private Long parentId;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ @NotBlank(message = "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 30, message = "閮ㄩ棬鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String deptName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+ private Integer orderNum;
+
+ /**
+ * 璐熻矗浜�
+ */
+ private Long leader;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ @Size(min = 0, max = 11, message = "鑱旂郴鐢佃瘽闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String phone;
+
+ /**
+ * 閭
+ */
+ @Email(message = "閭鏍煎紡涓嶆纭�")
+ @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String email;
+
+ /**
+ * 閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java
new file mode 100644
index 0000000..042946c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictDataBo.java
@@ -0,0 +1,80 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDictData;
+
+/**
+ * 瀛楀吀鏁版嵁涓氬姟瀵硅薄 sys_dict_data
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDictData.class, reverseConvertGenerate = false)
+public class SysDictDataBo extends BaseEntity {
+
+ /**
+ * 瀛楀吀缂栫爜
+ */
+ private Long dictCode;
+
+ /**
+ * 瀛楀吀鎺掑簭
+ */
+ private Integer dictSort;
+
+ /**
+ * 瀛楀吀鏍囩
+ */
+ @NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String dictLabel;
+
+ /**
+ * 瀛楀吀閿��
+ */
+ @NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
+ @Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+ private String dictValue;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String dictType;
+
+ /**
+ * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+ */
+ @Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩噞max}涓瓧绗�")
+ private String cssClass;
+
+ /**
+ * 琛ㄦ牸鍥炴樉鏍峰紡
+ */
+ private String listClass;
+
+ /**
+ * 鏄惁榛樿锛圷鏄� N鍚︼級
+ */
+ private String isDefault;
+
+ /**
+ * 鍒涘缓閮ㄩ棬
+ */
+ private Long createDept;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java
new file mode 100644
index 0000000..cfc82de
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysDictTypeBo.java
@@ -0,0 +1,50 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Pattern;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysDictType;
+
+/**
+ * 瀛楀吀绫诲瀷涓氬姟瀵硅薄 sys_dict_type
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysDictType.class, reverseConvertGenerate = false)
+public class SysDictTypeBo extends BaseEntity {
+
+ /**
+ * 瀛楀吀涓婚敭
+ */
+ private Long dictId;
+
+ /**
+ * 瀛楀吀鍚嶇О
+ */
+ @NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String dictName;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+ @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�")
+ private String dictType;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java
new file mode 100644
index 0000000..1cbe129
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysLogininforBo.java
@@ -0,0 +1,87 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysLogininfor;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 绯荤粺璁块棶璁板綍涓氬姟瀵硅薄 sys_logininfor
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@AutoMapper(target = SysLogininfor.class, reverseConvertGenerate = false)
+public class SysLogininforBo {
+
+ /**
+ * 璁块棶ID
+ */
+ private Long infoId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 瀹㈡埛绔�
+ */
+ private String clientKey;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ private String deviceType;
+
+ /**
+ * 鐧诲綍IP鍦板潃
+ */
+ private String ipaddr;
+
+ /**
+ * 鐧诲綍鍦扮偣
+ */
+ private String loginLocation;
+
+ /**
+ * 娴忚鍣ㄧ被鍨�
+ */
+ private String browser;
+
+ /**
+ * 鎿嶄綔绯荤粺
+ */
+ private String os;
+
+ /**
+ * 鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�
+ */
+ private String status;
+
+ /**
+ * 鎻愮ず娑堟伅
+ */
+ private String msg;
+
+ /**
+ * 璁块棶鏃堕棿
+ */
+ private Date loginTime;
+
+ /**
+ * 璇锋眰鍙傛暟
+ */
+ private Map<String, Object> params = new HashMap<>();
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
new file mode 100644
index 0000000..498280a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysMenuBo.java
@@ -0,0 +1,108 @@
+package org.dromara.system.domain.bo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysMenu;
+
+/**
+ * 鑿滃崟鏉冮檺涓氬姟瀵硅薄 sys_menu
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysMenu.class, reverseConvertGenerate = false)
+public class SysMenuBo extends BaseEntity {
+
+ /**
+ * 鑿滃崟ID
+ */
+ private Long menuId;
+
+ /**
+ * 鐖惰彍鍗旾D
+ */
+ private Long parentId;
+
+ /**
+ * 鑿滃崟鍚嶇О
+ */
+ @NotBlank(message = "鑿滃崟鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 50, message = "鑿滃崟鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String menuName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+ private Integer orderNum;
+
+ /**
+ * 璺敱鍦板潃
+ */
+ @Size(min = 0, max = 200, message = "璺敱鍦板潃涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String path;
+
+ /**
+ * 缁勪欢璺緞
+ */
+ @Size(min = 0, max = 200, message = "缁勪欢璺緞涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String component;
+
+ /**
+ * 璺敱鍙傛暟
+ */
+ private String queryParam;
+
+ /**
+ * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+ */
+ private String isFrame;
+
+ /**
+ * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+ */
+ private String isCache;
+
+ /**
+ * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+ */
+ @NotBlank(message = "鑿滃崟绫诲瀷涓嶈兘涓虹┖")
+ private String menuType;
+
+ /**
+ * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+ */
+ private String visible;
+
+ /**
+ * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鏉冮檺鏍囪瘑
+ */
+ @JsonInclude(JsonInclude.Include.NON_NULL)
+ @Size(min = 0, max = 100, message = "鏉冮檺鏍囪瘑闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String perms;
+
+ /**
+ * 鑿滃崟鍥炬爣
+ */
+ private String icon;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java
new file mode 100644
index 0000000..cdcc575
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysNoticeBo.java
@@ -0,0 +1,61 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysNotice;
+
+/**
+ * 閫氱煡鍏憡涓氬姟瀵硅薄 sys_notice
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysNotice.class, reverseConvertGenerate = false)
+public class SysNoticeBo extends BaseEntity {
+
+ /**
+ * 鍏憡ID
+ */
+ private Long noticeId;
+
+ /**
+ * 鍏憡鏍囬
+ */
+ @Xss(message = "鍏憡鏍囬涓嶈兘鍖呭惈鑴氭湰瀛楃")
+ @NotBlank(message = "鍏憡鏍囬涓嶈兘涓虹┖")
+ @Size(min = 0, max = 50, message = "鍏憡鏍囬涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String noticeTitle;
+
+ /**
+ * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+ */
+ private String noticeType;
+
+ /**
+ * 鍏憡鍐呭
+ */
+ private String noticeContent;
+
+ /**
+ * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鍒涘缓浜哄悕绉�
+ */
+ private String createByName;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java
new file mode 100644
index 0000000..407947c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysOperLogBo.java
@@ -0,0 +1,127 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.AutoMappers;
+import lombok.Data;
+import org.dromara.common.log.event.OperLogEvent;
+import org.dromara.system.domain.SysOperLog;
+
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍涓氬姟瀵硅薄 sys_oper_log
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+
+@Data
+@AutoMappers({
+ @AutoMapper(target = SysOperLog.class, reverseConvertGenerate = false),
+ @AutoMapper(target = OperLogEvent.class)
+})
+public class SysOperLogBo {
+
+ /**
+ * 鏃ュ織涓婚敭
+ */
+ private Long operId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 妯″潡鏍囬
+ */
+ private String title;
+
+ /**
+ * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+ */
+ private Integer businessType;
+
+ /**
+ * 涓氬姟绫诲瀷鏁扮粍
+ */
+ private Integer[] businessTypes;
+
+ /**
+ * 鏂规硶鍚嶇О
+ */
+ private String method;
+
+ /**
+ * 璇锋眰鏂瑰紡
+ */
+ private String requestMethod;
+
+ /**
+ * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+ */
+ private Integer operatorType;
+
+ /**
+ * 鎿嶄綔浜哄憳
+ */
+ private String operName;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ private String deptName;
+
+ /**
+ * 璇锋眰URL
+ */
+ private String operUrl;
+
+ /**
+ * 涓绘満鍦板潃
+ */
+ private String operIp;
+
+ /**
+ * 鎿嶄綔鍦扮偣
+ */
+ private String operLocation;
+
+ /**
+ * 璇锋眰鍙傛暟
+ */
+ private String operParam;
+
+ /**
+ * 杩斿洖鍙傛暟
+ */
+ private String jsonResult;
+
+ /**
+ * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+ */
+ private Integer status;
+
+ /**
+ * 閿欒娑堟伅
+ */
+ private String errorMsg;
+
+ /**
+ * 鎿嶄綔鏃堕棿
+ */
+ private Date operTime;
+
+ /**
+ * 娑堣�楁椂闂�
+ */
+ private Long costTime;
+
+ /**
+ * 璇锋眰鍙傛暟
+ */
+ private Map<String, Object> params = new HashMap<>();
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
new file mode 100644
index 0000000..b93c39c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysPostBo.java
@@ -0,0 +1,59 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysPost;
+
+/**
+ * 宀椾綅淇℃伅涓氬姟瀵硅薄 sys_post
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysPost.class, reverseConvertGenerate = false)
+public class SysPostBo extends BaseEntity {
+
+ /**
+ * 宀椾綅ID
+ */
+ private Long postId;
+
+ /**
+ * 宀椾綅缂栫爜
+ */
+ @NotBlank(message = "宀椾綅缂栫爜涓嶈兘涓虹┖")
+ @Size(min = 0, max = 64, message = "宀椾綅缂栫爜闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String postCode;
+
+ /**
+ * 宀椾綅鍚嶇О
+ */
+ @NotBlank(message = "宀椾綅鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 50, message = "宀椾綅鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String postName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+ private Integer postSort;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
new file mode 100644
index 0000000..0c8b4dc
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysRoleBo.java
@@ -0,0 +1,94 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysRole;
+
+/**
+ * 瑙掕壊淇℃伅涓氬姟瀵硅薄 sys_role
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysRole.class, reverseConvertGenerate = false)
+public class SysRoleBo extends BaseEntity {
+
+ /**
+ * 瑙掕壊ID
+ */
+ private Long roleId;
+
+ /**
+ * 瑙掕壊鍚嶇О
+ */
+ @NotBlank(message = "瑙掕壊鍚嶇О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 30, message = "瑙掕壊鍚嶇О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String roleName;
+
+ /**
+ * 瑙掕壊鏉冮檺瀛楃涓�
+ */
+ @NotBlank(message = "瑙掕壊鏉冮檺瀛楃涓蹭笉鑳戒负绌�")
+ @Size(min = 0, max = 100, message = "鏉冮檺瀛楃闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String roleKey;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @NotNull(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+ private Integer roleSort;
+
+ /**
+ * 鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級
+ */
+ private String dataScope;
+
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ private Boolean menuCheckStrictly;
+
+ /**
+ * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ private Boolean deptCheckStrictly;
+
+ /**
+ * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鑿滃崟缁�
+ */
+ private Long[] menuIds;
+
+ /**
+ * 閮ㄩ棬缁勶紙鏁版嵁鏉冮檺锛�
+ */
+ private Long[] deptIds;
+
+ public SysRoleBo(Long roleId) {
+ this.roleId = roleId;
+ }
+
+ public boolean isSuperAdmin() {
+ return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java
new file mode 100644
index 0000000..7784271
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysSocialBo.java
@@ -0,0 +1,142 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.tenant.core.TenantEntity;
+import org.dromara.system.domain.SysSocial;
+
+/**
+ * 绀句細鍖栧叧绯讳笟鍔″璞� sys_social
+ *
+ * @author Lion Li
+ */
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysSocial.class, reverseConvertGenerate = false)
+public class SysSocialBo extends TenantEntity {
+
+ /**
+ * 涓婚敭
+ */
+ @NotNull(message = "涓婚敭涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 鐨勫敮涓�ID
+ */
+ @NotBlank(message = "鐨勫敮涓�ID涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String authId;
+
+ /**
+ * 鐢ㄦ埛鏉ユ簮
+ */
+ @NotBlank(message = "鐢ㄦ埛鏉ユ簮涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String source;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+ */
+ @NotBlank(message = "鐢ㄦ埛鐨勬巿鏉冧护鐗屼笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+ private String accessToken;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private int expireIn;
+
+ /**
+ * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String refreshToken;
+
+ /**
+ * 骞冲彴鍞竴id
+ */
+ private String openId;
+
+ /**
+ * 鐢ㄦ埛鐨� ID
+ */
+ @NotBlank(message = "鐢ㄦ埛鐨� ID涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private Long userId;
+
+ /**
+ * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String accessCode;
+
+ /**
+ * 鐢ㄦ埛鐨� unionid
+ */
+ private String unionId;
+
+ /**
+ * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String scope;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟鏄电О
+ */
+ private String nickName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟閭
+ */
+ private String email;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+ */
+ private String avatar;
+
+ /**
+ * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String tokenType;
+
+ /**
+ * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String idToken;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macAlgorithm;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macKey;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String code;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthToken;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthTokenSecret;
+
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java
new file mode 100644
index 0000000..d98b3a8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantBo.java
@@ -0,0 +1,114 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysTenant;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import java.util.Date;
+
+/**
+ * 绉熸埛涓氬姟瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysTenant.class, reverseConvertGenerate = false)
+public class SysTenantBo extends BaseEntity {
+
+ /**
+ * id
+ */
+ @NotNull(message = "id涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private Long id;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鑱旂郴浜�
+ */
+ @NotBlank(message = "鑱旂郴浜轰笉鑳戒负绌�", groups = { AddGroup.class, EditGroup.class })
+ private String contactUserName;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ @NotBlank(message = "鑱旂郴鐢佃瘽涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String contactPhone;
+
+ /**
+ * 浼佷笟鍚嶇О
+ */
+ @NotBlank(message = "浼佷笟鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String companyName;
+
+ /**
+ * 鐢ㄦ埛鍚嶏紙鍒涘缓绯荤粺鐢ㄦ埛锛�
+ */
+ @NotBlank(message = "鐢ㄦ埛鍚嶄笉鑳戒负绌�", groups = { AddGroup.class })
+ private String username;
+
+ /**
+ * 瀵嗙爜锛堝垱寤虹郴缁熺敤鎴凤級
+ */
+ @NotBlank(message = "瀵嗙爜涓嶈兘涓虹┖", groups = { AddGroup.class })
+ private String password;
+
+ /**
+ * 缁熶竴绀句細淇$敤浠g爜
+ */
+ private String licenseNumber;
+
+ /**
+ * 鍦板潃
+ */
+ private String address;
+
+ /**
+ * 鍩熷悕
+ */
+ private String domain;
+
+ /**
+ * 浼佷笟绠�浠�
+ */
+ private String intro;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 绉熸埛濂楅缂栧彿
+ */
+ @NotNull(message = "绉熸埛濂楅涓嶈兘涓虹┖", groups = { AddGroup.class })
+ private Long packageId;
+
+ /**
+ * 杩囨湡鏃堕棿
+ */
+ private Date expireTime;
+
+ /**
+ * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+ */
+ private Long accountCount;
+
+ /**
+ * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java
new file mode 100644
index 0000000..9086f5c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysTenantPackageBo.java
@@ -0,0 +1,60 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.AutoMapping;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import org.dromara.common.core.validate.AddGroup;
+import org.dromara.common.core.validate.EditGroup;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysTenantPackage;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+
+/**
+ * 绉熸埛濂楅涓氬姟瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysTenantPackage.class, reverseConvertGenerate = false)
+public class SysTenantPackageBo extends BaseEntity {
+
+ /**
+ * 绉熸埛濂楅id
+ */
+ @NotNull(message = "绉熸埛濂楅id涓嶈兘涓虹┖", groups = { EditGroup.class })
+ private Long packageId;
+
+ /**
+ * 濂楅鍚嶇О
+ */
+ @NotBlank(message = "濂楅鍚嶇О涓嶈兘涓虹┖", groups = { AddGroup.class, EditGroup.class })
+ private String packageName;
+
+ /**
+ * 鍏宠仈鑿滃崟id
+ */
+ @AutoMapping(target = "menuIds", expression = "java(org.dromara.common.core.utils.StringUtils.join(source.getMenuIds(), \",\"))")
+ private Long[] menuIds;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ private Boolean menuCheckStrictly;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
new file mode 100644
index 0000000..011254e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserBo.java
@@ -0,0 +1,114 @@
+package org.dromara.system.domain.bo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Size;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.system.domain.SysUser;
+
+/**
+ * 鐢ㄦ埛淇℃伅涓氬姟瀵硅薄 sys_user
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+@AutoMapper(target = SysUser.class, reverseConvertGenerate = false)
+public class SysUserBo extends BaseEntity {
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ private Long userId;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ private Long deptId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ @Xss(message = "鐢ㄦ埛璐﹀彿涓嶈兘鍖呭惈鑴氭湰瀛楃")
+ @NotBlank(message = "鐢ㄦ埛璐﹀彿涓嶈兘涓虹┖")
+ @Size(min = 0, max = 30, message = "鐢ㄦ埛璐﹀彿闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String userName;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ @Xss(message = "鐢ㄦ埛鏄电О涓嶈兘鍖呭惈鑴氭湰瀛楃")
+ @NotBlank(message = "鐢ㄦ埛鏄电О涓嶈兘涓虹┖")
+ @Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+ */
+ private String userType;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ @Email(message = "閭鏍煎紡涓嶆纭�")
+ @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+ */
+ private String sex;
+
+ /**
+ * 瀵嗙爜
+ */
+ private String password;
+
+ /**
+ * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 瑙掕壊缁�
+ */
+ @Size(min = 1, message = "鐢ㄦ埛瑙掕壊涓嶈兘涓虹┖")
+ private Long[] roleIds;
+
+ /**
+ * 宀椾綅缁�
+ */
+ private Long[] postIds;
+
+ /**
+ * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
+ */
+ private Long roleId;
+
+ public SysUserBo(Long userId) {
+ this.userId = userId;
+ }
+
+ public boolean isSuperAdmin() {
+ return UserConstants.SUPER_ADMIN_ID.equals(this.userId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java
new file mode 100644
index 0000000..8615fcd
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserPasswordBo.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain.bo;
+
+import jakarta.validation.constraints.NotBlank;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛瀵嗙爜淇敼bo
+ */
+@Data
+public class SysUserPasswordBo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鏃у瘑鐮�
+ */
+ @NotBlank(message = "鏃у瘑鐮佷笉鑳戒负绌�")
+ private String oldPassword;
+
+ /**
+ * 鏂板瘑鐮�
+ */
+ @NotBlank(message = "鏂板瘑鐮佷笉鑳戒负绌�")
+ private String newPassword;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
new file mode 100644
index 0000000..f85b2be
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/bo/SysUserProfileBo.java
@@ -0,0 +1,56 @@
+package org.dromara.system.domain.bo;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.NoArgsConstructor;
+import org.dromara.common.mybatis.core.domain.BaseEntity;
+import org.dromara.common.core.xss.Xss;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.Size;
+
+/**
+ * 涓汉淇℃伅涓氬姟澶勭悊
+ *
+ * @author Michelle.Chung
+ */
+
+@Data
+@NoArgsConstructor
+@EqualsAndHashCode(callSuper = true)
+public class SysUserProfileBo extends BaseEntity {
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ private Long userId;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ @Xss(message = "鐢ㄦ埛鏄电О涓嶈兘鍖呭惈鑴氭湰瀛楃")
+ @Size(min = 0, max = 30, message = "鐢ㄦ埛鏄电О闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ @Sensitive(strategy = SensitiveStrategy.EMAIL)
+ @Email(message = "閭鏍煎紡涓嶆纭�")
+ @Size(min = 0, max = 50, message = "閭闀垮害涓嶈兘瓒呰繃{max}涓瓧绗�")
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ @Sensitive(strategy = SensitiveStrategy.PHONE)
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+ */
+ private String sex;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysClientVoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysClientVoConvert.java
new file mode 100644
index 0000000..59e0009
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysClientVoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.vo.RemoteClientVo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 瀹㈡埛绔暟鎹浆鎹㈠櫒
+ *
+ * @author Michelle.Chung
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysClientVoConvert extends BaseMapper<SysClientVo, RemoteClientVo> {
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDictDataVoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDictDataVoConvert.java
new file mode 100644
index 0000000..852aaec
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysDictDataVoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.vo.RemoteDictDataVo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 瀛楀吀鏁版嵁杞崲鍣�
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysDictDataVoConvert extends BaseMapper<SysDictDataVo, RemoteDictDataVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysLogininforBoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysLogininforBoConvert.java
new file mode 100644
index 0000000..a36b0ba
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysLogininforBoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.bo.RemoteLogininforBo;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 鐧诲綍鏃ュ織杞崲鍣�
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysLogininforBoConvert extends BaseMapper<RemoteLogininforBo, SysLogininforBo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysOperLogBoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysOperLogBoConvert.java
new file mode 100644
index 0000000..5f17281
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysOperLogBoConvert.java
@@ -0,0 +1,25 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.bo.RemoteOperLogBo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 鎿嶄綔鏃ュ織杞崲鍣�
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysOperLogBoConvert extends BaseMapper<RemoteOperLogBo, SysOperLogBo> {
+
+ /**
+ * RemoteOperLogBoToSysOperLogBo
+ * @param remoteOperLogBo 寰呰浆鎹㈠璞�
+ * @return 杞崲鍚庡璞�
+ */
+ @Mapping(target = "businessTypes", ignore = true)
+ SysOperLogBo convert(RemoteOperLogBo remoteOperLogBo);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialBoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialBoConvert.java
new file mode 100644
index 0000000..97b4c12
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialBoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.bo.RemoteSocialBo;
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 绀句氦鏁版嵁杞崲鍣�
+ *
+ * @author Michelle.Chung
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysSocialBoConvert extends BaseMapper<RemoteSocialBo, SysSocialBo> {
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialVoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialVoConvert.java
new file mode 100644
index 0000000..2d19ee7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysSocialVoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.vo.RemoteSocialVo;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 绀句氦鏁版嵁杞崲鍣�
+ *
+ * @author Michelle.Chung
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysSocialVoConvert extends BaseMapper<SysSocialVo, RemoteSocialVo> {
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysTenantVoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysTenantVoConvert.java
new file mode 100644
index 0000000..e1c5cf2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysTenantVoConvert.java
@@ -0,0 +1,17 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.vo.RemoteTenantVo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+
+/**
+ * 绉熸埛杞崲鍣�
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysTenantVoConvert extends BaseMapper<SysTenantVo, RemoteTenantVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysUserBoConvert.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysUserBoConvert.java
new file mode 100644
index 0000000..b0115f3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/convert/SysUserBoConvert.java
@@ -0,0 +1,29 @@
+package org.dromara.system.domain.convert;
+
+import io.github.linpeilie.BaseMapper;
+import org.dromara.system.api.domain.bo.RemoteOperLogBo;
+import org.dromara.system.api.domain.bo.RemoteUserBo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.mapstruct.Mapper;
+import org.mapstruct.Mapping;
+import org.mapstruct.MappingConstants;
+import org.mapstruct.ReportingPolicy;
+import org.mapstruct.factory.Mappers;
+
+/**
+ * 鐢ㄦ埛淇℃伅杞崲鍣�
+ * @author zhujie
+ */
+@Mapper(componentModel = MappingConstants.ComponentModel.SPRING, unmappedTargetPolicy = ReportingPolicy.IGNORE)
+public interface SysUserBoConvert extends BaseMapper<RemoteUserBo, SysUserBo> {
+
+ /**
+ * RemoteUserBoToSysUserBo
+ * @param remoteUserBo 寰呰浆鎹㈠璞�
+ * @return 杞崲鍚庡璞�
+ */
+ @Mapping(target = "roleIds", ignore = true)
+ @Mapping(target = "postIds", ignore = true)
+ SysUserBo convert(RemoteUserBo remoteUserBo);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java
new file mode 100644
index 0000000..79046ff
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/AvatarVo.java
@@ -0,0 +1,24 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛澶村儚淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class AvatarVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 澶村儚鍦板潃
+ */
+ private String imgUrl;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java
new file mode 100644
index 0000000..19a6b02
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/CacheListInfoVo.java
@@ -0,0 +1,28 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+
+/**
+ * 缂撳瓨鐩戞帶鍒楄〃淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class CacheListInfoVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ private Properties info;
+
+ private Long dbSize;
+
+ private List<Map<String, String>> commandStats;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java
new file mode 100644
index 0000000..e8d3b34
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/DeptTreeSelectVo.java
@@ -0,0 +1,31 @@
+package org.dromara.system.domain.vo;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 瑙掕壊閮ㄩ棬鍒楄〃鏍戜俊鎭�
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class DeptTreeSelectVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 閫変腑閮ㄩ棬鍒楄〃
+ */
+ private List<Long> checkedKeys;
+
+ /**
+ * 涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ private List<Tree<Long>> depts;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java
new file mode 100644
index 0000000..ad112fa
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MenuTreeSelectVo.java
@@ -0,0 +1,31 @@
+package org.dromara.system.domain.vo;
+
+import cn.hutool.core.lang.tree.Tree;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 瑙掕壊鑿滃崟鍒楄〃鏍戜俊鎭�
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class MenuTreeSelectVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 閫変腑鑿滃崟鍒楄〃
+ */
+ private List<Long> checkedKeys;
+
+ /**
+ * 鑿滃崟涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ private List<Tree<Long>> menus;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java
new file mode 100644
index 0000000..a7e2549
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/MetaVo.java
@@ -0,0 +1,67 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+import org.dromara.common.core.utils.StringUtils;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 璺敱鏄剧ず淇℃伅
+ *
+ * @author ruoyi
+ */
+
+@Data
+public class MetaVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+ */
+ private String title;
+
+ /**
+ * 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/assets/icons/svg
+ */
+ private String icon;
+
+ /**
+ * 璁剧疆涓簍rue锛屽垯涓嶄細琚� <keep-alive>缂撳瓨
+ */
+ private boolean noCache;
+
+ /**
+ * 鍐呴摼鍦板潃锛坔ttp(s)://寮�澶达級
+ */
+ private String link;
+
+ public MetaVo(String title, String icon) {
+ this.title = title;
+ this.icon = icon;
+ }
+
+ public MetaVo(String title, String icon, boolean noCache) {
+ this.title = title;
+ this.icon = icon;
+ this.noCache = noCache;
+ }
+
+ public MetaVo(String title, String icon, String link) {
+ this.title = title;
+ this.icon = icon;
+ this.link = link;
+ }
+
+ public MetaVo(String title, String icon, boolean noCache, String link) {
+ this.title = title;
+ this.icon = icon;
+ this.noCache = noCache;
+ if (StringUtils.ishttp(link)) {
+ this.link = link;
+ }
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java
new file mode 100644
index 0000000..f40cfb8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/ProfileVo.java
@@ -0,0 +1,35 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+/**
+ * 鐢ㄦ埛涓汉淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class ProfileVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛淇℃伅
+ */
+ private SysUserVo user;
+
+ /**
+ * 鐢ㄦ埛鎵�灞炶鑹茬粍
+ */
+ private String roleGroup;
+
+ /**
+ * 鐢ㄦ埛鎵�灞炲矖浣嶇粍
+ */
+ private String postGroup;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java
new file mode 100644
index 0000000..824e104
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/RouterVo.java
@@ -0,0 +1,67 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 璺敱閰嶇疆淇℃伅
+ *
+ * @author Lion Li
+ */
+@Data
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RouterVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 璺敱鍚嶅瓧
+ */
+ private String name;
+
+ /**
+ * 璺敱鍦板潃
+ */
+ private String path;
+
+ /**
+ * 鏄惁闅愯棌璺敱锛屽綋璁剧疆 true 鐨勬椂鍊欒璺敱涓嶄細鍐嶄晶杈规爮鍑虹幇
+ */
+ private boolean hidden;
+
+ /**
+ * 閲嶅畾鍚戝湴鍧�锛屽綋璁剧疆 noRedirect 鐨勬椂鍊欒璺敱鍦ㄩ潰鍖呭睉瀵艰埅涓笉鍙鐐瑰嚮
+ */
+ private String redirect;
+
+ /**
+ * 缁勪欢鍦板潃
+ */
+ private String component;
+
+ /**
+ * 璺敱鍙傛暟锛氬 {"id": 1, "name": "ry"}
+ */
+ private String query;
+
+ /**
+ * 褰撲綘涓�涓矾鐢变笅闈㈢殑 children 澹版槑鐨勮矾鐢卞ぇ浜�1涓椂锛岃嚜鍔ㄤ細鍙樻垚宓屽鐨勬ā寮�--濡傜粍浠堕〉闈�
+ */
+ private Boolean alwaysShow;
+
+ /**
+ * 鍏朵粬鍏冪礌
+ */
+ private MetaVo meta;
+
+ /**
+ * 瀛愯矾鐢�
+ */
+ private List<RouterVo> children;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java
new file mode 100644
index 0000000..04d2842
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysClientVo.java
@@ -0,0 +1,89 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysClient;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+
+/**
+ * 鎺堟潈绠$悊瑙嗗浘瀵硅薄 sys_client
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysClient.class)
+public class SysClientVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @ExcelProperty(value = "id")
+ private Long id;
+
+ /**
+ * 瀹㈡埛绔痠d
+ */
+ @ExcelProperty(value = "瀹㈡埛绔痠d")
+ private String clientId;
+
+ /**
+ * 瀹㈡埛绔痥ey
+ */
+ @ExcelProperty(value = "瀹㈡埛绔痥ey")
+ private String clientKey;
+
+ /**
+ * 瀹㈡埛绔閽�
+ */
+ @ExcelProperty(value = "瀹㈡埛绔閽�")
+ private String clientSecret;
+
+ /**
+ * 鎺堟潈绫诲瀷
+ */
+ @ExcelProperty(value = "鎺堟潈绫诲瀷")
+ private List<String> grantTypeList;
+
+ /**
+ * 鎺堟潈绫诲瀷
+ */
+ private String grantType;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ private String deviceType;
+
+ /**
+ * token娲昏穬瓒呮椂鏃堕棿
+ */
+ @ExcelProperty(value = "token娲昏穬瓒呮椂鏃堕棿")
+ private Long activeTimeout;
+
+ /**
+ * token鍥哄畾瓒呮椂鏃堕棿
+ */
+ @ExcelProperty(value = "token鍥哄畾瓒呮椂鏃堕棿")
+ private Long timeout;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java
new file mode 100644
index 0000000..946f3df
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysConfigVo.java
@@ -0,0 +1,72 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysConfig;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 鍙傛暟閰嶇疆瑙嗗浘瀵硅薄 sys_config
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysConfig.class)
+public class SysConfigVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鍙傛暟涓婚敭
+ */
+ @ExcelProperty(value = "鍙傛暟涓婚敭")
+ private Long configId;
+
+ /**
+ * 鍙傛暟鍚嶇О
+ */
+ @ExcelProperty(value = "鍙傛暟鍚嶇О")
+ private String configName;
+
+ /**
+ * 鍙傛暟閿悕
+ */
+ @ExcelProperty(value = "鍙傛暟閿悕")
+ private String configKey;
+
+ /**
+ * 鍙傛暟閿��
+ */
+ @ExcelProperty(value = "鍙傛暟閿��")
+ private String configValue;
+
+ /**
+ * 绯荤粺鍐呯疆锛圷鏄� N鍚︼級
+ */
+ @ExcelProperty(value = "绯荤粺鍐呯疆", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_yes_no")
+ private String configType;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java
new file mode 100644
index 0000000..a1ba194
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDeptVo.java
@@ -0,0 +1,96 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysDept;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 閮ㄩ棬瑙嗗浘瀵硅薄 sys_dept
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDept.class)
+public class SysDeptVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 閮ㄩ棬id
+ */
+ @ExcelProperty(value = "閮ㄩ棬id")
+ private Long deptId;
+
+ /**
+ * 鐖堕儴闂╥d
+ */
+ private Long parentId;
+
+ /**
+ * 鐖堕儴闂ㄥ悕绉�
+ */
+ private String parentName;
+
+ /**
+ * 绁栫骇鍒楄〃
+ */
+ private String ancestors;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+ private String deptName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ private Integer orderNum;
+
+ /**
+ * 璐熻矗浜篒D
+ */
+ private Long leader;
+
+ /**
+ * 璐熻矗浜�
+ */
+ @ExcelProperty(value = "璐熻矗浜�")
+ private String leaderName;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ @ExcelProperty(value = "鑱旂郴鐢佃瘽")
+ private String phone;
+
+ /**
+ * 閭
+ */
+ @ExcelProperty(value = "閭")
+ private String email;
+
+ /**
+ * 閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "閮ㄩ棬鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_normal_disable")
+ private String status;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java
new file mode 100644
index 0000000..cd84881
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictDataVo.java
@@ -0,0 +1,88 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysDictData;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 瀛楀吀鏁版嵁瑙嗗浘瀵硅薄 sys_dict_data
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDictData.class)
+public class SysDictDataVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 瀛楀吀缂栫爜
+ */
+ @ExcelProperty(value = "瀛楀吀缂栫爜")
+ private Long dictCode;
+
+ /**
+ * 瀛楀吀鎺掑簭
+ */
+ @ExcelProperty(value = "瀛楀吀鎺掑簭")
+ private Integer dictSort;
+
+ /**
+ * 瀛楀吀鏍囩
+ */
+ @ExcelProperty(value = "瀛楀吀鏍囩")
+ private String dictLabel;
+
+ /**
+ * 瀛楀吀閿��
+ */
+ @ExcelProperty(value = "瀛楀吀閿��")
+ private String dictValue;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ @ExcelProperty(value = "瀛楀吀绫诲瀷")
+ private String dictType;
+
+ /**
+ * 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�
+ */
+ private String cssClass;
+
+ /**
+ * 琛ㄦ牸鍥炴樉鏍峰紡
+ */
+ private String listClass;
+
+ /**
+ * 鏄惁榛樿锛圷鏄� N鍚︼級
+ */
+ @ExcelProperty(value = "鏄惁榛樿", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_yes_no")
+ private String isDefault;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java
new file mode 100644
index 0000000..1b1f95a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysDictTypeVo.java
@@ -0,0 +1,57 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysDictType;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 瀛楀吀绫诲瀷瑙嗗浘瀵硅薄 sys_dict_type
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysDictType.class)
+public class SysDictTypeVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 瀛楀吀涓婚敭
+ */
+ @ExcelProperty(value = "瀛楀吀涓婚敭")
+ private Long dictId;
+
+ /**
+ * 瀛楀吀鍚嶇О
+ */
+ @ExcelProperty(value = "瀛楀吀鍚嶇О")
+ private String dictName;
+
+ /**
+ * 瀛楀吀绫诲瀷
+ */
+ @ExcelProperty(value = "瀛楀吀绫诲瀷")
+ private String dictType;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java
new file mode 100644
index 0000000..7ec7047
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysLogininforVo.java
@@ -0,0 +1,106 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysLogininfor;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 绯荤粺璁块棶璁板綍瑙嗗浘瀵硅薄 sys_logininfor
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysLogininfor.class)
+public class SysLogininforVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 璁块棶ID
+ */
+ @ExcelProperty(value = "搴忓彿")
+ private Long infoId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ @ExcelProperty(value = "鐢ㄦ埛璐﹀彿")
+ private String userName;
+
+ /**
+ * 瀹㈡埛绔�
+ */
+ @ExcelProperty(value = "瀹㈡埛绔�")
+ private String clientKey;
+
+ /**
+ * 璁惧绫诲瀷
+ */
+ @ExcelProperty(value = "璁惧绫诲瀷", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_device_type")
+ private String deviceType;
+
+ /**
+ * 鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�
+ */
+ @ExcelProperty(value = "鐧诲綍鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_common_status")
+ private String status;
+
+ /**
+ * 鐧诲綍IP鍦板潃
+ */
+ @ExcelProperty(value = "鐧诲綍鍦板潃")
+ private String ipaddr;
+
+ /**
+ * 鐧诲綍鍦扮偣
+ */
+ @ExcelProperty(value = "鐧诲綍鍦扮偣")
+ private String loginLocation;
+
+ /**
+ * 娴忚鍣ㄧ被鍨�
+ */
+ @ExcelProperty(value = "娴忚鍣�")
+ private String browser;
+
+ /**
+ * 鎿嶄綔绯荤粺
+ */
+ @ExcelProperty(value = "鎿嶄綔绯荤粺")
+ private String os;
+
+
+ /**
+ * 鎻愮ず娑堟伅
+ */
+ @ExcelProperty(value = "鎻愮ず娑堟伅")
+ private String msg;
+
+ /**
+ * 璁块棶鏃堕棿
+ */
+ @ExcelProperty(value = "璁块棶鏃堕棿")
+ private Date loginTime;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java
new file mode 100644
index 0000000..a51564a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysMenuVo.java
@@ -0,0 +1,116 @@
+package org.dromara.system.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysMenu;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 鑿滃崟鏉冮檺瑙嗗浘瀵硅薄 sys_menu
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysMenu.class)
+public class SysMenuVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鑿滃崟ID
+ */
+ private Long menuId;
+
+ /**
+ * 鑿滃崟鍚嶇О
+ */
+ private String menuName;
+
+ /**
+ * 鐖惰彍鍗旾D
+ */
+ private Long parentId;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ private Integer orderNum;
+
+ /**
+ * 璺敱鍦板潃
+ */
+ private String path;
+
+ /**
+ * 缁勪欢璺緞
+ */
+ private String component;
+
+ /**
+ * 璺敱鍙傛暟
+ */
+ private String queryParam;
+
+ /**
+ * 鏄惁涓哄閾撅紙0鏄� 1鍚︼級
+ */
+ private String isFrame;
+
+ /**
+ * 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級
+ */
+ private String isCache;
+
+ /**
+ * 鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�
+ */
+ private String menuType;
+
+ /**
+ * 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛�
+ */
+ private String visible;
+
+ /**
+ * 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鏉冮檺鏍囪瘑
+ */
+ private String perms;
+
+ /**
+ * 鑿滃崟鍥炬爣
+ */
+ private String icon;
+
+ /**
+ * 鍒涘缓閮ㄩ棬
+ */
+ private Long createDept;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ private Date createTime;
+
+ /**
+ * 瀛愯彍鍗�
+ */
+ private List<SysMenuVo> children = new ArrayList<>();
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java
new file mode 100644
index 0000000..271ae62
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysNoticeVo.java
@@ -0,0 +1,73 @@
+package org.dromara.system.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysNotice;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 閫氱煡鍏憡瑙嗗浘瀵硅薄 sys_notice
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysNotice.class)
+public class SysNoticeVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鍏憡ID
+ */
+ private Long noticeId;
+
+ /**
+ * 鍏憡鏍囬
+ */
+ private String noticeTitle;
+
+ /**
+ * 鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�
+ */
+ private String noticeType;
+
+ /**
+ * 鍏憡鍐呭
+ */
+ private String noticeContent;
+
+ /**
+ * 鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�
+ */
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鍒涘缓鑰�
+ */
+ private Long createBy;
+
+ /**
+ * 鍒涘缓浜哄悕绉�
+ */
+ @Translation(type = TransConstant.USER_ID_TO_NAME, mapper = "createBy")
+ private String createByName;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java
new file mode 100644
index 0000000..145e11c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysOperLogVo.java
@@ -0,0 +1,144 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysOperLog;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍瑙嗗浘瀵硅薄 sys_oper_log
+ *
+ * @author Michelle.Chung
+ * @date 2023-02-07
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysOperLog.class)
+public class SysOperLogVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鏃ュ織涓婚敭
+ */
+ @ExcelProperty(value = "鏃ュ織涓婚敭")
+ private Long operId;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ private String tenantId;
+
+ /**
+ * 妯″潡鏍囬
+ */
+ @ExcelProperty(value = "鎿嶄綔妯″潡")
+ private String title;
+
+ /**
+ * 涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�
+ */
+ @ExcelProperty(value = "涓氬姟绫诲瀷", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_oper_type")
+ private Integer businessType;
+
+ /**
+ * 涓氬姟绫诲瀷鏁扮粍
+ */
+ private Integer[] businessTypes;
+
+ /**
+ * 鏂规硶鍚嶇О
+ */
+ @ExcelProperty(value = "璇锋眰鏂规硶")
+ private String method;
+
+ /**
+ * 璇锋眰鏂瑰紡
+ */
+ @ExcelProperty(value = "璇锋眰鏂瑰紡")
+ private String requestMethod;
+
+ /**
+ * 鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級
+ */
+ @ExcelProperty(value = "鎿嶄綔绫诲埆", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=鍏跺畠,1=鍚庡彴鐢ㄦ埛,2=鎵嬫満绔敤鎴�")
+ private Integer operatorType;
+
+ /**
+ * 鎿嶄綔浜哄憳
+ */
+ @ExcelProperty(value = "鎿嶄綔浜哄憳")
+ private String operName;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+ private String deptName;
+
+ /**
+ * 璇锋眰URL
+ */
+ @ExcelProperty(value = "璇锋眰鍦板潃")
+ private String operUrl;
+
+ /**
+ * 涓绘満鍦板潃
+ */
+ @ExcelProperty(value = "鎿嶄綔鍦板潃")
+ private String operIp;
+
+ /**
+ * 鎿嶄綔鍦扮偣
+ */
+ @ExcelProperty(value = "鎿嶄綔鍦扮偣")
+ private String operLocation;
+
+ /**
+ * 璇锋眰鍙傛暟
+ */
+ @ExcelProperty(value = "璇锋眰鍙傛暟")
+ private String operParam;
+
+ /**
+ * 杩斿洖鍙傛暟
+ */
+ @ExcelProperty(value = "杩斿洖鍙傛暟")
+ private String jsonResult;
+
+ /**
+ * 鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�
+ */
+ @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_common_status")
+ private Integer status;
+
+ /**
+ * 閿欒娑堟伅
+ */
+ @ExcelProperty(value = "閿欒娑堟伅")
+ private String errorMsg;
+
+ /**
+ * 鎿嶄綔鏃堕棿
+ */
+ @ExcelProperty(value = "鎿嶄綔鏃堕棿")
+ private Date operTime;
+
+ /**
+ * 娑堣�楁椂闂�
+ */
+ @ExcelProperty(value = "娑堣�楁椂闂�")
+ private Long costTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java
new file mode 100644
index 0000000..e3ad4cc
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysPostVo.java
@@ -0,0 +1,73 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysPost;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+
+/**
+ * 宀椾綅淇℃伅瑙嗗浘瀵硅薄 sys_post
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysPost.class)
+public class SysPostVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 宀椾綅ID
+ */
+ @ExcelProperty(value = "宀椾綅搴忓彿")
+ private Long postId;
+
+ /**
+ * 宀椾綅缂栫爜
+ */
+ @ExcelProperty(value = "宀椾綅缂栫爜")
+ private String postCode;
+
+ /**
+ * 宀椾綅鍚嶇О
+ */
+ @ExcelProperty(value = "宀椾綅鍚嶇О")
+ private String postName;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @ExcelProperty(value = "宀椾綅鎺掑簭")
+ private Integer postSort;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_normal_disable")
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
new file mode 100644
index 0000000..ce8442c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysRoleVo.java
@@ -0,0 +1,100 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysRole;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 瑙掕壊淇℃伅瑙嗗浘瀵硅薄 sys_role
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysRole.class)
+public class SysRoleVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 瑙掕壊ID
+ */
+ @ExcelProperty(value = "瑙掕壊搴忓彿")
+ private Long roleId;
+
+ /**
+ * 瑙掕壊鍚嶇О
+ */
+ @ExcelProperty(value = "瑙掕壊鍚嶇О")
+ private String roleName;
+
+ /**
+ * 瑙掕壊鏉冮檺瀛楃涓�
+ */
+ @ExcelProperty(value = "瑙掕壊鏉冮檺")
+ private String roleKey;
+
+ /**
+ * 鏄剧ず椤哄簭
+ */
+ @ExcelProperty(value = "瑙掕壊鎺掑簭")
+ private Integer roleSort;
+
+ /**
+ * 鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級
+ */
+ @ExcelProperty(value = "鏁版嵁鑼冨洿", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "1=鎵�鏈夋暟鎹潈闄�,2=鑷畾涔夋暟鎹潈闄�,3=鏈儴闂ㄦ暟鎹潈闄�,4=鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺,5=浠呮湰浜烘暟鎹潈闄�")
+ private String dataScope;
+
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ @ExcelProperty(value = "鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+ private Boolean menuCheckStrictly;
+
+ /**
+ * 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ @ExcelProperty(value = "閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+ private Boolean deptCheckStrictly;
+
+ /**
+ * 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "瑙掕壊鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_normal_disable")
+ private String status;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ @ExcelProperty(value = "鍒涘缓鏃堕棿")
+ private Date createTime;
+
+ /**
+ * 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦�
+ */
+ private boolean flag = false;
+
+ public boolean isSuperAdmin() {
+ return UserConstants.SUPER_ADMIN_ID.equals(this.roleId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java
new file mode 100644
index 0000000..1c029fe
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysSocialVo.java
@@ -0,0 +1,144 @@
+package org.dromara.system.domain.vo;
+
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.system.domain.SysSocial;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 绀句細鍖栧叧绯昏鍥惧璞� sys_social
+ *
+ * @author thiszhc
+ */
+@Data
+@AutoMapper(target = SysSocial.class)
+public class SysSocialVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 涓婚敭
+ */
+ private Long id;
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ private Long userId;
+
+ /**
+ * 绉熸埛ID
+ */
+ private String tenantId;
+
+ /**
+ * 鐨勫敮涓�ID
+ */
+ private String authId;
+
+ /**
+ * 鐢ㄦ埛鏉ユ簮
+ */
+ private String source;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗�
+ */
+ private String accessToken;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉冧护鐗岀殑鏈夋晥鏈燂紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private int expireIn;
+
+ /**
+ * 鍒锋柊浠ょ墝锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String refreshToken;
+
+ /**
+ * 鐢ㄦ埛鐨� open id
+ */
+ private String openId;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟鏄电О
+ */
+ private String nickName;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟閭
+ */
+ private String email;
+
+ /**
+ * 鎺堟潈鐨勭涓夋柟澶村儚鍦板潃
+ */
+ private String avatar;
+
+
+ /**
+ * 骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String accessCode;
+
+ /**
+ * 鐢ㄦ埛鐨� unionid
+ */
+ private String unionId;
+
+ /**
+ * 鎺堜簣鐨勬潈闄愶紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String scope;
+
+ /**
+ * 涓埆骞冲彴鐨勬巿鏉冧俊鎭紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String tokenType;
+
+ /**
+ * id token锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String idToken;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macAlgorithm;
+
+ /**
+ * 灏忕背骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String macKey;
+
+ /**
+ * 鐢ㄦ埛鐨勬巿鏉僣ode锛岄儴鍒嗗钩鍙板彲鑳芥病鏈�
+ */
+ private String code;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthToken;
+
+ /**
+ * Twitter骞冲彴鐢ㄦ埛鐨勯檮甯﹀睘鎬э紝閮ㄥ垎骞冲彴鍙兘娌℃湁
+ */
+ private String oauthTokenSecret;
+
+ /**
+ * 鏄剧ず缁戝畾鏃堕棿
+ */
+ private Date createTime;
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java
new file mode 100644
index 0000000..a413d63
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantPackageVo.java
@@ -0,0 +1,66 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysTenantPackage;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 绉熸埛濂楅瑙嗗浘瀵硅薄 sys_tenant_package
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysTenantPackage.class)
+public class SysTenantPackageVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 绉熸埛濂楅id
+ */
+ @ExcelProperty(value = "绉熸埛濂楅id")
+ private Long packageId;
+
+ /**
+ * 濂楅鍚嶇О
+ */
+ @ExcelProperty(value = "濂楅鍚嶇О")
+ private String packageName;
+
+ /**
+ * 鍏宠仈鑿滃崟id
+ */
+ @ExcelProperty(value = "鍏宠仈鑿滃崟id")
+ private String menuIds;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ */
+ @ExcelProperty(value = "鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�")
+ private Boolean menuCheckStrictly;
+
+ /**
+ * 鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java
new file mode 100644
index 0000000..90502da
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysTenantVo.java
@@ -0,0 +1,115 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+import org.dromara.system.domain.SysTenant;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+
+/**
+ * 绉熸埛瑙嗗浘瀵硅薄 sys_tenant
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@ExcelIgnoreUnannotated
+@AutoMapper(target = SysTenant.class)
+public class SysTenantVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * id
+ */
+ @ExcelProperty(value = "id")
+ private Long id;
+
+ /**
+ * 绉熸埛缂栧彿
+ */
+ @ExcelProperty(value = "绉熸埛缂栧彿")
+ private String tenantId;
+
+ /**
+ * 鑱旂郴浜�
+ */
+ @ExcelProperty(value = "鑱旂郴浜�")
+ private String contactUserName;
+
+ /**
+ * 鑱旂郴鐢佃瘽
+ */
+ @ExcelProperty(value = "鑱旂郴鐢佃瘽")
+ private String contactPhone;
+
+ /**
+ * 浼佷笟鍚嶇О
+ */
+ @ExcelProperty(value = "浼佷笟鍚嶇О")
+ private String companyName;
+
+ /**
+ * 缁熶竴绀句細淇$敤浠g爜
+ */
+ @ExcelProperty(value = "缁熶竴绀句細淇$敤浠g爜")
+ private String licenseNumber;
+
+ /**
+ * 鍦板潃
+ */
+ @ExcelProperty(value = "鍦板潃")
+ private String address;
+
+ /**
+ * 鍩熷悕
+ */
+ @ExcelProperty(value = "鍩熷悕")
+ private String domain;
+
+ /**
+ * 浼佷笟绠�浠�
+ */
+ @ExcelProperty(value = "浼佷笟绠�浠�")
+ private String intro;
+
+ /**
+ * 澶囨敞
+ */
+ @ExcelProperty(value = "澶囨敞")
+ private String remark;
+
+ /**
+ * 绉熸埛濂楅缂栧彿
+ */
+ @ExcelProperty(value = "绉熸埛濂楅缂栧彿")
+ private Long packageId;
+
+ /**
+ * 杩囨湡鏃堕棿
+ */
+ @ExcelProperty(value = "杩囨湡鏃堕棿")
+ private Date expireTime;
+
+ /**
+ * 鐢ㄦ埛鏁伴噺锛�-1涓嶉檺鍒讹級
+ */
+ @ExcelProperty(value = "鐢ㄦ埛鏁伴噺")
+ private Long accountCount;
+
+ /**
+ * 绉熸埛鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "绉熸埛鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(readConverterExp = "0=姝e父,1=鍋滅敤")
+ private String status;
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java
new file mode 100644
index 0000000..a1448f2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserExportVo.java
@@ -0,0 +1,99 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import io.github.linpeilie.annotations.ReverseAutoMapping;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎嚭VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+@AutoMapper(target = SysUserVo.class, convertGenerate = false)
+public class SysUserExportVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ @ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+ private Long userId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ @ExcelProperty(value = "鐧诲綍鍚嶇О")
+ private String userName;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ @ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ @ExcelProperty(value = "鐢ㄦ埛閭")
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ @ExcelProperty(value = "鎵嬫満鍙风爜")
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆
+ */
+ @ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_user_sex")
+ private String sex;
+
+ /**
+ * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_normal_disable")
+ private String status;
+
+ /**
+ * 鏈�鍚庣櫥褰旾P
+ */
+ @ExcelProperty(value = "鏈�鍚庣櫥褰旾P")
+ private String loginIp;
+
+ /**
+ * 鏈�鍚庣櫥褰曟椂闂�
+ */
+ @ExcelProperty(value = "鏈�鍚庣櫥褰曟椂闂�")
+ private Date loginDate;
+
+ /**
+ * 閮ㄩ棬鍚嶇О
+ */
+ @ReverseAutoMapping(target = "deptName", source = "dept.deptName")
+ @ExcelProperty(value = "閮ㄩ棬鍚嶇О")
+ private String deptName;
+
+ /**
+ * 璐熻矗浜�
+ */
+ @ReverseAutoMapping(target = "leaderName", source = "dept.leaderName")
+ @ExcelProperty(value = "閮ㄩ棬璐熻矗浜�")
+ private String leaderName;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
new file mode 100644
index 0000000..d3ac159
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserImportVo.java
@@ -0,0 +1,77 @@
+package org.dromara.system.domain.vo;
+
+import com.alibaba.excel.annotation.ExcelProperty;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.dromara.common.excel.annotation.ExcelDictFormat;
+import org.dromara.common.excel.convert.ExcelDictConvert;
+
+import java.io.Serial;
+import java.io.Serializable;
+
+
+/**
+ * 鐢ㄦ埛瀵硅薄瀵煎叆VO
+ *
+ * @author Lion Li
+ */
+
+@Data
+@NoArgsConstructor
+// @Accessors(chain = true) // 瀵煎叆涓嶅厑璁镐娇鐢� 浼氭壘涓嶅埌set鏂规硶
+public class SysUserImportVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ @ExcelProperty(value = "鐢ㄦ埛搴忓彿")
+ private Long userId;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ @ExcelProperty(value = "閮ㄩ棬缂栧彿")
+ private Long deptId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ @ExcelProperty(value = "鐧诲綍鍚嶇О")
+ private String userName;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ @ExcelProperty(value = "鐢ㄦ埛鍚嶇О")
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ @ExcelProperty(value = "鐢ㄦ埛閭")
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ @ExcelProperty(value = "鎵嬫満鍙风爜")
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆
+ */
+ @ExcelProperty(value = "鐢ㄦ埛鎬у埆", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_user_sex")
+ private String sex;
+
+ /**
+ * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ @ExcelProperty(value = "甯愬彿鐘舵��", converter = ExcelDictConvert.class)
+ @ExcelDictFormat(dictType = "sys_normal_disable")
+ private String status;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java
new file mode 100644
index 0000000..2525c89
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserInfoVo.java
@@ -0,0 +1,45 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class SysUserInfoVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛淇℃伅
+ */
+ private SysUserVo user;
+
+ /**
+ * 瑙掕壊ID鍒楄〃
+ */
+ private List<Long> roleIds;
+
+ /**
+ * 瑙掕壊鍒楄〃
+ */
+ private List<SysRoleVo> roles;
+
+ /**
+ * 宀椾綅ID鍒楄〃
+ */
+ private List<Long> postIds;
+
+ /**
+ * 宀椾綅鍒楄〃
+ */
+ private List<SysPostVo> posts;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
new file mode 100644
index 0000000..59fb0e5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/SysUserVo.java
@@ -0,0 +1,141 @@
+package org.dromara.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import io.github.linpeilie.annotations.AutoMapper;
+import lombok.Data;
+import org.dromara.common.sensitive.annotation.Sensitive;
+import org.dromara.common.sensitive.core.SensitiveStrategy;
+import org.dromara.common.translation.annotation.Translation;
+import org.dromara.common.translation.constant.TransConstant;
+import org.dromara.system.domain.SysUser;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+
+/**
+ * 鐢ㄦ埛淇℃伅瑙嗗浘瀵硅薄 sys_user
+ *
+ * @author Michelle.Chung
+ */
+@Data
+@AutoMapper(target = SysUser.class)
+public class SysUserVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛ID
+ */
+ private Long userId;
+
+ /**
+ * 绉熸埛ID
+ */
+ private String tenantId;
+
+ /**
+ * 閮ㄩ棬ID
+ */
+ private Long deptId;
+
+ /**
+ * 鐢ㄦ埛璐﹀彿
+ */
+ private String userName;
+
+ /**
+ * 鐢ㄦ埛鏄电О
+ */
+ private String nickName;
+
+ /**
+ * 鐢ㄦ埛绫诲瀷锛坰ys_user绯荤粺鐢ㄦ埛锛�
+ */
+ private String userType;
+
+ /**
+ * 鐢ㄦ埛閭
+ */
+ @Sensitive(strategy = SensitiveStrategy.EMAIL)
+ private String email;
+
+ /**
+ * 鎵嬫満鍙风爜
+ */
+ @Sensitive(strategy = SensitiveStrategy.PHONE)
+ private String phonenumber;
+
+ /**
+ * 鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�
+ */
+ private String sex;
+
+ /**
+ * 澶村儚鍦板潃
+ */
+ @Translation(type = TransConstant.OSS_ID_TO_URL)
+ private Long avatar;
+
+ /**
+ * 瀵嗙爜
+ */
+ @JsonIgnore
+ @JsonProperty
+ private String password;
+
+ /**
+ * 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�
+ */
+ private String status;
+
+ /**
+ * 鏈�鍚庣櫥褰旾P
+ */
+ private String loginIp;
+
+ /**
+ * 鏈�鍚庣櫥褰曟椂闂�
+ */
+ private Date loginDate;
+
+ /**
+ * 澶囨敞
+ */
+ private String remark;
+
+ /**
+ * 鍒涘缓鏃堕棿
+ */
+ private Date createTime;
+
+ /**
+ * 閮ㄩ棬瀵硅薄
+ */
+ private SysDeptVo dept;
+
+ /**
+ * 瑙掕壊瀵硅薄
+ */
+ private List<SysRoleVo> roles;
+
+ /**
+ * 瑙掕壊缁�
+ */
+ private Long[] roleIds;
+
+ /**
+ * 宀椾綅缁�
+ */
+ private Long[] postIds;
+
+ /**
+ * 鏁版嵁鏉冮檺 褰撳墠瑙掕壊ID
+ */
+ private Long roleId;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java
new file mode 100644
index 0000000..0606d26
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/domain/vo/UserInfoVo.java
@@ -0,0 +1,35 @@
+package org.dromara.system.domain.vo;
+
+import lombok.Data;
+
+import java.io.Serial;
+import java.io.Serializable;
+import java.util.Set;
+
+/**
+ * 鐧诲綍鐢ㄦ埛淇℃伅
+ *
+ * @author Michelle.Chung
+ */
+@Data
+public class UserInfoVo implements Serializable {
+
+ @Serial
+ private static final long serialVersionUID = 1L;
+
+ /**
+ * 鐢ㄦ埛鍩烘湰淇℃伅
+ */
+ private SysUserVo user;
+
+ /**
+ * 鑿滃崟鏉冮檺
+ */
+ private Set<String> permissions;
+
+ /**
+ * 瑙掕壊鏉冮檺
+ */
+ private Set<String> roles;
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteClientServiceImpl.java
new file mode 100644
index 0000000..b03dce2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteClientServiceImpl.java
@@ -0,0 +1,33 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.api.RemoteClientService;
+import org.dromara.system.api.domain.vo.RemoteClientVo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.service.ISysClientService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 瀹㈡埛绔湇鍔�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteClientServiceImpl implements RemoteClientService {
+
+ private final ISysClientService sysClientService;
+
+ /**
+ * 鏍规嵁瀹㈡埛绔痠d鑾峰彇瀹㈡埛绔鎯�
+ */
+ @Override
+ public RemoteClientVo queryByClientId(String clientId) {
+ SysClientVo vo = sysClientService.queryByClientId(clientId);
+ return MapstructUtils.convert(vo, RemoteClientVo.class);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteConfigServiceImpl.java
new file mode 100644
index 0000000..6a43c0b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteConfigServiceImpl.java
@@ -0,0 +1,29 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.system.api.RemoteConfigService;
+import org.dromara.system.service.ISysConfigService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 閰嶇疆鏈嶅姟
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteConfigServiceImpl implements RemoteConfigService {
+
+ private final ISysConfigService configService;
+
+ /**
+ * 鑾峰彇娉ㄥ唽寮�鍏�
+ */
+ @Override
+ public boolean selectRegisterEnabled(String tenantId) {
+ return configService.selectRegisterEnabled(tenantId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java
new file mode 100644
index 0000000..ea59a99
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDataScopeServiceImpl.java
@@ -0,0 +1,60 @@
+package org.dromara.system.dubbo;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.system.api.RemoteDataScopeService;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysRoleDept;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysRoleDeptMapper;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 鏁版嵁鏉冮檺 瀹炵幇
+ * <p>
+ * 娉ㄦ剰: 姝ervice鍐呬笉鍏佽璋冪敤鏍囨敞`鏁版嵁鏉冮檺`娉ㄨВ鐨勬柟娉�
+ * 渚嬪: deptMapper.selectList 姝� selectList 鏂规硶鏍囨敞浜哷鏁版嵁鏉冮檺`娉ㄨВ 浼氬嚭鐜板惊鐜В鏋愮殑闂
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteDataScopeServiceImpl implements RemoteDataScopeService {
+
+ private final SysRoleDeptMapper roleDeptMapper;
+ private final SysDeptMapper deptMapper;
+
+ @Override
+ public String getRoleCustom(Long roleId) {
+ List<SysRoleDept> list = roleDeptMapper.selectList(
+ new LambdaQueryWrapper<SysRoleDept>()
+ .select(SysRoleDept::getDeptId)
+ .eq(SysRoleDept::getRoleId, roleId));
+ if (CollUtil.isNotEmpty(list)) {
+ return StreamUtils.join(list, rd -> Convert.toStr(rd.getDeptId()));
+ }
+ return null;
+ }
+
+ @Override
+ public String getDeptAndChild(Long deptId) {
+ List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
+ .select(SysDept::getDeptId)
+ .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+ List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
+ ids.add(deptId);
+ if (CollUtil.isNotEmpty(ids)) {
+ return StreamUtils.join(ids, Convert::toStr);
+ }
+ return null;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java
new file mode 100644
index 0000000..bc9a466
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDeptServiceImpl.java
@@ -0,0 +1,25 @@
+package org.dromara.system.dubbo;
+
+import org.dromara.system.api.RemoteDeptService;
+import org.dromara.system.service.ISysDeptService;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 閮ㄩ棬鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteDeptServiceImpl implements RemoteDeptService {
+
+ private final ISysDeptService sysDeptService;
+
+ @Override
+ public String selectDeptNameByIds(String deptIds) {
+ return sysDeptService.selectDeptNameByIds(deptIds);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDictServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDictServiceImpl.java
new file mode 100644
index 0000000..10f9dff
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteDictServiceImpl.java
@@ -0,0 +1,33 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.api.RemoteDictService;
+import org.dromara.system.api.domain.vo.RemoteDictDataVo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteDictServiceImpl implements RemoteDictService {
+
+ private final ISysDictTypeService sysDictTypeService;
+
+
+ @Override
+ public List<RemoteDictDataVo> selectDictDataByType(String dictType) {
+ List<SysDictDataVo> list = sysDictTypeService.selectDictDataByType(dictType);
+ return MapstructUtils.convert(list, RemoteDictDataVo.class);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteLogServiceImpl.java
new file mode 100644
index 0000000..fd2a69e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteLogServiceImpl.java
@@ -0,0 +1,39 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.api.RemoteLogService;
+import org.dromara.system.api.domain.bo.RemoteLogininforBo;
+import org.dromara.system.api.domain.bo.RemoteOperLogBo;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.service.ISysLogininforService;
+import org.dromara.system.service.ISysOperLogService;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteLogServiceImpl implements RemoteLogService {
+
+ private final ISysOperLogService operLogService;
+ private final ISysLogininforService logininforService;
+
+ @Override
+ public void saveLog(RemoteOperLogBo remoteOperLogBo) {
+ SysOperLogBo sysOperLogBo = MapstructUtils.convert(remoteOperLogBo, SysOperLogBo.class);
+ operLogService.insertOperlog(sysOperLogBo);
+ }
+
+ @Override
+ public void saveLogininfor(RemoteLogininforBo remoteLogininforBo) {
+ SysLogininforBo sysLogininforBo = MapstructUtils.convert(remoteLogininforBo, SysLogininforBo.class);
+ logininforService.insertLogininfor(sysLogininforBo);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteSocialServiceImpl.java
new file mode 100644
index 0000000..3ddef24
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteSocialServiceImpl.java
@@ -0,0 +1,63 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.api.RemoteSocialService;
+import org.dromara.system.api.domain.bo.RemoteSocialBo;
+import org.dromara.system.api.domain.vo.RemoteSocialVo;
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.mapper.SysSocialMapper;
+import org.dromara.system.service.ISysSocialService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯绘湇鍔�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteSocialServiceImpl implements RemoteSocialService {
+
+ private final ISysSocialService sysSocialService;
+ private final SysSocialMapper sysSocialMapper;
+
+ /**
+ * 鏍规嵁 authId 鏌ヨ鐢ㄦ埛淇℃伅
+ */
+ @Override
+ public List<RemoteSocialVo> selectByAuthId(String authId) {
+ List<SysSocialVo> list = sysSocialService.selectByAuthId(authId);
+ return MapstructUtils.convert(list, RemoteSocialVo.class);
+ }
+
+ /**
+ * 淇濆瓨绀句細鍖栧叧绯�
+ */
+ @Override
+ public void insertByBo(RemoteSocialBo bo) {
+ sysSocialService.insertByBo(MapstructUtils.convert(bo, SysSocialBo.class));
+ }
+
+ /**
+ * 鏇存柊绀句細鍖栧叧绯�
+ */
+ @Override
+ public void updateByBo(RemoteSocialBo bo) {
+ sysSocialService.updateByBo(MapstructUtils.convert(bo, SysSocialBo.class));
+ }
+
+ /**
+ * 鍒犻櫎绀句細鍖栧叧绯�
+ */
+ @Override
+ public Boolean deleteWithValidById(Long socialId) {
+ return sysSocialService.deleteWithValidById(socialId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteTenantServiceImpl.java
new file mode 100644
index 0000000..7dc5839
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteTenantServiceImpl.java
@@ -0,0 +1,43 @@
+package org.dromara.system.dubbo;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.api.RemoteTenantService;
+import org.dromara.system.api.domain.vo.RemoteTenantVo;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.service.ISysTenantService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * @author zhujie
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteTenantServiceImpl implements RemoteTenantService {
+
+ private final ISysTenantService tenantService;
+
+ /**
+ * 鏍规嵁绉熸埛id鑾峰彇绉熸埛璇︽儏
+ */
+ @Override
+ public RemoteTenantVo queryByTenantId(String tenantId) {
+ SysTenantVo vo = tenantService.queryByTenantId(tenantId);
+ return MapstructUtils.convert(vo, RemoteTenantVo.class);
+ }
+
+ /**
+ * 鑾峰彇绉熸埛鍒楄〃
+ */
+ @Override
+ public List<RemoteTenantVo> queryList() {
+ List<SysTenantVo> list = tenantService.queryList(new SysTenantBo());
+ return MapstructUtils.convert(list, RemoteTenantVo.class);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
new file mode 100644
index 0000000..b3287f3
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/dubbo/RemoteUserServiceImpl.java
@@ -0,0 +1,203 @@
+package org.dromara.system.dubbo;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.apache.dubbo.config.annotation.DubboService;
+import org.dromara.common.core.enums.UserStatus;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.exception.user.UserException;
+import org.dromara.common.core.utils.DateUtils;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.mybatis.helper.DataPermissionHelper;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.api.RemoteUserService;
+import org.dromara.system.api.domain.bo.RemoteUserBo;
+import org.dromara.system.api.model.LoginUser;
+import org.dromara.system.api.model.RoleDTO;
+import org.dromara.system.api.model.XcxLoginUser;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysPermissionService;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛鏈嶅姟
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+@DubboService
+public class RemoteUserServiceImpl implements RemoteUserService {
+
+ private final ISysUserService userService;
+ private final ISysPermissionService permissionService;
+ private final ISysConfigService configService;
+ private final SysUserMapper userMapper;
+
+ @Override
+ public LoginUser getUserInfo(String username, String tenantId) throws UserException {
+ return TenantHelper.dynamic(tenantId, () -> {
+ SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getUserName, SysUser::getStatus)
+ .eq(SysUser::getUserName, username));
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new UserException("user.not.exists", username);
+ }
+ if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
+ throw new UserException("user.blocked", username);
+ }
+ // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+ // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+ return buildLoginUser(userMapper.selectUserByUserName(username));
+ });
+ }
+
+ @Override
+ public LoginUser getUserInfo(Long userId, String tenantId) throws UserException {
+ return TenantHelper.dynamic(tenantId, () -> {
+ SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getUserName, SysUser::getStatus)
+ .eq(SysUser::getUserId, userId));
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new UserException("user.not.exists", "");
+ }
+ if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
+ throw new UserException("user.blocked", sysUser.getUserName());
+ }
+ // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+ // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+ return buildLoginUser(userMapper.selectUserByUserName(sysUser.getUserName()));
+ });
+ }
+
+ @Override
+ public LoginUser getUserInfoByPhonenumber(String phonenumber, String tenantId) throws UserException {
+ return TenantHelper.dynamic(tenantId, () -> {
+ SysUser sysUser = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getPhonenumber, SysUser::getStatus)
+ .eq(SysUser::getPhonenumber, phonenumber));
+ if (ObjectUtil.isNull(sysUser)) {
+ throw new UserException("user.not.exists", phonenumber);
+ }
+ if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
+ throw new UserException("user.blocked", phonenumber);
+ }
+ // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+ // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+ return buildLoginUser(userMapper.selectUserByPhonenumber(phonenumber));
+ });
+ }
+
+ @Override
+ public LoginUser getUserInfoByEmail(String email, String tenantId) throws UserException {
+ return TenantHelper.dynamic(tenantId, () -> {
+ SysUser user = userMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getEmail, SysUser::getStatus)
+ .eq(SysUser::getEmail, email));
+ if (ObjectUtil.isNull(user)) {
+ throw new UserException("user.not.exists", email);
+ }
+ if (UserStatus.DISABLE.getCode().equals(user.getStatus())) {
+ throw new UserException("user.blocked", email);
+ }
+ // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+ // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+ return buildLoginUser(userMapper.selectUserByEmail(email));
+ });
+ }
+
+ @Override
+ public XcxLoginUser getUserInfoByOpenid(String openid) throws UserException {
+ // todo 鑷瀹炵幇 userService.selectUserByOpenid(openid);
+ SysUser sysUser = new SysUser();
+ if (ObjectUtil.isNull(sysUser)) {
+ // todo 鐢ㄦ埛涓嶅瓨鍦� 涓氬姟閫昏緫鑷瀹炵幇
+ }
+ if (UserStatus.DISABLE.getCode().equals(sysUser.getStatus())) {
+ // todo 鐢ㄦ埛宸茶鍋滅敤 涓氬姟閫昏緫鑷瀹炵幇
+ }
+ // 妗嗘灦鐧诲綍涓嶉檺鍒朵粠浠�涔堣〃鏌ヨ 鍙鏈�缁堟瀯寤哄嚭 LoginUser 鍗冲彲
+ // 姝ゅ鍙牴鎹櫥褰曠敤鎴风殑鏁版嵁涓嶅悓 鑷鍒涘缓 loginUser 灞炴�т笉澶熺敤缁ф壙鎵╁睍灏辫浜�
+ XcxLoginUser loginUser = new XcxLoginUser();
+ loginUser.setUserId(sysUser.getUserId());
+ loginUser.setUsername(sysUser.getUserName());
+ loginUser.setNickname(sysUser.getNickName());
+ loginUser.setUserType(sysUser.getUserType());
+ loginUser.setOpenid(openid);
+ return loginUser;
+ }
+
+ @Override
+ public Boolean registerUserInfo(RemoteUserBo remoteUserBo) throws UserException, ServiceException {
+ SysUserBo sysUserBo = MapstructUtils.convert(remoteUserBo, SysUserBo.class);
+ String username = sysUserBo.getUserName();
+ boolean exist = TenantHelper.dynamic(remoteUserBo.getTenantId(), () -> {
+ if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
+ throw new ServiceException("褰撳墠绯荤粺娌℃湁寮�鍚敞鍐屽姛鑳�");
+ }
+ return userMapper.exists(new LambdaQueryWrapper<SysUser>()
+ .eq(SysUser::getUserName, sysUserBo.getUserName())
+ .ne(ObjectUtil.isNotNull(sysUserBo.getUserId()), SysUser::getUserId, sysUserBo.getUserId()));
+ });
+ if (exist) {
+ throw new UserException("user.register.save.error", username);
+ }
+ return userService.registerUser(sysUserBo, remoteUserBo.getTenantId());
+ }
+
+ @Override
+ public String selectUserNameById(Long userId) {
+ return userService.selectUserNameById(userId);
+ }
+
+ @Override
+ public String selectNicknameById(Long userId) {
+ return userService.selectNicknameById(userId);
+ }
+
+ /**
+ * 鏋勫缓鐧诲綍鐢ㄦ埛
+ */
+ private LoginUser buildLoginUser(SysUserVo userVo) {
+ LoginUser loginUser = new LoginUser();
+ loginUser.setTenantId(userVo.getTenantId());
+ loginUser.setUserId(userVo.getUserId());
+ loginUser.setDeptId(userVo.getDeptId());
+ loginUser.setUsername(userVo.getUserName());
+ loginUser.setNickname(userVo.getNickName());
+ loginUser.setPassword(userVo.getPassword());
+ loginUser.setUserType(userVo.getUserType());
+ loginUser.setMenuPermission(permissionService.getMenuPermission(userVo.getUserId()));
+ loginUser.setRolePermission(permissionService.getRolePermission(userVo.getUserId()));
+ loginUser.setDeptName(ObjectUtil.isNull(userVo.getDept()) ? "" : userVo.getDept().getDeptName());
+ List<RoleDTO> roles = BeanUtil.copyToList(userVo.getRoles(), RoleDTO.class);
+ loginUser.setRoles(roles);
+ return loginUser;
+ }
+
+ /**
+ * 鏇存柊鐢ㄦ埛淇℃伅
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param ip IP鍦板潃
+ */
+ @Override
+ public void recordLoginInfo(Long userId, String ip) {
+ SysUser sysUser = new SysUser();
+ sysUser.setUserId(userId);
+ sysUser.setLoginIp(ip);
+ sysUser.setLoginDate(DateUtils.getNowDate());
+ sysUser.setUpdateBy(userId);
+ DataPermissionHelper.ignore(() -> userMapper.updateById(sysUser));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
new file mode 100644
index 0000000..9cd144d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/listener/SysUserImportListener.java
@@ -0,0 +1,119 @@
+package org.dromara.system.listener;
+
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.crypto.digest.BCrypt;
+import com.alibaba.excel.context.AnalysisContext;
+import com.alibaba.excel.event.AnalysisEventListener;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.ValidatorUtils;
+import org.dromara.common.excel.core.ExcelListener;
+import org.dromara.common.excel.core.ExcelResult;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysUserImportVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.service.ISysConfigService;
+import org.dromara.system.service.ISysUserService;
+import lombok.extern.slf4j.Slf4j;
+
+import java.util.List;
+
+/**
+ * 绯荤粺鐢ㄦ埛鑷畾涔夊鍏�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+public class SysUserImportListener extends AnalysisEventListener<SysUserImportVo> implements ExcelListener<SysUserImportVo> {
+
+ private final ISysUserService userService;
+
+ private final String password;
+
+ private final Boolean isUpdateSupport;
+
+ private final Long operUserId;
+
+ private int successNum = 0;
+ private int failureNum = 0;
+ private final StringBuilder successMsg = new StringBuilder();
+ private final StringBuilder failureMsg = new StringBuilder();
+
+ public SysUserImportListener(Boolean isUpdateSupport) {
+ String initPassword = SpringUtils.getBean(ISysConfigService.class).selectConfigByKey("sys.user.initPassword");
+ this.userService = SpringUtils.getBean(ISysUserService.class);
+ this.password = BCrypt.hashpw(initPassword);
+ this.isUpdateSupport = isUpdateSupport;
+ this.operUserId = LoginHelper.getUserId();
+ }
+
+ @Override
+ public void invoke(SysUserImportVo userVo, AnalysisContext context) {
+ SysUserVo sysUser = this.userService.selectUserByUserName(userVo.getUserName());
+ try {
+ // 楠岃瘉鏄惁瀛樺湪杩欎釜鐢ㄦ埛
+ if (ObjectUtil.isNull(sysUser)) {
+ SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class);
+ ValidatorUtils.validate(user);
+ user.setPassword(password);
+ user.setCreateBy(operUserId);
+ userService.insertUser(user);
+ successNum++;
+ successMsg.append("<br/>").append(successNum).append("銆佽处鍙� ").append(user.getUserName()).append(" 瀵煎叆鎴愬姛");
+ } else if (isUpdateSupport) {
+ Long userId = sysUser.getUserId();
+ SysUserBo user = BeanUtil.toBean(userVo, SysUserBo.class);
+ user.setUserId(userId);
+ ValidatorUtils.validate(user);
+ userService.checkUserAllowed(user.getUserId());
+ userService.checkUserDataScope(user.getUserId());
+ user.setUpdateBy(operUserId);
+ userService.updateUser(user);
+ successNum++;
+ successMsg.append("<br/>").append(successNum).append("銆佽处鍙� ").append(user.getUserName()).append(" 鏇存柊鎴愬姛");
+ } else {
+ failureNum++;
+ failureMsg.append("<br/>").append(failureNum).append("銆佽处鍙� ").append(sysUser.getUserName()).append(" 宸插瓨鍦�");
+ }
+ } catch (Exception e) {
+ failureNum++;
+ String msg = "<br/>" + failureNum + "銆佽处鍙� " + userVo.getUserName() + " 瀵煎叆澶辫触锛�";
+ failureMsg.append(msg).append(e.getMessage());
+ log.error(msg, e);
+ }
+ }
+
+ @Override
+ public void doAfterAllAnalysed(AnalysisContext context) {
+
+ }
+
+ @Override
+ public ExcelResult<SysUserImportVo> getExcelResult() {
+ return new ExcelResult<SysUserImportVo>() {
+
+ @Override
+ public String getAnalysis() {
+ if (failureNum > 0) {
+ failureMsg.insert(0, "寰堟姳姝夛紝瀵煎叆澶辫触锛佸叡 " + failureNum + " 鏉℃暟鎹牸寮忎笉姝g‘锛岄敊璇涓嬶細");
+ throw new ServiceException(failureMsg.toString());
+ } else {
+ successMsg.insert(0, "鎭枩鎮紝鏁版嵁宸插叏閮ㄥ鍏ユ垚鍔燂紒鍏� " + successNum + " 鏉★紝鏁版嵁濡備笅锛�");
+ }
+ return successMsg.toString();
+ }
+
+ @Override
+ public List<SysUserImportVo> getList() {
+ return null;
+ }
+
+ @Override
+ public List<String> getErrorList() {
+ return null;
+ }
+ };
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java
new file mode 100644
index 0000000..a8943de
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysClientMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.vo.SysClientVo;
+
+/**
+ * 鎺堟潈绠$悊Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface SysClientMapper extends BaseMapperPlus<SysClient, SysClientVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..0eaaee8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysConfigMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysConfig;
+import org.dromara.system.domain.vo.SysConfigVo;
+
+/**
+ * 鍙傛暟閰嶇疆 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysConfigMapper extends BaseMapperPlus<SysConfig, SysConfigVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..45ad77e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDeptMapper.java
@@ -0,0 +1,46 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDeptMapper extends BaseMapperPlus<SysDept, SysDeptVo> {
+
+ /**
+ * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 閮ㄩ棬淇℃伅闆嗗悎
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "dept_id")
+ })
+ List<SysDeptVo> selectDeptList(@Param(Constants.WRAPPER) Wrapper<SysDept> queryWrapper);
+
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "dept_id")
+ })
+ SysDeptVo selectDeptById(Long deptId);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @param deptCheckStrictly 閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ * @return 閫変腑閮ㄩ棬鍒楄〃
+ */
+ List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..c2f1a7c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictDataMapper.java
@@ -0,0 +1,23 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.system.domain.vo.SysDictDataVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDictDataMapper extends BaseMapperPlus<SysDictData, SysDictDataVo> {
+
+ default List<SysDictDataVo> selectDictDataByType(String dictType) {
+ return selectVoList(
+ new LambdaQueryWrapper<SysDictData>()
+ .eq(SysDictData::getDictType, dictType)
+ .orderByAsc(SysDictData::getDictSort));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..9a9bdd5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysDictTypeMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.SysDictType;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysDictTypeMapper extends BaseMapperPlus<SysDictType, SysDictTypeVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java
new file mode 100644
index 0000000..85edd1d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysLogininforMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysLogininfor;
+import org.dromara.system.domain.vo.SysLogininforVo;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysLogininforMapper extends BaseMapperPlus<SysLogininfor, SysLogininforVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..b2be0e9
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysMenuMapper.java
@@ -0,0 +1,83 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 鑿滃崟琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysMenuMapper extends BaseMapperPlus<SysMenu, SysMenuVo> {
+
+ /**
+ * 鏍规嵁鐢ㄦ埛鎵�鏈夋潈闄�
+ *
+ * @return 鏉冮檺鍒楄〃
+ */
+ List<String> selectMenuPerms();
+
+ /**
+ * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 鑿滃崟鍒楄〃
+ */
+ List<SysMenu> selectMenuListByUserId(@Param(Constants.WRAPPER) Wrapper<SysMenu> queryWrapper);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ List<String> selectMenuPermsByUserId(Long userId);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ List<String> selectMenuPermsByRoleId(Long roleId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+ *
+ * @return 鑿滃崟鍒楄〃
+ */
+ default List<SysMenu> selectMenuTreeAll() {
+ LambdaQueryWrapper<SysMenu> lqw = new LambdaQueryWrapper<SysMenu>()
+ .in(SysMenu::getMenuType, UserConstants.TYPE_DIR, UserConstants.TYPE_MENU)
+ .eq(SysMenu::getStatus, UserConstants.MENU_NORMAL)
+ .orderByAsc(SysMenu::getParentId)
+ .orderByAsc(SysMenu::getOrderNum);
+ return this.selectList(lqw);
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鑿滃崟鍒楄〃
+ */
+ List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @param menuCheckStrictly 鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�
+ * @return 閫変腑鑿滃崟鍒楄〃
+ */
+ List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java
new file mode 100644
index 0000000..1e27b77
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysNoticeMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysNotice;
+import org.dromara.system.domain.vo.SysNoticeVo;
+
+/**
+ * 閫氱煡鍏憡琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysNoticeMapper extends BaseMapperPlus<SysNotice, SysNoticeVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java
new file mode 100644
index 0000000..5d20404
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysOperLogMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysOperLog;
+import org.dromara.system.domain.vo.SysOperLogVo;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysOperLogMapper extends BaseMapperPlus<SysOperLog, SysOperLogVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
new file mode 100644
index 0000000..48e6a12
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysPostMapper.java
@@ -0,0 +1,32 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.vo.SysPostVo;
+
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysPostMapper extends BaseMapperPlus<SysPost, SysPostVo> {
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑宀椾綅ID鍒楄〃
+ */
+ List<Long> selectPostListByUserId(Long userId);
+
+ /**
+ * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 缁撴灉
+ */
+ List<SysPostVo> selectPostsByUserName(String userName);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java
new file mode 100644
index 0000000..3de0bb6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleDeptMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRoleDept;
+
+/**
+ * 瑙掕壊涓庨儴闂ㄥ叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleDeptMapper extends BaseMapperPlus<SysRoleDept, SysRoleDept> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..55ca769
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMapper.java
@@ -0,0 +1,71 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 瑙掕壊琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleMapper extends BaseMapperPlus<SysRole, SysRoleVo> {
+
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "r.create_by")
+ })
+ Page<SysRoleVo> selectPageRoleList(@Param("page") Page<SysRole> page, @Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "r.create_by")
+ })
+ List<SysRoleVo> selectRoleList(@Param(Constants.WRAPPER) Wrapper<SysRole> queryWrapper);
+
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "r.create_by")
+ })
+ SysRoleVo selectRoleById(Long roleId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 瑙掕壊鍒楄〃
+ */
+ List<SysRoleVo> selectRolePermissionByUserId(Long userId);
+
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑瑙掕壊ID鍒楄〃
+ */
+ List<Long> selectRoleListByUserId(Long userId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 瑙掕壊鍒楄〃
+ */
+ List<SysRoleVo> selectRolesByUserName(String userName);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..0a657b4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysRoleMenuMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysRoleMenu;
+
+/**
+ * 瑙掕壊涓庤彍鍗曞叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysRoleMenuMapper extends BaseMapperPlus<SysRoleMenu, SysRoleMenu> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java
new file mode 100644
index 0000000..b942061
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysSocialMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysSocial;
+import org.dromara.system.domain.vo.SysSocialVo;
+
+/**
+ * 绀句細鍖栧叧绯籑apper鎺ュ彛
+ *
+ * @author thiszhc
+ */
+public interface SysSocialMapper extends BaseMapperPlus<SysSocial, SysSocialVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
new file mode 100644
index 0000000..7e1167a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.system.domain.SysTenant;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+
+/**
+ * 绉熸埛Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface SysTenantMapper extends BaseMapperPlus<SysTenant, SysTenantVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java
new file mode 100644
index 0000000..10ca170
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysTenantPackageMapper.java
@@ -0,0 +1,14 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+
+/**
+ * 绉熸埛濂楅Mapper鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface SysTenantPackageMapper extends BaseMapperPlus<SysTenantPackage, SysTenantPackageVo> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..4322225
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserMapper.java
@@ -0,0 +1,114 @@
+package org.dromara.system.mapper;
+
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.toolkit.Constants;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import org.apache.ibatis.annotations.Param;
+import org.dromara.common.mybatis.annotation.DataColumn;
+import org.dromara.common.mybatis.annotation.DataPermission;
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.vo.SysUserVo;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛琛� 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserMapper extends BaseMapperPlus<SysUser, SysUserVo> {
+
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "u.user_id")
+ })
+ Page<SysUserVo> selectPageUserList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "u.user_id")
+ })
+ List<SysUserVo> selectUserList(@Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸查厤鐢ㄦ埛瑙掕壊鍒楄〃
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "u.user_id")
+ })
+ Page<SysUserVo> selectAllocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+ *
+ * @param queryWrapper 鏌ヨ鏉′欢
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "u.user_id")
+ })
+ Page<SysUserVo> selectUnallocatedList(@Param("page") Page<SysUser> page, @Param(Constants.WRAPPER) Wrapper<SysUser> queryWrapper);
+
+ /**
+ * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserByUserName(String userName);
+
+ /**
+ * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴�
+ *
+ * @param phonenumber 鎵嬫満鍙�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserByPhonenumber(String phonenumber);
+
+ /**
+ * 閫氳繃閭鏌ヨ鐢ㄦ埛
+ *
+ * @param email 閭
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserByEmail(String email);
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "d.dept_id"),
+ @DataColumn(key = "userName", value = "u.user_id")
+ })
+ SysUserVo selectUserById(Long userId);
+
+ @Override
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "dept_id"),
+ @DataColumn(key = "userName", value = "user_id")
+ })
+ int update(@Param(Constants.ENTITY) SysUser user, @Param(Constants.WRAPPER) Wrapper<SysUser> updateWrapper);
+
+ @Override
+ @DataPermission({
+ @DataColumn(key = "deptName", value = "dept_id"),
+ @DataColumn(key = "userName", value = "user_id")
+ })
+ int updateById(@Param(Constants.ENTITY) SysUser user);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java
new file mode 100644
index 0000000..07c1371
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserPostMapper.java
@@ -0,0 +1,13 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUserPost;
+
+/**
+ * 鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserPostMapper extends BaseMapperPlus<SysUserPost, SysUserPost> {
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..e2f706c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/mapper/SysUserRoleMapper.java
@@ -0,0 +1,17 @@
+package org.dromara.system.mapper;
+
+import org.dromara.common.mybatis.core.mapper.BaseMapperPlus;
+import org.dromara.system.domain.SysUserRole;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛涓庤鑹插叧鑱旇〃 鏁版嵁灞�
+ *
+ * @author Lion Li
+ */
+public interface SysUserRoleMapper extends BaseMapperPlus<SysUserRole, SysUserRole> {
+
+ List<Long> selectUserIdsByRoleId(Long roleId);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
new file mode 100644
index 0000000..4382844
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysClientService.java
@@ -0,0 +1,58 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.domain.vo.SysClientVo;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀹㈡埛绔鐞哠ervice鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface ISysClientService {
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞�
+ */
+ SysClientVo queryById(Long id);
+
+ /**
+ * 鏌ヨ瀹㈡埛绔俊鎭熀浜庡鎴风id
+ */
+ SysClientVo queryByClientId(String clientId);
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+ */
+ TableDataInfo<SysClientVo> queryPageList(SysClientBo bo, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+ */
+ List<SysClientVo> queryList(SysClientBo bo);
+
+ /**
+ * 鏂板瀹㈡埛绔鐞�
+ */
+ Boolean insertByBo(SysClientBo bo);
+
+ /**
+ * 淇敼瀹㈡埛绔鐞�
+ */
+ Boolean updateByBo(SysClientBo bo);
+
+ /**
+ * 淇敼鐘舵��
+ */
+ int updateUserStatus(Long id, String status);
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄ゅ鎴风绠$悊淇℃伅
+ */
+ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java
new file mode 100644
index 0000000..f7efda7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysConfigService.java
@@ -0,0 +1,87 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+
+import java.util.List;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysConfigService {
+
+
+ TableDataInfo<SysConfigVo> selectPageConfigList(SysConfigBo config, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+ *
+ * @param configId 鍙傛暟閰嶇疆ID
+ * @return 鍙傛暟閰嶇疆淇℃伅
+ */
+ SysConfigVo selectConfigById(Long configId);
+
+ /**
+ * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+ *
+ * @param configKey 鍙傛暟閿悕
+ * @return 鍙傛暟閿��
+ */
+ String selectConfigByKey(String configKey);
+
+ /**
+ * 鑾峰彇娉ㄥ唽寮�鍏�
+ * @param tenantId 绉熸埛id
+ * @return true寮�鍚紝false鍏抽棴
+ */
+ boolean selectRegisterEnabled(String tenantId);
+
+ /**
+ * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+ *
+ * @param config 鍙傛暟閰嶇疆淇℃伅
+ * @return 鍙傛暟閰嶇疆闆嗗悎
+ */
+ List<SysConfigVo> selectConfigList(SysConfigBo config);
+
+ /**
+ * 鏂板鍙傛暟閰嶇疆
+ *
+ * @param bo 鍙傛暟閰嶇疆淇℃伅
+ * @return 缁撴灉
+ */
+ String insertConfig(SysConfigBo bo);
+
+ /**
+ * 淇敼鍙傛暟閰嶇疆
+ *
+ * @param bo 鍙傛暟閰嶇疆淇℃伅
+ * @return 缁撴灉
+ */
+ String updateConfig(SysConfigBo bo);
+
+ /**
+ * 鎵归噺鍒犻櫎鍙傛暟淇℃伅
+ *
+ * @param configIds 闇�瑕佸垹闄ょ殑鍙傛暟ID
+ */
+ void deleteConfigByIds(Long[] configIds);
+
+ /**
+ * 閲嶇疆鍙傛暟缂撳瓨鏁版嵁
+ */
+ void resetConfigCache();
+
+ /**
+ * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+ *
+ * @param config 鍙傛暟淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkConfigKeyUnique(SysConfigBo config);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
new file mode 100644
index 0000000..3625486
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDeptService.java
@@ -0,0 +1,125 @@
+package org.dromara.system.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDeptService {
+ /**
+ * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+ *
+ * @param dept 閮ㄩ棬淇℃伅
+ * @return 閮ㄩ棬淇℃伅闆嗗悎
+ */
+ List<SysDeptVo> selectDeptList(SysDeptBo dept);
+
+ /**
+ * 鏌ヨ閮ㄩ棬鏍戠粨鏋勪俊鎭�
+ *
+ * @param dept 閮ㄩ棬淇℃伅
+ * @return 閮ㄩ棬鏍戜俊鎭泦鍚�
+ */
+ List<Tree<Long>> selectDeptTreeList(SysDeptBo dept);
+
+ /**
+ * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+ *
+ * @param depts 閮ㄩ棬鍒楄〃
+ * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ List<Tree<Long>> buildDeptTreeSelect(List<SysDeptVo> depts);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 閫変腑閮ㄩ棬鍒楄〃
+ */
+ List<Long> selectDeptListByRoleId(Long roleId);
+
+ /**
+ * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 閮ㄩ棬淇℃伅
+ */
+ SysDeptVo selectDeptById(Long deptId);
+
+ /**
+ * 閫氳繃閮ㄩ棬ID鏌ヨ閮ㄩ棬鍚嶇О
+ *
+ * @param deptIds 閮ㄩ棬ID涓查�楀彿鍒嗛殧
+ * @return 閮ㄩ棬鍚嶇О涓查�楀彿鍒嗛殧
+ */
+ String selectDeptNameByIds(String deptIds);
+
+ /**
+ * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬鏁帮紙姝e父鐘舵�侊級
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 瀛愰儴闂ㄦ暟
+ */
+ long selectNormalChildrenDeptById(Long deptId);
+
+ /**
+ * 鏄惁瀛樺湪閮ㄩ棬瀛愯妭鐐�
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉
+ */
+ boolean hasChildByDeptId(Long deptId);
+
+ /**
+ * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+ */
+ boolean checkDeptExistUser(Long deptId);
+
+ /**
+ * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+ *
+ * @param dept 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkDeptNameUnique(SysDeptBo dept);
+
+ /**
+ * 鏍¢獙閮ㄩ棬鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param deptId 閮ㄩ棬id
+ */
+ void checkDeptDataScope(Long deptId);
+
+ /**
+ * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+ *
+ * @param bo 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ int insertDept(SysDeptBo bo);
+
+ /**
+ * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+ *
+ * @param bo 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ int updateDept(SysDeptBo bo);
+
+ /**
+ * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉
+ */
+ int deleteDeptById(Long deptId);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java
new file mode 100644
index 0000000..30442ce
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictDataService.java
@@ -0,0 +1,67 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDictDataService {
+
+
+ TableDataInfo<SysDictDataVo> selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+ *
+ * @param dictData 瀛楀吀鏁版嵁淇℃伅
+ * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+ */
+ List<SysDictDataVo> selectDictDataList(SysDictDataBo dictData);
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @param dictValue 瀛楀吀閿��
+ * @return 瀛楀吀鏍囩
+ */
+ String selectDictLabel(String dictType, String dictValue);
+
+ /**
+ * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+ *
+ * @param dictCode 瀛楀吀鏁版嵁ID
+ * @return 瀛楀吀鏁版嵁
+ */
+ SysDictDataVo selectDictDataById(Long dictCode);
+
+ /**
+ * 鎵归噺鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param dictCodes 闇�瑕佸垹闄ょ殑瀛楀吀鏁版嵁ID
+ */
+ void deleteDictDataByIds(Long[] dictCodes);
+
+ /**
+ * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param bo 瀛楀吀鏁版嵁淇℃伅
+ * @return 缁撴灉
+ */
+ List<SysDictDataVo> insertDictData(SysDictDataBo bo);
+
+ /**
+ * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param bo 瀛楀吀鏁版嵁淇℃伅
+ * @return 缁撴灉
+ */
+ List<SysDictDataVo> updateDictData(SysDictDataBo bo);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java
new file mode 100644
index 0000000..3b32d6c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysDictTypeService.java
@@ -0,0 +1,95 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysDictTypeService {
+
+
+ TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+ *
+ * @param dictType 瀛楀吀绫诲瀷淇℃伅
+ * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+ */
+ List<SysDictTypeVo> selectDictTypeList(SysDictTypeBo dictType);
+
+ /**
+ * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+ *
+ * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+ */
+ List<SysDictTypeVo> selectDictTypeAll();
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+ */
+ List<SysDictDataVo> selectDictDataByType(String dictType);
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+ *
+ * @param dictId 瀛楀吀绫诲瀷ID
+ * @return 瀛楀吀绫诲瀷
+ */
+ SysDictTypeVo selectDictTypeById(Long dictId);
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 瀛楀吀绫诲瀷
+ */
+ SysDictTypeVo selectDictTypeByType(String dictType);
+
+ /**
+ * 鎵归噺鍒犻櫎瀛楀吀淇℃伅
+ *
+ * @param dictIds 闇�瑕佸垹闄ょ殑瀛楀吀ID
+ */
+ void deleteDictTypeByIds(Long[] dictIds);
+
+ /**
+ * 閲嶇疆瀛楀吀缂撳瓨鏁版嵁
+ */
+ void resetDictCache();
+
+ /**
+ * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+ *
+ * @param bo 瀛楀吀绫诲瀷淇℃伅
+ * @return 缁撴灉
+ */
+ List<SysDictDataVo> insertDictType(SysDictTypeBo bo);
+
+ /**
+ * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+ *
+ * @param bo 瀛楀吀绫诲瀷淇℃伅
+ * @return 缁撴灉
+ */
+ List<SysDictDataVo> updateDictType(SysDictTypeBo bo);
+
+ /**
+ * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 缁撴灉
+ */
+ boolean checkDictTypeUnique(SysDictTypeBo dictType);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java
new file mode 100644
index 0000000..6b3b7a6
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysLogininforService.java
@@ -0,0 +1,47 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+
+import java.util.List;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysLogininforService {
+
+
+ TableDataInfo<SysLogininforVo> selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery);
+
+ /**
+ * 鏂板绯荤粺鐧诲綍鏃ュ織
+ *
+ * @param bo 璁块棶鏃ュ織瀵硅薄
+ */
+ void insertLogininfor(SysLogininforBo bo);
+
+ /**
+ * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+ *
+ * @param logininfor 璁块棶鏃ュ織瀵硅薄
+ * @return 鐧诲綍璁板綍闆嗗悎
+ */
+ List<SysLogininforVo> selectLogininforList(SysLogininforBo logininfor);
+
+ /**
+ * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+ *
+ * @param infoIds 闇�瑕佸垹闄ょ殑鐧诲綍鏃ュ織ID
+ * @return 缁撴灉
+ */
+ int deleteLogininforByIds(Long[] infoIds);
+
+ /**
+ * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+ */
+ void cleanLogininfor();
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java
new file mode 100644
index 0000000..72d705e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysMenuService.java
@@ -0,0 +1,147 @@
+package org.dromara.system.service;
+
+import cn.hutool.core.lang.tree.Tree;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 鑿滃崟 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysMenuService {
+
+ /**
+ * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鑿滃崟鍒楄〃
+ */
+ List<SysMenuVo> selectMenuList(Long userId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+ *
+ * @param menu 鑿滃崟淇℃伅
+ * @param userId 鐢ㄦ埛ID
+ * @return 鑿滃崟鍒楄〃
+ */
+ List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ Set<String> selectMenuPermsByUserId(Long userId);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ Set<String> selectMenuPermsByRoleId(Long roleId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鑿滃崟鍒楄〃
+ */
+ List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 閫変腑鑿滃崟鍒楄〃
+ */
+ List<Long> selectMenuListByRoleId(Long roleId);
+
+ /**
+ * 鏍规嵁绉熸埛濂楅ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param packageId 绉熸埛濂楅ID
+ * @return 閫変腑鑿滃崟鍒楄〃
+ */
+ List<Long> selectMenuListByPackageId(Long packageId);
+
+ /**
+ * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+ *
+ * @param menus 鑿滃崟鍒楄〃
+ * @return 璺敱鍒楄〃
+ */
+ List<RouterVo> buildMenus(List<SysMenu> menus);
+
+ /**
+ * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+ *
+ * @param menus 鑿滃崟鍒楄〃
+ * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ List<Tree<Long>> buildMenuTreeSelect(List<SysMenuVo> menus);
+
+ /**
+ * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 鑿滃崟淇℃伅
+ */
+ SysMenuVo selectMenuById(Long menuId);
+
+ /**
+ * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+ */
+ boolean hasChildByMenuId(Long menuId);
+
+ /**
+ * 鏌ヨ鑿滃崟鏄惁瀛樺湪瑙掕壊
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+ */
+ boolean checkMenuExistRole(Long menuId);
+
+ /**
+ * 鏂板淇濆瓨鑿滃崟淇℃伅
+ *
+ * @param bo 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ int insertMenu(SysMenuBo bo);
+
+ /**
+ * 淇敼淇濆瓨鑿滃崟淇℃伅
+ *
+ * @param bo 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ int updateMenu(SysMenuBo bo);
+
+ /**
+ * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉
+ */
+ int deleteMenuById(Long menuId);
+
+ /**
+ * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+ *
+ * @param menu 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkMenuNameUnique(SysMenuBo menu);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java
new file mode 100644
index 0000000..8ec999d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysNoticeService.java
@@ -0,0 +1,67 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+
+import java.util.List;
+
+/**
+ * 鍏憡 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysNoticeService {
+
+
+ TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ鍏憡淇℃伅
+ *
+ * @param noticeId 鍏憡ID
+ * @return 鍏憡淇℃伅
+ */
+ SysNoticeVo selectNoticeById(Long noticeId);
+
+ /**
+ * 鏌ヨ鍏憡鍒楄〃
+ *
+ * @param notice 鍏憡淇℃伅
+ * @return 鍏憡闆嗗悎
+ */
+ List<SysNoticeVo> selectNoticeList(SysNoticeBo notice);
+
+ /**
+ * 鏂板鍏憡
+ *
+ * @param bo 鍏憡淇℃伅
+ * @return 缁撴灉
+ */
+ int insertNotice(SysNoticeBo bo);
+
+ /**
+ * 淇敼鍏憡
+ *
+ * @param bo 鍏憡淇℃伅
+ * @return 缁撴灉
+ */
+ int updateNotice(SysNoticeBo bo);
+
+ /**
+ * 鍒犻櫎鍏憡淇℃伅
+ *
+ * @param noticeId 鍏憡ID
+ * @return 缁撴灉
+ */
+ int deleteNoticeById(Long noticeId);
+
+ /**
+ * 鎵归噺鍒犻櫎鍏憡淇℃伅
+ *
+ * @param noticeIds 闇�瑕佸垹闄ょ殑鍏憡ID
+ * @return 缁撴灉
+ */
+ int deleteNoticeByIds(Long[] noticeIds);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java
new file mode 100644
index 0000000..9573510
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysOperLogService.java
@@ -0,0 +1,54 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+
+import java.util.List;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysOperLogService {
+
+ TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery);
+
+ /**
+ * 鏂板鎿嶄綔鏃ュ織
+ *
+ * @param bo 鎿嶄綔鏃ュ織瀵硅薄
+ */
+ void insertOperlog(SysOperLogBo bo);
+
+ /**
+ * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+ *
+ * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+ * @return 鎿嶄綔鏃ュ織闆嗗悎
+ */
+ List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog);
+
+ /**
+ * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+ *
+ * @param operIds 闇�瑕佸垹闄ょ殑鎿嶄綔鏃ュ織ID
+ * @return 缁撴灉
+ */
+ int deleteOperLogByIds(Long[] operIds);
+
+ /**
+ * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+ *
+ * @param operId 鎿嶄綔ID
+ * @return 鎿嶄綔鏃ュ織瀵硅薄
+ */
+ SysOperLogVo selectOperLogById(Long operId);
+
+ /**
+ * 娓呯┖鎿嶄綔鏃ュ織
+ */
+ void cleanOperLog();
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java
new file mode 100644
index 0000000..0116df5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPermissionService.java
@@ -0,0 +1,28 @@
+package org.dromara.system.service;
+
+import java.util.Set;
+
+/**
+ * 鐢ㄦ埛鏉冮檺澶勭悊
+ *
+ * @author Lion Li
+ */
+public interface ISysPermissionService {
+
+ /**
+ * 鑾峰彇瑙掕壊鏁版嵁鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛id
+ * @return 瑙掕壊鏉冮檺淇℃伅
+ */
+ Set<String> getRolePermission(Long userId);
+
+ /**
+ * 鑾峰彇鑿滃崟鏁版嵁鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛id
+ * @return 鑿滃崟鏉冮檺淇℃伅
+ */
+ Set<String> getMenuPermission(Long userId);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
new file mode 100644
index 0000000..c6409c8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysPostService.java
@@ -0,0 +1,106 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysPostService {
+
+
+ TableDataInfo<SysPostVo> selectPagePostList(SysPostBo post, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 宀椾綅鍒楄〃
+ */
+ List<SysPostVo> selectPostList(SysPostBo post);
+
+ /**
+ * 鏌ヨ鎵�鏈夊矖浣�
+ *
+ * @return 宀椾綅鍒楄〃
+ */
+ List<SysPostVo> selectPostAll();
+
+ /**
+ * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+ *
+ * @param postId 宀椾綅ID
+ * @return 瑙掕壊瀵硅薄淇℃伅
+ */
+ SysPostVo selectPostById(Long postId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑宀椾綅ID鍒楄〃
+ */
+ List<Long> selectPostListByUserId(Long userId);
+
+ /**
+ * 鏍¢獙宀椾綅鍚嶇О
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkPostNameUnique(SysPostBo post);
+
+ /**
+ * 鏍¢獙宀椾綅缂栫爜
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkPostCodeUnique(SysPostBo post);
+
+ /**
+ * 閫氳繃宀椾綅ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+ *
+ * @param postId 宀椾綅ID
+ * @return 缁撴灉
+ */
+ long countUserPostById(Long postId);
+
+ /**
+ * 鍒犻櫎宀椾綅淇℃伅
+ *
+ * @param postId 宀椾綅ID
+ * @return 缁撴灉
+ */
+ int deletePostById(Long postId);
+
+ /**
+ * 鎵归噺鍒犻櫎宀椾綅淇℃伅
+ *
+ * @param postIds 闇�瑕佸垹闄ょ殑宀椾綅ID
+ * @return 缁撴灉
+ */
+ int deletePostByIds(Long[] postIds);
+
+ /**
+ * 鏂板淇濆瓨宀椾綅淇℃伅
+ *
+ * @param bo 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ int insertPost(SysPostBo bo);
+
+ /**
+ * 淇敼淇濆瓨宀椾綅淇℃伅
+ *
+ * @param bo 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ int updatePost(SysPostBo bo);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
new file mode 100644
index 0000000..d2ee61f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysRoleService.java
@@ -0,0 +1,183 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.vo.SysRoleVo;
+
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 瑙掕壊涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysRoleService {
+
+
+ TableDataInfo<SysRoleVo> selectPageRoleList(SysRoleBo role, PageQuery pageQuery);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+ */
+ List<SysRoleVo> selectRoleList(SysRoleBo role);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鍒楄〃
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 瑙掕壊鍒楄〃
+ */
+ List<SysRoleVo> selectRolesByUserId(Long userId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ Set<String> selectRolePermissionByUserId(Long userId);
+
+ /**
+ * 鏌ヨ鎵�鏈夎鑹�
+ *
+ * @return 瑙掕壊鍒楄〃
+ */
+ List<SysRoleVo> selectRoleAll();
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑瑙掕壊ID鍒楄〃
+ */
+ List<Long> selectRoleListByUserId(Long userId);
+
+ /**
+ * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 瑙掕壊瀵硅薄淇℃伅
+ */
+ SysRoleVo selectRoleById(Long roleId);
+
+ /**
+ * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkRoleNameUnique(SysRoleBo role);
+
+ /**
+ * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkRoleKeyUnique(SysRoleBo role);
+
+ /**
+ * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+ *
+ * @param role 瑙掕壊淇℃伅
+ */
+ void checkRoleAllowed(SysRoleBo role);
+
+ /**
+ * 鏍¢獙瑙掕壊鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param roleId 瑙掕壊id
+ */
+ void checkRoleDataScope(Long roleId);
+
+ /**
+ * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 缁撴灉
+ */
+ long countUserRoleByRoleId(Long roleId);
+
+ /**
+ * 鏂板淇濆瓨瑙掕壊淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ int insertRole(SysRoleBo bo);
+
+ /**
+ * 淇敼淇濆瓨瑙掕壊淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ int updateRole(SysRoleBo bo);
+
+ /**
+ * 淇敼瑙掕壊鐘舵��
+ *
+ * @param roleId 瑙掕壊ID
+ * @param status 瑙掕壊鐘舵��
+ * @return 缁撴灉
+ */
+ int updateRoleStatus(Long roleId, String status);
+
+ /**
+ * 淇敼鏁版嵁鏉冮檺淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ int authDataScope(SysRoleBo bo);
+
+ /**
+ * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 缁撴灉
+ */
+ int deleteRoleById(Long roleId);
+
+ /**
+ * 鎵归噺鍒犻櫎瑙掕壊淇℃伅
+ *
+ * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
+ * @return 缁撴灉
+ */
+ int deleteRoleByIds(Long[] roleIds);
+
+ /**
+ * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+ * @return 缁撴灉
+ */
+ int deleteAuthUser(SysUserRole userRole);
+
+ /**
+ * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+ * @return 缁撴灉
+ */
+ int deleteAuthUsers(Long roleId, Long[] userIds);
+
+ /**
+ * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID
+ * @return 缁撴灉
+ */
+ int insertAuthUsers(Long roleId, Long[] userIds);
+
+ void cleanOnlineUserByRole(Long roleId);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java
new file mode 100644
index 0000000..0950b60
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysSocialService.java
@@ -0,0 +1,56 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.SysSocialVo;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯籗ervice鎺ュ彛
+ *
+ * @author thiszhc
+ */
+public interface ISysSocialService {
+
+
+ /**
+ * 鏌ヨ绀句細鍖栧叧绯�
+ */
+ SysSocialVo queryById(String id);
+
+ /**
+ * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+ */
+ List<SysSocialVo> queryList();
+
+ /**
+ * 鏌ヨ绀句細鍖栧叧绯诲垪琛�
+ */
+ List<SysSocialVo> queryListByUserId(Long userId);
+
+ /**
+ * 鏂板鎺堟潈鍏崇郴
+ */
+ Boolean insertByBo(SysSocialBo bo);
+
+ /**
+ * 鏇存柊绀句細鍖栧叧绯�
+ */
+
+ Boolean updateByBo(SysSocialBo bo);
+
+ /**
+ * 鍒犻櫎绀句細鍖栧叧绯讳俊鎭�
+ */
+ Boolean deleteWithValidById(Long id);
+
+
+ /**
+ * 鏍规嵁 authId 鏌ヨ SysSocial 琛ㄥ拰 SysUser 琛紝杩斿洖 SysSocialAuthResult 鏄犲皠鐨勫璞�
+ * @param authId 璁よ瘉ID
+ * @return SysSocial
+ */
+ List<SysSocialVo> selectByAuthId(String authId);
+
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
new file mode 100644
index 0000000..cdb887c
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantPackageService.java
@@ -0,0 +1,57 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅Service鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface ISysTenantPackageService {
+
+ /**
+ * 鏌ヨ绉熸埛濂楅
+ */
+ SysTenantPackageVo queryById(Long packageId);
+
+ /**
+ * 鏌ヨ绉熸埛濂楅鍒楄〃
+ */
+ TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ绉熸埛濂楅宸插惎鐢ㄥ垪琛�
+ */
+ List<SysTenantPackageVo> selectList();
+
+ /**
+ * 鏌ヨ绉熸埛濂楅鍒楄〃
+ */
+ List<SysTenantPackageVo> queryList(SysTenantPackageBo bo);
+
+ /**
+ * 鏂板绉熸埛濂楅
+ */
+ Boolean insertByBo(SysTenantPackageBo bo);
+
+ /**
+ * 淇敼绉熸埛濂楅
+ */
+ Boolean updateByBo(SysTenantPackageBo bo);
+
+ /**
+ * 淇敼濂楅鐘舵��
+ */
+ int updatePackageStatus(SysTenantPackageBo bo);
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄ょ鎴峰椁愪俊鎭�
+ */
+ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
new file mode 100644
index 0000000..d12ed95
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysTenantService.java
@@ -0,0 +1,82 @@
+package org.dromara.system.service;
+
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.core.page.PageQuery;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛Service鎺ュ彛
+ *
+ * @author Michelle.Chung
+ */
+public interface ISysTenantService {
+
+ /**
+ * 鏌ヨ绉熸埛
+ */
+ SysTenantVo queryById(Long id);
+
+ /**
+ * 鍩轰簬绉熸埛ID鏌ヨ绉熸埛
+ */
+ SysTenantVo queryByTenantId(String tenantId);
+
+ /**
+ * 鏌ヨ绉熸埛鍒楄〃
+ */
+ TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery);
+
+ /**
+ * 鏌ヨ绉熸埛鍒楄〃
+ */
+ List<SysTenantVo> queryList(SysTenantBo bo);
+
+ /**
+ * 鏂板绉熸埛
+ */
+ Boolean insertByBo(SysTenantBo bo);
+
+ /**
+ * 淇敼绉熸埛
+ */
+ Boolean updateByBo(SysTenantBo bo);
+
+ /**
+ * 淇敼绉熸埛鐘舵��
+ */
+ int updateTenantStatus(SysTenantBo bo);
+
+ /**
+ * 鏍¢獙绉熸埛鏄惁鍏佽鎿嶄綔
+ */
+ void checkTenantAllowed(String tenantId);
+
+ /**
+ * 鏍¢獙骞舵壒閲忓垹闄ょ鎴蜂俊鎭�
+ */
+ Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
+
+ /**
+ * 鏍¢獙浼佷笟鍚嶇О鏄惁鍞竴
+ */
+ boolean checkCompanyNameUnique(SysTenantBo bo);
+
+ /**
+ * 鏍¢獙璐﹀彿浣欓
+ */
+ boolean checkAccountBalance(String tenantId);
+
+ /**
+ * 鏍¢獙鏈夋晥鏈�
+ */
+ boolean checkExpireTime(String tenantId);
+
+ /**
+ * 鍚屾绉熸埛濂楅
+ */
+ Boolean syncTenantPackage(String tenantId, Long packageId);
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
new file mode 100644
index 0000000..32ae8fc
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/ISysUserService.java
@@ -0,0 +1,229 @@
+package org.dromara.system.service;
+
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysUserVo;
+
+import java.util.List;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞�
+ *
+ * @author Lion Li
+ */
+public interface ISysUserService {
+
+
+ TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ List<SysUserVo> selectUserList(SysUserBo user);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery);
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery);
+
+ /**
+ * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserByUserName(String userName);
+
+ /**
+ * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴�
+ *
+ * @param phonenumber 鎵嬫満鍙�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserByPhonenumber(String phonenumber);
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ SysUserVo selectUserById(Long userId);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 缁撴灉
+ */
+ String selectUserRoleGroup(String userName);
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 缁撴灉
+ */
+ String selectUserPostGroup(String userName);
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkUserNameUnique(SysUserBo user);
+
+ /**
+ * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkPhoneUnique(SysUserBo user);
+
+ /**
+ * 鏍¢獙email鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ boolean checkEmailUnique(SysUserBo user);
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+ *
+ * @param userId 鐢ㄦ埛ID
+ */
+ void checkUserAllowed(Long userId);
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param userId 鐢ㄦ埛id
+ */
+ void checkUserDataScope(Long userId);
+
+ /**
+ * 鏂板鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ int insertUser(SysUserBo user);
+
+ /**
+ * 娉ㄥ唽鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ boolean registerUser(SysUserBo user, String tenantId);
+
+ /**
+ * 淇敼鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ int updateUser(SysUserBo user);
+
+ /**
+ * 鐢ㄦ埛鎺堟潈瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param roleIds 瑙掕壊缁�
+ */
+ void insertUserAuth(Long userId, Long[] roleIds);
+
+ /**
+ * 淇敼鐢ㄦ埛鐘舵��
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param status 甯愬彿鐘舵��
+ * @return 缁撴灉
+ */
+ int updateUserStatus(Long userId, String status);
+
+ /**
+ * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ int updateUserProfile(SysUserBo user);
+
+ /**
+ * 淇敼鐢ㄦ埛澶村儚
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param avatar 澶村儚鍦板潃
+ * @return 缁撴灉
+ */
+ boolean updateUserAvatar(Long userId, Long avatar);
+
+ /**
+ * 閲嶇疆鐢ㄦ埛瀵嗙爜
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param password 瀵嗙爜
+ * @return 缁撴灉
+ */
+ int resetUserPwd(Long userId, String password);
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 缁撴灉
+ */
+ int deleteUserById(Long userId);
+
+ /**
+ * 鎵归噺鍒犻櫎鐢ㄦ埛淇℃伅
+ *
+ * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛ID
+ * @return 缁撴灉
+ */
+ int deleteUserByIds(Long[] userIds);
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鐢ㄦ埛璐︽埛
+ */
+ String selectUserNameById(Long userId);
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛璐︽埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鐢ㄦ埛璐︽埛
+ */
+ String selectNicknameById(Long userId);
+
+ /**
+ * 閫氳繃閮ㄩ棬id鏌ヨ褰撳墠閮ㄩ棬鎵�鏈夌敤鎴�
+ *
+ * @param deptId
+ * @return
+ */
+ List<SysUserVo> selectUserListByDept(Long deptId);
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
new file mode 100644
index 0000000..9ed56af
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysClientServiceImpl.java
@@ -0,0 +1,143 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.crypto.SecureUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysClient;
+import org.dromara.system.domain.bo.SysClientBo;
+import org.dromara.system.domain.vo.SysClientVo;
+import org.dromara.system.mapper.SysClientMapper;
+import org.dromara.system.service.ISysClientService;
+import org.springframework.stereotype.Service;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 瀹㈡埛绔鐞哠ervice涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysClientServiceImpl implements ISysClientService {
+
+ private final SysClientMapper baseMapper;
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞�
+ */
+ @Override
+ public SysClientVo queryById(Long id) {
+ SysClientVo vo = baseMapper.selectVoById(id);
+ vo.setGrantTypeList(List.of(vo.getGrantType().split(",")));
+ return vo;
+ }
+
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞�
+ */
+ @Override
+ public SysClientVo queryByClientId(String clientId) {
+ return baseMapper.selectVoOne(new LambdaQueryWrapper<SysClient>().eq(SysClient::getClientId, clientId));
+ }
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+ */
+ @Override
+ public TableDataInfo<SysClientVo> queryPageList(SysClientBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(bo);
+ Page<SysClientVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ result.getRecords().forEach(r -> r.setGrantTypeList(List.of(r.getGrantType().split(","))));
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 鏌ヨ瀹㈡埛绔鐞嗗垪琛�
+ */
+ @Override
+ public List<SysClientVo> queryList(SysClientBo bo) {
+ LambdaQueryWrapper<SysClient> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysClient> buildQueryWrapper(SysClientBo bo) {
+ LambdaQueryWrapper<SysClient> lqw = Wrappers.lambdaQuery();
+ lqw.eq(StringUtils.isNotBlank(bo.getClientId()), SysClient::getClientId, bo.getClientId());
+ lqw.eq(StringUtils.isNotBlank(bo.getClientKey()), SysClient::getClientKey, bo.getClientKey());
+ lqw.eq(StringUtils.isNotBlank(bo.getClientSecret()), SysClient::getClientSecret, bo.getClientSecret());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysClient::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysClient::getId);
+ return lqw;
+ }
+
+ /**
+ * 鏂板瀹㈡埛绔鐞�
+ */
+ @Override
+ public Boolean insertByBo(SysClientBo bo) {
+ SysClient add = MapstructUtils.convert(bo, SysClient.class);
+ validEntityBeforeSave(add);
+ add.setGrantType(String.join(",", bo.getGrantTypeList()));
+ // 鐢熸垚clientid
+ String clientKey = bo.getClientKey();
+ String clientSecret = bo.getClientSecret();
+ add.setClientId(SecureUtil.md5(clientKey + clientSecret));
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setId(add.getId());
+ }
+ return flag;
+ }
+
+ /**
+ * 淇敼瀹㈡埛绔鐞�
+ */
+ @Override
+ public Boolean updateByBo(SysClientBo bo) {
+ SysClient update = MapstructUtils.convert(bo, SysClient.class);
+ validEntityBeforeSave(update);
+ update.setGrantType(String.join(",", bo.getGrantTypeList()));
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 淇敼鐘舵��
+ */
+ @Override
+ public int updateUserStatus(Long id, String status) {
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysClient>()
+ .set(SysClient::getStatus, status)
+ .eq(SysClient::getId, id));
+ }
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(SysClient entity) {
+ //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎瀹㈡埛绔鐞�
+ */
+ @Override
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+ if (isValid) {
+ //TODO 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..7f72159
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,205 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.dynamic.datasource.annotation.DS;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.dromara.system.domain.SysConfig;
+import org.dromara.system.domain.bo.SysConfigBo;
+import org.dromara.system.domain.vo.SysConfigVo;
+import org.dromara.system.mapper.SysConfigMapper;
+import org.dromara.system.service.ISysConfigService;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysConfigServiceImpl implements ISysConfigService {
+
+ private final SysConfigMapper baseMapper;
+
+ @Override
+ public TableDataInfo<SysConfigVo> selectPageConfigList(SysConfigBo config, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysConfig> lqw = buildQueryWrapper(config);
+ Page<SysConfigVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+ *
+ * @param configId 鍙傛暟閰嶇疆ID
+ * @return 鍙傛暟閰嶇疆淇℃伅
+ */
+ @Override
+ @DS("master")
+ public SysConfigVo selectConfigById(Long configId) {
+ return baseMapper.selectVoById(configId);
+ }
+
+ /**
+ * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+ *
+ * @param configKey 鍙傛暟key
+ * @return 鍙傛暟閿��
+ */
+ @Cacheable(cacheNames = CacheNames.SYS_CONFIG, key = "#configKey")
+ @Override
+ public String selectConfigByKey(String configKey) {
+ SysConfig retConfig = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
+ .eq(SysConfig::getConfigKey, configKey));
+ if (ObjectUtil.isNotNull(retConfig)) {
+ return retConfig.getConfigValue();
+ }
+ return StringUtils.EMPTY;
+ }
+
+ /**
+ * 鑾峰彇娉ㄥ唽寮�鍏�
+ * @param tenantId 绉熸埛id
+ * @return true寮�鍚紝false鍏抽棴
+ */
+ @Override
+ public boolean selectRegisterEnabled(String tenantId) {
+ SysConfig retConfig = TenantHelper.dynamic(tenantId, () -> {
+ return baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>()
+ .eq(SysConfig::getConfigKey, "sys.account.registerUser"));
+ });
+ if (ObjectUtil.isNull(retConfig)) {
+ return false;
+ }
+ return Convert.toBool(retConfig.getConfigValue());
+ }
+
+ /**
+ * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+ *
+ * @param config 鍙傛暟閰嶇疆淇℃伅
+ * @return 鍙傛暟閰嶇疆闆嗗悎
+ */
+ @Override
+ public List<SysConfigVo> selectConfigList(SysConfigBo config) {
+ LambdaQueryWrapper<SysConfig> lqw = buildQueryWrapper(config);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysConfig> buildQueryWrapper(SysConfigBo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<SysConfig> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getConfigName()), SysConfig::getConfigName, bo.getConfigName());
+ lqw.eq(StringUtils.isNotBlank(bo.getConfigType()), SysConfig::getConfigType, bo.getConfigType());
+ lqw.like(StringUtils.isNotBlank(bo.getConfigKey()), SysConfig::getConfigKey, bo.getConfigKey());
+ lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysConfig::getCreateTime, params.get("beginTime"), params.get("endTime"));
+ lqw.orderByAsc(SysConfig::getConfigId);
+ return lqw;
+ }
+
+ /**
+ * 鏂板鍙傛暟閰嶇疆
+ *
+ * @param bo 鍙傛暟閰嶇疆淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey")
+ @Override
+ public String insertConfig(SysConfigBo bo) {
+ SysConfig config = MapstructUtils.convert(bo, SysConfig.class);
+ int row = baseMapper.insert(config);
+ if (row > 0) {
+ return config.getConfigValue();
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+ /**
+ * 淇敼鍙傛暟閰嶇疆
+ *
+ * @param bo 鍙傛暟閰嶇疆淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_CONFIG, key = "#bo.configKey")
+ @Override
+ public String updateConfig(SysConfigBo bo) {
+ int row = 0;
+ SysConfig config = MapstructUtils.convert(bo, SysConfig.class);
+ if (config.getConfigId() != null) {
+ SysConfig temp = baseMapper.selectById(config.getConfigId());
+ if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey())) {
+ CacheUtils.evict(CacheNames.SYS_CONFIG, temp.getConfigKey());
+ }
+ row = baseMapper.updateById(config);
+ } else {
+ row = baseMapper.update(config, new LambdaQueryWrapper<SysConfig>()
+ .eq(SysConfig::getConfigKey, config.getConfigKey()));
+ }
+ if (row > 0) {
+ return config.getConfigValue();
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎鍙傛暟淇℃伅
+ *
+ * @param configIds 闇�瑕佸垹闄ょ殑鍙傛暟ID
+ */
+ @Override
+ public void deleteConfigByIds(Long[] configIds) {
+ for (Long configId : configIds) {
+ SysConfig config = baseMapper.selectById(configId);
+ if (StringUtils.equals(UserConstants.YES, config.getConfigType())) {
+ throw new ServiceException(String.format("鍐呯疆鍙傛暟銆�%1$s銆戜笉鑳藉垹闄� ", config.getConfigKey()));
+ }
+ CacheUtils.evict(CacheNames.SYS_CONFIG, config.getConfigKey());
+ }
+ baseMapper.deleteBatchIds(Arrays.asList(configIds));
+ }
+
+ /**
+ * 閲嶇疆鍙傛暟缂撳瓨鏁版嵁
+ */
+ @Override
+ public void resetConfigCache() {
+ CacheUtils.clear(CacheNames.SYS_CONFIG);
+ }
+
+ /**
+ * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+ *
+ * @param config 鍙傛暟閰嶇疆淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkConfigKeyUnique(SysConfigBo config) {
+ long configId = ObjectUtil.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+ SysConfig info = baseMapper.selectOne(new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getConfigKey, config.getConfigKey()));
+ if (ObjectUtil.isNotNull(info) && info.getConfigId() != configId) {
+ return false;
+ }
+ return true;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..44383a5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDeptServiceImpl.java
@@ -0,0 +1,326 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.bo.SysDeptBo;
+import org.dromara.system.domain.vo.SysDeptVo;
+import org.dromara.system.mapper.SysDeptMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysDeptService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟瀹炵幇
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDeptServiceImpl implements ISysDeptService{
+
+ private final SysDeptMapper baseMapper;
+ private final SysRoleMapper roleMapper;
+ private final SysUserMapper userMapper;
+
+ /**
+ * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+ *
+ * @param dept 閮ㄩ棬淇℃伅
+ * @return 閮ㄩ棬淇℃伅闆嗗悎
+ */
+ @Override
+ public List<SysDeptVo> selectDeptList(SysDeptBo dept) {
+ LambdaQueryWrapper<SysDept> lqw = buildQueryWrapper(dept);
+ return baseMapper.selectDeptList(lqw);
+ }
+
+ /**
+ * 鏌ヨ閮ㄩ棬鏍戠粨鏋勪俊鎭�
+ *
+ * @param bo 閮ㄩ棬淇℃伅
+ * @return 閮ㄩ棬鏍戜俊鎭泦鍚�
+ */
+ @Override
+ public List<Tree<Long>> selectDeptTreeList(SysDeptBo bo) {
+ // 鍙煡璇㈡湭绂佺敤閮ㄩ棬
+ bo.setStatus(UserConstants.DEPT_NORMAL);
+ LambdaQueryWrapper<SysDept> lqw = buildQueryWrapper(bo);
+ List<SysDeptVo> depts = baseMapper.selectDeptList(lqw);
+ return buildDeptTreeSelect(depts);
+ }
+
+ private LambdaQueryWrapper<SysDept> buildQueryWrapper(SysDeptBo bo) {
+ LambdaQueryWrapper<SysDept> lqw = Wrappers.lambdaQuery();
+ lqw.eq(SysDept::getDelFlag, "0");
+ lqw.eq(ObjectUtil.isNotNull(bo.getDeptId()), SysDept::getDeptId, bo.getDeptId());
+ lqw.eq(ObjectUtil.isNotNull(bo.getParentId()), SysDept::getParentId, bo.getParentId());
+ lqw.like(StringUtils.isNotBlank(bo.getDeptName()), SysDept::getDeptName, bo.getDeptName());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysDept::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysDept::getParentId);
+ lqw.orderByAsc(SysDept::getOrderNum);
+ lqw.orderByAsc(SysDept::getDeptId);
+ return lqw;
+ }
+
+ /**
+ * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+ *
+ * @param depts 閮ㄩ棬鍒楄〃
+ * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ @Override
+ public List<Tree<Long>> buildDeptTreeSelect(List<SysDeptVo> depts) {
+ if (CollUtil.isEmpty(depts)) {
+ return CollUtil.newArrayList();
+ }
+ return TreeBuildUtils.build(depts, (dept, tree) ->
+ tree.setId(dept.getDeptId())
+ .setParentId(dept.getParentId())
+ .setName(dept.getDeptName())
+ .setWeight(dept.getOrderNum()));
+ }
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 閫変腑閮ㄩ棬鍒楄〃
+ */
+ @Override
+ public List<Long> selectDeptListByRoleId(Long roleId) {
+ SysRole role = roleMapper.selectById(roleId);
+ return baseMapper.selectDeptListByRoleId(roleId, role.getDeptCheckStrictly());
+ }
+
+ /**
+ * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 閮ㄩ棬淇℃伅
+ */
+ @Cacheable(cacheNames = CacheNames.SYS_DEPT, key = "#deptId")
+ @Override
+ public SysDeptVo selectDeptById(Long deptId) {
+ SysDeptVo dept = baseMapper.selectVoById(deptId);
+ if (ObjectUtil.isNull(dept)) {
+ return null;
+ }
+ SysDeptVo parentDept = baseMapper.selectVoOne(new LambdaQueryWrapper<SysDept>()
+ .select(SysDept::getDeptName).eq(SysDept::getDeptId, dept.getParentId()));
+ dept.setParentName(ObjectUtil.isNotNull(parentDept) ? parentDept.getDeptName() : null);
+ return dept;
+ }
+
+ /**
+ * 閫氳繃閮ㄩ棬ID鏌ヨ閮ㄩ棬鍚嶇О
+ *
+ * @param deptIds 閮ㄩ棬ID涓查�楀彿鍒嗛殧
+ * @return 閮ㄩ棬鍚嶇О涓查�楀彿鍒嗛殧
+ */
+ public String selectDeptNameByIds(String deptIds) {
+ List<String> list = new ArrayList<>();
+ for (Long id : StringUtils.splitTo(deptIds, Convert::toLong)) {
+ SysDeptVo vo = SpringUtils.getAopProxy(this).selectDeptById(id);
+ if (ObjectUtil.isNotNull(vo)) {
+ list.add(vo.getDeptName());
+ }
+ }
+ return String.join(StringUtils.SEPARATOR, list);
+ }
+
+ /**
+ * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬鏁帮紙姝e父鐘舵�侊級
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 瀛愰儴闂ㄦ暟
+ */
+ @Override
+ public long selectNormalChildrenDeptById(Long deptId) {
+ return baseMapper.selectCount(new LambdaQueryWrapper<SysDept>()
+ .eq(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+ .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+ }
+
+ /**
+ * 鏄惁瀛樺湪瀛愯妭鐐�
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean hasChildByDeptId(Long deptId) {
+ return baseMapper.exists(new LambdaQueryWrapper<SysDept>()
+ .eq(SysDept::getParentId, deptId));
+ }
+
+ /**
+ * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+ */
+ @Override
+ public boolean checkDeptExistUser(Long deptId) {
+ return userMapper.exists(new LambdaQueryWrapper<SysUser>()
+ .eq(SysUser::getDeptId, deptId));
+ }
+
+ /**
+ * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+ *
+ * @param dept 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkDeptNameUnique(SysDeptBo dept) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDept>()
+ .eq(SysDept::getDeptName, dept.getDeptName())
+ .eq(SysDept::getParentId, dept.getParentId())
+ .ne(ObjectUtil.isNotNull(dept.getDeptId()), SysDept::getDeptId, dept.getDeptId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙閮ㄩ棬鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param deptId 閮ㄩ棬id
+ */
+ @Override
+ public void checkDeptDataScope(Long deptId) {
+ if (ObjectUtil.isNull(deptId)) {
+ return;
+ }
+ if (LoginHelper.isSuperAdmin()) {
+ return;
+ }
+ SysDeptVo dept = baseMapper.selectDeptById(deptId);
+ if (ObjectUtil.isNull(dept)) {
+ throw new ServiceException("娌℃湁鏉冮檺璁块棶閮ㄩ棬鏁版嵁锛�");
+ }
+ }
+
+ /**
+ * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+ *
+ * @param bo 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertDept(SysDeptBo bo) {
+ SysDept info = baseMapper.selectById(bo.getParentId());
+ // 濡傛灉鐖惰妭鐐逛笉涓烘甯哥姸鎬�,鍒欎笉鍏佽鏂板瀛愯妭鐐�
+ if (!UserConstants.DEPT_NORMAL.equals(info.getStatus())) {
+ throw new ServiceException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
+ }
+ SysDept dept = MapstructUtils.convert(bo, SysDept.class);
+ dept.setAncestors(info.getAncestors() + StringUtils.SEPARATOR + dept.getParentId());
+ return baseMapper.insert(dept);
+ }
+
+ /**
+ * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+ *
+ * @param bo 閮ㄩ棬淇℃伅
+ * @return 缁撴灉
+ */
+ @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#bo.deptId")
+ @Override
+ public int updateDept(SysDeptBo bo) {
+ SysDept dept = MapstructUtils.convert(bo, SysDept.class);
+ SysDept oldDept = baseMapper.selectById(dept.getDeptId());
+ if (!oldDept.getParentId().equals(dept.getParentId())) {
+ // 濡傛灉鏄柊鐖堕儴闂� 鍒欐牎楠屾槸鍚﹀叿鏈夋柊鐖堕儴闂ㄦ潈闄� 閬垮厤瓒婃潈
+ this.checkDeptDataScope(dept.getParentId());
+ SysDept newParentDept = baseMapper.selectById(dept.getParentId());
+ if (ObjectUtil.isNotNull(newParentDept) && ObjectUtil.isNotNull(oldDept)) {
+ String newAncestors = newParentDept.getAncestors() + StringUtils.SEPARATOR + newParentDept.getDeptId();
+ String oldAncestors = oldDept.getAncestors();
+ dept.setAncestors(newAncestors);
+ updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
+ }
+ }
+ int result = baseMapper.updateById(dept);
+ if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()) && StringUtils.isNotEmpty(dept.getAncestors())
+ && !StringUtils.equals(UserConstants.DEPT_NORMAL, dept.getAncestors())) {
+ // 濡傛灉璇ラ儴闂ㄦ槸鍚敤鐘舵�侊紝鍒欏惎鐢ㄨ閮ㄩ棬鐨勬墍鏈変笂绾ч儴闂�
+ updateParentDeptStatusNormal(dept);
+ }
+ return result;
+ }
+
+ /**
+ * 淇敼璇ラ儴闂ㄧ殑鐖剁骇閮ㄩ棬鐘舵��
+ *
+ * @param dept 褰撳墠閮ㄩ棬
+ */
+ private void updateParentDeptStatusNormal(SysDept dept) {
+ String ancestors = dept.getAncestors();
+ Long[] deptIds = Convert.toLongArray(ancestors);
+ baseMapper.update(null, new LambdaUpdateWrapper<SysDept>()
+ .set(SysDept::getStatus, UserConstants.DEPT_NORMAL)
+ .in(SysDept::getDeptId, Arrays.asList(deptIds)));
+ }
+
+ /**
+ * 淇敼瀛愬厓绱犲叧绯�
+ *
+ * @param deptId 琚慨鏀圭殑閮ㄩ棬ID
+ * @param newAncestors 鏂扮殑鐖禝D闆嗗悎
+ * @param oldAncestors 鏃х殑鐖禝D闆嗗悎
+ */
+ private void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors) {
+ List<SysDept> children = baseMapper.selectList(new LambdaQueryWrapper<SysDept>()
+ .apply(DataBaseHelper.findInSet(deptId, "ancestors")));
+ List<SysDept> list = new ArrayList<>();
+ for (SysDept child : children) {
+ SysDept dept = new SysDept();
+ dept.setDeptId(child.getDeptId());
+ dept.setAncestors(child.getAncestors().replaceFirst(oldAncestors, newAncestors));
+ list.add(dept);
+ }
+ if (CollUtil.isNotEmpty(list)) {
+ if (baseMapper.updateBatchById(list)) {
+ list.forEach(dept -> CacheUtils.evict(CacheNames.SYS_DEPT, dept.getDeptId()));
+ }
+ }
+ }
+
+ /**
+ * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+ *
+ * @param deptId 閮ㄩ棬ID
+ * @return 缁撴灉
+ */
+ @CacheEvict(cacheNames = CacheNames.SYS_DEPT, key = "#deptId")
+ @Override
+ public int deleteDeptById(Long deptId) {
+ return baseMapper.deleteById(deptId);
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..c0a62c7
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictDataServiceImpl.java
@@ -0,0 +1,138 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.system.domain.bo.SysDictDataBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.mapper.SysDictDataMapper;
+import org.dromara.system.service.ISysDictDataService;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDictDataServiceImpl implements ISysDictDataService {
+
+ private final SysDictDataMapper baseMapper;
+
+ @Override
+ public TableDataInfo<SysDictDataVo> selectPageDictDataList(SysDictDataBo dictData, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysDictData> lqw = buildQueryWrapper(dictData);
+ Page<SysDictDataVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+ *
+ * @param dictData 瀛楀吀鏁版嵁淇℃伅
+ * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+ */
+ @Override
+ public List<SysDictDataVo> selectDictDataList(SysDictDataBo dictData) {
+ LambdaQueryWrapper<SysDictData> lqw = buildQueryWrapper(dictData);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysDictData> buildQueryWrapper(SysDictDataBo bo) {
+ LambdaQueryWrapper<SysDictData> lqw = Wrappers.lambdaQuery();
+ lqw.eq(bo.getDictSort() != null, SysDictData::getDictSort, bo.getDictSort());
+ lqw.like(StringUtils.isNotBlank(bo.getDictLabel()), SysDictData::getDictLabel, bo.getDictLabel());
+ lqw.eq(StringUtils.isNotBlank(bo.getDictType()), SysDictData::getDictType, bo.getDictType());
+ lqw.orderByAsc(SysDictData::getDictSort);
+ return lqw;
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @param dictValue 瀛楀吀閿��
+ * @return 瀛楀吀鏍囩
+ */
+ @Override
+ public String selectDictLabel(String dictType, String dictValue) {
+ return baseMapper.selectOne(new LambdaQueryWrapper<SysDictData>()
+ .select(SysDictData::getDictLabel)
+ .eq(SysDictData::getDictType, dictType)
+ .eq(SysDictData::getDictValue, dictValue))
+ .getDictLabel();
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+ *
+ * @param dictCode 瀛楀吀鏁版嵁ID
+ * @return 瀛楀吀鏁版嵁
+ */
+ @Override
+ public SysDictDataVo selectDictDataById(Long dictCode) {
+ return baseMapper.selectVoById(dictCode);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param dictCodes 闇�瑕佸垹闄ょ殑瀛楀吀鏁版嵁ID
+ */
+ @Override
+ public void deleteDictDataByIds(Long[] dictCodes) {
+ for (Long dictCode : dictCodes) {
+ SysDictData data = baseMapper.selectById(dictCode);
+ baseMapper.deleteById(dictCode);
+ CacheUtils.evict(CacheNames.SYS_DICT, data.getDictType());
+ }
+ }
+
+ /**
+ * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param bo 瀛楀吀鏁版嵁淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+ @Override
+ public List<SysDictDataVo> insertDictData(SysDictDataBo bo) {
+ SysDictData data = MapstructUtils.convert(bo, SysDictData.class);
+ int row = baseMapper.insert(data);
+ if (row > 0) {
+ return baseMapper.selectDictDataByType(data.getDictType());
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+ /**
+ * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+ *
+ * @param bo 瀛楀吀鏁版嵁淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+ @Override
+ public List<SysDictDataVo> updateDictData(SysDictDataBo bo) {
+ SysDictData data = MapstructUtils.convert(bo, SysDictData.class);
+ int row = baseMapper.updateById(data);
+ if (row > 0) {
+ return baseMapper.selectDictDataByType(data.getDictType());
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..8f958e8
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysDictTypeServiceImpl.java
@@ -0,0 +1,206 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.redis.utils.CacheUtils;
+import org.dromara.system.domain.SysDictData;
+import org.dromara.system.domain.SysDictType;
+import org.dromara.system.domain.bo.SysDictTypeBo;
+import org.dromara.system.domain.vo.SysDictDataVo;
+import org.dromara.system.domain.vo.SysDictTypeVo;
+import org.dromara.system.mapper.SysDictDataMapper;
+import org.dromara.system.mapper.SysDictTypeMapper;
+import org.dromara.system.service.ISysDictTypeService;
+import org.springframework.cache.annotation.CachePut;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysDictTypeServiceImpl implements ISysDictTypeService {
+
+ private final SysDictTypeMapper baseMapper;
+ private final SysDictDataMapper dictDataMapper;
+
+ @Override
+ public TableDataInfo<SysDictTypeVo> selectPageDictTypeList(SysDictTypeBo dictType, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysDictType> lqw = buildQueryWrapper(dictType);
+ Page<SysDictTypeVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+ *
+ * @param dictType 瀛楀吀绫诲瀷淇℃伅
+ * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+ */
+ @Override
+ public List<SysDictTypeVo> selectDictTypeList(SysDictTypeBo dictType) {
+ LambdaQueryWrapper<SysDictType> lqw = buildQueryWrapper(dictType);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysDictType> buildQueryWrapper(SysDictTypeBo bo) {
+ Map<String, Object> params = bo.getParams();
+ LambdaQueryWrapper<SysDictType> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getDictName()), SysDictType::getDictName, bo.getDictName());
+ lqw.like(StringUtils.isNotBlank(bo.getDictType()), SysDictType::getDictType, bo.getDictType());
+ lqw.between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysDictType::getCreateTime, params.get("beginTime"), params.get("endTime"));
+ lqw.orderByAsc(SysDictType::getDictId);
+ return lqw;
+ }
+
+ /**
+ * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+ *
+ * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+ */
+ @Override
+ public List<SysDictTypeVo> selectDictTypeAll() {
+ return baseMapper.selectVoList();
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+ */
+ @Cacheable(cacheNames = CacheNames.SYS_DICT, key = "#dictType")
+ @Override
+ public List<SysDictDataVo> selectDictDataByType(String dictType) {
+ List<SysDictDataVo> dictDatas = dictDataMapper.selectDictDataByType(dictType);
+ if (CollUtil.isNotEmpty(dictDatas)) {
+ return dictDatas;
+ }
+ return null;
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+ *
+ * @param dictId 瀛楀吀绫诲瀷ID
+ * @return 瀛楀吀绫诲瀷
+ */
+ @Override
+ public SysDictTypeVo selectDictTypeById(Long dictId) {
+ return baseMapper.selectVoById(dictId);
+ }
+
+ /**
+ * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 瀛楀吀绫诲瀷
+ */
+ @Override
+ public SysDictTypeVo selectDictTypeByType(String dictType) {
+ return baseMapper.selectVoOne(new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getDictType, dictType));
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎瀛楀吀绫诲瀷淇℃伅
+ *
+ * @param dictIds 闇�瑕佸垹闄ょ殑瀛楀吀ID
+ */
+ @Override
+ public void deleteDictTypeByIds(Long[] dictIds) {
+ for (Long dictId : dictIds) {
+ SysDictType dictType = baseMapper.selectById(dictId);
+ if (dictDataMapper.exists(new LambdaQueryWrapper<SysDictData>()
+ .eq(SysDictData::getDictType, dictType.getDictType()))) {
+ throw new ServiceException(String.format("%1$s宸插垎閰�,涓嶈兘鍒犻櫎", dictType.getDictName()));
+ }
+ CacheUtils.evict(CacheNames.SYS_DICT, dictType.getDictType());
+ }
+ baseMapper.deleteBatchIds(Arrays.asList(dictIds));
+ }
+
+ /**
+ * 閲嶇疆瀛楀吀缂撳瓨鏁版嵁
+ */
+ @Override
+ public void resetDictCache() {
+ CacheUtils.clear(CacheNames.SYS_DICT);
+ }
+
+ /**
+ * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+ *
+ * @param bo 瀛楀吀绫诲瀷淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+ @Override
+ public List<SysDictDataVo> insertDictType(SysDictTypeBo bo) {
+ SysDictType dict = MapstructUtils.convert(bo, SysDictType.class);
+ int row = baseMapper.insert(dict);
+ if (row > 0) {
+ // 鏂板 type 涓嬫棤 data 鏁版嵁 杩斿洖绌洪槻姝㈢紦瀛樼┛閫�
+ return new ArrayList<>();
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+ /**
+ * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+ *
+ * @param bo 瀛楀吀绫诲瀷淇℃伅
+ * @return 缁撴灉
+ */
+ @CachePut(cacheNames = CacheNames.SYS_DICT, key = "#bo.dictType")
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public List<SysDictDataVo> updateDictType(SysDictTypeBo bo) {
+ SysDictType dict = MapstructUtils.convert(bo, SysDictType.class);
+ SysDictType oldDict = baseMapper.selectById(dict.getDictId());
+ dictDataMapper.update(null, new LambdaUpdateWrapper<SysDictData>()
+ .set(SysDictData::getDictType, dict.getDictType())
+ .eq(SysDictData::getDictType, oldDict.getDictType()));
+ int row = baseMapper.updateById(dict);
+ if (row > 0) {
+ CacheUtils.evict(CacheNames.SYS_DICT, oldDict.getDictType());
+ return dictDataMapper.selectDictDataByType(dict.getDictType());
+ }
+ throw new ServiceException("鎿嶄綔澶辫触");
+ }
+
+ /**
+ * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+ *
+ * @param dictType 瀛楀吀绫诲瀷
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkDictTypeUnique(SysDictTypeBo dictType) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysDictType>()
+ .eq(SysDictType::getDictType, dictType.getDictType())
+ .ne(ObjectUtil.isNotNull(dictType.getDictId()), SysDictType::getDictId, dictType.getDictId()));
+ return !exist;
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
new file mode 100644
index 0000000..ebea956
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysLogininforServiceImpl.java
@@ -0,0 +1,108 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysLogininfor;
+import org.dromara.system.domain.bo.SysLogininforBo;
+import org.dromara.system.domain.vo.SysLogininforVo;
+import org.dromara.system.mapper.SysLogininforMapper;
+import org.dromara.system.service.ISysLogininforService;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Slf4j
+@Service
+public class SysLogininforServiceImpl implements ISysLogininforService {
+
+ private final SysLogininforMapper baseMapper;
+
+
+ private String getBlock(Object msg) {
+ if (msg == null) {
+ msg = "";
+ }
+ return "[" + msg.toString() + "]";
+ }
+
+ @Override
+ public TableDataInfo<SysLogininforVo> selectPageLogininforList(SysLogininforBo logininfor, PageQuery pageQuery) {
+ Map<String, Object> params = logininfor.getParams();
+ LambdaQueryWrapper<SysLogininfor> lqw = new LambdaQueryWrapper<SysLogininfor>()
+ .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
+ .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
+ .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"));
+ if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
+ pageQuery.setOrderByColumn("info_id");
+ pageQuery.setIsAsc("desc");
+ }
+ Page<SysLogininforVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏂板绯荤粺鐧诲綍鏃ュ織
+ *
+ * @param bo 璁块棶鏃ュ織瀵硅薄
+ */
+ @Override
+ public void insertLogininfor(SysLogininforBo bo) {
+ SysLogininfor logininfor = MapstructUtils.convert(bo, SysLogininfor.class);
+ logininfor.setLoginTime(new Date());
+ baseMapper.insert(logininfor);
+ }
+
+ /**
+ * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+ *
+ * @param logininfor 璁块棶鏃ュ織瀵硅薄
+ * @return 鐧诲綍璁板綍闆嗗悎
+ */
+ @Override
+ public List<SysLogininforVo> selectLogininforList(SysLogininforBo logininfor) {
+ Map<String, Object> params = logininfor.getParams();
+ return baseMapper.selectVoList(new LambdaQueryWrapper<SysLogininfor>()
+ .like(StringUtils.isNotBlank(logininfor.getIpaddr()), SysLogininfor::getIpaddr, logininfor.getIpaddr())
+ .eq(StringUtils.isNotBlank(logininfor.getStatus()), SysLogininfor::getStatus, logininfor.getStatus())
+ .like(StringUtils.isNotBlank(logininfor.getUserName()), SysLogininfor::getUserName, logininfor.getUserName())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysLogininfor::getLoginTime, params.get("beginTime"), params.get("endTime"))
+ .orderByDesc(SysLogininfor::getInfoId));
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+ *
+ * @param infoIds 闇�瑕佸垹闄ょ殑鐧诲綍鏃ュ織ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteLogininforByIds(Long[] infoIds) {
+ return baseMapper.deleteBatchIds(Arrays.asList(infoIds));
+ }
+
+ /**
+ * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+ */
+ @Override
+ public void cleanLogininfor() {
+ baseMapper.delete(new LambdaQueryWrapper<>());
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..3685e2a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysMenuServiceImpl.java
@@ -0,0 +1,365 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.lang.tree.Tree;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.core.utils.TreeBuildUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysMenu;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysRoleMenu;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.bo.SysMenuBo;
+import org.dromara.system.domain.vo.MetaVo;
+import org.dromara.system.domain.vo.RouterVo;
+import org.dromara.system.domain.vo.SysMenuVo;
+import org.dromara.system.mapper.SysMenuMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysRoleMenuMapper;
+import org.dromara.system.mapper.SysTenantPackageMapper;
+import org.dromara.system.service.ISysMenuService;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+
+/**
+ * 鑿滃崟 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysMenuServiceImpl implements ISysMenuService {
+
+ private final SysMenuMapper baseMapper;
+ private final SysRoleMapper roleMapper;
+ private final SysRoleMenuMapper roleMenuMapper;
+ private final SysTenantPackageMapper tenantPackageMapper;
+
+ /**
+ * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鑿滃崟鍒楄〃
+ */
+ @Override
+ public List<SysMenuVo> selectMenuList(Long userId) {
+ return selectMenuList(new SysMenuBo(), userId);
+ }
+
+ /**
+ * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+ *
+ * @param menu 鑿滃崟淇℃伅
+ * @return 鑿滃崟鍒楄〃
+ */
+ @Override
+ public List<SysMenuVo> selectMenuList(SysMenuBo menu, Long userId) {
+ List<SysMenuVo> menuList;
+ // 绠$悊鍛樻樉绀烘墍鏈夎彍鍗曚俊鎭�
+ if (LoginHelper.isSuperAdmin(userId)) {
+ menuList = baseMapper.selectVoList(new LambdaQueryWrapper<SysMenu>()
+ .like(StringUtils.isNotBlank(menu.getMenuName()), SysMenu::getMenuName, menu.getMenuName())
+ .eq(StringUtils.isNotBlank(menu.getVisible()), SysMenu::getVisible, menu.getVisible())
+ .eq(StringUtils.isNotBlank(menu.getStatus()), SysMenu::getStatus, menu.getStatus())
+ .orderByAsc(SysMenu::getParentId)
+ .orderByAsc(SysMenu::getOrderNum));
+ } else {
+ QueryWrapper<SysMenu> wrapper = Wrappers.query();
+ wrapper.eq("sur.user_id", userId)
+ .like(StringUtils.isNotBlank(menu.getMenuName()), "m.menu_name", menu.getMenuName())
+ .eq(StringUtils.isNotBlank(menu.getVisible()), "m.visible", menu.getVisible())
+ .eq(StringUtils.isNotBlank(menu.getStatus()), "m.status", menu.getStatus())
+ .orderByAsc("m.parent_id")
+ .orderByAsc("m.order_num");
+ List<SysMenu> list = baseMapper.selectMenuListByUserId(wrapper);
+ menuList = MapstructUtils.convert(list, SysMenuVo.class);
+ }
+ return menuList;
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ @Override
+ public Set<String> selectMenuPermsByUserId(Long userId) {
+ List<String> perms = baseMapper.selectMenuPermsByUserId(userId);
+ Set<String> permsSet = new HashSet<>();
+ for (String perm : perms) {
+ if (StringUtils.isNotEmpty(perm)) {
+ permsSet.addAll(StringUtils.splitList(perm.trim()));
+ }
+ }
+ return permsSet;
+ }
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ @Override
+ public Set<String> selectMenuPermsByRoleId(Long roleId) {
+ List<String> perms = baseMapper.selectMenuPermsByRoleId(roleId);
+ Set<String> permsSet = new HashSet<>();
+ for (String perm : perms) {
+ if (StringUtils.isNotEmpty(perm)) {
+ permsSet.addAll(StringUtils.splitList(perm.trim()));
+ }
+ }
+ return permsSet;
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+ *
+ * @param userId 鐢ㄦ埛鍚嶇О
+ * @return 鑿滃崟鍒楄〃
+ */
+ @Override
+ public List<SysMenu> selectMenuTreeByUserId(Long userId) {
+ List<SysMenu> menus;
+ if (LoginHelper.isSuperAdmin(userId)) {
+ menus = baseMapper.selectMenuTreeAll();
+ } else {
+ menus = baseMapper.selectMenuTreeByUserId(userId);
+ }
+ return getChildPerms(menus, 0);
+ }
+
+ /**
+ * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 閫変腑鑿滃崟鍒楄〃
+ */
+ @Override
+ public List<Long> selectMenuListByRoleId(Long roleId) {
+ SysRole role = roleMapper.selectById(roleId);
+ return baseMapper.selectMenuListByRoleId(roleId, role.getMenuCheckStrictly());
+ }
+
+ /**
+ * 鏍规嵁绉熸埛濂楅ID鏌ヨ鑿滃崟鏍戜俊鎭�
+ *
+ * @param packageId 绉熸埛濂楅ID
+ * @return 閫変腑鑿滃崟鍒楄〃
+ */
+ @Override
+ public List<Long> selectMenuListByPackageId(Long packageId) {
+ SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+ List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+ if (CollUtil.isEmpty(menuIds)) {
+ return new ArrayList<>();
+ }
+ List<Long> parentIds = null;
+ if (tenantPackage.getMenuCheckStrictly()) {
+ parentIds = baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
+ .select(SysMenu::getParentId)
+ .in(SysMenu::getMenuId, menuIds), x -> {return Convert.toLong(x);});
+ }
+ return baseMapper.selectObjs(new LambdaQueryWrapper<SysMenu>()
+ .in(SysMenu::getMenuId, menuIds)
+ .notIn(CollUtil.isNotEmpty(parentIds), SysMenu::getMenuId, parentIds), x -> {return Convert.toLong(x);});
+ }
+
+ /**
+ * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+ *
+ * @param menus 鑿滃崟鍒楄〃
+ * @return 璺敱鍒楄〃
+ */
+ @Override
+ public List<RouterVo> buildMenus(List<SysMenu> menus) {
+ List<RouterVo> routers = new LinkedList<>();
+ for (SysMenu menu : menus) {
+ RouterVo router = new RouterVo();
+ router.setHidden("1".equals(menu.getVisible()));
+ router.setName(menu.getRouteName());
+ router.setPath(menu.getRouterPath());
+ router.setComponent(menu.getComponentInfo());
+ router.setQuery(menu.getQueryParam());
+ router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+ List<SysMenu> cMenus = menu.getChildren();
+ if (CollUtil.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType())) {
+ router.setAlwaysShow(true);
+ router.setRedirect("noRedirect");
+ router.setChildren(buildMenus(cMenus));
+ } else if (menu.isMenuFrame()) {
+ router.setMeta(null);
+ List<RouterVo> childrenList = new ArrayList<>();
+ RouterVo children = new RouterVo();
+ children.setPath(menu.getPath());
+ children.setComponent(menu.getComponent());
+ children.setName(StringUtils.capitalize(menu.getPath()));
+ children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+ children.setQuery(menu.getQueryParam());
+ childrenList.add(children);
+ router.setChildren(childrenList);
+ } else if (menu.getParentId().intValue() == 0 && menu.isInnerLink()) {
+ router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+ router.setPath("/");
+ List<RouterVo> childrenList = new ArrayList<>();
+ RouterVo children = new RouterVo();
+ String routerPath = SysMenu.innerLinkReplaceEach(menu.getPath());
+ children.setPath(routerPath);
+ children.setComponent(UserConstants.INNER_LINK);
+ children.setName(StringUtils.capitalize(routerPath));
+ children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
+ childrenList.add(children);
+ router.setChildren(childrenList);
+ }
+ routers.add(router);
+ }
+ return routers;
+ }
+
+ /**
+ * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+ *
+ * @param menus 鑿滃崟鍒楄〃
+ * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+ */
+ @Override
+ public List<Tree<Long>> buildMenuTreeSelect(List<SysMenuVo> menus) {
+ if (CollUtil.isEmpty(menus)) {
+ return CollUtil.newArrayList();
+ }
+ return TreeBuildUtils.build(menus, (menu, tree) ->
+ tree.setId(menu.getMenuId())
+ .setParentId(menu.getParentId())
+ .setName(menu.getMenuName())
+ .setWeight(menu.getOrderNum()));
+ }
+
+ /**
+ * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 鑿滃崟淇℃伅
+ */
+ @Override
+ public SysMenuVo selectMenuById(Long menuId) {
+ return baseMapper.selectVoById(menuId);
+ }
+
+ /**
+ * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean hasChildByMenuId(Long menuId) {
+ return baseMapper.exists(new LambdaQueryWrapper<SysMenu>().eq(SysMenu::getParentId, menuId));
+ }
+
+ /**
+ * 鏌ヨ鑿滃崟浣跨敤鏁伴噺
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkMenuExistRole(Long menuId) {
+ return roleMenuMapper.exists(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getMenuId, menuId));
+ }
+
+ /**
+ * 鏂板淇濆瓨鑿滃崟淇℃伅
+ *
+ * @param bo 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertMenu(SysMenuBo bo) {
+ SysMenu menu = MapstructUtils.convert(bo, SysMenu.class);
+ return baseMapper.insert(menu);
+ }
+
+ /**
+ * 淇敼淇濆瓨鑿滃崟淇℃伅
+ *
+ * @param bo 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateMenu(SysMenuBo bo) {
+ SysMenu menu = MapstructUtils.convert(bo, SysMenu.class);
+ return baseMapper.updateById(menu);
+ }
+
+ /**
+ * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+ *
+ * @param menuId 鑿滃崟ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteMenuById(Long menuId) {
+ return baseMapper.deleteById(menuId);
+ }
+
+ /**
+ * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+ *
+ * @param menu 鑿滃崟淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkMenuNameUnique(SysMenuBo menu) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysMenu>()
+ .eq(SysMenu::getMenuName, menu.getMenuName())
+ .eq(SysMenu::getParentId, menu.getParentId())
+ .ne(ObjectUtil.isNotNull(menu.getMenuId()), SysMenu::getMenuId, menu.getMenuId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍规嵁鐖惰妭鐐圭殑ID鑾峰彇鎵�鏈夊瓙鑺傜偣
+ *
+ * @param list 鍒嗙被琛�
+ * @param parentId 浼犲叆鐨勭埗鑺傜偣ID
+ * @return String
+ */
+ private List<SysMenu> getChildPerms(List<SysMenu> list, int parentId) {
+ List<SysMenu> returnList = new ArrayList<>();
+ for (SysMenu t : list) {
+ // 涓�銆佹牴鎹紶鍏ョ殑鏌愪釜鐖惰妭鐐笽D,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+ if (t.getParentId() == parentId) {
+ recursionFn(list, t);
+ returnList.add(t);
+ }
+ }
+ return returnList;
+ }
+
+ /**
+ * 閫掑綊鍒楄〃
+ */
+ private void recursionFn(List<SysMenu> list, SysMenu t) {
+ // 寰楀埌瀛愯妭鐐瑰垪琛�
+ List<SysMenu> childList = StreamUtils.filter(list, n -> n.getParentId().equals(t.getMenuId()));
+ t.setChildren(childList);
+ for (SysMenu tChild : childList) {
+ // 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+ if (list.stream().anyMatch(n -> n.getParentId().equals(tChild.getMenuId()))) {
+ recursionFn(list, tChild);
+ }
+ }
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
new file mode 100644
index 0000000..87f0dd2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysNoticeServiceImpl.java
@@ -0,0 +1,123 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysNotice;
+import org.dromara.system.domain.bo.SysNoticeBo;
+import org.dromara.system.domain.vo.SysNoticeVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.SysNoticeMapper;
+import org.dromara.system.mapper.SysUserMapper;
+import org.dromara.system.service.ISysNoticeService;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 鍏憡 鏈嶅姟灞傚疄鐜�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysNoticeServiceImpl implements ISysNoticeService {
+
+ private final SysNoticeMapper baseMapper;
+ private final SysUserMapper userMapper;
+
+ @Override
+ public TableDataInfo<SysNoticeVo> selectPageNoticeList(SysNoticeBo notice, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);
+ Page<SysNoticeVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏌ヨ鍏憡淇℃伅
+ *
+ * @param noticeId 鍏憡ID
+ * @return 鍏憡淇℃伅
+ */
+ @Override
+ public SysNoticeVo selectNoticeById(Long noticeId) {
+ return baseMapper.selectVoById(noticeId);
+ }
+
+ /**
+ * 鏌ヨ鍏憡鍒楄〃
+ *
+ * @param notice 鍏憡淇℃伅
+ * @return 鍏憡闆嗗悎
+ */
+ @Override
+ public List<SysNoticeVo> selectNoticeList(SysNoticeBo notice) {
+ LambdaQueryWrapper<SysNotice> lqw = buildQueryWrapper(notice);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysNotice> buildQueryWrapper(SysNoticeBo bo) {
+ LambdaQueryWrapper<SysNotice> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getNoticeTitle()), SysNotice::getNoticeTitle, bo.getNoticeTitle());
+ lqw.eq(StringUtils.isNotBlank(bo.getNoticeType()), SysNotice::getNoticeType, bo.getNoticeType());
+ if (StringUtils.isNotBlank(bo.getCreateByName())) {
+ SysUserVo sysUser = userMapper.selectUserByUserName(bo.getCreateByName());
+ lqw.eq(SysNotice::getCreateBy, ObjectUtil.isNotNull(sysUser) ? sysUser.getUserId() : null);
+ }
+ lqw.orderByAsc(SysNotice::getNoticeId);
+ return lqw;
+ }
+
+ /**
+ * 鏂板鍏憡
+ *
+ * @param bo 鍏憡淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertNotice(SysNoticeBo bo) {
+ SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);
+ return baseMapper.insert(notice);
+ }
+
+ /**
+ * 淇敼鍏憡
+ *
+ * @param bo 鍏憡淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateNotice(SysNoticeBo bo) {
+ SysNotice notice = MapstructUtils.convert(bo, SysNotice.class);
+ return baseMapper.updateById(notice);
+ }
+
+ /**
+ * 鍒犻櫎鍏憡瀵硅薄
+ *
+ * @param noticeId 鍏憡ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteNoticeById(Long noticeId) {
+ return baseMapper.deleteById(noticeId);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎鍏憡淇℃伅
+ *
+ * @param noticeIds 闇�瑕佸垹闄ょ殑鍏憡ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteNoticeByIds(Long[] noticeIds) {
+ return baseMapper.deleteBatchIds(Arrays.asList(noticeIds));
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
new file mode 100644
index 0000000..ce9ab23
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysOperLogServiceImpl.java
@@ -0,0 +1,129 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ArrayUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysOperLog;
+import org.dromara.system.domain.bo.SysOperLogBo;
+import org.dromara.system.domain.vo.SysOperLogVo;
+import org.dromara.system.mapper.SysOperLogMapper;
+import org.dromara.system.service.ISysOperLogService;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysOperLogServiceImpl implements ISysOperLogService {
+
+ private final SysOperLogMapper baseMapper;
+
+
+ @Override
+ public TableDataInfo<SysOperLogVo> selectPageOperLogList(SysOperLogBo operLog, PageQuery pageQuery) {
+ Map<String, Object> params = operLog.getParams();
+ LambdaQueryWrapper<SysOperLog> lqw = new LambdaQueryWrapper<SysOperLog>()
+ .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
+ .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
+ .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
+ SysOperLog::getBusinessType, operLog.getBusinessType())
+ .func(f -> {
+ if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
+ f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
+ }
+ })
+ .eq(operLog.getStatus() != null,
+ SysOperLog::getStatus, operLog.getStatus())
+ .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"));
+ if (StringUtils.isBlank(pageQuery.getOrderByColumn())) {
+ pageQuery.setOrderByColumn("oper_id");
+ pageQuery.setIsAsc("desc");
+ }
+ Page<SysOperLogVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏂板鎿嶄綔鏃ュ織
+ *
+ * @param bo 鎿嶄綔鏃ュ織瀵硅薄
+ */
+ @Override
+ public void insertOperlog(SysOperLogBo bo) {
+ SysOperLog operLog = MapstructUtils.convert(bo, SysOperLog.class);
+ operLog.setOperTime(new Date());
+ baseMapper.insert(operLog);
+ }
+
+ /**
+ * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+ *
+ * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+ * @return 鎿嶄綔鏃ュ織闆嗗悎
+ */
+ @Override
+ public List<SysOperLogVo> selectOperLogList(SysOperLogBo operLog) {
+ Map<String, Object> params = operLog.getParams();
+ return baseMapper.selectVoList(new LambdaQueryWrapper<SysOperLog>()
+ .like(StringUtils.isNotBlank(operLog.getOperIp()), SysOperLog::getOperIp, operLog.getOperIp())
+ .like(StringUtils.isNotBlank(operLog.getTitle()), SysOperLog::getTitle, operLog.getTitle())
+ .eq(operLog.getBusinessType() != null && operLog.getBusinessType() > 0,
+ SysOperLog::getBusinessType, operLog.getBusinessType())
+ .func(f -> {
+ if (ArrayUtil.isNotEmpty(operLog.getBusinessTypes())) {
+ f.in(SysOperLog::getBusinessType, Arrays.asList(operLog.getBusinessTypes()));
+ }
+ })
+ .eq(operLog.getStatus() != null && operLog.getStatus() > 0,
+ SysOperLog::getStatus, operLog.getStatus())
+ .like(StringUtils.isNotBlank(operLog.getOperName()), SysOperLog::getOperName, operLog.getOperName())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ SysOperLog::getOperTime, params.get("beginTime"), params.get("endTime"))
+ .orderByDesc(SysOperLog::getOperId));
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+ *
+ * @param operIds 闇�瑕佸垹闄ょ殑鎿嶄綔鏃ュ織ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteOperLogByIds(Long[] operIds) {
+ return baseMapper.deleteBatchIds(Arrays.asList(operIds));
+ }
+
+ /**
+ * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+ *
+ * @param operId 鎿嶄綔ID
+ * @return 鎿嶄綔鏃ュ織瀵硅薄
+ */
+ @Override
+ public SysOperLogVo selectOperLogById(Long operId) {
+ return baseMapper.selectVoById(operId);
+ }
+
+ /**
+ * 娓呯┖鎿嶄綔鏃ュ織
+ */
+ @Override
+ public void cleanOperLog() {
+ baseMapper.delete(new LambdaQueryWrapper<>());
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java
new file mode 100644
index 0000000..7ccae4b
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPermissionServiceImpl.java
@@ -0,0 +1,61 @@
+package org.dromara.system.service.impl;
+
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.service.ISysMenuService;
+import org.dromara.system.service.ISysPermissionService;
+import org.dromara.system.service.ISysRoleService;
+import org.springframework.stereotype.Service;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 鐢ㄦ埛鏉冮檺澶勭悊
+ *
+ * @author ruoyi
+ */
+@RequiredArgsConstructor
+@Service
+public class SysPermissionServiceImpl implements ISysPermissionService {
+
+ private final ISysRoleService roleService;
+ private final ISysMenuService menuService;
+
+ /**
+ * 鑾峰彇瑙掕壊鏁版嵁鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛id
+ * @return 瑙掕壊鏉冮檺淇℃伅
+ */
+ @Override
+ public Set<String> getRolePermission(Long userId) {
+ Set<String> roles = new HashSet<>();
+ // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+ if (LoginHelper.isSuperAdmin(userId)) {
+ roles.add(TenantConstants.SUPER_ADMIN_ROLE_KEY);
+ } else {
+ roles.addAll(roleService.selectRolePermissionByUserId(userId));
+ }
+ return roles;
+ }
+
+ /**
+ * 鑾峰彇鑿滃崟鏁版嵁鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛id
+ * @return 鑿滃崟鏉冮檺淇℃伅
+ */
+ @Override
+ public Set<String> getMenuPermission(Long userId) {
+ Set<String> perms = new HashSet<>();
+ // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+ if (LoginHelper.isSuperAdmin(userId)) {
+ perms.add("*:*:*");
+ } else {
+ perms.addAll(menuService.selectMenuPermsByUserId(userId));
+ }
+ return perms;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
new file mode 100644
index 0000000..1c65a48
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysPostServiceImpl.java
@@ -0,0 +1,188 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysPost;
+import org.dromara.system.domain.SysUserPost;
+import org.dromara.system.domain.bo.SysPostBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.mapper.SysPostMapper;
+import org.dromara.system.mapper.SysUserPostMapper;
+import org.dromara.system.service.ISysPostService;
+import org.springframework.stereotype.Service;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysPostServiceImpl implements ISysPostService {
+
+ private final SysPostMapper baseMapper;
+ private final SysUserPostMapper userPostMapper;
+
+ @Override
+ public TableDataInfo<SysPostVo> selectPagePostList(SysPostBo post, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysPost> lqw = buildQueryWrapper(post);
+ Page<SysPostVo> page = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 宀椾綅淇℃伅闆嗗悎
+ */
+ @Override
+ public List<SysPostVo> selectPostList(SysPostBo post) {
+ LambdaQueryWrapper<SysPost> lqw = buildQueryWrapper(post);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysPost> buildQueryWrapper(SysPostBo bo) {
+ LambdaQueryWrapper<SysPost> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getPostCode()), SysPost::getPostCode, bo.getPostCode());
+ lqw.like(StringUtils.isNotBlank(bo.getPostName()), SysPost::getPostName, bo.getPostName());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysPost::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysPost::getPostSort);
+ return lqw;
+ }
+
+ /**
+ * 鏌ヨ鎵�鏈夊矖浣�
+ *
+ * @return 宀椾綅鍒楄〃
+ */
+ @Override
+ public List<SysPostVo> selectPostAll() {
+ return baseMapper.selectVoList(new QueryWrapper<>());
+ }
+
+ /**
+ * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+ *
+ * @param postId 宀椾綅ID
+ * @return 瑙掕壊瀵硅薄淇℃伅
+ */
+ @Override
+ public SysPostVo selectPostById(Long postId) {
+ return baseMapper.selectVoById(postId);
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑宀椾綅ID鍒楄〃
+ */
+ @Override
+ public List<Long> selectPostListByUserId(Long userId) {
+ return baseMapper.selectPostListByUserId(userId);
+ }
+
+ /**
+ * 鏍¢獙宀椾綅鍚嶇О鏄惁鍞竴
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkPostNameUnique(SysPostBo post) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysPost>()
+ .eq(SysPost::getPostName, post.getPostName())
+ .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙宀椾綅缂栫爜鏄惁鍞竴
+ *
+ * @param post 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkPostCodeUnique(SysPostBo post) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysPost>()
+ .eq(SysPost::getPostCode, post.getPostCode())
+ .ne(ObjectUtil.isNotNull(post.getPostId()), SysPost::getPostId, post.getPostId()));
+ return !exist;
+ }
+
+ /**
+ * 閫氳繃宀椾綅ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+ *
+ * @param postId 宀椾綅ID
+ * @return 缁撴灉
+ */
+ @Override
+ public long countUserPostById(Long postId) {
+ return userPostMapper.selectCount(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getPostId, postId));
+ }
+
+ /**
+ * 鍒犻櫎宀椾綅淇℃伅
+ *
+ * @param postId 宀椾綅ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deletePostById(Long postId) {
+ return baseMapper.deleteById(postId);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎宀椾綅淇℃伅
+ *
+ * @param postIds 闇�瑕佸垹闄ょ殑宀椾綅ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deletePostByIds(Long[] postIds) {
+ for (Long postId : postIds) {
+ SysPost post = baseMapper.selectById(postId);
+ if (countUserPostById(postId) > 0) {
+ throw new ServiceException(String.format("%1$s宸插垎閰嶏紝涓嶈兘鍒犻櫎!", post.getPostName()));
+ }
+ }
+ return baseMapper.deleteBatchIds(Arrays.asList(postIds));
+ }
+
+ /**
+ * 鏂板淇濆瓨宀椾綅淇℃伅
+ *
+ * @param bo 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertPost(SysPostBo bo) {
+ SysPost post = MapstructUtils.convert(bo, SysPost.class);
+ return baseMapper.insert(post);
+ }
+
+ /**
+ * 淇敼淇濆瓨宀椾綅淇℃伅
+ *
+ * @param bo 宀椾綅淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int updatePost(SysPostBo bo) {
+ SysPost post = MapstructUtils.convert(bo, SysPost.class);
+ return baseMapper.updateById(post);
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..ad1065d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysRoleServiceImpl.java
@@ -0,0 +1,486 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.stp.StpUtil;
+import cn.hutool.core.bean.BeanUtil;
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.api.model.LoginUser;
+import org.dromara.system.domain.SysRole;
+import org.dromara.system.domain.SysRoleDept;
+import org.dromara.system.domain.SysRoleMenu;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysRoleBo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.mapper.SysRoleDeptMapper;
+import org.dromara.system.mapper.SysRoleMapper;
+import org.dromara.system.mapper.SysRoleMenuMapper;
+import org.dromara.system.mapper.SysUserRoleMapper;
+import org.dromara.system.service.ISysRoleService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.*;
+
+/**
+ * 瑙掕壊 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@RequiredArgsConstructor
+@Service
+public class SysRoleServiceImpl implements ISysRoleService {
+
+ private final SysRoleMapper baseMapper;
+ private final SysRoleMenuMapper roleMenuMapper;
+ private final SysUserRoleMapper userRoleMapper;
+ private final SysRoleDeptMapper roleDeptMapper;
+
+ @Override
+ public TableDataInfo<SysRoleVo> selectPageRoleList(SysRoleBo role, PageQuery pageQuery) {
+ Page<SysRoleVo> page = baseMapper.selectPageRoleList(pageQuery.build(), this.buildQueryWrapper(role));
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+ */
+ @Override
+ public List<SysRoleVo> selectRoleList(SysRoleBo role) {
+ return baseMapper.selectRoleList(this.buildQueryWrapper(role));
+ }
+
+ private Wrapper<SysRole> buildQueryWrapper(SysRoleBo bo) {
+ Map<String, Object> params = bo.getParams();
+ QueryWrapper<SysRole> wrapper = Wrappers.query();
+ wrapper.eq("r.del_flag", UserConstants.ROLE_NORMAL)
+ .eq(ObjectUtil.isNotNull(bo.getRoleId()), "r.role_id", bo.getRoleId())
+ .like(StringUtils.isNotBlank(bo.getRoleName()), "r.role_name", bo.getRoleName())
+ .eq(StringUtils.isNotBlank(bo.getStatus()), "r.status", bo.getStatus())
+ .like(StringUtils.isNotBlank(bo.getRoleKey()), "r.role_key", bo.getRoleKey())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ "r.create_time", params.get("beginTime"), params.get("endTime"))
+ .orderByAsc("r.role_sort").orderByAsc("r.create_time");;
+ return wrapper;
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 瑙掕壊鍒楄〃
+ */
+ @Override
+ public List<SysRoleVo> selectRolesByUserId(Long userId) {
+ List<SysRoleVo> userRoles = baseMapper.selectRolePermissionByUserId(userId);
+ List<SysRoleVo> roles = selectRoleAll();
+ for (SysRoleVo role : roles) {
+ for (SysRoleVo userRole : userRoles) {
+ if (role.getRoleId().longValue() == userRole.getRoleId().longValue()) {
+ role.setFlag(true);
+ break;
+ }
+ }
+ }
+ return roles;
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鏉冮檺鍒楄〃
+ */
+ @Override
+ public Set<String> selectRolePermissionByUserId(Long userId) {
+ List<SysRoleVo> perms = baseMapper.selectRolePermissionByUserId(userId);
+ Set<String> permsSet = new HashSet<>();
+ for (SysRoleVo perm : perms) {
+ if (ObjectUtil.isNotNull(perm)) {
+ permsSet.addAll(StringUtils.splitList(perm.getRoleKey().trim()));
+ }
+ }
+ return permsSet;
+ }
+
+ /**
+ * 鏌ヨ鎵�鏈夎鑹�
+ *
+ * @return 瑙掕壊鍒楄〃
+ */
+ @Override
+ public List<SysRoleVo> selectRoleAll() {
+ return this.selectRoleList(new SysRoleBo());
+ }
+
+ /**
+ * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 閫変腑瑙掕壊ID鍒楄〃
+ */
+ @Override
+ public List<Long> selectRoleListByUserId(Long userId) {
+ return baseMapper.selectRoleListByUserId(userId);
+ }
+
+ /**
+ * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 瑙掕壊瀵硅薄淇℃伅
+ */
+ @Override
+ public SysRoleVo selectRoleById(Long roleId) {
+ return baseMapper.selectRoleById(roleId);
+ }
+
+ /**
+ * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkRoleNameUnique(SysRoleBo role) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysRole>()
+ .eq(SysRole::getRoleName, role.getRoleName())
+ .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+ *
+ * @param role 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkRoleKeyUnique(SysRoleBo role) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysRole>()
+ .eq(SysRole::getRoleKey, role.getRoleKey())
+ .ne(ObjectUtil.isNotNull(role.getRoleId()), SysRole::getRoleId, role.getRoleId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+ *
+ * @param role 瑙掕壊淇℃伅
+ */
+ @Override
+ public void checkRoleAllowed(SysRoleBo role) {
+ if (ObjectUtil.isNotNull(role.getRoleId()) && LoginHelper.isSuperAdmin(role.getRoleId())) {
+ throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
+ }
+ String[] keys = new String[]{TenantConstants.SUPER_ADMIN_ROLE_KEY, TenantConstants.TENANT_ADMIN_ROLE_KEY};
+ // 鏂板涓嶅厑璁镐娇鐢� 绠$悊鍛樻爣璇嗙
+ if (ObjectUtil.isNull(role.getRoleId())
+ && StringUtils.equalsAny(role.getRoleKey(), keys)) {
+ throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+ }
+ // 淇敼涓嶅厑璁镐慨鏀� 绠$悊鍛樻爣璇嗙
+ if (ObjectUtil.isNotNull(role.getRoleId())) {
+ SysRole sysRole = baseMapper.selectById(role.getRoleId());
+ // 濡傛灉鏍囪瘑绗︿笉鐩哥瓑 鍒ゆ柇涓轰慨鏀逛簡绠$悊鍛樻爣璇嗙
+ if (!StringUtils.equals(sysRole.getRoleKey(), role.getRoleKey())) {
+ if (StringUtils.equalsAny(sysRole.getRoleKey(), keys)) {
+ throw new ServiceException("涓嶅厑璁镐慨鏀圭郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+ } else if (StringUtils.equalsAny(role.getRoleKey(), keys)) {
+ throw new ServiceException("涓嶅厑璁镐娇鐢ㄧ郴缁熷唴缃鐞嗗憳瑙掕壊鏍囪瘑绗�!");
+ }
+ }
+ }
+ }
+
+ /**
+ * 鏍¢獙瑙掕壊鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param roleId 瑙掕壊id
+ */
+ @Override
+ public void checkRoleDataScope(Long roleId) {
+ if (ObjectUtil.isNull(roleId)) {
+ return;
+ }
+ if (LoginHelper.isSuperAdmin()) {
+ return;
+ }
+ List<SysRoleVo> roles = this.selectRoleList(new SysRoleBo(roleId));
+ if (CollUtil.isEmpty(roles)) {
+ throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鏁版嵁锛�");
+ }
+
+ }
+
+ /**
+ * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 缁撴灉
+ */
+ @Override
+ public long countUserRoleByRoleId(Long roleId) {
+ return userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
+ }
+
+ /**
+ * 鏂板淇濆瓨瑙掕壊淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int insertRole(SysRoleBo bo) {
+ SysRole role = MapstructUtils.convert(bo, SysRole.class);
+ // 鏂板瑙掕壊淇℃伅
+ baseMapper.insert(role);
+ bo.setRoleId(role.getRoleId());
+ return insertRoleMenu(bo);
+ }
+
+ /**
+ * 淇敼淇濆瓨瑙掕壊淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int updateRole(SysRoleBo bo) {
+ SysRole role = MapstructUtils.convert(bo, SysRole.class);
+ // 淇敼瑙掕壊淇℃伅
+ baseMapper.updateById(role);
+ // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+ roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, role.getRoleId()));
+ return insertRoleMenu(bo);
+ }
+
+ /**
+ * 淇敼瑙掕壊鐘舵��
+ *
+ * @param roleId 瑙掕壊ID
+ * @param status 瑙掕壊鐘舵��
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateRoleStatus(Long roleId, String status) {
+ if (UserConstants.ROLE_DISABLE.equals(status) && this.countUserRoleByRoleId(roleId) > 0) {
+ throw new ServiceException("瑙掕壊宸插垎閰嶏紝涓嶈兘绂佺敤!");
+ }
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysRole>()
+ .set(SysRole::getStatus, status)
+ .eq(SysRole::getRoleId, roleId));
+ }
+
+ /**
+ * 淇敼鏁版嵁鏉冮檺淇℃伅
+ *
+ * @param bo 瑙掕壊淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int authDataScope(SysRoleBo bo) {
+ SysRole role = MapstructUtils.convert(bo, SysRole.class);
+ // 淇敼瑙掕壊淇℃伅
+ baseMapper.updateById(role);
+ // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+ roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, role.getRoleId()));
+ // 鏂板瑙掕壊鍜岄儴闂ㄤ俊鎭紙鏁版嵁鏉冮檺锛�
+ return insertRoleDept(bo);
+ }
+
+ /**
+ * 鏂板瑙掕壊鑿滃崟淇℃伅
+ *
+ * @param role 瑙掕壊瀵硅薄
+ */
+ private int insertRoleMenu(SysRoleBo role) {
+ int rows = 1;
+ // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+ List<SysRoleMenu> list = new ArrayList<SysRoleMenu>();
+ for (Long menuId : role.getMenuIds()) {
+ SysRoleMenu rm = new SysRoleMenu();
+ rm.setRoleId(role.getRoleId());
+ rm.setMenuId(menuId);
+ list.add(rm);
+ }
+ if (list.size() > 0) {
+ rows = roleMenuMapper.insertBatch(list) ? list.size() : 0;
+ }
+ return rows;
+ }
+
+ /**
+ * 鏂板瑙掕壊閮ㄩ棬淇℃伅(鏁版嵁鏉冮檺)
+ *
+ * @param role 瑙掕壊瀵硅薄
+ */
+ private int insertRoleDept(SysRoleBo role) {
+ int rows = 1;
+ // 鏂板瑙掕壊涓庨儴闂紙鏁版嵁鏉冮檺锛夌鐞�
+ List<SysRoleDept> list = new ArrayList<SysRoleDept>();
+ for (Long deptId : role.getDeptIds()) {
+ SysRoleDept rd = new SysRoleDept();
+ rd.setRoleId(role.getRoleId());
+ rd.setDeptId(deptId);
+ list.add(rd);
+ }
+ if (list.size() > 0) {
+ rows = roleDeptMapper.insertBatch(list) ? list.size() : 0;
+ }
+ return rows;
+ }
+
+ /**
+ * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteRoleById(Long roleId) {
+ // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+ roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, roleId));
+ // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+ roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().eq(SysRoleDept::getRoleId, roleId));
+ return baseMapper.deleteById(roleId);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎瑙掕壊淇℃伅
+ *
+ * @param roleIds 闇�瑕佸垹闄ょ殑瑙掕壊ID
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteRoleByIds(Long[] roleIds) {
+ for (Long roleId : roleIds) {
+ SysRole role = baseMapper.selectById(roleId);
+ checkRoleAllowed(BeanUtil.toBean(role, SysRoleBo.class));
+ checkRoleDataScope(roleId);
+ if (countUserRoleByRoleId(roleId) > 0) {
+ throw new ServiceException(String.format("%1$s宸插垎閰嶏紝涓嶈兘鍒犻櫎!", role.getRoleName()));
+ }
+ }
+ List<Long> ids = Arrays.asList(roleIds);
+ // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+ roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, ids));
+ // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+ roleDeptMapper.delete(new LambdaQueryWrapper<SysRoleDept>().in(SysRoleDept::getRoleId, ids));
+ return baseMapper.deleteBatchIds(ids);
+ }
+
+ /**
+ * 鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteAuthUser(SysUserRole userRole) {
+ int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+ .eq(SysUserRole::getRoleId, userRole.getRoleId())
+ .eq(SysUserRole::getUserId, userRole.getUserId()));
+ if (rows > 0) {
+ cleanOnlineUserByRole(userRole.getRoleId());
+ }
+ return rows;
+ }
+
+ /**
+ * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 闇�瑕佸彇娑堟巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int deleteAuthUsers(Long roleId, Long[] userIds) {
+ int rows = userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>()
+ .eq(SysUserRole::getRoleId, roleId)
+ .in(SysUserRole::getUserId, Arrays.asList(userIds)));
+ if (rows > 0) {
+ cleanOnlineUserByRole(roleId);
+ }
+ return rows;
+ }
+
+ /**
+ * 鎵归噺閫夋嫨鎺堟潈鐢ㄦ埛瑙掕壊
+ *
+ * @param roleId 瑙掕壊ID
+ * @param userIds 闇�瑕佹巿鏉冪殑鐢ㄦ埛鏁版嵁ID
+ * @return 缁撴灉
+ */
+ @Override
+ public int insertAuthUsers(Long roleId, Long[] userIds) {
+ // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+ int rows = 1;
+ List<SysUserRole> list = StreamUtils.toList(List.of(userIds), userId -> {
+ SysUserRole ur = new SysUserRole();
+ ur.setUserId(userId);
+ ur.setRoleId(roleId);
+ return ur;
+ });
+ if (CollUtil.isNotEmpty(list)) {
+ rows = userRoleMapper.insertBatch(list) ? list.size() : 0;
+ }
+ if (rows > 0) {
+ cleanOnlineUserByRole(roleId);
+ }
+ return rows;
+ }
+
+ @Override
+ public void cleanOnlineUserByRole(Long roleId) {
+ // 濡傛灉瑙掕壊鏈粦瀹氱敤鎴� 鐩存帴杩斿洖
+ Long num = userRoleMapper.selectCount(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getRoleId, roleId));
+ if (num == 0) {
+ return;
+ }
+ List<String> keys = StpUtil.searchTokenValue("", 0, -1, false);
+ if (CollUtil.isEmpty(keys)) {
+ return;
+ }
+ // 瑙掕壊鍏宠仈鐨勫湪绾跨敤鎴烽噺杩囧ぇ浼氬鑷磖edis闃诲鍗¢】 璋ㄦ厧鎿嶄綔
+ keys.parallelStream().forEach(key -> {
+ String token = StringUtils.substringAfterLast(key, ":");
+ // 濡傛灉宸茬粡杩囨湡鍒欒烦杩�
+ if (StpUtil.stpLogic.getTokenActiveTimeoutByToken(token) < -1) {
+ return;
+ }
+ LoginUser loginUser = LoginHelper.getLoginUser(token);
+ if (loginUser.getRoles().stream().anyMatch(r -> r.getRoleId().equals(roleId))) {
+ try {
+ StpUtil.logoutByTokenValue(token);
+ } catch (NotLoginException ignored) {
+ }
+ }
+ });
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
new file mode 100644
index 0000000..369ac6a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSensitiveServiceImpl.java
@@ -0,0 +1,47 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.stp.StpUtil;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.common.sensitive.core.SensitiveService;
+import org.dromara.common.tenant.helper.TenantHelper;
+import org.springframework.stereotype.Service;
+
+/**
+ * 鑴辨晱鏈嶅姟
+ * 榛樿绠$悊鍛樹笉杩囨护
+ * 闇�鑷鏍规嵁涓氬姟閲嶅啓瀹炵幇
+ *
+ * @author Lion Li
+ * @version 3.6.0
+ */
+@Service
+public class SysSensitiveServiceImpl implements SensitiveService {
+
+ /**
+ * 鏄惁鑴辨晱
+ */
+ @Override
+ public boolean isSensitive(String roleKey, String perms) {
+ if (!LoginHelper.isLogin()) {
+ return true;
+ }
+ boolean roleExist = StringUtils.isNotEmpty(roleKey);
+ boolean permsExist = StringUtils.isNotEmpty(perms);
+ if (roleExist && permsExist) {
+ if (StpUtil.hasRole(roleKey) && StpUtil.hasPermission(perms)) {
+ return false;
+ }
+ } else if (roleExist && StpUtil.hasRole(roleKey)) {
+ return false;
+ } else if (permsExist && StpUtil.hasPermission(perms)) {
+ return false;
+ }
+
+ if (TenantHelper.isEnable()) {
+ return !LoginHelper.isSuperAdmin() && !LoginHelper.isTenantAdmin();
+ }
+ return !LoginHelper.isSuperAdmin();
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java
new file mode 100644
index 0000000..a35a708
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysSocialServiceImpl.java
@@ -0,0 +1,107 @@
+package org.dromara.system.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.system.domain.SysSocial;
+import org.dromara.system.domain.bo.SysSocialBo;
+import org.dromara.system.domain.vo.SysSocialVo;
+import org.dromara.system.mapper.SysSocialMapper;
+import org.dromara.system.service.ISysSocialService;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 绀句細鍖栧叧绯籗ervice涓氬姟灞傚鐞�
+ *
+ * @author thiszhc
+ * @date 2023-06-12
+ */
+@RequiredArgsConstructor
+@Service
+public class SysSocialServiceImpl implements ISysSocialService {
+
+ private final SysSocialMapper baseMapper;
+
+
+ /**
+ * 鏌ヨ绀句細鍖栧叧绯�
+ */
+ @Override
+ public SysSocialVo queryById(String id) {
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 鎺堟潈鍒楄〃
+ */
+ @Override
+ public List<SysSocialVo> queryList() {
+ return baseMapper.selectVoList();
+ }
+
+ @Override
+ public List<SysSocialVo> queryListByUserId(Long userId) {
+ return baseMapper.selectVoList(new LambdaQueryWrapper<SysSocial>().eq(SysSocial::getUserId, userId));
+ }
+
+
+ /**
+ * 鏂板绀句細鍖栧叧绯�
+ */
+ @Override
+ public Boolean insertByBo(SysSocialBo bo) {
+ SysSocial add = MapstructUtils.convert(bo, SysSocial.class);
+ validEntityBeforeSave(add);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ if (add != null) {
+ bo.setId(add.getId());
+ } else {
+ return false;
+ }
+ }
+ return flag;
+ }
+
+ /**
+ * 鏇存柊绀句細鍖栧叧绯�
+ */
+ @Override
+ public Boolean updateByBo(SysSocialBo bo) {
+ SysSocial update = MapstructUtils.convert(bo, SysSocial.class);
+ validEntityBeforeSave(update);
+ return baseMapper.updateById(update) > 0;
+ }
+
+
+ /**
+ * 淇濆瓨鍓嶇殑鏁版嵁鏍¢獙
+ */
+ private void validEntityBeforeSave(SysSocial entity) {
+ //TODO 鍋氫竴浜涙暟鎹牎楠�,濡傚敮涓�绾︽潫
+ }
+
+
+ /**
+ * 鍒犻櫎绀句細鍖栧叧绯�
+ */
+ @Override
+ public Boolean deleteWithValidById(Long id) {
+ return baseMapper.deleteById(id) > 0;
+ }
+
+
+ /**
+ * 鏍规嵁 authId 鏌ヨ鐢ㄦ埛淇℃伅
+ *
+ * @param authId 璁よ瘉id
+ * @return 鎺堟潈淇℃伅
+ */
+ @Override
+ public List<SysSocialVo> selectByAuthId(String authId) {
+ return baseMapper.selectVoList(new LambdaQueryWrapper<SysSocial>().eq(SysSocial::getAuthId, authId));
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
new file mode 100644
index 0000000..f7f8d46
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantPackageServiceImpl.java
@@ -0,0 +1,145 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.SysTenant;
+import org.dromara.system.domain.SysTenantPackage;
+import org.dromara.system.domain.bo.SysTenantPackageBo;
+import org.dromara.system.domain.vo.SysTenantPackageVo;
+import org.dromara.system.mapper.SysTenantMapper;
+import org.dromara.system.mapper.SysTenantPackageMapper;
+import org.dromara.system.service.ISysTenantPackageService;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * 绉熸埛濂楅Service涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantPackageServiceImpl implements ISysTenantPackageService {
+
+ private final SysTenantPackageMapper baseMapper;
+ private final SysTenantMapper tenantMapper;
+
+ /**
+ * 鏌ヨ绉熸埛濂楅
+ */
+ @Override
+ public SysTenantPackageVo queryById(Long packageId){
+ return baseMapper.selectVoById(packageId);
+ }
+
+ /**
+ * 鏌ヨ绉熸埛濂楅鍒楄〃
+ */
+ @Override
+ public TableDataInfo<SysTenantPackageVo> queryPageList(SysTenantPackageBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
+ Page<SysTenantPackageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ @Override
+ public List<SysTenantPackageVo> selectList() {
+ return baseMapper.selectVoList(new LambdaQueryWrapper<SysTenantPackage>()
+ .eq(SysTenantPackage::getStatus, TenantConstants.NORMAL));
+ }
+
+ /**
+ * 鏌ヨ绉熸埛濂楅鍒楄〃
+ */
+ @Override
+ public List<SysTenantPackageVo> queryList(SysTenantPackageBo bo) {
+ LambdaQueryWrapper<SysTenantPackage> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysTenantPackage> buildQueryWrapper(SysTenantPackageBo bo) {
+ LambdaQueryWrapper<SysTenantPackage> lqw = Wrappers.lambdaQuery();
+ lqw.like(StringUtils.isNotBlank(bo.getPackageName()), SysTenantPackage::getPackageName, bo.getPackageName());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenantPackage::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysTenantPackage::getPackageId);
+ return lqw;
+ }
+
+ /**
+ * 鏂板绉熸埛濂楅
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean insertByBo(SysTenantPackageBo bo) {
+ SysTenantPackage add = MapstructUtils.convert(bo, SysTenantPackage.class);
+ // 淇濆瓨鑿滃崟id
+ List<Long> menuIds = Arrays.asList(bo.getMenuIds());
+ if (CollUtil.isNotEmpty(menuIds)) {
+ add.setMenuIds(StringUtils.join(menuIds, ", "));
+ } else {
+ add.setMenuIds("");
+ }
+ boolean flag = baseMapper.insert(add) > 0;
+ if (flag) {
+ bo.setPackageId(add.getPackageId());
+ }
+ return flag;
+ }
+
+ /**
+ * 淇敼绉熸埛濂楅
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean updateByBo(SysTenantPackageBo bo) {
+ SysTenantPackage update = MapstructUtils.convert(bo, SysTenantPackage.class);
+ // 淇濆瓨鑿滃崟id
+ List<Long> menuIds = Arrays.asList(bo.getMenuIds());
+ if (CollUtil.isNotEmpty(menuIds)) {
+ update.setMenuIds(StringUtils.join(menuIds, ", "));
+ } else {
+ update.setMenuIds("");
+ }
+ return baseMapper.updateById(update) > 0;
+ }
+
+ /**
+ * 淇敼濂楅鐘舵��
+ *
+ * @param bo 濂楅淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int updatePackageStatus(SysTenantPackageBo bo) {
+ SysTenantPackage tenantPackage = MapstructUtils.convert(bo, SysTenantPackage.class);
+ return baseMapper.updateById(tenantPackage);
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎绉熸埛濂楅
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+ if(isValid){
+ boolean exists = tenantMapper.exists(new LambdaQueryWrapper<SysTenant>().in(SysTenant::getPackageId, ids));
+ if (exists) {
+ throw new ServiceException("绉熸埛濂楅宸茶浣跨敤");
+ }
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
new file mode 100644
index 0000000..516149f
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysTenantServiceImpl.java
@@ -0,0 +1,372 @@
+package org.dromara.system.service.impl;
+
+import cn.dev33.satoken.secure.BCrypt;
+import cn.hutool.core.convert.Convert;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.core.util.RandomUtil;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.Constants;
+import org.dromara.common.core.constant.TenantConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.SpringUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.system.domain.*;
+import org.dromara.system.domain.bo.SysTenantBo;
+import org.dromara.system.domain.vo.SysTenantVo;
+import org.dromara.system.mapper.*;
+import org.dromara.system.service.ISysTenantService;
+import org.springframework.cache.annotation.CacheEvict;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 绉熸埛Service涓氬姟灞傚鐞�
+ *
+ * @author Michelle.Chung
+ */
+@RequiredArgsConstructor
+@Service
+public class SysTenantServiceImpl implements ISysTenantService {
+
+ private final SysTenantMapper baseMapper;
+ private final SysTenantPackageMapper tenantPackageMapper;
+ private final SysUserMapper userMapper;
+ private final SysDeptMapper deptMapper;
+ private final SysRoleMapper roleMapper;
+ private final SysRoleMenuMapper roleMenuMapper;
+ private final SysRoleDeptMapper roleDeptMapper;
+ private final SysUserRoleMapper userRoleMapper;
+ private final SysDictTypeMapper dictTypeMapper;
+ private final SysDictDataMapper dictDataMapper;
+ private final SysConfigMapper configMapper;
+
+ /**
+ * 鏌ヨ绉熸埛
+ */
+ @Override
+ public SysTenantVo queryById(Long id) {
+ return baseMapper.selectVoById(id);
+ }
+
+ /**
+ * 鍩轰簬绉熸埛ID鏌ヨ绉熸埛
+ */
+ @Cacheable(cacheNames = CacheNames.SYS_TENANT, key = "#tenantId")
+ @Override
+ public SysTenantVo queryByTenantId(String tenantId) {
+ return baseMapper.selectVoOne(new LambdaQueryWrapper<SysTenant>().eq(SysTenant::getTenantId, tenantId));
+ }
+
+ /**
+ * 鏌ヨ绉熸埛鍒楄〃
+ */
+ @Override
+ public TableDataInfo<SysTenantVo> queryPageList(SysTenantBo bo, PageQuery pageQuery) {
+ LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
+ Page<SysTenantVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
+ return TableDataInfo.build(result);
+ }
+
+ /**
+ * 鏌ヨ绉熸埛鍒楄〃
+ */
+ @Override
+ public List<SysTenantVo> queryList(SysTenantBo bo) {
+ LambdaQueryWrapper<SysTenant> lqw = buildQueryWrapper(bo);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ private LambdaQueryWrapper<SysTenant> buildQueryWrapper(SysTenantBo bo) {
+ LambdaQueryWrapper<SysTenant> lqw = Wrappers.lambdaQuery();
+ lqw.eq(StringUtils.isNotBlank(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId());
+ lqw.like(StringUtils.isNotBlank(bo.getContactUserName()), SysTenant::getContactUserName, bo.getContactUserName());
+ lqw.eq(StringUtils.isNotBlank(bo.getContactPhone()), SysTenant::getContactPhone, bo.getContactPhone());
+ lqw.like(StringUtils.isNotBlank(bo.getCompanyName()), SysTenant::getCompanyName, bo.getCompanyName());
+ lqw.eq(StringUtils.isNotBlank(bo.getLicenseNumber()), SysTenant::getLicenseNumber, bo.getLicenseNumber());
+ lqw.eq(StringUtils.isNotBlank(bo.getAddress()), SysTenant::getAddress, bo.getAddress());
+ lqw.eq(StringUtils.isNotBlank(bo.getIntro()), SysTenant::getIntro, bo.getIntro());
+ lqw.like(StringUtils.isNotBlank(bo.getDomain()), SysTenant::getDomain, bo.getDomain());
+ lqw.eq(bo.getPackageId() != null, SysTenant::getPackageId, bo.getPackageId());
+ lqw.eq(bo.getExpireTime() != null, SysTenant::getExpireTime, bo.getExpireTime());
+ lqw.eq(bo.getAccountCount() != null, SysTenant::getAccountCount, bo.getAccountCount());
+ lqw.eq(StringUtils.isNotBlank(bo.getStatus()), SysTenant::getStatus, bo.getStatus());
+ lqw.orderByAsc(SysTenant::getId);
+ return lqw;
+ }
+
+ /**
+ * 鏂板绉熸埛
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean insertByBo(SysTenantBo bo) {
+ SysTenant add = MapstructUtils.convert(bo, SysTenant.class);
+
+ // 鑾峰彇鎵�鏈夌鎴风紪鍙�
+ List<String> tenantIds = baseMapper.selectObjs(
+ new LambdaQueryWrapper<SysTenant>().select(SysTenant::getTenantId), x -> {return Convert.toStr(x);});
+ String tenantId = generateTenantId(tenantIds);
+ add.setTenantId(tenantId);
+ boolean flag = baseMapper.insert(add) > 0;
+ if (!flag) {
+ throw new ServiceException("鍒涘缓绉熸埛澶辫触");
+ }
+ bo.setId(add.getId());
+
+ // 鏍规嵁濂楅鍒涘缓瑙掕壊
+ Long roleId = createTenantRole(tenantId, bo.getPackageId());
+
+ // 鍒涘缓閮ㄩ棬: 鍏徃鍚嶆槸閮ㄩ棬鍚嶇О
+ SysDept dept = new SysDept();
+ dept.setTenantId(tenantId);
+ dept.setDeptName(bo.getCompanyName());
+ dept.setParentId(Constants.TOP_PARENT_ID);
+ dept.setAncestors(Constants.TOP_PARENT_ID.toString());
+ deptMapper.insert(dept);
+ Long deptId = dept.getDeptId();
+
+ // 瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃
+ SysRoleDept roleDept = new SysRoleDept();
+ roleDept.setRoleId(roleId);
+ roleDept.setDeptId(deptId);
+ roleDeptMapper.insert(roleDept);
+
+ // 鍒涘缓绯荤粺鐢ㄦ埛
+ SysUser user = new SysUser();
+ user.setTenantId(tenantId);
+ user.setUserName(bo.getUsername());
+ user.setNickName(bo.getUsername());
+ user.setPassword(BCrypt.hashpw(bo.getPassword()));
+ user.setDeptId(deptId);
+ userMapper.insert(user);
+ //鏂板绯荤粺鐢ㄦ埛鍚庯紝榛樿褰撳墠鐢ㄦ埛涓洪儴闂ㄧ殑璐熻矗浜�
+ SysDept sd = new SysDept();
+ sd.setLeader(user.getUserId());
+ sd.setDeptId(deptId);
+ deptMapper.updateById(sd);
+
+ // 鐢ㄦ埛鍜岃鑹插叧鑱旇〃
+ SysUserRole userRole = new SysUserRole();
+ userRole.setUserId(user.getUserId());
+ userRole.setRoleId(roleId);
+ userRoleMapper.insert(userRole);
+
+ String defaultTenantId = TenantConstants.DEFAULT_TENANT_ID;
+ List<SysDictType> dictTypeList = dictTypeMapper.selectList(
+ new LambdaQueryWrapper<SysDictType>().eq(SysDictType::getTenantId, defaultTenantId));
+ List<SysDictData> dictDataList = dictDataMapper.selectList(
+ new LambdaQueryWrapper<SysDictData>().eq(SysDictData::getTenantId, defaultTenantId));
+ for (SysDictType dictType : dictTypeList) {
+ dictType.setDictId(null);
+ dictType.setTenantId(tenantId);
+ }
+ for (SysDictData dictData : dictDataList) {
+ dictData.setDictCode(null);
+ dictData.setTenantId(tenantId);
+ }
+ dictTypeMapper.insertBatch(dictTypeList);
+ dictDataMapper.insertBatch(dictDataList);
+
+ List<SysConfig> sysConfigList = configMapper.selectList(
+ new LambdaQueryWrapper<SysConfig>().eq(SysConfig::getTenantId, defaultTenantId));
+ for (SysConfig config : sysConfigList) {
+ config.setConfigId(null);
+ config.setTenantId(tenantId);
+ }
+ configMapper.insertBatch(sysConfigList);
+ return true;
+ }
+
+ /**
+ * 鐢熸垚绉熸埛id
+ *
+ * @param tenantIds 宸叉湁绉熸埛id鍒楄〃
+ * @return 绉熸埛id
+ */
+ private String generateTenantId(List<String> tenantIds) {
+ // 闅忔満鐢熸垚6浣�
+ String numbers = RandomUtil.randomNumbers(6);
+ // 鍒ゆ柇鏄惁瀛樺湪锛屽鏋滃瓨鍦ㄥ垯閲嶆柊鐢熸垚
+ if (tenantIds.contains(numbers)) {
+ generateTenantId(tenantIds);
+ }
+ return numbers;
+ }
+
+ /**
+ * 鏍规嵁绉熸埛鑿滃崟鍒涘缓绉熸埛瑙掕壊
+ *
+ * @param tenantId 绉熸埛缂栧彿
+ * @param packageId 绉熸埛濂楅id
+ * @return 瑙掕壊id
+ */
+ private Long createTenantRole(String tenantId, Long packageId) {
+ // 鑾峰彇绉熸埛濂楅
+ SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+ if (ObjectUtil.isNull(tenantPackage)) {
+ throw new ServiceException("濂楅涓嶅瓨鍦�");
+ }
+ // 鑾峰彇濂楅鑿滃崟id
+ List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+
+ // 鍒涘缓瑙掕壊
+ SysRole role = new SysRole();
+ role.setTenantId(tenantId);
+ role.setRoleName(TenantConstants.TENANT_ADMIN_ROLE_NAME);
+ role.setRoleKey(TenantConstants.TENANT_ADMIN_ROLE_KEY);
+ role.setRoleSort(1);
+ role.setStatus(TenantConstants.NORMAL);
+ roleMapper.insert(role);
+ Long roleId = role.getRoleId();
+
+ // 鍒涘缓瑙掕壊鑿滃崟
+ List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
+ menuIds.forEach(menuId -> {
+ SysRoleMenu roleMenu = new SysRoleMenu();
+ roleMenu.setRoleId(roleId);
+ roleMenu.setMenuId(menuId);
+ roleMenus.add(roleMenu);
+ });
+ roleMenuMapper.insertBatch(roleMenus);
+
+ return roleId;
+ }
+
+ /**
+ * 淇敼绉熸埛
+ */
+ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
+ @Override
+ public Boolean updateByBo(SysTenantBo bo) {
+ SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
+ tenant.setTenantId(null);
+ tenant.setPackageId(null);
+ return baseMapper.updateById(tenant) > 0;
+ }
+
+ /**
+ * 淇敼绉熸埛鐘舵��
+ *
+ * @param bo 绉熸埛淇℃伅
+ * @return 缁撴灉
+ */
+ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, key = "#bo.tenantId")
+ @Override
+ public int updateTenantStatus(SysTenantBo bo) {
+ SysTenant tenant = MapstructUtils.convert(bo, SysTenant.class);
+ return baseMapper.updateById(tenant);
+ }
+
+ /**
+ * 鏍¢獙绉熸埛鏄惁鍏佽鎿嶄綔
+ *
+ * @param tenantId 绉熸埛ID
+ */
+ @Override
+ public void checkTenantAllowed(String tenantId) {
+ if (ObjectUtil.isNotNull(tenantId) && TenantConstants.DEFAULT_TENANT_ID.equals(tenantId)) {
+ throw new ServiceException("涓嶅厑璁告搷浣滅鐞嗙鎴�");
+ }
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎绉熸埛
+ */
+ @CacheEvict(cacheNames = CacheNames.SYS_TENANT, allEntries = true)
+ @Override
+ public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
+ if (isValid) {
+ // 鍋氫竴浜涗笟鍔′笂鐨勬牎楠�,鍒ゆ柇鏄惁闇�瑕佹牎楠�
+ if (ids.contains(TenantConstants.SUPER_ADMIN_ID)) {
+ throw new ServiceException("瓒呯绉熸埛涓嶈兘鍒犻櫎");
+ }
+ }
+ return baseMapper.deleteBatchIds(ids) > 0;
+ }
+
+ /**
+ * 鏍¢獙浼佷笟鍚嶇О鏄惁鍞竴
+ */
+ @Override
+ public boolean checkCompanyNameUnique(SysTenantBo bo) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysTenant>()
+ .eq(SysTenant::getCompanyName, bo.getCompanyName())
+ .ne(ObjectUtil.isNotNull(bo.getTenantId()), SysTenant::getTenantId, bo.getTenantId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙璐﹀彿浣欓
+ */
+ @Override
+ public boolean checkAccountBalance(String tenantId) {
+ SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
+ // 濡傛灉浣欓涓�-1浠h〃涓嶉檺鍒�
+ if (tenant.getAccountCount() == -1) {
+ return true;
+ }
+ Long userNumber = userMapper.selectCount(new LambdaQueryWrapper<>());
+ // 濡傛灉浣欓澶т簬0浠h〃杩樻湁鍙敤鍚嶉
+ return tenant.getAccountCount() - userNumber > 0;
+ }
+
+ /**
+ * 鏍¢獙鏈夋晥鏈�
+ */
+ @Override
+ public boolean checkExpireTime(String tenantId) {
+ SysTenantVo tenant = SpringUtils.getAopProxy(this).queryByTenantId(tenantId);
+ // 濡傛灉鏈缃繃鏈熸椂闂翠唬琛ㄤ笉闄愬埗
+ if (ObjectUtil.isNull(tenant.getExpireTime())) {
+ return true;
+ }
+ // 濡傛灉褰撳墠鏃堕棿鍦ㄨ繃鏈熸椂闂翠箣鍓嶅垯閫氳繃
+ return new Date().before(tenant.getExpireTime());
+ }
+
+ /**
+ * 鍚屾绉熸埛濂楅
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public Boolean syncTenantPackage(String tenantId, Long packageId) {
+ SysTenantPackage tenantPackage = tenantPackageMapper.selectById(packageId);
+ List<SysRole> roles = roleMapper.selectList(
+ new LambdaQueryWrapper<SysRole>().eq(SysRole::getTenantId, tenantId));
+ List<Long> roleIds = new ArrayList<>(roles.size() - 1);
+ List<Long> menuIds = StringUtils.splitTo(tenantPackage.getMenuIds(), Convert::toLong);
+ roles.forEach(item -> {
+ if (TenantConstants.TENANT_ADMIN_ROLE_KEY.equals(item.getRoleKey())) {
+ List<SysRoleMenu> roleMenus = new ArrayList<>(menuIds.size());
+ menuIds.forEach(menuId -> {
+ SysRoleMenu roleMenu = new SysRoleMenu();
+ roleMenu.setRoleId(item.getRoleId());
+ roleMenu.setMenuId(menuId);
+ roleMenus.add(roleMenu);
+ });
+ roleMenuMapper.delete(new LambdaQueryWrapper<SysRoleMenu>().eq(SysRoleMenu::getRoleId, item.getRoleId()));
+ roleMenuMapper.insertBatch(roleMenus);
+ } else {
+ roleIds.add(item.getRoleId());
+ }
+ });
+ if (!roleIds.isEmpty()) {
+ roleMenuMapper.delete(
+ new LambdaQueryWrapper<SysRoleMenu>().in(SysRoleMenu::getRoleId, roleIds).notIn(!menuIds.isEmpty(), SysRoleMenu::getMenuId, menuIds));
+ }
+ return true;
+ }
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..4ffc5c2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/java/org/dromara/system/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,548 @@
+package org.dromara.system.service.impl;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.util.ArrayUtil;
+import cn.hutool.core.util.ObjectUtil;
+import com.baomidou.mybatisplus.core.conditions.Wrapper;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import lombok.RequiredArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.dromara.common.core.constant.CacheNames;
+import org.dromara.common.core.constant.UserConstants;
+import org.dromara.common.core.exception.ServiceException;
+import org.dromara.common.core.utils.MapstructUtils;
+import org.dromara.common.core.utils.StreamUtils;
+import org.dromara.common.core.utils.StringUtils;
+import org.dromara.common.mybatis.core.page.PageQuery;
+import org.dromara.common.mybatis.core.page.TableDataInfo;
+import org.dromara.common.mybatis.helper.DataBaseHelper;
+import org.dromara.common.satoken.utils.LoginHelper;
+import org.dromara.system.domain.SysDept;
+import org.dromara.system.domain.SysUser;
+import org.dromara.system.domain.SysUserPost;
+import org.dromara.system.domain.SysUserRole;
+import org.dromara.system.domain.bo.SysUserBo;
+import org.dromara.system.domain.vo.SysPostVo;
+import org.dromara.system.domain.vo.SysRoleVo;
+import org.dromara.system.domain.vo.SysUserVo;
+import org.dromara.system.mapper.*;
+import org.dromara.system.service.ISysUserService;
+import org.springframework.cache.annotation.Cacheable;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞傚鐞�
+ *
+ * @author Lion Li
+ */
+@Slf4j
+@RequiredArgsConstructor
+@Service
+public class SysUserServiceImpl implements ISysUserService {
+
+ private final SysUserMapper baseMapper;
+ private final SysDeptMapper deptMapper;
+ private final SysRoleMapper roleMapper;
+ private final SysPostMapper postMapper;
+ private final SysUserRoleMapper userRoleMapper;
+ private final SysUserPostMapper userPostMapper;
+
+ @Override
+ public TableDataInfo<SysUserVo> selectPageUserList(SysUserBo user, PageQuery pageQuery) {
+ Page<SysUserVo> page = baseMapper.selectPageUserList(pageQuery.build(), this.buildQueryWrapper(user));
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @Override
+ public List<SysUserVo> selectUserList(SysUserBo user) {
+ return baseMapper.selectUserList(this.buildQueryWrapper(user));
+ }
+
+ private Wrapper<SysUser> buildQueryWrapper(SysUserBo user) {
+ Map<String, Object> params = user.getParams();
+ QueryWrapper<SysUser> wrapper = Wrappers.query();
+ wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+ .eq(ObjectUtil.isNotNull(user.getUserId()), "u.user_id", user.getUserId())
+ .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+ .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
+ .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+ .between(params.get("beginTime") != null && params.get("endTime") != null,
+ "u.create_time", params.get("beginTime"), params.get("endTime"))
+ .and(ObjectUtil.isNotNull(user.getDeptId()), w -> {
+ List<SysDept> deptList = deptMapper.selectList(new LambdaQueryWrapper<SysDept>()
+ .select(SysDept::getDeptId)
+ .apply(DataBaseHelper.findInSet(user.getDeptId(), "ancestors")));
+ List<Long> ids = StreamUtils.toList(deptList, SysDept::getDeptId);
+ ids.add(user.getDeptId());
+ w.in("u.dept_id", ids);
+ }).orderByAsc("u.user_id");
+ return wrapper;
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ宸插垎閰嶇敤鎴疯鑹插垪琛�
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @Override
+ public TableDataInfo<SysUserVo> selectAllocatedList(SysUserBo user, PageQuery pageQuery) {
+ QueryWrapper<SysUser> wrapper = Wrappers.query();
+ wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+ .eq(ObjectUtil.isNotNull(user.getRoleId()), "r.role_id", user.getRoleId())
+ .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+ .eq(StringUtils.isNotBlank(user.getStatus()), "u.status", user.getStatus())
+ .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+ .orderByAsc("u.user_id");
+ Page<SysUserVo> page = baseMapper.selectAllocatedList(pageQuery.build(), wrapper);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鏈垎閰嶇敤鎴疯鑹插垪琛�
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+ */
+ @Override
+ public TableDataInfo<SysUserVo> selectUnallocatedList(SysUserBo user, PageQuery pageQuery) {
+ List<Long> userIds = userRoleMapper.selectUserIdsByRoleId(user.getRoleId());
+ QueryWrapper<SysUser> wrapper = Wrappers.query();
+ wrapper.eq("u.del_flag", UserConstants.USER_NORMAL)
+ .and(w -> w.ne("r.role_id", user.getRoleId()).or().isNull("r.role_id"))
+ .notIn(CollUtil.isNotEmpty(userIds), "u.user_id", userIds)
+ .like(StringUtils.isNotBlank(user.getUserName()), "u.user_name", user.getUserName())
+ .like(StringUtils.isNotBlank(user.getPhonenumber()), "u.phonenumber", user.getPhonenumber())
+ .orderByAsc("u.user_id");
+ Page<SysUserVo> page = baseMapper.selectUnallocatedList(pageQuery.build(), wrapper);
+ return TableDataInfo.build(page);
+ }
+
+ /**
+ * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ @Override
+ public SysUserVo selectUserByUserName(String userName) {
+ return baseMapper.selectUserByUserName(userName);
+ }
+
+ /**
+ * 閫氳繃鎵嬫満鍙锋煡璇㈢敤鎴�
+ *
+ * @param phonenumber 鎵嬫満鍙�
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ @Override
+ public SysUserVo selectUserByPhonenumber(String phonenumber) {
+ return baseMapper.selectUserByPhonenumber(phonenumber);
+ }
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 鐢ㄦ埛瀵硅薄淇℃伅
+ */
+ @Override
+ public SysUserVo selectUserById(Long userId) {
+ return baseMapper.selectUserById(userId);
+ }
+
+ /**
+ * 鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 缁撴灉
+ */
+ @Override
+ public String selectUserRoleGroup(String userName) {
+ List<SysRoleVo> list = roleMapper.selectRolesByUserName(userName);
+ if (CollUtil.isEmpty(list)) {
+ return StringUtils.EMPTY;
+ }
+ return StreamUtils.join(list, SysRoleVo::getRoleName);
+ }
+
+ /**
+ * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+ *
+ * @param userName 鐢ㄦ埛鍚�
+ * @return 缁撴灉
+ */
+ @Override
+ public String selectUserPostGroup(String userName) {
+ List<SysPostVo> list = postMapper.selectPostsByUserName(userName);
+ if (CollUtil.isEmpty(list)) {
+ return StringUtils.EMPTY;
+ }
+ return StreamUtils.join(list, SysPostVo::getPostName);
+ }
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean checkUserNameUnique(SysUserBo user) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+ .eq(SysUser::getUserName, user.getUserName())
+ .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ */
+ @Override
+ public boolean checkPhoneUnique(SysUserBo user) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+ .eq(SysUser::getPhonenumber, user.getPhonenumber())
+ .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙email鏄惁鍞竴
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ */
+ @Override
+ public boolean checkEmailUnique(SysUserBo user) {
+ boolean exist = baseMapper.exists(new LambdaQueryWrapper<SysUser>()
+ .eq(SysUser::getEmail, user.getEmail())
+ .ne(ObjectUtil.isNotNull(user.getUserId()), SysUser::getUserId, user.getUserId()));
+ return !exist;
+ }
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+ *
+ * @param userId 鐢ㄦ埛ID
+ */
+ @Override
+ public void checkUserAllowed(Long userId) {
+ if (ObjectUtil.isNotNull(userId) && LoginHelper.isSuperAdmin(userId)) {
+ throw new ServiceException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳鐢ㄦ埛");
+ }
+ }
+
+ /**
+ * 鏍¢獙鐢ㄦ埛鏄惁鏈夋暟鎹潈闄�
+ *
+ * @param userId 鐢ㄦ埛id
+ */
+ @Override
+ public void checkUserDataScope(Long userId) {
+ if (ObjectUtil.isNull(userId)) {
+ return;
+ }
+ if (LoginHelper.isSuperAdmin()) {
+ return;
+ }
+ if (ObjectUtil.isNull(baseMapper.selectUserById(userId))) {
+ throw new ServiceException("娌℃湁鏉冮檺璁块棶鐢ㄦ埛鏁版嵁锛�");
+ }
+ }
+
+ /**
+ * 鏂板淇濆瓨鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int insertUser(SysUserBo user) {
+ SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+ // 鏂板鐢ㄦ埛淇℃伅
+ int rows = baseMapper.insert(sysUser);
+ user.setUserId(sysUser.getUserId());
+ // 鏂板鐢ㄦ埛宀椾綅鍏宠仈
+ insertUserPost(user, false);
+ // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+ insertUserRole(user, false);
+ return rows;
+ }
+
+ /**
+ * 娉ㄥ唽鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean registerUser(SysUserBo user, String tenantId) {
+ user.setCreateBy(user.getUserId());
+ user.setUpdateBy(user.getUserId());
+ SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+ sysUser.setTenantId(tenantId);
+ return baseMapper.insert(sysUser) > 0;
+ }
+
+ /**
+ * 淇敼淇濆瓨鐢ㄦ埛淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int updateUser(SysUserBo user) {
+ // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+ insertUserRole(user, true);
+ // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+ insertUserPost(user, true);
+ SysUser sysUser = MapstructUtils.convert(user, SysUser.class);
+ // 闃叉閿欒鏇存柊鍚庡鑷寸殑鏁版嵁璇垹闄�
+ int flag = baseMapper.updateById(sysUser);
+ if (flag < 1) {
+ throw new ServiceException("淇敼鐢ㄦ埛" + user.getUserName() + "淇℃伅澶辫触");
+ }
+ return flag;
+ }
+
+ /**
+ * 鐢ㄦ埛鎺堟潈瑙掕壊
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param roleIds 瑙掕壊缁�
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public void insertUserAuth(Long userId, Long[] roleIds) {
+ insertUserRole(userId, roleIds, true);
+ }
+
+ /**
+ * 淇敼鐢ㄦ埛鐘舵��
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param status 甯愬彿鐘舵��
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateUserStatus(Long userId, String status) {
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysUser>()
+ .set(SysUser::getStatus, status)
+ .eq(SysUser::getUserId, userId));
+ }
+
+ /**
+ * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+ *
+ * @param user 鐢ㄦ埛淇℃伅
+ * @return 缁撴灉
+ */
+ @Override
+ public int updateUserProfile(SysUserBo user) {
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysUser>()
+ .set(ObjectUtil.isNotNull(user.getNickName()), SysUser::getNickName, user.getNickName())
+ .set(SysUser::getPhonenumber, user.getPhonenumber())
+ .set(SysUser::getEmail, user.getEmail())
+ .set(SysUser::getSex, user.getSex())
+ .eq(SysUser::getUserId, user.getUserId()));
+ }
+
+ /**
+ * 淇敼鐢ㄦ埛澶村儚
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param avatar 澶村儚鍦板潃
+ * @return 缁撴灉
+ */
+ @Override
+ public boolean updateUserAvatar(Long userId, Long avatar) {
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysUser>()
+ .set(SysUser::getAvatar, avatar)
+ .eq(SysUser::getUserId, userId)) > 0;
+ }
+
+ /**
+ * 閲嶇疆鐢ㄦ埛瀵嗙爜
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param password 瀵嗙爜
+ * @return 缁撴灉
+ */
+ @Override
+ public int resetUserPwd(Long userId, String password) {
+ return baseMapper.update(null,
+ new LambdaUpdateWrapper<SysUser>()
+ .set(SysUser::getPassword, password)
+ .eq(SysUser::getUserId, userId));
+ }
+
+ /**
+ * 鏂板鐢ㄦ埛瑙掕壊淇℃伅
+ *
+ * @param user 鐢ㄦ埛瀵硅薄
+ * @param clear 娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+ */
+ private void insertUserRole(SysUserBo user, boolean clear) {
+ this.insertUserRole(user.getUserId(), user.getRoleIds(), clear);
+ }
+
+ /**
+ * 鏂板鐢ㄦ埛宀椾綅淇℃伅
+ *
+ * @param user 鐢ㄦ埛瀵硅薄
+ * @param clear 娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+ */
+ private void insertUserPost(SysUserBo user, boolean clear) {
+ Long[] posts = user.getPostIds();
+ if (ArrayUtil.isNotEmpty(posts)) {
+ if (clear) {
+ // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶅叧鑱�
+ userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, user.getUserId()));
+ }
+ // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+ List<SysUserPost> list = StreamUtils.toList(Arrays.asList(posts), postId -> {
+ SysUserPost up = new SysUserPost();
+ up.setUserId(user.getUserId());
+ up.setPostId(postId);
+ return up;
+ });
+ userPostMapper.insertBatch(list);
+ }
+ }
+
+ /**
+ * 鏂板鐢ㄦ埛瑙掕壊淇℃伅
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @param roleIds 瑙掕壊缁�
+ * @param clear 娓呴櫎宸插瓨鍦ㄧ殑鍏宠仈鏁版嵁
+ */
+ private void insertUserRole(Long userId, Long[] roleIds, boolean clear) {
+ if (ArrayUtil.isNotEmpty(roleIds)) {
+ // 鍒ゆ柇鏄惁鍏锋湁姝よ鑹茬殑鎿嶄綔鏉冮檺
+ List<SysRoleVo> roles = roleMapper.selectRoleList(new LambdaQueryWrapper<>());
+ if (CollUtil.isEmpty(roles)) {
+ throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鐨勬暟鎹�");
+ }
+ List<Long> roleList = StreamUtils.toList(roles, SysRoleVo::getRoleId);
+ if (!LoginHelper.isSuperAdmin(userId)) {
+ roleList.remove(UserConstants.SUPER_ADMIN_ID);
+ }
+ List<Long> canDoRoleList = StreamUtils.filter(Arrays.asList(roleIds), roleList::contains);
+ if (CollUtil.isEmpty(canDoRoleList)) {
+ throw new ServiceException("娌℃湁鏉冮檺璁块棶瑙掕壊鐨勬暟鎹�");
+ }
+ if (clear) {
+ // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+ userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
+ }
+ // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+ List<SysUserRole> list = StreamUtils.toList(canDoRoleList, roleId -> {
+ SysUserRole ur = new SysUserRole();
+ ur.setUserId(userId);
+ ur.setRoleId(roleId);
+ return ur;
+ });
+ userRoleMapper.insertBatch(list);
+ }
+ }
+
+ /**
+ * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+ *
+ * @param userId 鐢ㄦ埛ID
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteUserById(Long userId) {
+ // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+ userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().eq(SysUserRole::getUserId, userId));
+ // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶈〃
+ userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().eq(SysUserPost::getUserId, userId));
+ // 闃叉鏇存柊澶辫触瀵艰嚧鐨勬暟鎹垹闄�
+ int flag = baseMapper.deleteById(userId);
+ if (flag < 1) {
+ throw new ServiceException("鍒犻櫎鐢ㄦ埛澶辫触!");
+ }
+ return flag;
+ }
+
+ /**
+ * 鎵归噺鍒犻櫎鐢ㄦ埛淇℃伅
+ *
+ * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛ID
+ * @return 缁撴灉
+ */
+ @Override
+ @Transactional(rollbackFor = Exception.class)
+ public int deleteUserByIds(Long[] userIds) {
+ for (Long userId : userIds) {
+ checkUserAllowed(userId);
+ checkUserDataScope(userId);
+ }
+ List<Long> ids = Arrays.asList(userIds);
+ // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+ userRoleMapper.delete(new LambdaQueryWrapper<SysUserRole>().in(SysUserRole::getUserId, ids));
+ // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶈〃
+ userPostMapper.delete(new LambdaQueryWrapper<SysUserPost>().in(SysUserPost::getUserId, ids));
+ // 闃叉鏇存柊澶辫触瀵艰嚧鐨勬暟鎹垹闄�
+ int flag = baseMapper.deleteBatchIds(ids);
+ if (flag < 1) {
+ throw new ServiceException("鍒犻櫎鐢ㄦ埛澶辫触!");
+ }
+ return flag;
+ }
+
+ /**
+ * 閫氳繃閮ㄩ棬id鏌ヨ褰撳墠閮ㄩ棬鎵�鏈夌敤鎴�
+ *
+ * @param deptId
+ * @return
+ */
+ @Override
+ public List<SysUserVo> selectUserListByDept(Long deptId) {
+ LambdaQueryWrapper<SysUser> lqw = Wrappers.lambdaQuery();
+ lqw.eq(SysUser::getDeptId, deptId);
+ lqw.orderByAsc(SysUser::getUserId);
+ return baseMapper.selectVoList(lqw);
+ }
+
+ @Cacheable(cacheNames = CacheNames.SYS_USER_NAME, key = "#userId")
+ @Override
+ public String selectUserNameById(Long userId) {
+ SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getUserName).eq(SysUser::getUserId, userId));
+ return ObjectUtil.isNull(sysUser) ? null : sysUser.getUserName();
+ }
+
+ @Override
+ @Cacheable(cacheNames = CacheNames.SYS_NICKNAME, key = "#userId")
+ public String selectNicknameById(Long userId) {
+ SysUser sysUser = baseMapper.selectOne(new LambdaQueryWrapper<SysUser>()
+ .select(SysUser::getNickName).eq(SysUser::getUserId, userId));
+ return ObjectUtil.isNull(sysUser) ? null : sysUser.getNickName();
+ }
+
+}
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/application.yml b/ruoyi-modules/ruoyi-system/src/main/resources/application.yml
new file mode 100644
index 0000000..e2ec852
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/application.yml
@@ -0,0 +1,32 @@
+# Tomcat
+server:
+ port: 9201
+
+# Spring
+spring:
+ application:
+ # 搴旂敤鍚嶇О
+ name: ruoyi-system
+ profiles:
+ # 鐜閰嶇疆
+ active: @profiles.active@
+
+--- # nacos 閰嶇疆
+spring:
+ cloud:
+ nacos:
+ # nacos 鏈嶅姟鍦板潃
+ server-addr: @nacos.server@
+ discovery:
+ # 娉ㄥ唽缁�
+ group: @nacos.discovery.group@
+ namespace: ${spring.profiles.active}
+ config:
+ # 閰嶇疆缁�
+ group: @nacos.config.group@
+ namespace: ${spring.profiles.active}
+ config:
+ import:
+ - optional:nacos:application-common.yml
+ - optional:nacos:datasource.yml
+ - optional:nacos:${spring.application.name}.yml
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt b/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt
new file mode 100644
index 0000000..fbd45f5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt
@@ -0,0 +1,10 @@
+Spring Boot Version: ${spring-boot.version}
+Spring Application Name: ${spring.application.name}
+ _ _
+ (_) | |
+ _ __ _ _ ___ _ _ _ ______ ___ _ _ ___ | |_ ___ _ __ ___
+| '__|| | | | / _ \ | | | || ||______|/ __|| | | |/ __|| __| / _ \| '_ ` _ \
+| | | |_| || (_) || |_| || | \__ \| |_| |\__ \| |_ | __/| | | | | |
+|_| \__,_| \___/ \__, ||_| |___/ \__, ||___/ \__| \___||_| |_| |_|
+ __/ | __/ |
+ |___/ |___/
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml b/ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml
new file mode 100644
index 0000000..caaa345
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration scan="true" scanPeriod="60 seconds" debug="false">
+ <!-- 鏃ュ織瀛樻斁璺緞 -->
+ <property name="log.path" value="logs/${project.artifactId}" />
+ <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+ <property name="console.log.pattern"
+ value="%red(%d{yyyy-MM-dd HH:mm:ss}) %green([%thread]) %highlight(%-5level) %boldMagenta(%logger{36}%n) - %msg%n"/>
+
+ <!-- 鎺у埗鍙拌緭鍑� -->
+ <appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+ <encoder>
+ <pattern>${console.log.pattern}</pattern>
+ <charset>utf-8</charset>
+ </encoder>
+ </appender>
+
+ <include resource="logback-common.xml" />
+
+ <include resource="logback-logstash.xml" />
+
+ <!-- 寮�鍚� skywalking 鏃ュ織鏀堕泦 -->
+ <include resource="logback-skylog.xml" />
+
+ <!--绯荤粺鎿嶄綔鏃ュ織-->
+ <root level="info">
+ <appender-ref ref="console" />
+ </root>
+</configuration>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
new file mode 100644
index 0000000..c938b1e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/package-info.md
@@ -0,0 +1,3 @@
+java鍖呬娇鐢� `.` 鍒嗗壊 resource 鐩綍浣跨敤 `/` 鍒嗗壊
+<br>
+姝ゆ枃浠剁洰鐨� 闃叉鏂囦欢澶圭矘杩炴壘涓嶅埌 `xml` 鏂囦欢
\ No newline at end of file
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml
new file mode 100644
index 0000000..fd150ad
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysClientMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysClientMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
new file mode 100644
index 0000000..e542a10
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysConfigMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
new file mode 100644
index 0000000..bba949d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDeptMapper">
+
+ <resultMap type="org.dromara.system.domain.vo.SysDeptVo" id="SysDeptResult">
+ </resultMap>
+
+ <select id="selectDeptList" resultMap="SysDeptResult">
+ select * from sys_dept ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectDeptById" resultMap="SysDeptResult">
+ select * from sys_dept where del_flag = '0' and dept_id = #{deptId}
+ </select>
+
+ <select id="selectDeptListByRoleId" resultType="Long">
+ select d.dept_id
+ from sys_dept d
+ left join sys_role_dept rd on d.dept_id = rd.dept_id
+ where rd.role_id = #{roleId}
+ <if test="deptCheckStrictly">
+ and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
+ </if>
+ order by d.parent_id, d.order_num
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
new file mode 100644
index 0000000..6bcce51
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDictDataMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
new file mode 100644
index 0000000..6975da4
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysDictTypeMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
new file mode 100644
index 0000000..c64b551
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysLogininforMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
new file mode 100644
index 0000000..fad1812
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -0,0 +1,85 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysMenuMapper">
+
+ <resultMap type="org.dromara.system.domain.SysMenu" id="SysMenuResult">
+ </resultMap>
+
+ <select id="selectMenuListByUserId" resultMap="SysMenuResult">
+ select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.query_param, m.visible, m.status,
+ m.perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ left join sys_user_role sur on rm.role_id = sur.role_id
+ left join sys_role ro on sur.role_id = ro.role_id
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
+ select distinct m.menu_id,
+ m.parent_id,
+ m.menu_name,
+ m.path,
+ m.component,
+ m.query_param,
+ m.visible,
+ m.status,
+ m.perms,
+ m.is_frame,
+ m.is_cache,
+ m.menu_type,
+ m.icon,
+ m.order_num,
+ m.create_time
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ left join sys_user_role sur on rm.role_id = sur.role_id
+ left join sys_role ro on sur.role_id = ro.role_id
+ left join sys_user u on sur.user_id = u.user_id
+ where u.user_id = #{userId}
+ and m.menu_type in ('M', 'C')
+ and m.status = '0'
+ and ro.status = '0'
+ order by m.parent_id, m.order_num
+ </select>
+
+ <select id="selectMenuListByRoleId" resultType="Long">
+ select m.menu_id
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ where rm.role_id = #{roleId}
+ <if test="menuCheckStrictly">
+ and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id =
+ rm.menu_id and rm.role_id = #{roleId})
+ </if>
+ order by m.parent_id, m.order_num
+ </select>
+
+ <select id="selectMenuPerms" resultType="String">
+ select distinct m.perms
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ left join sys_user_role sur on rm.role_id = sur.role_id
+ </select>
+
+ <select id="selectMenuPermsByUserId" parameterType="Long" resultType="String">
+ select distinct m.perms
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ left join sys_user_role sur on rm.role_id = sur.role_id
+ left join sys_role r on r.role_id = sur.role_id
+ where m.status = '0'
+ and r.status = '0'
+ and sur.user_id = #{userId}
+ </select>
+
+ <select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">
+ select distinct m.perms
+ from sys_menu m
+ left join sys_role_menu rm on m.menu_id = rm.menu_id
+ where m.status = '0' and rm.role_id = #{roleId}
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
new file mode 100644
index 0000000..43f494d
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysNoticeMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
new file mode 100644
index 0000000..5ef14ee
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysOperLogMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
new file mode 100644
index 0000000..d2108eb
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysPostMapper">
+
+ <resultMap type="org.dromara.system.domain.vo.SysPostVo" id="SysPostResult">
+ </resultMap>
+
+ <select id="selectPostListByUserId" parameterType="Long" resultType="Long">
+ select p.post_id
+ from sys_post p
+ left join sys_user_post up on up.post_id = p.post_id
+ left join sys_user u on u.user_id = up.user_id
+ where u.user_id = #{userId}
+ </select>
+
+ <select id="selectPostsByUserName" parameterType="String" resultMap="SysPostResult">
+ select p.post_id, p.post_name, p.post_code
+ from sys_post p
+ left join sys_user_post up on up.post_id = p.post_id
+ left join sys_user u on u.user_id = up.user_id
+ where u.user_name = #{userName}
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
new file mode 100644
index 0000000..1705bb2
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleDeptMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
new file mode 100644
index 0000000..b191698
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleMapper">
+
+ <resultMap type="org.dromara.system.domain.vo.SysRoleVo" id="SysRoleResult">
+ </resultMap>
+
+ <sql id="selectRoleVo">
+ select distinct r.role_id,
+ r.role_name,
+ r.role_key,
+ r.role_sort,
+ r.data_scope,
+ r.menu_check_strictly,
+ r.dept_check_strictly,
+ r.status,
+ r.del_flag,
+ r.create_time,
+ r.remark
+ from sys_role r
+ left join sys_user_role sur on sur.role_id = r.role_id
+ left join sys_user u on u.user_id = sur.user_id
+ left join sys_dept d on u.dept_id = d.dept_id
+ </sql>
+
+ <select id="selectPageRoleList" resultMap="SysRoleResult">
+ <include refid="selectRoleVo"/>
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectRoleList" resultMap="SysRoleResult">
+ <include refid="selectRoleVo"/>
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult">
+ <include refid="selectRoleVo"/>
+ WHERE r.del_flag = '0' and sur.user_id = #{userId}
+ </select>
+
+ <select id="selectRoleListByUserId" parameterType="Long" resultType="Long">
+ select r.role_id
+ from sys_role r
+ left join sys_user_role sur on sur.role_id = r.role_id
+ left join sys_user u on u.user_id = sur.user_id
+ where u.user_id = #{userId}
+ </select>
+
+ <select id="selectRolesByUserName" parameterType="String" resultMap="SysRoleResult">
+ select r.role_id,
+ r.role_name,
+ r.role_key,
+ r.role_sort
+ from sys_role r
+ left join sys_user_role sur on sur.role_id = r.role_id
+ left join sys_user u on u.user_id = sur.user_id
+ WHERE r.del_flag = '0' and u.user_name = #{userName}
+ </select>
+
+ <select id="selectRoleById" resultMap="SysRoleResult">
+ <include refid="selectRoleVo"/>
+ WHERE r.del_flag = '0' and r.role_id = #{roleId}
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
new file mode 100644
index 0000000..f01dc5e
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysRoleMenuMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml
new file mode 100644
index 0000000..baa4b59
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysSocialMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysSocialMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml
new file mode 100644
index 0000000..0d96e13
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysTenantMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
new file mode 100644
index 0000000..79cf4c5
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysTenantPackageMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysTenantPackageMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
new file mode 100644
index 0000000..e7831fc
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserMapper">
+
+ <!-- 澶氱粨鏋勫祵濂楄嚜鍔ㄦ槧灏勯渶甯︿笂姣忎釜瀹炰綋鐨勪富閿甶d 鍚﹀垯鏄犲皠浼氬け璐� -->
+ <resultMap type="org.dromara.system.domain.vo.SysUserVo" id="SysUserResult">
+ <id property="userId" column="user_id"/>
+ <result property="deptId" column="dept_id"/>
+ <association property="dept" column="dept_id" resultMap="deptResult"/>
+ <collection property="roles" javaType="java.util.List" resultMap="RoleResult"/>
+ </resultMap>
+
+ <resultMap id="deptResult" type="org.dromara.system.domain.vo.SysDeptVo">
+ <id property="deptId" column="dept_id"/>
+ <result property="email" column="dept_email"/>
+ <result property="status" column="dept_status"/>
+ <result property="createTime" column="dept_create_time"/>
+ </resultMap>
+
+ <resultMap id="RoleResult" type="org.dromara.system.domain.vo.SysRoleVo">
+ <id property="roleId" column="role_id"/>
+ <result property="status" column="role_status"/>
+ <result property="createTime" column="role_create_time"/>
+ </resultMap>
+
+ <sql id="selectUserVo">
+ select u.user_id,
+ u.tenant_id,
+ u.dept_id,
+ u.user_name,
+ u.nick_name,
+ u.user_type,
+ u.email,
+ u.avatar,
+ u.phonenumber,
+ u.password,
+ u.sex,
+ u.status,
+ u.del_flag,
+ u.login_ip,
+ u.login_date,
+ u.create_by,
+ u.create_time,
+ u.remark,
+ d.dept_id,
+ d.parent_id,
+ d.ancestors,
+ d.dept_name,
+ d.order_num,
+ d.leader,
+ d.status as dept_status,
+ r.role_id,
+ r.role_name,
+ r.role_key,
+ r.role_sort,
+ r.data_scope,
+ r.status as role_status
+ from sys_user u
+ left join sys_dept d on u.dept_id = d.dept_id
+ left join sys_user_role sur on u.user_id = sur.user_id
+ left join sys_role r on r.role_id = sur.role_id
+ </sql>
+
+ <select id="selectPageUserList" resultMap="SysUserResult">
+ select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex,
+ u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
+ d.dept_name, d.leader, u1.user_name as leaderName
+ from sys_user u
+ left join sys_dept d on u.dept_id = d.dept_id
+ left join sys_user u1 on u1.user_id = d.leader
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectUserList" resultMap="SysUserResult">
+ select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex,
+ u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark,
+ d.dept_name, d.leader, u1.user_name as leaderName
+ from sys_user u
+ left join sys_dept d on u.dept_id = d.dept_id
+ left join sys_user u1 on u1.user_id = d.leader
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectAllocatedList" resultMap="SysUserResult">
+ select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+ from sys_user u
+ left join sys_dept d on u.dept_id = d.dept_id
+ left join sys_user_role sur on u.user_id = sur.user_id
+ left join sys_role r on r.role_id = sur.role_id
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectUnallocatedList" resultMap="SysUserResult">
+ select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+ from sys_user u
+ left join sys_dept d on u.dept_id = d.dept_id
+ left join sys_user_role sur on u.user_id = sur.user_id
+ left join sys_role r on r.role_id = sur.role_id
+ ${ew.getCustomSqlSegment}
+ </select>
+
+ <select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
+ <include refid="selectUserVo"/>
+ where u.del_flag = '0' and u.user_name = #{userName}
+ </select>
+
+ <select id="selectUserByPhonenumber" parameterType="String" resultMap="SysUserResult">
+ <include refid="selectUserVo"/>
+ where u.del_flag = '0' and u.phonenumber = #{phonenumber}
+ </select>
+
+ <select id="selectUserByEmail" parameterType="String" resultMap="SysUserResult">
+ <include refid="selectUserVo"/>
+ where u.del_flag = '0' and u.email = #{email}
+ </select>
+
+ <select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
+ <include refid="selectUserVo"/>
+ where u.del_flag = '0' and u.user_id = #{userId}
+ </select>
+
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
new file mode 100644
index 0000000..e9f2496
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserPostMapper">
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
new file mode 100644
index 0000000..bc52d1a
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+ PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+ "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="org.dromara.system.mapper.SysUserRoleMapper">
+
+ <select id="selectUserIdsByRoleId" resultType="Long">
+ select u.user_id from sys_user u
+ inner join sys_user_role sur
+ on u.user_id = sur.user_id and sur.role_id = #{roleId}
+ </select>
+
+</mapper>
diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/spy.properties b/ruoyi-modules/ruoyi-system/src/main/resources/spy.properties
new file mode 100644
index 0000000..abbd893
--- /dev/null
+++ b/ruoyi-modules/ruoyi-system/src/main/resources/spy.properties
@@ -0,0 +1,28 @@
+# p6spy 鎬ц兘鍒嗘瀽鎻掍欢閰嶇疆鏂囦欢
+modulelist=com.baomidou.mybatisplus.extension.p6spy.MybatisPlusLogFactory,com.p6spy.engine.outage.P6OutageFactory
+# 鑷畾涔夋棩蹇楁墦鍗�
+logMessageFormat=com.baomidou.mybatisplus.extension.p6spy.P6SpyLogger
+#鏃ュ織杈撳嚭鍒版帶鍒跺彴
+appender=com.baomidou.mybatisplus.extension.p6spy.StdoutLogger
+# 浣跨敤鏃ュ織绯荤粺璁板綍 sql
+#appender=com.p6spy.engine.spy.appender.Slf4JLogger
+# 璁剧疆 p6spy driver 浠g悊
+#deregisterdrivers=true
+# 鍙栨秷JDBC URL鍓嶇紑
+useprefix=true
+# 閰嶇疆璁板綍 Log 渚嬪,鍙幓鎺夌殑缁撴灉闆嗘湁error,info,batch,debug,statement,commit,rollback,result,resultset.
+excludecategories=info,debug,result,commit,resultset
+# 鏃ユ湡鏍煎紡
+dateformat=yyyy-MM-dd HH:mm:ss
+# SQL璇彞鎵撳嵃鏃堕棿鏍煎紡
+databaseDialectTimestampFormat=yyyy-MM-dd HH:mm:ss
+# 瀹為檯椹卞姩鍙涓�
+#driverlist=org.h2.Driver
+# 鏄惁寮�鍚參SQL璁板綍
+outagedetection=true
+# 鎱QL璁板綍鏍囧噯 2 绉�
+outagedetectioninterval=2
+# 鏄惁杩囨护 Log
+filter=true
+# 杩囨护 Log 鏃舵墍鎺掗櫎鐨� sql 鍏抽敭瀛楋紝浠ラ�楀彿鍒嗛殧
+exclude=SELECT 1
--
Gitblit v1.9.1