From 46444bd0feacd7652522debda65ad4d88042b667 Mon Sep 17 00:00:00 2001
From: RuoYi <yzz_ivy@163.com>
Date: 星期二, 08 十月 2019 09:14:38 +0800
Subject: [PATCH] RuoYi-Vue 1.0

---
 ruoyi-ui/.eslintignore                                                                        |   10 
 ruoyi-ui/src/components/ThemePicker/index.vue                                                 |  175 
 ruoyi-ui/src/utils/scroll-to.js                                                               |   58 
 ruoyi-ui/src/layout/components/index.js                                                       |    5 
 ruoyi-ui/src/assets/icons/svg/international.svg                                               |    1 
 ruoyi-ui/src/assets/icons/svg/druid.svg                                                       |    1 
 ruoyi-ui/src/assets/icons/svg/eye.svg                                                         |    1 
 ruoyi-ui/src/assets/styles/index.scss                                                         |  191 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java                     |   83 
 ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml                                     |  137 
 ruoyi-ui/package.json                                                                         |  102 
 ruoyi-ui/src/api/system/dict/type.js                                                          |   44 
 ruoyi-ui/src/assets/icons/svg/system.svg                                                      |    2 
 ruoyi-ui/src/assets/icons/svg/tree.svg                                                        |    1 
 ruoyi-ui/src/assets/icons/svg/bug.svg                                                         |    1 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataScope.java                |   28 
 ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue                                        |   85 
 ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml                                     |  115 
 ruoyi-ui/src/assets/icons/svg/pdf.svg                                                         |    1 
 ruoyi-ui/src/views/system/dept/index.vue                                                      |  307 
 ruoyi/src/main/java/com/ruoyi/common/utils/DateUtils.java                                     |  155 
 ruoyi-ui/build/index.js                                                                       |   35 
 ruoyi/src/main/java/com/ruoyi/framework/security/service/PermissionService.java               |  169 
 ruoyi-ui/src/assets/icons/svg/monitor.svg                                                     |    2 
 ruoyi/src/main/java/com/ruoyi/framework/config/FilterConfig.java                              |   46 
 ruoyi-ui/.env.development                                                                     |    8 
 ruoyi-ui/src/assets/icons/svg/job.svg                                                         |    1 
 ruoyi/src/main/java/com/ruoyi/common/constant/Constants.java                                  |   96 
 ruoyi-ui/src/store/modules/user.js                                                            |   96 
 ruoyi-ui/src/components/Editor/index.vue                                                      |  226 
 ruoyi-ui/src/store/index.js                                                                   |   23 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysMenuService.java                     |  127 
 ruoyi-ui/src/assets/icons/svg/date.svg                                                        |    1 
 ruoyi-ui/src/views/system/menu/index.vue                                                      |  337 
 ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml                                 |  116 
 ruoyi-ui/src/assets/icons/svg/guide.svg                                                       |    1 
 ruoyi-ui/src/api/system/user.js                                                               |  109 
 ruoyi-ui/src/views/system/log/index.vue                                                       |    3 
 ruoyi-ui/src/assets/icons/svg/validCode.svg                                                   |    1 
 ruoyi/src/main/java/com/ruoyi/common/core/text/StrFormatter.java                              |   92 
 ruoyi/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java     |   34 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java             |  106 
 ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java                     |   26 
 ruoyi-ui/src/assets/404_images/404.png                                                        |    0 
 ruoyi-ui/src/assets/icons/svg/lock.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java                             |  105 
 ruoyi-ui/src/assets/image/profile.jpg                                                         |    0 
 ruoyi-ui/src/api/menu.js                                                                      |    9 
 ruoyi-ui/src/components/Screenfull/index.vue                                                  |   60 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java                |  153 
 ruoyi/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java |   16 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java         |  105 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java             |  141 
 ruoyi/src/main/java/com/ruoyi/framework/config/DruidConfig.java                               |  106 
 ruoyi-ui/src/assets/icons/svg/user.svg                                                        |    1 
 ruoyi-ui/src/assets/icons/svg/tree-table.svg                                                  |    1 
 ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java                            |   46 
 ruoyi-ui/src/views/components/icons/element-icons.js                                          |   74 
 ruoyi/src/main/java/com/ruoyi/framework/web/page/PageDomain.java                              |   69 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/MetaVo.java                            |   49 
 ruoyi-ui/src/assets/icons/svg/form.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java                          |  145 
 ruoyi-ui/src/assets/icons/svg/edit.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java                             |   66 
 ruoyi-ui/src/assets/image/login-background.jpg                                                |    0 
 ruoyi-ui/src/assets/styles/element-variables.scss                                             |   31 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java                    |   77 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java                 |   69 
 LICENSE                                                                                       |   27 
 ruoyi-ui/src/views/system/user/profile/userInfo.vue                                           |   80 
 ruoyi-ui/src/store/modules/tagsView.js                                                        |  165 
 ruoyi/src/main/java/com/ruoyi/common/utils/IdUtils.java                                       |   51 
 ruoyi/src/main/java/com/ruoyi/project/common/CaptchaController.java                           |   62 
 ruoyi-ui/src/layout/components/Sidebar/index.vue                                              |   54 
 ruoyi-ui/src/assets/icons/svg/drag.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/common/utils/Arith.java                                         |  114 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java                   |   52 
 ruoyi-ui/bin/package.bat                                                                      |   12 
 ruoyi-ui/src/layout/components/Navbar.vue                                                     |  181 
 ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java               |   16 
 ruoyi/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java                                |  248 
 ruoyi-ui/src/components/RightPanel/index.vue                                                  |  149 
 ruoyi-ui/src/layout/components/Sidebar/Logo.vue                                               |   84 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java                            |   84 
 ruoyi-ui/src/api/system/menu.js                                                               |   60 
 ruoyi-ui/src/views/monitor/online/index.vue                                                   |    5 
 ruoyi/src/main/java/com/ruoyi/framework/config/RuoYiConfig.java                               |  116 
 ruoyi/src/main/java/com/ruoyi/framework/security/service/SysPermissionService.java            |   66 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java                            |   61 
 ruoyi-ui/src/assets/icons/svg/theme.svg                                                       |    1 
 ruoyi-ui/src/assets/icons/svgo.yml                                                            |   22 
 ruoyi/src/main/java/com/ruoyi/common/constant/UserConstants.java                              |   39 
 ruoyi-ui/src/store/modules/permission.js                                                      |   53 
 ruoyi/src/main/resources/logback.xml                                                          |   93 
 ruoyi-ui/.gitignore                                                                           |   23 
 ruoyi-ui/src/views/login/auth-redirect.vue                                                    |   15 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java                        |  105 
 ruoyi-ui/src/components/Hamburger/index.vue                                                   |   44 
 ruoyi-ui/src/assets/icons/svg/eye-open.svg                                                    |    1 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java                   |   68 
 ruoyi/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java                |   77 
 ruoyi-ui/src/assets/styles/btn.scss                                                           |   99 
 ruoyi-ui/src/api/monitor/server.js                                                            |    9 
 ruoyi-ui/src/assets/icons/svg/documentation.svg                                               |    1 
 ruoyi-ui/src/assets/icons/svg/code.svg                                                        |    1 
 ruoyi/bin/clean.bat                                                                           |   12 
 ruoyi-ui/src/assets/icons/index.js                                                            |    9 
 ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java                           |   26 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java                              |  270 
 ruoyi/src/main/java/com/ruoyi/common/enums/UserStatus.java                                    |   30 
 ruoyi-ui/src/views/tool/build/index.vue                                                       |    5 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java                              |  184 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java                    |   87 
 ruoyi/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java     |   44 
 ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java                 |   48 
 ruoyi-ui/src/assets/icons/svg/phone.svg                                                       |    1 
 ruoyi-ui/src/layout/components/Settings/index.vue                                             |  108 
 ruoyi-ui/.editorconfig                                                                        |   22 
 ruoyi-ui/src/store/getters.js                                                                 |   15 
 ruoyi-ui/src/views/tool/swagger/index.vue                                                     |   25 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java            |   99 
 ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml                              |   56 
 ruoyi/src/main/java/com/ruoyi/framework/manager/AsyncManager.java                             |   55 
 ruoyi-ui/src/assets/icons/svg/qq.svg                                                          |    1 
 ruoyi-ui/src/components/RuoYi/index.vue                                                       |   21 
 ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java         |   34 
 ruoyi-ui/src/views/system/user/profile/userAvatar.vue                                         |  135 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java             |  275 
 ruoyi-ui/src/assets/icons/svg/logininfor.svg                                                  |    1 
 ruoyi-ui/src/directive/permission/index.js                                                    |   15 
 ruoyi-ui/src/assets/logo/logo.png                                                             |    0 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java                        |  109 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDeptService.java                     |  101 
 ruoyi-ui/src/utils/request.js                                                                 |   65 
 ruoyi/src/main/java/com/ruoyi/common/utils/sign/Base64.java                                   |  291 
 ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java                          |  235 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java             |  359 
 ruoyi-ui/src/components/SvgIcon/index.vue                                                     |   61 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java                            |   78 
 ruoyi/src/main/java/com/ruoyi/common/exception/user/UserException.java                        |   18 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java                |  143 
 ruoyi/src/main/java/com/ruoyi/common/utils/ServletUtils.java                                  |  136 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java                          |  133 
 ruoyi-ui/src/store/modules/app.js                                                             |   56 
 ruoyi-ui/src/views/dashboard/RaddarChart.vue                                                  |  116 
 ruoyi-ui/src/views/system/user/index.vue                                                      |  515 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/Server.java                                |  241 
 ruoyi-ui/src/assets/icons/svg/online.svg                                                      |    1 
 ruoyi/ry.sh                                                                                   |   86 
 ruoyi-ui/src/views/components/icons/index.vue                                                 |   87 
 ruoyi/src/main/resources/banner.txt                                                           |   24 
 ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java                     |   16 
 ruoyi-ui/src/assets/icons/svg/component.svg                                                   |    1 
 ruoyi-ui/src/assets/icons/svg/clipboard.svg                                                   |    1 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessType.java                  |   59 
 ruoyi-ui/src/components/IconSelect/requireIcons.js                                            |   11 
 ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue                                        |   93 
 ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml                                     |  174 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/AjaxResult.java                            |  148 
 ruoyi/src/main/java/com/ruoyi/common/exception/BaseException.java                             |   97 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java                     |  115 
 ruoyi-ui/vue.config.js                                                                        |  130 
 ruoyi-ui/src/assets/icons/svg/server.svg                                                      |    1 
 README.md                                                                                     |  107 
 ruoyi-ui/src/assets/styles/mixin.scss                                                         |   66 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java                         |   76 
 ruoyi-ui/src/layout/index.vue                                                                 |  102 
 ruoyi/src/main/java/com/ruoyi/framework/config/ServerConfig.java                              |   32 
 ruoyi-ui/src/assets/icons/svg/message.svg                                                     |    1 
 ruoyi-ui/bin/run-web.bat                                                                      |   12 
 ruoyi/src/main/java/com/ruoyi/framework/config/RedisConfig.java                               |   43 
 ruoyi-ui/src/views/dashboard/PieChart.vue                                                     |   79 
 ruoyi-ui/src/views/error/401.vue                                                              |   99 
 ruoyi-ui/src/store/modules/settings.js                                                        |   34 
 ruoyi-ui/README.md                                                                            |   30 
 ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js                                           |   25 
 ruoyi-ui/src/layout/components/Sidebar/Link.vue                                               |   36 
 ruoyi-ui/src/assets/icons/svg/star.svg                                                        |    1 
 ruoyi-ui/src/views/system/dict/data.vue                                                       |  276 
 ruoyi-ui/src/settings.js                                                                      |   31 
 ruoyi/src/main/java/com/ruoyi/common/core/lang/UUID.java                                      |  481 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java                        |  100 
 ruoyi-ui/public/favicon.ico                                                                   |    0 
 ruoyi-ui/src/views/monitor/server/index.vue                                                   |  209 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java                |  118 
 ruoyi-ui/src/views/components/icons/svg-icons.js                                              |   10 
 ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml                                 |   98 
 ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java                    |  179 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserRole.java                          |   46 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java                              |  171 
 ruoyi-ui/src/assets/styles/element-ui.scss                                                    |   79 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java                |  133 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java             |  363 
 ruoyi-ui/src/views/dashboard/mixins/resize.js                                                 |   52 
 ruoyi/src/main/java/com/ruoyi/common/utils/security/Md5Utils.java                             |   66 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java                          |  160 
 ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java                       |  131 
 ruoyi-ui/src/views/dashboard/LineChart.vue                                                    |  135 
 ruoyi/src/main/resources/mybatis/system/SysUserPostMapper.xml                                 |   34 
 ruoyi-ui/src/views/system/dict/index.vue                                                      |  275 
 ruoyi-ui/src/assets/icons/svg/build.svg                                                       |    1 
 ruoyi-ui/src/views/system/user/profile/index.vue                                              |  101 
 ruoyi/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java                |   28 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java             |  289 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java                      |   52 
 ruoyi-ui/src/api/system/dept.js                                                               |   60 
 ruoyi-ui/src/assets/icons/svg/icon.svg                                                        |    1 
 ruoyi-ui/src/layout/components/TagsView/index.vue                                             |  286 
 ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml                                 |   82 
 ruoyi/src/main/resources/mybatis/system/SysDeptMapper.xml                                     |  151 
 ruoyi-ui/src/assets/icons/svg/example.svg                                                     |    1 
 ruoyi-ui/src/views/system/post/index.vue                                                      |  252 
 ruoyi/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java              |   69 
 ruoyi-ui/src/assets/styles/sidebar.scss                                                       |  209 
 ruoyi-ui/src/api/system/post.js                                                               |   44 
 ruoyi-ui/src/components/IconSelect/index.vue                                                  |   69 
 ruoyi/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java                            |   55 
 ruoyi-ui/src/assets/icons/svg/excel.svg                                                       |    1 
 ruoyi-ui/src/assets/401_images/401.gif                                                        |    0 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java                              |   98 
 ruoyi/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java         |   51 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java              |   91 
 ruoyi-ui/src/components/PanThumb/index.vue                                                    |  142 
 ruoyi-ui/src/utils/index.js                                                                   |  317 
 ruoyi-ui/src/assets/icons/svg/link.svg                                                        |    1 
 ruoyi-ui/src/assets/icons/svg/email.svg                                                       |    1 
 ruoyi-ui/src/views/system/role/index.vue                                                      |  478 
 ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java        |   45 
 ruoyi-ui/src/assets/icons/svg/people.svg                                                      |    1 
 ruoyi/src/main/java/com/ruoyi/common/exception/UtilException.java                             |   26 
 ruoyi/sql/ry_20191008.sql                                                                     |  693 +
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java                        |  114 
 ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml                                   |  105 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/BaseEntity.java                            |  131 
 ruoyi-ui/src/api/login.js                                                                     |   40 
 ruoyi-ui/src/assets/icons/svg/log.svg                                                         |    1 
 ruoyi-ui/src/assets/icons/svg/nested.svg                                                      |    1 
 ruoyi/src/main/resources/mybatis/system/SysUserRoleMapper.xml                                 |   44 
 ruoyi-ui/src/permission.js                                                                    |   64 
 ruoyi-ui/src/views/monitor/druid/index.vue                                                    |   25 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java                        |  108 
 ruoyi-ui/src/assets/icons/svg/chart.svg                                                       |    1 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java                            |  122 
 ruoyi-ui/src/views/login.vue                                                                  |  203 
 ruoyi-ui/src/api/system/config.js                                                             |   52 
 ruoyi-ui/src/views/redirect.vue                                                               |   12 
 ruoyi/src/main/resources/application.yml                                                      |  109 
 ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml                                   |   82 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java                     |  149 
 ruoyi/src/main/java/com/ruoyi/common/utils/SecurityUtils.java                                 |   90 
 ruoyi/src/main/resources/mybatis/mybatis-config.xml                                           |   15 
 ruoyi-ui/src/views/error/404.vue                                                              |  228 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessStatus.java                |   20 
 ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java              |   40 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserPostMapper.java                    |   44 
 ruoyi-ui/.env.production                                                                      |    5 
 ruoyi-ui/.env.staging                                                                         |    7 
 ruoyi-ui/src/main.js                                                                          |   69 
 ruoyi-ui/src/assets/404_images/404_cloud.png                                                  |    0 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java           |  117 
 ruoyi-ui/src/router/index.js                                                                  |  101 
 ruoyi-ui/src/assets/icons/svg/education.svg                                                   |    1 
 ruoyi-ui/src/assets/styles/transition.scss                                                    |   48 
 ruoyi-ui/public/index.html                                                                    |  207 
 ruoyi/src/main/java/com/ruoyi/common/exception/DemoModeException.java                         |   15 
 ruoyi-ui/src/assets/icons/svg/table.svg                                                       |    1 
 ruoyi-ui/src/layout/mixin/ResizeHandler.js                                                    |   45 
 ruoyi/src/main/java/com/ruoyi/RuoYiApplication.java                                           |   30 
 ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java                               |  168 
 ruoyi-ui/src/components/SizeSelect/index.vue                                                  |   57 
 ruoyi-ui/src/layout/components/AppMain.vue                                                    |   57 
 ruoyi-ui/src/assets/icons/svg/tool.svg                                                        |    1 
 ruoyi-ui/src/views/dashboard/PanelGroup.vue                                                   |  181 
 ruoyi/src/main/java/com/ruoyi/framework/web/page/TableDataInfo.java                           |   85 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java                |  130 
 ruoyi/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java                          |   39 
 ruoyi/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java            |   71 
 ruoyi-ui/src/assets/icons/svg/money.svg                                                       |    1 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java                            |   86 
 ruoyi/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java                         |   20 
 ruoyi-ui/src/components/Breadcrumb/index.vue                                                  |   81 
 ruoyi-ui/src/assets/styles/variables.scss                                                     |   35 
 ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java      |   66 
 ruoyi-ui/src/assets/icons/svg/skill.svg                                                       |    1 
 ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java            |   34 
 ruoyi/src/main/java/com/ruoyi/common/core/text/CharsetKit.java                                |   86 
 ruoyi/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java                    |  105 
 ruoyi-ui/src/assets/icons/svg/tab.svg                                                         |    1 
 ruoyi/pom.xml                                                                                 |  267 
 ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUtils.java                                |  142 
 ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java                                 |  200 
 ruoyi/src/main/resources/i18n/messages.properties                                             |   36 
 ruoyi-ui/src/assets/icons/svg/password.svg                                                    |    1 
 ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java             |   93 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserPost.java                          |   46 
 ruoyi-ui/src/assets/icons/svg/wechat.svg                                                      |    1 
 ruoyi/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java       |   16 
 ruoyi-ui/src/assets/icons/svg/dashboard.svg                                                   |    1 
 ruoyi/src/main/java/com/ruoyi/common/constant/HttpStatus.java                                 |   89 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeSelect.java                            |   77 
 ruoyi/src/main/java/com/ruoyi/common/utils/MessageUtils.java                                  |   26 
 ruoyi/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java                                   |   36 
 ruoyi-ui/src/assets/icons/svg/size.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/common/exception/CustomException.java                           |   43 
 ruoyi-ui/src/directive/permission/hasRole.js                                                  |   28 
 ruoyi-ui/src/assets/icons/svg/shopping.svg                                                    |    1 
 ruoyi-ui/src/utils/ruoyi.js                                                                   |   76 
 ruoyi/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java                            |  114 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java                        |   91 
 ruoyi-ui/src/utils/permission.js                                                              |   24 
 ruoyi/src/main/java/com/ruoyi/framework/web/page/TableSupport.java                            |   49 
 ruoyi-ui/src/assets/icons/svg/dict.svg                                                        |    1 
 ruoyi/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java                               |  226 
 ruoyi/src/main/java/com/ruoyi/framework/security/service/UserDetailsServiceImpl.java          |   60 
 ruoyi/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java                          |   62 
 ruoyi-ui/src/utils/auth.js                                                                    |   15 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserRoleMapper.java                    |   62 
 ruoyi-ui/src/components/Pagination/index.vue                                                  |  101 
 ruoyi/src/main/java/com/ruoyi/common/xss/XssFilter.java                                       |   97 
 ruoyi-ui/src/views/tool/gen/index.vue                                                         |    5 
 ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java                 |   75 
 ruoyi-ui/src/views/dashboard/BarChart.vue                                                     |  102 
 ruoyi-ui/src/api/system/notice.js                                                             |   44 
 ruoyi-ui/src/views/index.vue                                                                  |   98 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DataSourceType.java                |   19 
 ruoyi-ui/src/assets/icons/svg/zip.svg                                                         |    1 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java         |  130 
 ruoyi-ui/src/assets/icons/svg/404.svg                                                         |    1 
 ruoyi/src/main/java/com/ruoyi/RuoYiServletInitializer.java                                    |   18 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java                      |   60 
 ruoyi/src/main/java/com/ruoyi/framework/security/service/SysLoginService.java                 |   88 
 ruoyi/src/main/resources/application-druid.yml                                                |   57 
 ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg                                             |    1 
 ruoyi/src/main/java/com/ruoyi/common/exception/file/FileException.java                        |   19 
 ruoyi-ui/src/utils/validate.js                                                                |   83 
 ruoyi/src/main/resources/mybatis/system/SysRoleDeptMapper.xml                                 |   34 
 ruoyi-ui/src/api/monitor/operlog.js                                                           |   10 
 ruoyi/src/main/java/com/ruoyi/framework/web/controller/BaseController.java                    |   85 
 ruoyi/src/main/resources/mybatis/system/SysRoleMenuMapper.xml                                 |   27 
 ruoyi-ui/src/assets/styles/ruoyi.scss                                                         |  126 
 ruoyi-ui/src/views/monitor/operlog/index.vue                                                  |  226 
 ruoyi/src/main/java/com/ruoyi/project/tool/swagger/TestController.java                        |  175 
 ruoyi/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java                               |   41 
 ruoyi-ui/src/layout/components/Sidebar/Item.vue                                               |   29 
 ruoyi-ui/src/api/monitor/logininfor.js                                                        |   10 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java                              |  163 
 ruoyi-ui/src/directive/permission/hasPermi.js                                                 |   28 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java                                |  204 
 ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java                            |  133 
 ruoyi/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java                                    |  189 
 ruoyi-ui/src/assets/icons/svg/fullscreen.svg                                                  |    1 
 ruoyi/src/main/java/com/ruoyi/common/utils/LogUtils.java                                      |   18 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleMenu.java                          |   46 
 ruoyi-ui/src/assets/icons/svg/post.svg                                                        |    1 
 ruoyi/bin/run-tomcat.bat                                                                      |   14 
 ruoyi-ui/src/assets/icons/svg/swagger.svg                                                     |    1 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleDept.java                          |   46 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java               |   94 
 ruoyi-ui/src/views/system/notice/index.vue                                                    |  292 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java            |  100 
 ruoyi-ui/.eslintrc.js                                                                         |  199 
 ruoyi/.gitignore                                                                              |   43 
 ruoyi/bin/package.bat                                                                         |   12 
 ruoyi-ui/src/views/monitor/job/index.vue                                                      |    5 
 ruoyi-ui/src/views/system/config/index.vue                                                    |  270 
 ruoyi-ui/src/assets/icons/svg/peoples.svg                                                     |    1 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataSource.java               |   26 
 ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java                    |   48 
 ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java         |   77 
 ruoyi/src/main/java/com/ruoyi/common/utils/StringUtils.java                                   |  453 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMenuMapper.java                    |   36 
 ruoyi/src/main/java/com/ruoyi/common/enums/HttpMethod.java                                    |   36 
 ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java                          |   71 
 ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleDeptMapper.java                    |   44 
 ruoyi-ui/src/api/system/dict/data.js                                                          |   52 
 ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java              |  110 
 ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java           |   80 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/OperatorType.java                  |   24 
 ruoyi-ui/src/assets/icons/svg/search.svg                                                      |    1 
 ruoyi-ui/src/views/login/components/SocialSignin.vue                                          |   72 
 ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Log.java                      |   41 
 ruoyi-ui/src/assets/icons/svg/language.svg                                                    |    1 
 ruoyi/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java                     |  101 
 ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java                               |  152 
 ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java                          |  243 
 ruoyi/src/main/java/com/ruoyi/common/core/text/Convert.java                                   |  999 +
 ruoyi-ui/babel.config.js                                                                      |    5 
 ruoyi-ui/src/views/monitor/logininfor/index.vue                                               |  138 
 ruoyi-ui/src/assets/icons/svg/download.svg                                                    |    1 
 ruoyi-ui/src/assets/icons/svg/list.svg                                                        |    1 
 ruoyi/src/main/resources/mybatis/system/SysMenuMapper.xml                                     |  158 
 ruoyi-ui/src/api/system/role.js                                                               |   66 
 ruoyi-ui/src/components/HeaderSearch/index.vue                                                |  180 
 ruoyi-ui/src/views/system/user/profile/resetPwd.vue                                           |   76 
 ruoyi-ui/src/App.vue                                                                          |   11 
 /dev/null                                                                                     |   36 
 ruoyi/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java        |   16 
 ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java                 |   42 
 ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java                            |  101 
 ruoyi/src/main/java/com/ruoyi/common/utils/Threads.java                                       |   99 
 400 files changed, 32,457 insertions(+), 84 deletions(-)

diff --git a/LICENSE b/LICENSE
index 933dab9..8564f29 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,21 +1,20 @@
-MIT License
+The MIT License (MIT)
 
-Copyright (c) 2019 鑻ヤ緷
+Copyright (c) 2018 RuoYi
 
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
 
 The above copyright notice and this permission notice shall be included in all
 copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/README.en.md b/README.en.md
deleted file mode 100644
index e0dfdb1..0000000
--- a/README.en.md
+++ /dev/null
@@ -1,36 +0,0 @@
-# RuoYi-Vue
-
-#### Description
-{**When you're done, you can delete the content in this README and update the file with details for others getting started with your repository**}
-
-#### Software Architecture
-Software architecture description
-
-#### Installation
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Instructions
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### Contribution
-
-1. Fork the repository
-2. Create Feat_xxx branch
-3. Commit your code
-4. Create Pull Request
-
-
-#### Gitee Feature
-
-1. You can use Readme\_XXX.md to support different languages, such as Readme\_en.md, Readme\_zh.md
-2. Gitee blog [blog.gitee.com](https://blog.gitee.com)
-3. Explore open source project [https://gitee.com/explore](https://gitee.com/explore)
-4. The most valuable open source project [GVP](https://gitee.com/gvp)
-5. The manual of Gitee [https://gitee.com/help](https://gitee.com/help)
-6. The most popular members  [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
\ No newline at end of file
diff --git a/README.md b/README.md
index 244ef66..a894f90 100644
--- a/README.md
+++ b/README.md
@@ -1,39 +1,78 @@
-# RuoYi-Vue
+## 骞冲彴绠�浠�
 
-#### 浠嬬粛
-{**浠ヤ笅鏄爜浜戝钩鍙拌鏄庯紝鎮ㄥ彲浠ユ浛鎹㈡绠�浠�**
-鐮佷簯鏄� OSCHINA 鎺ㄥ嚭鐨勫熀浜� Git 鐨勪唬鐮佹墭绠″钩鍙帮紙鍚屾椂鏀寔 SVN锛夈�備笓涓哄紑鍙戣�呮彁渚涚ǔ瀹氥�侀珮鏁堛�佸畨鍏ㄧ殑浜戠杞欢寮�鍙戝崗浣滃钩鍙�
-鏃犺鏄釜浜恒�佸洟闃熴�佹垨鏄紒涓氾紝閮借兘澶熺敤鐮佷簯瀹炵幇浠g爜鎵樼銆侀」鐩鐞嗐�佸崗浣滃紑鍙戙�備紒涓氶」鐩鐪� [https://gitee.com/enterprises](https://gitee.com/enterprises)}
+涓�鐩存兂鍋氫竴娆惧悗鍙扮鐞嗙郴缁燂紝鐪嬩簡寰堝浼樼鐨勫紑婧愰」鐩絾鏄彂鐜版病鏈夊悎閫傜殑銆備簬鏄埄鐢ㄧ┖闂蹭紤鎭椂闂村紑濮嬭嚜宸卞啓浜嗕竴濂楀悗鍙扮郴缁熴�傚姝ゆ湁浜嗚嫢渚濄�傚ス鍙互鐢ㄤ簬鎵�鏈夌殑Web搴旂敤绋嬪簭锛屽缃戠珯绠$悊鍚庡彴锛岀綉绔欎細鍛樹腑蹇冿紝CMS锛孋RM锛孫A銆傛墍鏈夊墠绔悗鍙颁唬鐮佸皝瑁呰繃鍚庡崄鍒嗙簿绠�鏄撲笂鎵嬶紝鍑洪敊姒傜巼浣庛�傚悓鏃舵敮鎸佺Щ鍔ㄥ鎴风璁块棶銆傜郴缁熶細闄嗙画鏇存柊涓�浜涘疄鐢ㄥ姛鑳姐��
 
-#### 杞欢鏋舵瀯
-杞欢鏋舵瀯璇存槑
+鎬у埆鐢凤紝鑻ヤ緷鏄粰杩樻病鏈夊嚭鐢熷コ鍎垮彇鐨勫悕瀛楋紙瀵撴剰锛氫綘鑻ヤ笉绂讳笉寮冿紝鎴戝繀鐢熸鐩镐緷锛�
+
+鍙傝�冨悗鍙版ā鏉縖vue-element-admin](https://github.com/PanJiaChen/vue-element-admin)
+
+> 濡傞渶涓嶅垎绂诲簲鐢紝璇风Щ姝� [RuoYi](https://gitee.com/y_project/RuoYi)  `(淇濇寔鍚屾鏇存柊)`锛屽闇�鍏朵粬鐗堟湰锛岃绉绘 [椤圭洰鎵╁睍](http://doc.ruoyi.vip/ruoyi/document/xmkz.html)  `(涓嶅畾鏃舵洿鏂�)`
+
+> 闃块噷浜戦�氱敤浜戜骇鍝�1888浼樻儬鍒� 锛歔鐐规垜棰嗗彇](https://promotion.aliyun.com/ntms/yunparter/invite.html?userCode=brki8iof)&nbsp;&nbsp;&nbsp;&nbsp;鑵捐浜戦�氱敤浜戜骇鍝�2860浼樻儬鍒� 锛歔鐐规垜棰嗗彇](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)&nbsp;&nbsp;`(浠呴檺鏂扮敤鎴�)`
+
+> 闃块噷浜慔i鎷艰喘 闄愰噺鐖嗘 浣庤嚦199鍏�/骞� [鐐规垜杩涘叆](https://www.aliyun.com/acts/hi-group-buying?userCode=brki8iof)&nbsp;&nbsp;`(浠呴檺鏂扮敤鎴�)`
+
+## 鍐呯疆鍔熻兘
+
+1.  鐢ㄦ埛绠$悊锛氱敤鎴锋槸绯荤粺鎿嶄綔鑰咃紝璇ュ姛鑳戒富瑕佸畬鎴愮郴缁熺敤鎴烽厤缃��
+2.  閮ㄩ棬绠$悊锛氶厤缃郴缁熺粍缁囨満鏋勶紙鍏徃銆侀儴闂ㄣ�佸皬缁勶級锛屾爲缁撴瀯灞曠幇鏀寔鏁版嵁鏉冮檺銆�
+3.  宀椾綅绠$悊锛氶厤缃郴缁熺敤鎴锋墍灞炴媴浠昏亴鍔°��
+4.  鑿滃崟绠$悊锛氶厤缃郴缁熻彍鍗曪紝鎿嶄綔鏉冮檺锛屾寜閽潈闄愭爣璇嗙瓑銆�
+5.  瑙掕壊绠$悊锛氳鑹茶彍鍗曟潈闄愬垎閰嶃�佽缃鑹叉寜鏈烘瀯杩涜鏁版嵁鑼冨洿鏉冮檺鍒掑垎銆�
+6.  瀛楀吀绠$悊锛氬绯荤粺涓粡甯镐娇鐢ㄧ殑涓�浜涜緝涓哄浐瀹氱殑鏁版嵁杩涜缁存姢銆�
+7.  鍙傛暟绠$悊锛氬绯荤粺鍔ㄦ�侀厤缃父鐢ㄥ弬鏁般��
+8.  閫氱煡鍏憡锛氱郴缁熼�氱煡鍏憡淇℃伅鍙戝竷缁存姢銆�
+9.  鎿嶄綔鏃ュ織锛氱郴缁熸甯告搷浣滄棩蹇楄褰曞拰鏌ヨ锛涚郴缁熷紓甯镐俊鎭棩蹇楄褰曞拰鏌ヨ銆�
+10. 鐧诲綍鏃ュ織锛氱郴缁熺櫥褰曟棩蹇楄褰曟煡璇㈠寘鍚櫥褰曞紓甯搞��
+11. 鍦ㄧ嚎鐢ㄦ埛锛氬綋鍓嶇郴缁熶腑娲昏穬鐢ㄦ埛鐘舵�佺洃鎺с��
+12. 瀹氭椂浠诲姟锛氬湪绾匡紙娣诲姞銆佷慨鏀广�佸垹闄�)浠诲姟璋冨害鍖呭惈鎵ц缁撴灉鏃ュ織銆�
+13. 浠g爜鐢熸垚锛氬墠鍚庣浠g爜鐨勭敓鎴愶紙java銆乭tml銆亁ml銆乻ql锛夋敮鎸丆RUD涓嬭浇 銆�
+14. 绯荤粺鎺ュ彛锛氭牴鎹笟鍔′唬鐮佽嚜鍔ㄧ敓鎴愮浉鍏崇殑api鎺ュ彛鏂囨。銆�
+15. 鏈嶅姟鐩戞帶锛氱洃瑙嗗綋鍓嶇郴缁烠PU銆佸唴瀛樸�佺鐩樸�佸爢鏍堢瓑鐩稿叧淇℃伅銆�
+16. 鍦ㄧ嚎鏋勫缓鍣細鎷栧姩琛ㄥ崟鍏冪礌鐢熸垚鐩稿簲鐨凥TML浠g爜銆�
+17. 杩炴帴姹犵洃瑙嗭細鐩戣褰撳墠绯荤粺鏁版嵁搴撹繛鎺ユ睜鐘舵�侊紝鍙繘琛屽垎鏋怱QL鎵惧嚭绯荤粺鎬ц兘鐡堕銆�
+## 鍦ㄧ嚎浣撻獙
+> admin/admin123  
+> 闄嗛檰缁画鏀跺埌涓�浜涙墦璧忥紝涓轰簡鏇村ソ鐨勪綋楠屽凡鐢ㄤ簬婕旂ず鏈嶅姟鍣ㄥ崌绾с�傝阿璋㈠悇浣嶅皬浼欎即銆�
+
+婕旂ず鍦板潃锛歨ttp://vue.ruoyi.vip  
+
+鏂囨。鍦板潃锛歨ttp://doc.ruoyi.vip
+
+## 婕旂ず鍥�
+
+<table>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/97fcdc766fa04c03722aef4b3d77f71e8d2.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/642858372da91853c39e2d4746f036ea171.jpg"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/8678d5204148e2610c9d02822274a961dcf.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/feb2b25a08bf9dd121b8f51274ae935ead6.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/71c2d48905221a09a728df4aff4160b8607.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/c14c1ee9a64a6a9c2c22f67d43198767dbe.jpg"/></td>
+    </tr>	 
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/c162686bf3a39e3cd6b4fd6b5919f515ebf.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/412fb931faa8b3e3de6f9cbbc5b7979cf36.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/5f3d39a141f21f81b90536f391b8408f1fa.jpg"/></td>
+    </tr>
+</table>
 
 
-#### 瀹夎鏁欑▼
+## 鑻ヤ緷浜ゆ祦缇�
 
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 浣跨敤璇存槑
-
-1. xxxx
-2. xxxx
-3. xxxx
-
-#### 鍙備笌璐$尞
-
-1. Fork 鏈粨搴�
-2. 鏂板缓 Feat_xxx 鍒嗘敮
-3. 鎻愪氦浠g爜
-4. 鏂板缓 Pull Request
-
-
-#### 鐮佷簯鐗规妧
-
-1. 浣跨敤 Readme\_XXX.md 鏉ユ敮鎸佷笉鍚岀殑璇█锛屼緥濡� Readme\_en.md, Readme\_zh.md
-2. 鐮佷簯瀹樻柟鍗氬 [blog.gitee.com](https://blog.gitee.com)
-3. 浣犲彲浠� [https://gitee.com/explore](https://gitee.com/explore) 杩欎釜鍦板潃鏉ヤ簡瑙g爜浜戜笂鐨勪紭绉�寮�婧愰」鐩�
-4. [GVP](https://gitee.com/gvp) 鍏ㄧО鏄爜浜戞渶鏈変环鍊煎紑婧愰」鐩紝鏄爜浜戠患鍚堣瘎瀹氬嚭鐨勪紭绉�寮�婧愰」鐩�
-5. 鐮佷簯瀹樻柟鎻愪緵鐨勪娇鐢ㄦ墜鍐� [https://gitee.com/help](https://gitee.com/help)
-6. 鐮佷簯灏侀潰浜虹墿鏄竴妗g敤鏉ュ睍绀虹爜浜戜細鍛橀閲囩殑鏍忕洰 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/)
\ No newline at end of file
+QQ缇わ細 [![鍔犲叆QQ缇(https://img.shields.io/badge/12633588-blue.svg)](https://jq.qq.com/?_wv=1027&k=5PjgQ8e)  鐐瑰嚮鎸夐挳鍏ョ兢銆�
\ No newline at end of file
diff --git a/ruoyi-ui/.editorconfig b/ruoyi-ui/.editorconfig
new file mode 100644
index 0000000..22d302e
--- /dev/null
+++ b/ruoyi-ui/.editorconfig
@@ -0,0 +1,22 @@
+# 鍛婅瘔EditorConfig鎻掍欢锛岃繖鏄牴鏂囦欢锛屼笉鐢ㄧ户缁線涓婃煡鎵�
+root = true
+
+# 鍖归厤鍏ㄩ儴鏂囦欢
+[*]
+# 璁剧疆瀛楃闆�
+charset = utf-8
+# 缂╄繘椋庢牸锛屽彲閫塻pace銆乼ab
+indent_style = space
+# 缂╄繘鐨勭┖鏍兼暟
+indent_size = 2
+# 缁撳熬鎹㈣绗︼紝鍙�塴f銆乧r銆乧rlf
+end_of_line = lf
+# 鍦ㄦ枃浠剁粨灏炬彃鍏ユ柊琛�
+insert_final_newline = true
+# 鍒犻櫎涓�琛屼腑鐨勫墠鍚庣┖鏍�
+trim_trailing_whitespace = true
+
+# 鍖归厤md缁撳熬鐨勬枃浠�
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development
new file mode 100644
index 0000000..0cb1c61
--- /dev/null
+++ b/ruoyi-ui/.env.development
@@ -0,0 +1,8 @@
+# 寮�鍙戠幆澧冮厤缃�
+ENV = 'development'
+
+# 鑻ヤ緷绠$悊绯荤粺/寮�鍙戠幆澧�
+VUE_APP_BASE_API = '/dev-api'
+
+# 璺敱鎳掑姞杞�
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production
new file mode 100644
index 0000000..a8e4af3
--- /dev/null
+++ b/ruoyi-ui/.env.production
@@ -0,0 +1,5 @@
+# 鐢熶骇鐜閰嶇疆
+ENV = 'production'
+
+# 鑻ヤ緷绠$悊绯荤粺/鐢熶骇鐜
+VUE_APP_BASE_API = '/prod-api'
diff --git a/ruoyi-ui/.env.staging b/ruoyi-ui/.env.staging
new file mode 100644
index 0000000..41d4817
--- /dev/null
+++ b/ruoyi-ui/.env.staging
@@ -0,0 +1,7 @@
+NODE_ENV = production
+
+# 娴嬭瘯鐜閰嶇疆
+ENV = 'staging'
+
+# 鑻ヤ緷绠$悊绯荤粺/娴嬭瘯鐜
+VUE_APP_BASE_API = '/stage-api'
diff --git a/ruoyi-ui/.eslintignore b/ruoyi-ui/.eslintignore
new file mode 100644
index 0000000..7dd2c2a
--- /dev/null
+++ b/ruoyi-ui/.eslintignore
@@ -0,0 +1,10 @@
+# 蹇界暐build鐩綍涓嬬被鍨嬩负js鐨勬枃浠剁殑璇硶妫�鏌�
+build/*.js
+# 蹇界暐src/assets鐩綍涓嬫枃浠剁殑璇硶妫�鏌�
+src/assets
+# 蹇界暐public鐩綍涓嬫枃浠剁殑璇硶妫�鏌�
+public
+# 蹇界暐褰撳墠鐩綍涓嬩负js鐨勬枃浠剁殑璇硶妫�鏌�
+*.js
+# 蹇界暐褰撳墠鐩綍涓嬩负vue鐨勬枃浠剁殑璇硶妫�鏌�
+*.vue
\ No newline at end of file
diff --git a/ruoyi-ui/.eslintrc.js b/ruoyi-ui/.eslintrc.js
new file mode 100644
index 0000000..b321fbe
--- /dev/null
+++ b/ruoyi-ui/.eslintrc.js
@@ -0,0 +1,199 @@
+// ESlint 妫�鏌ラ厤缃�
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/singleline-html-element-content-newline": "off",
+    "vue/multiline-html-element-content-newline":"off",
+    "vue/name-property-casing": ["error", "PascalCase"],
+    "vue/no-v-html": "off",
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': ["error", "always", {"null": "ignore"}],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}
diff --git a/ruoyi-ui/.gitignore b/ruoyi-ui/.gitignore
new file mode 100644
index 0000000..2c9b3a7
--- /dev/null
+++ b/ruoyi-ui/.gitignore
@@ -0,0 +1,23 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
diff --git a/ruoyi-ui/README.md b/ruoyi-ui/README.md
new file mode 100644
index 0000000..1b108f3
--- /dev/null
+++ b/ruoyi-ui/README.md
@@ -0,0 +1,30 @@
+## 开发
+
+```bash
+# 克隆项目
+git clone https://gitee.com/y_project/RuoYi-Vue
+
+# 进入项目目录
+cd ruoyi-ui
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npm.taobao.org
+
+# 启动服务
+npm run dev
+```
+
+浏览器访问 http://localhost:80
+
+## 发布
+
+```bash
+# 构建测试环境
+npm run build:stage
+
+# 构建生产环境
+npm run build:prod
+```
\ No newline at end of file
diff --git a/ruoyi-ui/babel.config.js b/ruoyi-ui/babel.config.js
new file mode 100644
index 0000000..c8e69f5
--- /dev/null
+++ b/ruoyi-ui/babel.config.js
@@ -0,0 +1,5 @@
+module.exports = {
+  presets: [
+    '@vue/app'
+  ]
+}
diff --git a/ruoyi-ui/bin/package.bat b/ruoyi-ui/bin/package.bat
new file mode 100644
index 0000000..ecc8db4
--- /dev/null
+++ b/ruoyi-ui/bin/package.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成node_modules包文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npm.taobao.org
+
+pause
\ No newline at end of file
diff --git a/ruoyi-ui/bin/run-web.bat b/ruoyi-ui/bin/run-web.bat
new file mode 100644
index 0000000..a696280
--- /dev/null
+++ b/ruoyi-ui/bin/run-web.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 使用 Vue 运行 Web 工程。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
+pause
\ No newline at end of file
diff --git a/ruoyi-ui/build/index.js b/ruoyi-ui/build/index.js
new file mode 100644
index 0000000..385da08
--- /dev/null
+++ b/ruoyi-ui/build/index.js
@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
new file mode 100644
index 0000000..1122913
--- /dev/null
+++ b/ruoyi-ui/package.json
@@ -0,0 +1,102 @@
+{
+  "name": "ruoyi",
+  "version": "1.0.0",
+  "description": "鑻ヤ緷绠$悊绯荤粺",
+  "author": "鑻ヤ緷",
+  "license": "MIT",
+  "scripts": {
+    "dev": "vue-cli-service serve",
+    "build:prod": "vue-cli-service build",
+    "build:stage": "vue-cli-service build --mode staging",
+    "preview": "node build/index.js --preview",
+    "lint": "eslint --ext .js,.vue src",
+    "test:unit": "jest --clearCache && vue-cli-service test:unit",
+    "test:ci": "npm run lint && npm run test:unit",
+    "svgo": "svgo -f src/icons/svg --config=src/icons/svgo.yml",
+    "new": "plop"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  },
+  "lint-staged": {
+    "src/**/*.{js,vue}": [
+      "eslint --fix",
+      "git add"
+    ]
+  },
+  "keywords": [
+    "vue",
+    "admin",
+    "dashboard",
+    "element-ui",
+    "boilerplate",
+    "admin-template",
+    "management-system"
+  ],
+  "repository": {
+    "type": "git",
+    "url": "https://gitee.com/y_project/RuoYi-Vue.git"
+  },
+  "dependencies": {
+    "@riophae/vue-treeselect": "0.1.0",
+    "vue-quill-editor": "3.0.6",
+    "vue-cropper": "0.4.9",
+    "axios": "0.18.1",
+    "echarts": "4.2.1",
+    "element-ui": "2.11.1",
+    "fuse.js": "3.4.4",
+    "js-cookie": "2.2.0",
+    "normalize.css": "7.0.0",
+    "nprogress": "0.2.0",
+    "path-to-regexp": "2.4.0",
+    "screenfull": "4.2.0",
+    "vue": "2.6.10",
+    "vue-count-to": "1.0.13",
+    "vue-router": "3.0.2",
+    "vue-splitpane": "1.0.4",
+    "vuex": "3.1.0"
+  },
+  "devDependencies": {
+    "@babel/core": "7.0.0",
+    "@babel/register": "7.0.0",
+    "@vue/cli-plugin-babel": "3.5.3",
+    "@vue/cli-plugin-eslint": "^3.9.1",
+    "@vue/cli-plugin-unit-jest": "3.5.3",
+    "@vue/cli-service": "3.5.3",
+    "@vue/test-utils": "1.0.0-beta.29",
+    "autoprefixer": "^9.5.1",
+    "babel-core": "7.0.0-bridge.0",
+    "babel-eslint": "10.0.1",
+    "babel-jest": "23.6.0",
+    "chalk": "2.4.2",
+    "chokidar": "2.1.5",
+    "connect": "3.6.6",
+    "eslint": "5.15.3",
+    "eslint-plugin-vue": "5.2.2",
+    "html-webpack-plugin": "3.2.0",
+    "http-proxy-middleware": "^0.19.1",
+    "husky": "1.3.1",
+    "lint-staged": "8.1.5",
+    "mockjs": "1.0.1-beta3",
+    "node-sass": "^4.9.0",
+    "plop": "2.3.0",
+    "runjs": "^4.3.2",
+    "sass-loader": "^7.1.0",
+    "script-ext-html-webpack-plugin": "2.1.3",
+    "script-loader": "0.7.2",
+    "serve-static": "^1.13.2",
+    "svg-sprite-loader": "4.1.3",
+    "svgo": "1.2.0",
+    "vue-template-compiler": "2.6.10"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
+}
diff --git a/ruoyi-ui/public/favicon.ico b/ruoyi-ui/public/favicon.ico
new file mode 100644
index 0000000..e263760
--- /dev/null
+++ b/ruoyi-ui/public/favicon.ico
Binary files differ
diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html
new file mode 100644
index 0000000..525e2ac
--- /dev/null
+++ b/ruoyi-ui/public/index.html
@@ -0,0 +1,207 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="renderer" content="webkit">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= webpackConfig.name %></title>
+	  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0px;
+      padding: 0px;
+    }
+    .chromeframe {
+      margin: 0.2em 0;
+      background: #ccc;
+      color: #000;
+      padding: 0.2em 0;
+    }
+
+    #loader-wrapper {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 999999;
+    }
+
+    #loader {
+      display: block;
+      position: relative;
+      left: 50%;
+      top: 50%;
+      width: 150px;
+      height: 150px;
+      margin: -75px 0 0 -75px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 2s linear infinite;
+      -ms-animation: spin 2s linear infinite;
+      -moz-animation: spin 2s linear infinite;
+      -o-animation: spin 2s linear infinite;
+      animation: spin 2s linear infinite;
+      z-index: 1001;
+    }
+
+    #loader:before {
+      content: "";
+      position: absolute;
+      top: 5px;
+      left: 5px;
+      right: 5px;
+      bottom: 5px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 3s linear infinite;
+      -moz-animation: spin 3s linear infinite;
+      -o-animation: spin 3s linear infinite;
+      -ms-animation: spin 3s linear infinite;
+      animation: spin 3s linear infinite;
+    }
+
+    #loader:after {
+      content: "";
+      position: absolute;
+      top: 15px;
+      left: 15px;
+      right: 15px;
+      bottom: 15px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -moz-animation: spin 1.5s linear infinite;
+      -o-animation: spin 1.5s linear infinite;
+      -ms-animation: spin 1.5s linear infinite;
+      -webkit-animation: spin 1.5s linear infinite;
+      animation: spin 1.5s linear infinite;
+    }
+
+
+    @-webkit-keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+    @keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+
+    #loader-wrapper .loader-section {
+      position: fixed;
+      top: 0;
+      width: 51%;
+      height: 100%;
+      background: #7171C6;
+      z-index: 1000;
+      -webkit-transform: translateX(0);
+      -ms-transform: translateX(0);
+      transform: translateX(0);
+    }
+
+    #loader-wrapper .loader-section.section-left {
+      left: 0;
+    }
+
+    #loader-wrapper .loader-section.section-right {
+      right: 0;
+    }
+
+
+    .loaded #loader-wrapper .loader-section.section-left {
+      -webkit-transform: translateX(-100%);
+      -ms-transform: translateX(-100%);
+      transform: translateX(-100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader-wrapper .loader-section.section-right {
+      -webkit-transform: translateX(100%);
+      -ms-transform: translateX(100%);
+      transform: translateX(100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader {
+      opacity: 0;
+      -webkit-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+    }
+
+    .loaded #loader-wrapper {
+      visibility: hidden;
+      -webkit-transform: translateY(-100%);
+      -ms-transform: translateY(-100%);
+      transform: translateY(-100%);
+      -webkit-transition: all 0.3s 1s ease-out;
+      transition: all 0.3s 1s ease-out;
+    }
+
+    .no-js #loader-wrapper {
+      display: none;
+    }
+
+    .no-js h1 {
+      color: #222222;
+    }
+
+    #loader-wrapper .load_title {
+      font-family: 'Open Sans';
+      color: #FFF;
+      font-size: 19px;
+      width: 100%;
+      text-align: center;
+      z-index: 9999999999999;
+      position: absolute;
+      top: 60%;
+      opacity: 1;
+      line-height: 30px;
+    }
+
+    #loader-wrapper .load_title span {
+      font-weight: normal;
+      font-style: italic;
+      font-size: 13px;
+      color: #FFF;
+      opacity: 0.5;
+    }
+  </style>
+  </head>
+  <body>
+    <div id="app">
+	    <div id="loader-wrapper">
+		    <div id="loader"></div>
+		    <div class="loader-section section-left"></div>
+		    <div class="loader-section section-right"></div>
+		    <div class="load_title">姝e湪鍔犺浇绯荤粺璧勬簮锛岃鑰愬績绛夊緟</div>
+        </div>
+	</div>
+  </body>
+</html>
diff --git a/ruoyi-ui/src/App.vue b/ruoyi-ui/src/App.vue
new file mode 100644
index 0000000..1d0634c
--- /dev/null
+++ b/ruoyi-ui/src/App.vue
@@ -0,0 +1,11 @@
+<template>
+  <div id="app">
+    <router-view />
+  </div>
+</template>
+
+<script>
+export default  {
+  name:  'App'
+}
+</script>
diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js
new file mode 100644
index 0000000..faa7bbe
--- /dev/null
+++ b/ruoyi-ui/src/api/login.js
@@ -0,0 +1,40 @@
+import request from '@/utils/request'
+
+// 鐧诲綍鏂规硶
+export function login(username, password, code, uuid) {
+  const data = {
+    username,
+    password,
+    code,
+    uuid
+  }
+  return request({
+    url: '/login',
+    method: 'post',
+    params: data
+  })
+}
+
+// 鑾峰彇鐢ㄦ埛璇︾粏淇℃伅
+export function getInfo() {
+  return request({
+    url: '/getInfo',
+    method: 'get'
+  })
+}
+
+// 閫�鍑烘柟娉�
+export function logout() {
+  return request({
+    url: '/logout',
+    method: 'post'
+  })
+}
+
+// 鑾峰彇楠岃瘉鐮�
+export function getCodeImg() {
+  return request({
+    url: '/captchaImage',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/menu.js b/ruoyi-ui/src/api/menu.js
new file mode 100644
index 0000000..6e52e6e
--- /dev/null
+++ b/ruoyi-ui/src/api/menu.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 鑾峰彇璺敱
+export const getRouters = () => {
+  return request({
+    url: '/getRouters',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/logininfor.js b/ruoyi-ui/src/api/monitor/logininfor.js
new file mode 100644
index 0000000..9914aaf
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/logininfor.js
@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鐧诲綍鏃ュ織鍒楄〃
+export function list(query) {
+  return request({
+    url: '/monitor/logininfor/list',
+    method: 'get',
+    params: query
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/operlog.js b/ruoyi-ui/src/api/monitor/operlog.js
new file mode 100644
index 0000000..a6088ad
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/operlog.js
@@ -0,0 +1,10 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鎿嶄綔鏃ュ織鍒楄〃
+export function list(query) {
+  return request({
+    url: '/monitor/operlog/list',
+    method: 'get',
+    params: query
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/server.js b/ruoyi-ui/src/api/monitor/server.js
new file mode 100644
index 0000000..4991a44
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/server.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鏈嶅姟鍣ㄨ缁�
+export function getServer() {
+  return request({
+    url: '/monitor/server',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/config.js b/ruoyi-ui/src/api/system/config.js
new file mode 100644
index 0000000..6ed1050
--- /dev/null
+++ b/ruoyi-ui/src/api/system/config.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍙傛暟鍒楄〃
+export function listConfig(query) {
+  return request({
+    url: '/system/config/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鍙傛暟璇︾粏
+export function getConfig(configId) {
+  return request({
+    url: '/system/config/' + configId,
+    method: 'get'
+  })
+}
+
+// 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+export function getConfigKey(configKey) {
+  return request({
+    url: '/system/config/configKey/' + configKey,
+    method: 'get'
+  })
+}
+
+// 鏂板鍙傛暟閰嶇疆
+export function addConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鍙傛暟閰嶇疆
+export function updateConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鍙傛暟閰嶇疆
+export function delConfig(configId) {
+  return request({
+    url: '/system/config/' + configId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dept.js b/ruoyi-ui/src/api/system/dept.js
new file mode 100644
index 0000000..2debf5a
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dept.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鏌ヨ閮ㄩ棬鍒楄〃
+export function listDept(query) {
+  return request({
+    url: '/system/dept/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ閮ㄩ棬璇︾粏
+export function getDept(deptId) {
+  return request({
+    url: '/system/dept/' + deptId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋�
+export function treeselect() {
+  return request({
+    url: '/system/dept/treeselect',
+    method: 'get'
+  })
+}
+
+// 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戠粨鏋�
+export function roleDeptTreeselect(roleId) {
+  return request({
+    url: '/system/dept/roleDeptTreeselect/' + roleId,
+    method: 'get'
+  })
+}
+
+// 鏂板閮ㄩ棬
+export function addDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼閮ㄩ棬
+export function updateDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎閮ㄩ棬
+export function delDept(deptId) {
+  return request({
+    url: '/system/dept/' + deptId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js
new file mode 100644
index 0000000..a0fb115
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dict/data.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+export function listData(query) {
+  return request({
+    url: '/system/dict/data/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+export function getData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'get'
+  })
+}
+
+// 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+export function getDicts(dictType) {
+  return request({
+    url: '/system/dict/data/dictType/' + dictType,
+    method: 'get'
+  })
+}
+
+// 鏂板瀛楀吀鏁版嵁
+export function addData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瀛楀吀鏁版嵁
+export function updateData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瀛楀吀鏁版嵁
+export function delData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/type.js b/ruoyi-ui/src/api/system/dict/type.js
new file mode 100644
index 0000000..749bfaa
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dict/type.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀛楀吀绫诲瀷鍒楄〃
+export function listType(query) {
+  return request({
+    url: '/system/dict/type/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+export function getType(dictId) {
+  return request({
+    url: '/system/dict/type/' + dictId,
+    method: 'get'
+  })
+}
+
+// 鏂板瀛楀吀绫诲瀷
+export function addType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瀛楀吀绫诲瀷
+export function updateType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瀛楀吀绫诲瀷
+export function delType(dictId) {
+  return request({
+    url: '/system/dict/type/' + dictId,
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/system/menu.js b/ruoyi-ui/src/api/system/menu.js
new file mode 100644
index 0000000..97258ee
--- /dev/null
+++ b/ruoyi-ui/src/api/system/menu.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鑿滃崟鍒楄〃
+export function listMenu(query) {
+  return request({
+    url: '/system/menu/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鑿滃崟璇︾粏
+export function getMenu(menuId) {
+  return request({
+    url: '/system/menu/' + menuId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋�
+export function treeselect() {
+  return request({
+    url: '/system/menu/treeselect',
+    method: 'get'
+  })
+}
+
+// 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋�
+export function roleMenuTreeselect(roleId) {
+  return request({
+    url: '/system/menu/roleMenuTreeselect/' + roleId,
+    method: 'get'
+  })
+}
+
+// 鏂板鑿滃崟
+export function addMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鑿滃崟
+export function updateMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鑿滃崟
+export function delMenu(menuId) {
+  return request({
+    url: '/system/menu/' + menuId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/notice.js b/ruoyi-ui/src/api/system/notice.js
new file mode 100644
index 0000000..737fc16
--- /dev/null
+++ b/ruoyi-ui/src/api/system/notice.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍏憡鍒楄〃
+export function listNotice(query) {
+  return request({
+    url: '/system/notice/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鍏憡璇︾粏
+export function getNotice(noticeId) {
+  return request({
+    url: '/system/notice/' + noticeId,
+    method: 'get'
+  })
+}
+
+// 鏂板鍏憡
+export function addNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鍏憡
+export function updateNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鍏憡
+export function delNotice(noticeId) {
+  return request({
+    url: '/system/notice/' + noticeId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/post.js b/ruoyi-ui/src/api/system/post.js
new file mode 100644
index 0000000..1bdf069
--- /dev/null
+++ b/ruoyi-ui/src/api/system/post.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ宀椾綅鍒楄〃
+export function listPost(query) {
+  return request({
+    url: '/system/post/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ宀椾綅璇︾粏
+export function getPost(postId) {
+  return request({
+    url: '/system/post/' + postId,
+    method: 'get'
+  })
+}
+
+// 鏂板宀椾綅
+export function addPost(data) {
+  return request({
+    url: '/system/post',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼宀椾綅
+export function updatePost(data) {
+  return request({
+    url: '/system/post',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎宀椾綅
+export function delPost(postId) {
+  return request({
+    url: '/system/post/' + postId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js
new file mode 100644
index 0000000..95a606d
--- /dev/null
+++ b/ruoyi-ui/src/api/system/role.js
@@ -0,0 +1,66 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瑙掕壊鍒楄〃
+export function listRole(query) {
+  return request({
+    url: '/system/role/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瑙掕壊璇︾粏
+export function getRole(roleId) {
+  return request({
+    url: '/system/role/' + roleId,
+    method: 'get'
+  })
+}
+
+// 鏂板瑙掕壊
+export function addRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瑙掕壊
+export function updateRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'put',
+    data: data
+  })
+}
+
+// 瑙掕壊鏁版嵁鏉冮檺
+export function dataScope(data) {
+  return request({
+    url: '/system/role/dataScope',
+    method: 'put',
+    data: data
+  })
+}
+
+// 瑙掕壊鐘舵�佷慨鏀�
+export function changeRoleStatus(roleId, status) {
+  const data = {
+    roleId,
+    status
+  }
+  return request({
+    url: '/system/role/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瑙掕壊
+export function delRole(roleId) {
+  return request({
+    url: '/system/role/' + roleId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js
new file mode 100644
index 0000000..55766af
--- /dev/null
+++ b/ruoyi-ui/src/api/system/user.js
@@ -0,0 +1,109 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鐢ㄦ埛鍒楄〃
+export function listUser(query) {
+  return request({
+    url: '/system/user/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鐢ㄦ埛璇︾粏
+export function getUser(userId) {
+  return request({
+    url: '/system/user/' + userId,
+    method: 'get'
+  })
+}
+
+// 鏂板鐢ㄦ埛
+export function addUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鐢ㄦ埛
+export function updateUser(data) {
+  return request({
+    url: '/system/user',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鐢ㄦ埛
+export function delUser(userId) {
+  return request({
+    url: '/system/user/' + userId,
+    method: 'delete'
+  })
+}
+
+// 鐢ㄦ埛瀵嗙爜閲嶇疆
+export function resetUserPwd(userId, password) {
+  const data = {
+    userId,
+    password
+  }
+  return request({
+    url: '/system/user/resetPwd',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鐢ㄦ埛鐘舵�佷慨鏀�
+export function changeUserStatus(userId, status) {
+  const data = {
+    userId,
+    status
+  }
+  return request({
+    url: '/system/user/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鏌ヨ鐢ㄦ埛涓汉淇℃伅
+export function getUserProfile() {
+  return request({
+    url: '/system/user/profile',
+    method: 'get'
+  })
+}
+
+// 淇敼鐢ㄦ埛涓汉淇℃伅
+export function updateUserProfile(data) {
+  return request({
+    url: '/system/user/profile',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鐢ㄦ埛瀵嗙爜閲嶇疆
+export function updateUserPwd(oldPassword, newPassword) {
+  const data = {
+    oldPassword,
+    newPassword
+  }
+  return request({
+    url: '/system/user/profile/updatePwd',
+    method: 'put',
+    params: data
+  })
+}
+
+// 鐢ㄦ埛澶村儚涓婁紶
+export function uploadAvatar(data) {
+  return request({
+    url: '/system/user/profile/avatar',
+    method: 'post',
+    data: data
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/401_images/401.gif b/ruoyi-ui/src/assets/401_images/401.gif
new file mode 100644
index 0000000..cd6e0d9
--- /dev/null
+++ b/ruoyi-ui/src/assets/401_images/401.gif
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404.png b/ruoyi-ui/src/assets/404_images/404.png
new file mode 100644
index 0000000..3d8e230
--- /dev/null
+++ b/ruoyi-ui/src/assets/404_images/404.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404_cloud.png b/ruoyi-ui/src/assets/404_images/404_cloud.png
new file mode 100644
index 0000000..c6281d0
--- /dev/null
+++ b/ruoyi-ui/src/assets/404_images/404_cloud.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/icons/index.js b/ruoyi-ui/src/assets/icons/index.js
new file mode 100644
index 0000000..d79e164
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/index.js
@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)
diff --git a/ruoyi-ui/src/assets/icons/svg/404.svg b/ruoyi-ui/src/assets/icons/svg/404.svg
new file mode 100644
index 0000000..6df5019
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/404.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/bug.svg b/ruoyi-ui/src/assets/icons/svg/bug.svg
new file mode 100644
index 0000000..05a150d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/bug.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/build.svg b/ruoyi-ui/src/assets/icons/svg/build.svg
new file mode 100644
index 0000000..97c4688
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/build.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/chart.svg b/ruoyi-ui/src/assets/icons/svg/chart.svg
new file mode 100644
index 0000000..27728fb
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/chart.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/clipboard.svg b/ruoyi-ui/src/assets/icons/svg/clipboard.svg
new file mode 100644
index 0000000..90923ff
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/clipboard.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/code.svg b/ruoyi-ui/src/assets/icons/svg/code.svg
new file mode 100644
index 0000000..ed4d23c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/code.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1546567861908" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2422" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M318.577778 819.2L17.066667 512l301.511111-307.2 45.511111 45.511111L96.711111 512l267.377778 261.688889zM705.422222 819.2l-45.511111-45.511111L927.288889 512l-267.377778-261.688889 45.511111-45.511111L1006.933333 512zM540.785778 221.866667l55.751111 11.150222L483.157333 802.133333l-55.751111-11.093333z" fill="#bfbfbf" p-id="2423"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/component.svg b/ruoyi-ui/src/assets/icons/svg/component.svg
new file mode 100644
index 0000000..207ada3
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/component.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 0h54.857v54.857H0V0zm0 73.143h54.857V128H0V73.143zm73.143 0H128V128H73.143V73.143zm27.428-18.286C115.72 54.857 128 42.577 128 27.43 128 12.28 115.72 0 100.571 0 85.423 0 73.143 12.28 73.143 27.429c0 15.148 12.28 27.428 27.428 27.428z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/dashboard.svg b/ruoyi-ui/src/assets/icons/svg/dashboard.svg
new file mode 100644
index 0000000..5317d37
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/dashboard.svg
@@ -0,0 +1 @@
+<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/date.svg b/ruoyi-ui/src/assets/icons/svg/date.svg
new file mode 100644
index 0000000..2a28112
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/date.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1567417179372" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1155" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M947.2 1024 76.8 1024C38.4 1024 0 992 0 953.6L0 172.8c0-38.4 38.4-70.4 76.8-70.4l38.4 0 0 102.4c0 38.4 38.4 70.4 76.8 70.4l76.8 0c44.8 0 76.8-32 76.8-70.4L345.6 102.4l313.6 0 0 102.4c0 38.4 38.4 70.4 76.8 70.4l76.8 0c44.8 0 76.8-32 76.8-70.4L889.6 102.4l38.4 0c44.8 0 76.8 32 76.8 70.4l0 787.2C1024 992 985.6 1024 947.2 1024zM352 339.2 115.2 339.2 115.2 512l236.8 0L352 339.2zM352 544 115.2 544l0 172.8 236.8 0L352 544zM352 748.8 115.2 748.8l0 172.8 236.8 0L352 748.8zM627.2 339.2 396.8 339.2 396.8 512l236.8 0L633.6 339.2zM627.2 544 396.8 544l0 172.8 236.8 0L633.6 544zM627.2 748.8 396.8 748.8l0 172.8 236.8 0L633.6 748.8zM908.8 339.2l-236.8 0L672 512l236.8 0L908.8 339.2zM908.8 544l-236.8 0 0 172.8 236.8 0L908.8 544zM908.8 748.8l-236.8 0 0 172.8 236.8 0L908.8 748.8zM787.2 236.8c-44.8 0-76.8-32-76.8-70.4L710.4 70.4c0-38.4 38.4-70.4 76.8-70.4s76.8 32 76.8 70.4l0 102.4C864 211.2 832 236.8 787.2 236.8zM236.8 236.8C192 236.8 160 211.2 160 172.8L160 70.4C160 32 192 0 236.8 0s76.8 32 76.8 70.4l0 102.4C313.6 211.2 281.6 236.8 236.8 236.8z" p-id="1156"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/dict.svg b/ruoyi-ui/src/assets/icons/svg/dict.svg
new file mode 100644
index 0000000..4849377
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/dict.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035680909" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3601" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1002.0848 744.672l-33.568 10.368c0.96 7.264 2.144 14.304 2.144 21.76 0 7.328-1.184 14.432-2.368 21.568l33.792 10.56c7.936 2.24 14.496 7.616 18.336 14.752 3.84 7.328 4.672 15.808 1.952 23.552-5.376 16-23.168 24.672-39.936 19.68l-34.176-10.624c-7.136 12.8-15.776 24.672-26.208 35.2l20.8 27.488a28.96 28.96 0 0 1 5.824 22.816 29.696 29.696 0 0 1-12.704 19.616 32.544 32.544 0 0 1-44.416-6.752l-20.8-27.552c-13.696 6.56-28.192 11.2-43.008 13.888v33.632c0 16.736-14.112 30.432-31.648 30.432-17.6 0-31.872-13.696-31.872-30.432v-33.632a167.616 167.616 0 0 1-42.88-13.888l-20.928 27.552c-10.72 13.76-30.08 16.64-44.288 6.752a29.632 29.632 0 0 1-12.704-19.616 29.28 29.28 0 0 1 5.696-22.816l20.896-27.808a166.72 166.72 0 0 1-27.008-34.688l-33.376 10.432c-16.8 5.184-34.56-3.552-39.936-19.616a29.824 29.824 0 0 1 20.224-38.24l33.472-10.432c-0.8-7.264-2.016-14.304-2.016-21.824 0-7.36 1.184-14.496 2.304-21.632l-33.792-10.368c-16.672-5.376-25.632-22.496-20.224-38.432 5.376-16 23.136-24.672 39.936-19.68l34.016 10.752c7.328-12.672 15.84-24.8 26.336-35.328l-20.8-27.552a29.44 29.44 0 0 1 6.944-42.432 32.704 32.704 0 0 1 44.384 6.752l20.832 27.616c13.696-6.432 28.224-11.2 43.104-13.952v-33.568c0-16.736 14.048-30.432 31.648-30.432 17.536 0 31.808 13.568 31.808 30.432v33.504c15.072 2.688 29.344 7.808 42.848 14.016l20.992-27.616a32.48 32.48 0 0 1 44.224-6.752 29.568 29.568 0 0 1 7.136 42.432l-21.024 27.808c10.432 10.432 19.872 21.888 27.04 34.752l33.376-10.432c16.768-5.12 34.56 3.68 39.936 19.68 5.536 15.936-3.712 33.056-20.32 38.304z m-206.016-74.432c-61.344 0-111.136 47.808-111.136 106.56 0 58.88 49.792 106.496 111.136 106.496 61.312 0 111.104-47.616 111.104-106.496 0-58.752-49.792-106.56-111.104-106.56z" p-id="3602"></path><path d="M802.7888 57.152h-76.448c0-22.08-21.024-38.24-42.848-38.24H39.3968a39.68 39.68 0 0 0-39.36 40.032v795.616s41.888 120.192 110.752 120.192H673.2848a227.488 227.488 0 0 1-107.04-97.44H117.6368s-40.608-13.696-40.608-41.248l470.304-0.256 1.664 3.36a227.68 227.68 0 0 1-12.64-73.632c0-60.576 24-118.624 66.88-161.44a228.352 228.352 0 0 1 123.552-63.392l-3.2 0.288 2.144-424.672h38.208l0.576 421.024c27.04 0 52.672 4.8 76.64 13.344V101.536c0.032 0-6.304-44.384-38.368-44.384zM149.7648 514.336H72.3888v-77.408H149.7648v77.408z m0-144.32H72.3888v-77.44H149.7648v77.44z m0-137.248H72.3888v-77.44H149.7648v77.44z m501.856 281.568H206.0848v-77.408h445.536v77.408z m0-144.32H206.0848v-77.44h445.536v77.44z m0-137.248H206.0848v-77.44h445.536v77.44z" p-id="3603"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/documentation.svg b/ruoyi-ui/src/assets/icons/svg/documentation.svg
new file mode 100644
index 0000000..7043122
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/documentation.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/download.svg b/ruoyi-ui/src/assets/icons/svg/download.svg
new file mode 100644
index 0000000..c896951
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/download.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569915748289" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3062" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M768.35456 416a256 256 0 1 0-512 0 192 192 0 1 0 0 384v64a256 256 0 0 1-58.88-505.216 320.128 320.128 0 0 1 629.76 0A256.128 256.128 0 0 1 768.35456 864v-64a192 192 0 0 0 0-384z m-512 384h64v64H256.35456v-64z m448 0h64v64h-64v-64z" fill="#333333" p-id="3063"></path><path d="M539.04256 845.248V512.192a32.448 32.448 0 0 0-32-32.192c-17.664 0-32 14.912-32 32.192v333.056l-36.096-36.096a32.192 32.192 0 0 0-45.056 0.192 31.616 31.616 0 0 0-0.192 45.056l90.88 90.944a31.36 31.36 0 0 0 22.528 9.088 30.08 30.08 0 0 0 22.4-9.088l90.88-90.88a32.192 32.192 0 0 0-0.192-45.12 31.616 31.616 0 0 0-45.056-0.192l-36.096 36.096z" fill="#333333" p-id="3064"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/drag.svg b/ruoyi-ui/src/assets/icons/svg/drag.svg
new file mode 100644
index 0000000..4185d3c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/drag.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M73.137 29.08h-9.209 29.7L63.886.093 34.373 29.08h20.49v27.035H27.238v17.948h27.625v27.133h18.274V74.063h27.41V56.115h-27.41V29.08zm-9.245 98.827l27.518-26.711H36.59l27.302 26.71zM.042 64.982l27.196 27.029V38.167L.042 64.982zm100.505-26.815V92.01l27.41-27.029-27.41-26.815z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/druid.svg b/ruoyi-ui/src/assets/icons/svg/druid.svg
new file mode 100644
index 0000000..a2b4b4e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/druid.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036347051" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5853" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M832 128H192a64.19 64.19 0 0 0-64 64v640a64.19 64.19 0 0 0 64 64h640a64.19 64.19 0 0 0 64-64V192a64.19 64.19 0 0 0-64-64z m0 703.89l-0.11 0.11H192.11l-0.11-0.11V768h640zM832 544H720L605.6 696.54 442.18 435.07 333.25 544H192v-64h114.75l147.07-147.07L610.4 583.46 688 480h144z m0-288H192v-63.89l0.11-0.11h639.78l0.11 0.11z" p-id="5854"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/edit.svg b/ruoyi-ui/src/assets/icons/svg/edit.svg
new file mode 100644
index 0000000..d26101f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/edit.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/education.svg b/ruoyi-ui/src/assets/icons/svg/education.svg
new file mode 100644
index 0000000..7bfb01d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/education.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/email.svg b/ruoyi-ui/src/assets/icons/svg/email.svg
new file mode 100644
index 0000000..74d25e2
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/email.svg
@@ -0,0 +1 @@
+<svg width="128" height="96" xmlns="http://www.w3.org/2000/svg"><path d="M64.125 56.975L120.188.912A12.476 12.476 0 0 0 115.5 0h-103c-1.588 0-3.113.3-4.513.838l56.138 56.137z"/><path d="M64.125 68.287l-62.3-62.3A12.42 12.42 0 0 0 0 12.5v71C0 90.4 5.6 96 12.5 96h103c6.9 0 12.5-5.6 12.5-12.5v-71a12.47 12.47 0 0 0-1.737-6.35L64.125 68.287z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/example.svg b/ruoyi-ui/src/assets/icons/svg/example.svg
new file mode 100644
index 0000000..46f42b5
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/example.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/excel.svg b/ruoyi-ui/src/assets/icons/svg/excel.svg
new file mode 100644
index 0000000..74d97b8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/excel.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.208 16.576v8.384h38.72v5.376h-38.72v8.704h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.512h38.72v5.376h-38.72v11.136H128v-94.72H78.208zM0 114.368L72.128 128V0L0 13.632v100.736z"/><path d="M28.672 82.56h-11.2l14.784-23.488-14.08-22.592h11.52l8.192 14.976 8.448-14.976h11.136l-14.08 22.208L58.368 82.56H46.656l-8.768-15.68z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg b/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg
new file mode 100644
index 0000000..485c128
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/eye-open.svg b/ruoyi-ui/src/assets/icons/svg/eye-open.svg
new file mode 100644
index 0000000..88dcc98
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/eye-open.svg
@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/eye.svg b/ruoyi-ui/src/assets/icons/svg/eye.svg
new file mode 100644
index 0000000..16ed2d8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/eye.svg
@@ -0,0 +1 @@
+<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/form.svg b/ruoyi-ui/src/assets/icons/svg/form.svg
new file mode 100644
index 0000000..dcbaa18
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/form.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/fullscreen.svg b/ruoyi-ui/src/assets/icons/svg/fullscreen.svg
new file mode 100644
index 0000000..0e86b6f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/fullscreen.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/guide.svg b/ruoyi-ui/src/assets/icons/svg/guide.svg
new file mode 100644
index 0000000..b271001
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/guide.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.482 70.131l36.204 16.18 69.932-65.485-61.38 70.594 46.435 18.735c1.119.425 2.397-.17 2.797-1.363v-.085L127.998.047 1.322 65.874c-1.12.597-1.519 1.959-1.04 3.151.32.511.72.937 1.2 1.107zm44.676 57.821L64.22 107.26l-18.062-7.834v28.527z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/icon.svg b/ruoyi-ui/src/assets/icons/svg/icon.svg
new file mode 100644
index 0000000..82be8ee
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/icon.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.147.062a13 13 0 0 1 4.94.945c1.55.63 2.907 1.526 4.069 2.688a13.148 13.148 0 0 1 2.761 4.069c.678 1.55 1.017 3.245 1.017 5.086v102.3c0 3.681-1.187 6.733-3.56 9.155-2.373 2.422-5.352 3.633-8.937 3.633H12.992c-3.875 0-7-1.26-9.373-3.779-2.373-2.518-3.56-5.667-3.56-9.445V12.704c0-3.39 1.163-6.345 3.488-8.863C5.872 1.32 8.972.062 12.847.062h102.3zM81.434 109.047c1.744 0 3.003-.412 3.778-1.235.775-.824 1.163-1.914 1.163-3.27 0-1.26-.388-2.325-1.163-3.197-.775-.872-2.034-1.307-3.778-1.307H72.57c.097-.194.145-.485.145-.872V27.09h9.01c1.743 0 2.954-.436 3.633-1.308.678-.872 1.017-1.938 1.017-3.197 0-1.26-.34-2.325-1.017-3.197-.679-.872-1.89-1.308-3.633-1.308H46.268c-1.743 0-2.954.436-3.632 1.308-.678.872-1.018 1.938-1.018 3.197 0 1.26.34 2.325 1.018 3.197.678.872 1.889 1.308 3.632 1.308h8.138v72.075c0 .193.024.339.073.436.048.096.072.242.072.436H46.56c-1.744 0-3.003.435-3.778 1.307-.775.872-1.163 1.938-1.163 3.197 0 1.356.388 2.446 1.163 3.27.775.823 2.034 1.235 3.778 1.235h34.875z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/international.svg b/ruoyi-ui/src/assets/icons/svg/international.svg
new file mode 100644
index 0000000..e9b56ee
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/international.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M83.287 103.01c-1.57-3.84-6.778-10.414-15.447-19.548-2.327-2.444-2.182-4.306-1.338-9.862v-.64c.553-3.81 1.513-6.05 14.313-8.087 6.516-1.018 8.203 1.57 10.589 5.178l.785 1.193a12.625 12.625 0 0 0 6.43 5.207c1.134.524 2.53 1.164 4.421 2.24 4.596 2.53 4.596 5.41 4.596 11.753v.727a26.91 26.91 0 0 1-5.178 17.454 59.055 59.055 0 0 1-19.025 11.026c3.49-6.546.814-14.313 0-16.553l-.146-.087zM64 5.12a58.502 58.502 0 0 1 25.484 5.818 54.313 54.313 0 0 0-12.859 10.327c-.93 1.28-1.716 2.473-2.472 3.579-2.444 3.694-3.637 5.352-5.818 5.614a25.105 25.105 0 0 1-4.219 0c-4.276-.29-10.094-.64-11.956 4.422-1.193 3.23-1.396 11.956 2.444 16.495.66 1.077.778 2.4.32 3.578a7.01 7.01 0 0 1-2.066 3.229 18.938 18.938 0 0 1-2.909-2.91 18.91 18.91 0 0 0-8.32-6.603c-1.25-.349-2.647-.64-3.985-.93-3.782-.786-8.03-1.688-9.019-3.812a14.895 14.895 0 0 1-.727-5.818 21.935 21.935 0 0 0-1.396-9.25 8.873 8.873 0 0 0-5.557-4.946A58.705 58.705 0 0 1 64 5.12zM0 64c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64 0-35.346-28.654-64-64-64C28.654 0 0 28.654 0 64z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/job.svg b/ruoyi-ui/src/assets/icons/svg/job.svg
new file mode 100644
index 0000000..2a93a25
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/job.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036191400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5472" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M934.912 1016.832H192c-14.336 0-25.6-11.264-25.6-25.6v-189.44c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v163.84h691.712V64H217.6v148.48c0 14.336-11.264 25.6-25.6 25.6s-25.6-11.264-25.6-25.6v-174.08c0-14.336 11.264-25.6 25.6-25.6h742.912c14.336 0 25.6 11.264 25.6 25.6v952.832c0 14.336-11.264 25.6-25.6 25.6z" p-id="5473"></path><path d="M232.96 371.2h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 540.16h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 698.88h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM574.464 762.88c-134.144 0-243.2-109.056-243.2-243.2S440.32 276.48 574.464 276.48s243.2 109.056 243.2 243.2-109.056 243.2-243.2 243.2z m0-435.2c-105.984 0-192 86.016-192 192S468.48 711.68 574.464 711.68s192-86.016 192-192S680.448 327.68 574.464 327.68z" p-id="5474"></path><path d="M663.04 545.28h-87.04c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h87.04c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6z" p-id="5475"></path><path d="M576 545.28c-14.336 0-25.6-11.264-25.6-25.6v-87.04c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v87.04c0 14.336-11.264 25.6-25.6 25.6z" p-id="5476"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/language.svg b/ruoyi-ui/src/assets/icons/svg/language.svg
new file mode 100644
index 0000000..0082b57
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/language.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.742 36.8c2.398 7.2 5.595 12.8 11.19 18.4 4.795-4.8 7.992-11.2 10.39-18.4h-21.58zm-52.748 40h20.78l-10.39-28-10.39 28z"/><path d="M111.916 0H16.009C7.218 0 .025 7.2.025 16v96c0 8.8 7.193 16 15.984 16h95.907c8.791 0 15.984-7.2 15.984-16V16c0-8.8-6.394-16-15.984-16zM72.754 103.2c-1.598 1.6-3.197 1.6-4.795 1.6-.8 0-2.398 0-3.197-.8-.8-.8-1.599 0-1.599-.8s-.799-1.6-1.598-3.2c-.8-1.6-.8-2.4-1.599-4l-3.196-8.8H28.797L25.6 96c-1.598 3.2-2.398 5.6-3.197 7.2-.8 1.6-2.398 1.6-4.795 1.6-1.599 0-3.197-.8-4.796-1.6-1.598-1.6-2.397-2.4-2.397-4 0-.8 0-1.6.799-3.2.8-1.6.8-2.4 1.598-4l17.583-44.8c.8-1.6.8-3.2 1.599-4.8.799-1.6 1.598-3.2 2.397-4 .8-.8 1.599-2.4 3.197-3.2 1.599-.8 3.197-.8 4.796-.8 1.598 0 3.196 0 4.795.8 1.598.8 2.398 1.6 3.197 3.2.799.8 1.598 2.4 2.397 4 .8 1.6 1.599 3.2 2.398 5.6l17.583 44c1.598 3.2 2.398 5.6 2.398 7.2-.8.8-1.599 2.4-2.398 4zM116.711 72c-8.791-3.2-15.185-7.2-20.78-12-5.594 5.6-12.787 9.6-21.579 12l-2.397-4c8.791-2.4 15.984-5.6 21.579-11.2C87.939 51.2 83.144 44 81.545 36h-7.992v-3.2h21.58c-1.6-2.4-3.198-5.6-4.796-8l2.397-.8c1.599 2.4 3.997 5.6 5.595 8.8h19.98v4h-7.992c-2.397 8-6.393 15.2-11.189 20 5.595 4.8 11.988 8.8 20.78 11.2l-3.197 4z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/link.svg b/ruoyi-ui/src/assets/icons/svg/link.svg
new file mode 100644
index 0000000..48197ba
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/link.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/list.svg b/ruoyi-ui/src/assets/icons/svg/list.svg
new file mode 100644
index 0000000..20259ed
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/list.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.585 12.087c0 6.616 3.974 11.98 8.877 11.98 4.902 0 8.877-5.364 8.877-11.98 0-6.616-3.975-11.98-8.877-11.98-4.903 0-8.877 5.364-8.877 11.98zM125.86.107H35.613c-1.268 0-2.114 1.426-2.114 2.852v18.255c0 1.712 1.057 2.853 2.114 2.853h90.247c1.268 0 2.114-1.426 2.114-2.853V2.96c0-1.711-1.057-2.852-2.114-2.852zM.106 62.86c0 6.615 3.974 11.979 8.876 11.979 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zM124.17 50.88H33.921c-1.268 0-2.114 1.425-2.114 2.851v18.256c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852V53.73c0-1.426-.846-2.852-2.114-2.852zM.106 115.913c0 6.616 3.974 11.98 8.876 11.98 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zm124.064-11.98H33.921c-1.268 0-2.114 1.426-2.114 2.853v18.255c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852v-18.255c0-1.427-.846-2.853-2.114-2.853z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/lock.svg b/ruoyi-ui/src/assets/icons/svg/lock.svg
new file mode 100644
index 0000000..74fee54
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/lock.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M119.88 49.674h-7.987V39.52C111.893 17.738 90.45.08 63.996.08 37.543.08 16.1 17.738 16.1 39.52v10.154H8.113c-4.408 0-7.987 2.94-7.987 6.577v65.13c0 3.637 3.57 6.577 7.987 6.577H119.88c4.407 0 7.987-2.94 7.987-6.577v-65.13c-.008-3.636-3.58-6.577-7.987-6.577zm-23.953 0H32.065V39.52c0-14.524 14.301-26.295 31.931-26.295 17.63 0 31.932 11.777 31.932 26.295v10.153z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/log.svg b/ruoyi-ui/src/assets/icons/svg/log.svg
new file mode 100644
index 0000000..d879d33
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/log.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035943711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4805" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M208.736 566.336H64.384v59.328h144.352v-59.328z m0-336.096H165.44V74.592c0-7.968 4.896-14.848 10.464-14.848h502.016V0.448H175.936c-38.72 1.248-69.248 34.368-68.192 74.144v155.648H64.384V289.6h144.352V230.24z m0 168.096H64.384v59.328h144.352v-59.328z m714.656 76.576h-57.76v474.496c0 7.936-4.896 14.848-10.464 14.848H175.936c-5.568 0-10.464-6.912-10.464-14.848v-155.68h43.296v-59.296H64.384v59.296h43.328v155.68c-1.024 39.776 29.472 72.896 68.192 74.144h679.232c38.72-1.184 69.248-34.368 68.256-74.144V474.912z m14.944-290.336l-83.072-85.312a71.264 71.264 0 0 0-52.544-21.728 71.52 71.52 0 0 0-51.616 23.872L386.528 507.264a30.496 30.496 0 0 0-6.176 10.72L308.16 740.512a30.016 30.016 0 0 0 6.976 30.24c7.712 7.968 19.2 10.752 29.568 7.2l216.544-74.112a28.736 28.736 0 0 0 12.128-7.936L940.448 287.456a75.552 75.552 0 0 0-2.112-102.88z m-557.12 518.272l39.104-120.64 78.336 80.416-117.44 40.224z m170.048-70.016l-103.552-106.016 200.16-222.4 103.52 106.304-200.128 222.112zM897.952 247.072l-0.256 0.224-107.136 119.168-103.52-106.528 106.432-118.624a14.144 14.144 0 0 1 10.304-4.736 13.44 13.44 0 0 1 10.464 4.288l83.264 85.696c5.472 5.6 5.664 14.72 0.448 20.512z" p-id="4806"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/logininfor.svg b/ruoyi-ui/src/assets/icons/svg/logininfor.svg
new file mode 100644
index 0000000..267f844
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/logininfor.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036016814" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5261" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 128h-85.333333a42.666667 42.666667 0 0 0 0 85.333333h42.666666v640H170.666667V213.333333h42.666666a42.666667 42.666667 0 0 0 0-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666667v725.333333a42.666667 42.666667 0 0 0 42.666667 42.666667h768a42.666667 42.666667 0 0 0 42.666667-42.666667V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667z" p-id="5262"></path><path d="M341.333333 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666666 42.666667zM512 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333334 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM682.666667 298.666667a42.666667 42.666667 0 0 0 42.666666-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM341.333333 768a42.666667 42.666667 0 0 0 42.666667-42.666667 128 128 0 0 1 256 0 42.666667 42.666667 0 0 0 85.333333 0 213.333333 213.333333 0 0 0-107.52-184.32A128 128 0 0 0 640 469.333333a128 128 0 0 0-256 0 128 128 0 0 0 22.186667 71.68A213.333333 213.333333 0 0 0 298.666667 725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667z m128-298.666667a42.666667 42.666667 0 1 1 42.666667 42.666667 42.666667 42.666667 0 0 1-42.666667-42.666667z" p-id="5263"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/message.svg b/ruoyi-ui/src/assets/icons/svg/message.svg
new file mode 100644
index 0000000..14ca817
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/message.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/money.svg b/ruoyi-ui/src/assets/icons/svg/money.svg
new file mode 100644
index 0000000..c1580de
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/money.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/monitor.svg b/ruoyi-ui/src/assets/icons/svg/monitor.svg
new file mode 100644
index 0000000..70db62b
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/monitor.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/nested.svg b/ruoyi-ui/src/assets/icons/svg/nested.svg
new file mode 100644
index 0000000..06713a8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/nested.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/online.svg b/ruoyi-ui/src/assets/icons/svg/online.svg
new file mode 100644
index 0000000..330a202
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/online.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899557259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="535" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M356.246145 681.56286c-68.156286-41.949414-107.246583-103.84102-107.246583-169.805384 0-65.966411 39.090297-127.860063 107.246583-169.809477 12.046361-7.414877 15.800871-23.190165 8.385994-35.236526-7.413853-12.046361-23.191188-15.801894-35.236526-8.387018-39.640836 24.399713-72.539106 56.044434-95.137801 91.515297-23.86657 37.461193-36.481889 79.620385-36.481889 121.917724 0 42.297338 12.615319 84.454484 36.481889 121.914654 22.598694 35.469839 55.496965 67.11456 95.137801 91.51325 4.185322 2.576685 8.821923 3.804652 13.400195 3.804652 8.598842 0 16.998139-4.329609 21.836331-12.190647C372.047016 704.752002 368.291482 688.976714 356.246145 681.56286zM263.943926 754.580874c-92.603071-61.111846-145.713686-149.623739-145.713686-242.840794 0-93.195565 53.094242-181.682899 145.667637-242.774279 11.805884-7.79043 15.061021-23.677259 7.269567-35.483142-7.79043-11.805884-23.677259-15.062044-35.483142-7.269567C128.487861 296.954249 67.006602 401.024489 67.006602 511.74008c0 110.73708 61.496609 214.830857 168.721703 285.593504 4.343935 2.867304 9.240455 4.238534 14.08274 4.238534 8.317433 0 16.476253-4.046153 21.400403-11.507078C279.003923 778.258133 275.748786 762.372328 263.943926 754.580874zM788.660552 226.213092c-11.80486-7.791453-27.692712-4.536316-35.483142 7.269567-7.79043 11.805884-4.536316 27.692712 7.269567 35.483142 92.575442 61.092403 145.670707 149.579737 145.670707 242.774279 0 93.216032-53.111638 181.727924-145.715733 242.840794-11.805884 7.79043-15.059997 23.678282-7.269567 35.484166 4.925173 7.461949 13.081946 11.507078 21.400403 11.507078 4.841262 0 9.739828-1.37123 14.083763-4.238534 107.22714-70.761624 168.724773-174.857447 168.724773-285.593504C957.341323 401.025513 895.860063 296.955272 788.660552 226.213092zM790.090111 633.67213c23.865547-37.459147 36.480866-79.617315 36.480866-121.914654 0-42.298362-12.615319-84.45653-36.480866-121.917724-22.598694-35.470863-55.496965-67.115584-95.139847-91.515297-12.047384-7.413853-27.821649-3.659343-35.236526 8.387018-7.414877 12.045337-3.659343 27.821649 8.385994 35.236526 68.156286 41.949414 107.247606 103.842043 107.247606 169.809477 0 65.964364-39.090297 127.85597-107.247606 169.804361-12.045337 7.414877-15.800871 23.190165-8.385994 35.237549 4.838192 7.861038 13.236466 12.190647 21.835308 12.190647 4.579295 0 9.215896-1.227967 13.400195-3.804652C734.591099 700.786691 767.490394 669.142993 790.090111 633.67213zM567.129086 518.274914c24.12342-17.150612 39.887452-45.305859 39.887452-77.07133 0-52.128241-42.452881-94.538143-94.634334-94.538143-52.18043 0-94.633311 42.408879-94.633311 94.538143 0 31.695886 15.696494 59.797921 39.730886 76.958766-49.875944 21.128203-84.917018 70.234621-84.917018 127.301338 0 2.366907 0.061398 4.762467 0.182149 7.119141l1.249457 24.296359 276.373515 0 1.238201-24.308639c0.119727-2.358721 0.181125-4.750187 0.181125-7.106862C651.786185 588.497255 616.865861 539.465538 567.129086 518.274914zM512.381182 397.889079c23.937179 0 43.411719 19.430538 43.411719 43.314505 0 23.882943-19.47454 43.313481-43.411719 43.313481-23.936155 0-43.409672-19.430538-43.409672-43.313481C468.971509 417.320641 488.445026 397.889079 512.381182 397.889079zM426.08884 625.656573c9.119705-38.542828 44.254923-67.337641 86.085634-67.337641s76.966952 28.794813 86.085634 67.337641L426.08884 625.656573z" p-id="536"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/password.svg b/ruoyi-ui/src/assets/icons/svg/password.svg
new file mode 100644
index 0000000..e291d85
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/password.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M108.8 44.322H89.6v-5.36c0-9.04-3.308-24.163-25.6-24.163-23.145 0-25.6 16.881-25.6 24.162v5.361H19.2v-5.36C19.2 15.281 36.798 0 64 0c27.202 0 44.8 15.281 44.8 38.961v5.361zm-32 39.356c0-5.44-5.763-9.832-12.8-9.832-7.037 0-12.8 4.392-12.8 9.832 0 3.682 2.567 6.808 6.407 8.477v11.205c0 2.718 2.875 4.962 6.4 4.962 3.524 0 6.4-2.244 6.4-4.962V92.155c3.833-1.669 6.393-4.795 6.393-8.477zM128 64v49.201c0 8.158-8.645 14.799-19.2 14.799H19.2C8.651 128 0 121.359 0 113.201V64c0-8.153 8.645-14.799 19.2-14.799h89.6c10.555 0 19.2 6.646 19.2 14.799z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/pdf.svg b/ruoyi-ui/src/assets/icons/svg/pdf.svg
new file mode 100644
index 0000000..957aa0c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/pdf.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><path d="M869.073 277.307H657.111V65.344l211.962 211.963zm-238.232 26.27V65.344l-476.498-.054v416.957h714.73v-178.67H630.841zm-335.836 360.57c-5.07-3.064-10.944-5.133-17.61-6.201-6.67-1.064-13.603-1.6-20.81-1.6h-48.821v85.641h48.822c7.206 0 14.14-.532 20.81-1.6 6.665-1.065 12.54-3.133 17.609-6.202 5.064-3.063 9.134-7.406 12.208-13.007 3.065-5.602 4.6-12.937 4.6-22.011 0-9.07-1.535-16.408-4.6-22.01-3.074-5.603-7.144-9.94-12.208-13.01zM35.82 541.805v416.904h952.358V541.805H35.821zm331.421 191.179c-3.6 11.071-9.343 20.879-17.209 29.413-7.874 8.542-18.078 15.408-30.617 20.61-12.544 5.206-27.747 7.807-45.621 7.807h-66.036v102.45h-62.831V607.517h128.867c17.874 0 33.077 2.6 45.62 7.802 12.541 5.207 22.745 12.076 30.618 20.615 7.866 8.538 13.604 18.277 17.21 29.212 3.6 10.943 5.401 22.278 5.401 34.018 0 11.477-1.8 22.752-5.402 33.819zM644.9 806.417c-5.343 17.61-13.408 32.818-24.212 45.627-10.807 12.803-24.283 22.879-40.423 30.213-16.146 7.343-35.155 11.007-57.03 11.007h-123.26V607.518h123.26c18.41 0 35.552 2.941 51.428 8.808 15.873 5.869 29.618 14.671 41.22 26.412 11.608 11.744 20.674 26.411 27.217 44.02 6.535 17.61 9.803 38.288 9.803 62.035 0 20.81-2.67 40.02-8.003 57.624zm245.362-146.07h-138.07v66.03h119.66v48.829h-119.66v118.058h-62.83V607.518h200.9v52.829h-.001zm-318.2 25.611c-6.402-8.266-14.877-14.604-25.412-19.01-10.544-4.402-23.551-6.602-39.019-6.602h-44.825v180.088h56.029c9.07 0 17.872-1.463 26.415-4.401 8.535-2.932 16.14-7.802 22.812-14.609 6.665-6.8 12.007-15.667 16.007-26.61 4.003-10.94 6.003-24.275 6.003-40.021 0-14.408-1.4-27.416-4.202-39.019-2.8-11.607-7.406-21.542-13.808-29.816zm0 0"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/people.svg b/ruoyi-ui/src/assets/icons/svg/people.svg
new file mode 100644
index 0000000..2bd54ae
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/people.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M104.185 95.254c8.161 7.574 13.145 17.441 13.145 28.28 0 1.508-.098 2.998-.285 4.466h-10.784c.238-1.465.403-2.948.403-4.465 0-8.983-4.36-17.115-11.419-23.216C86 104.66 75.355 107.162 64 107.162c-11.344 0-21.98-2.495-31.22-6.83-7.064 6.099-11.444 14.218-11.444 23.203 0 1.517.165 3 .403 4.465H10.955a35.444 35.444 0 0 1-.285-4.465c0-10.838 4.974-20.713 13.127-28.291C9.294 85.42.003 70.417.003 53.58.003 23.99 28.656.001 64 .001s63.997 23.988 63.997 53.58c0 16.842-9.299 31.85-23.812 41.673zM64 36.867c-29.454 0-53.33-10.077-53.33 15.342 0 25.418 23.876 46.023 53.33 46.023 29.454 0 53.33-20.605 53.33-46.023 0-25.419-23.876-15.342-53.33-15.342zm24.888 25.644c-3.927 0-7.111-2.665-7.111-5.953 0-3.288 3.184-5.954 7.11-5.954 3.928 0 7.111 2.666 7.111 5.954s-3.183 5.953-7.11 5.953zm-3.556 16.372c0 4.11-9.55 7.442-21.332 7.442-11.781 0-21.332-3.332-21.332-7.442 0-1.06.656-2.064 1.8-2.976 3.295 2.626 10.79 4.465 19.532 4.465 8.743 0 16.237-1.84 19.531-4.465 1.145.912 1.801 1.916 1.801 2.976zm-46.22-16.372c-3.927 0-7.11-2.665-7.11-5.953 0-3.288 3.183-5.954 7.11-5.954 3.927 0 7.111 2.666 7.111 5.954s-3.184 5.953-7.11 5.953z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/peoples.svg b/ruoyi-ui/src/assets/icons/svg/peoples.svg
new file mode 100644
index 0000000..aab852e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/peoples.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M95.648 118.762c0 5.035-3.563 9.121-7.979 9.121H7.98c-4.416 0-7.979-4.086-7.979-9.121C0 100.519 15.408 83.47 31.152 76.75c-9.099-6.43-15.216-17.863-15.216-30.987v-9.128c0-20.16 14.293-36.518 31.893-36.518s31.894 16.358 31.894 36.518v9.122c0 13.137-6.123 24.556-15.216 30.993 15.738 6.726 31.141 23.769 31.141 42.012z"/><path d="M106.032 118.252h15.867c3.376 0 6.101-3.125 6.101-6.972 0-13.957-11.787-26.984-23.819-32.123 6.955-4.919 11.638-13.66 11.638-23.704v-6.985c0-15.416-10.928-27.926-24.39-27.926-1.674 0-3.306.193-4.89.561 1.936 4.713 3.018 9.974 3.018 15.526v9.121c0 13.137-3.056 23.111-11.066 30.993 14.842 4.41 27.312 23.42 27.541 41.509z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/phone.svg b/ruoyi-ui/src/assets/icons/svg/phone.svg
new file mode 100644
index 0000000..ab8e8c4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/phone.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1567417214476" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2266" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M761.503029 2.90619 242.121921 2.90619c-32.405037 0-58.932204 26.060539-58.932204 58.527998l0 902.302287c0 32.156374 26.217105 58.216913 58.932204 58.216913l519.381108 0c32.344662 0 58.591443-26.060539 58.591443-58.216913L820.094472 61.123103C820.094472 28.966729 793.847691 2.90619 761.503029 2.90619M452.878996 61.123103l98.147344 0c6.780427 0 12.31549 5.536087 12.31549 12.253068 0 6.748704-5.535063 12.253068-12.31549 12.253068l-98.147344 0c-6.779404 0-12.345166-5.504364-12.345166-12.253068C440.532807 66.659189 446.099592 61.123103 452.878996 61.123103M501.641583 980.593398c-29.636994 0-53.987588-23.946388-53.987588-53.677527 0-29.356608 24.039509-53.614082 53.987588-53.614082 29.91738 0 53.987588 23.883967 53.987588 53.614082C555.629171 956.647009 531.559986 980.593398 501.641583 980.593398M766.35657 803.142893c0 16.23373-13.186324 29.107945-29.233811 29.107945l-470.618521 0c-16.35755 0-29.325909-13.186324-29.325909-29.107945L237.178329 163.500794c0-16.232706 13.279445-29.138644 29.325909-29.138644l470.246037 0c16.420995 0 29.357632 13.1853 29.357632 29.138644l0 639.642099L766.35657 803.142893zM766.35657 803.142893" p-id="2267"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/post.svg b/ruoyi-ui/src/assets/icons/svg/post.svg
new file mode 100644
index 0000000..2922c61
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/post.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035724641" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3998" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M136.4 434.3h77.7c21.5 0 38.9-17.4 38.9-38.9s-17.4-38.9-38.9-38.9h-77.7c-21.5 0-38.9 17.4-38.9 38.9s17.4 38.9 38.9 38.9zM252.9 628.6c0-21.5-17.4-38.9-38.9-38.9h-77.7c-21.5 0-38.9 17.4-38.9 38.9s17.4 38.9 38.9 38.9H214c21.5-0.1 38.9-17.5 38.9-38.9z" p-id="3999"></path><path d="M874.7 97.5H227c-28.6 0-51.8 23.2-51.8 51.8v194.3h38.9c28.6 0 51.8 23.2 51.8 51.8 0 28.6-23.2 51.8-51.8 51.8h-38.9v129.5h38.9c28.6 0 51.8 23.2 51.8 51.8 0 28.6-23.2 51.8-51.8 51.8h-38.9v194.3c0 28.6 23.2 51.8 51.8 51.8h647.7c28.6 0 51.8-23.2 51.8-51.8V149.3c0-28.6-23.2-51.8-51.8-51.8z m-311.3 723c-15.6 0-146.7-71.6-146.7-91 0-19.4 102-368.6 102-368.6l-83.6-104s-12.3-23.1 24.6-23.1h208.9c36.9 0 18.4 23.1 18.4 23.1l-79 104s102 351.3 102 368.6c0.1 17.3-131 91-146.6 91z m169.2-253.6l-27.9 40.2-74.5-240 103.4 171.7c4.6 7.9 4.2 20.6-1 28.1z" p-id="4000"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/qq.svg b/ruoyi-ui/src/assets/icons/svg/qq.svg
new file mode 100644
index 0000000..ee13d4e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/qq.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M18.448 57.545l-.244-.744-.198-.968-.132-.53v-2.181l.236-.859.24-.908.317-.953.428-1.06.561-1.103.794-1.104v-.773l.077-.724.123-.984.34-1.106.313-1.194.25-.548.289-.511.371-.569.405-.423v-2.73l.234-1.407.236-1.633.42-1.955.577-2.035.43-1.118.426-1.217.468-1.135.559-1.216.57-1.332.655-1.247.737-1.331.929-1.33.43-.762.457-.624.995-1.406 1.025-1.403 1.163-1.444 1.246-1.405 1.352-1.384 1.41-1.423 1.708-1.536 1.083-.934 1.322-1.008 1.34-.89 1.448-.855 1.392-.76 1.57-.63 1.667-.775 1.657-.532 1.653-.552 1.787-.548 1.785-.417 1.876-.347L59.128.68l1.879-.245 1.876-.252 2.002-.106h5.912l1.97.243 1.981.231 2.019.207 1.874.441 1.979.413 1.857.475 2.035.53 1.862.646 1.782.738 1.904.78 1.736.853 1.689.95 1.655 1.044 1.425.971.662.548.693.401 1.323 1.1 1.115 1.064 1.112 1.1 1.083 1.214.894 1.178 1.064 1.217.74 1.306.752 1.162.798 1.352.661 1.175 1.113 2.489.546 1.286.428 1.192.428 1.294.384 1.217.267 1.047.347 1.231.607 2.198.388 1.924.253 1.861.217 1.497.342 2.28.077.362.274.41.737 1.18.473.8.42.832.534.892.472 1.07.307 1.093.334 1.2.252 1.232.115.605.106.746v.648l-.106.643v.8l-.192.774-.35 1.5-.403.76-.299.852v.213l.142.264.4.623 1.746 2.53 1.377 1.9.66 1.267.889 1.389.774 1.52.893 1.627.894 1.828 1.006 2.069.567 1.268.518 1.239.447 1.307.44 1.175.336 1.235.342 1.16.432 2.261.343 2.31.235 2.05v2.891l-.158 1.025-.226 1.768-.308 1.59-.48 1.44-.18.588-.336.707-.28.493-.375.607-.33.383-.42.494-.375.4-.401.34-.48.207-.432.207-.355.114h-.543l-.346-.114-.66-.32-.302-.212-.317-.223-.347-.304-.35-.342-.579-.63-.684-.89-.539-.917-.538-.734-.526-.855-.741-1.517-.833-1.579-.098-.055h-.138l-.338.247-.196.415-.326.516-.567 1.533-.856 2.182-1.096 2.626-.824 1.308-.864 1.366-1.027 1.536-1.09 1.503-.557.68-.676.743-1.555 1.497.136.135.21.214.777.446 3.235 1.524 1.41.779 1.347.756 1.332.953 1.187.982.574.443.432.511.445.593.367.643.198.533.242.64.105.554.115.647-.115.433v.44l-.105.454-.242.415-.092.325-.22.394-.587.784-.543.627-.42.47-.35.348-.893.638-1.01.556-1.077.532-1.155.511-1.287.495-.693.207-.608.167-1.496.342-1.545.325-1.552.323-1.689.27-1.74.072-1.785.21h-5.539l-1.998-.114-1.86-.168-2.005-.27-1.99-.209-2.095-.286-2.03-.495-1.981-.374-1.968-.552-2.019-.707-1.98-.585-1.044-.342-.927-.323-.586-.223-.582-.12h-1.647l-1.904-.131-.962-.096-1.24-.135-.795.705-1.085.665-1.471.701-1.628.875-.99.475-1.033.376-2.281.914-1.24.305-1.3.343-1.803.344-1.13.086-1.193.1-1.246.135-1.45.053h-5.926l-3.346-.053-3.25-.321-1.644-.23-1.589-.23-1.546-.227-1.547-.305-1.442-.456-1.434-.325-1.294-.51-1.223-.474-1.142-.533-.99-.583-.984-.71-.336-.343-.44-.415-.334-.362-.3-.417-.278-.415-.215-.42-.311-.89-.109-.46-.138-.51v-.473l.138-.533v-.53l.109-.53v-1.069l.052-.564.259-.647.215-.646.39-.779.286-.3.236-.348.615-.738.49-.38.464-.266.428-.338.676-.21.543-.324.676-.341.77-.227.775-.231.897-.192.85-.11 1.008-.13 1.093-.081.284-.092h.063l.137-.115v-.13l-.2-.266-.58-.27-1.45-1.231-.975-.761-1.127-.967-1.136-1.082-1.181-1.382-1.36-1.558-.508-.843-.672-.87-.58-1.007-.522-1.1-.704-1.047-.459-1.194-.547-1.192-.546-1.33-.397-1.273-.378-1.575-.112-.057h-.115l-.059-.113h-.14l-.23.113-.114.057-.158.264-.057.321-.119.286-.206.477-.664 1.157-.345.701-.546.612-.58.736-.641.816-.677.724-.795.701-.734.658-.814.524-.89.546-.855.325-1.008.247-.99.095h-.233l-.228-.095-.18-.384-.29-.188-.38-.912-.237-.493-.255-.707-.21-.734-.113-.724-.313-1.648-.12-.972v-3.185l.12-2.379.196-1.214.23-1.252.21-1.347.374-1.254.42-1.443.431-1.407.578-1.448.545-1.38.754-1.4.699-1.52.855-1.425 1.006-1.538 1.023-1.382 1.069-1.538.891-1.071 1.142-1.227 1.202-1.237.56-.59.678-.662.985-.836 1.012-.853 1.647-1.446 1.242-.889z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/search.svg b/ruoyi-ui/src/assets/icons/svg/search.svg
new file mode 100644
index 0000000..84233dd
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/search.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/server.svg b/ruoyi-ui/src/assets/icons/svg/server.svg
new file mode 100644
index 0000000..ca37b00
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/server.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547360688278" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M890 120H134a70 70 0 0 0-70 70v500a70 70 0 0 0 70 70h756a70 70 0 0 0 70-70V190a70 70 0 0 0-70-70z m-10 520a40 40 0 0 1-40 40H712V448a40 40 0 0 0-80 0v232h-80V368a40 40 0 0 0-80 0v312h-80V512a40 40 0 0 0-80 0v168H184a40 40 0 0 1-40-40V240a40 40 0 0 1 40-40h656a40 40 0 0 1 40 40zM696 824H328a40 40 0 0 0 0 80h368a40 40 0 0 0 0-80z" fill="#bfbfbf" p-id="6718"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/shopping.svg b/ruoyi-ui/src/assets/icons/svg/shopping.svg
new file mode 100644
index 0000000..87513e7
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/shopping.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M42.913 101.36c1.642 0 3.198.332 4.667.996a12.28 12.28 0 0 1 3.89 2.772c1.123 1.184 1.987 2.582 2.592 4.193.605 1.612.908 3.318.908 5.118 0 1.8-.303 3.507-.908 5.118-.605 1.611-1.469 3.01-2.593 4.194a13.3 13.3 0 0 1-3.889 2.843 10.582 10.582 0 0 1-4.667 1.066c-1.729 0-3.306-.355-4.732-1.066a13.604 13.604 0 0 1-3.825-2.843c-1.123-1.185-1.988-2.583-2.593-4.194a14.437 14.437 0 0 1-.907-5.118c0-1.8.302-3.506.907-5.118.605-1.61 1.47-3.009 2.593-4.193a12.515 12.515 0 0 1 3.825-2.772c1.426-.664 3.003-.996 4.732-.996zm53.932.285c1.643 0 3.22.331 4.733.995a11.386 11.386 0 0 1 3.889 2.772c1.08 1.185 1.945 2.583 2.593 4.194.648 1.61.972 3.317.972 5.118 0 1.8-.324 3.506-.972 5.117-.648 1.611-1.513 3.01-2.593 4.194a12.253 12.253 0 0 1-3.89 2.843 11 11 0 0 1-4.732 1.066 10.58 10.58 0 0 1-4.667-1.066 12.478 12.478 0 0 1-3.824-2.843c-1.08-1.185-1.945-2.583-2.593-4.194a13.581 13.581 0 0 1-.973-5.117c0-1.801.325-3.507.973-5.118.648-1.611 1.512-3.01 2.593-4.194a11.559 11.559 0 0 1 3.824-2.772 11.212 11.212 0 0 1 4.667-.995zm21.781-80.747c2.42 0 4.3.355 5.64 1.066 1.34.71 2.29 1.587 2.852 2.63a6.427 6.427 0 0 1 .778 3.34c-.044 1.185-.195 2.204-.454 3.057-.26.853-.8 2.606-1.62 5.26a589.268 589.268 0 0 1-2.788 8.743 1236.373 1236.373 0 0 0-3.047 9.453c-.994 3.128-1.75 5.592-2.269 7.393-1.123 3.79-2.55 6.42-4.278 7.89-1.728 1.469-3.846 2.203-6.352 2.203H39.023l1.945 12.795h65.342c4.148 0 6.223 1.943 6.223 5.828 0 1.896-.41 3.53-1.232 4.905-.821 1.374-2.442 2.061-4.862 2.061H38.505c-1.729 0-3.176-.426-4.343-1.28-1.167-.852-2.14-1.966-2.917-3.34a21.277 21.277 0 0 1-1.88-4.478 44.128 44.128 0 0 1-1.102-4.55c-.087-.568-.324-1.942-.713-4.122-.39-2.18-.865-4.904-1.426-8.174l-1.88-10.947c-.692-4.027-1.383-8.079-2.075-12.154-1.642-9.572-3.5-20.234-5.574-31.986H6.87c-1.296 0-2.377-.356-3.24-1.067a9.024 9.024 0 0 1-2.14-2.558 10.416 10.416 0 0 1-1.167-3.2C.108 8.53 0 7.488 0 6.54c0-1.896.583-3.46 1.75-4.69C2.917.615 4.494 0 6.482 0h13.095c1.728 0 3.111.284 4.148.853 1.037.569 1.858 1.28 2.463 2.132a8.548 8.548 0 0 1 1.297 2.701c.26.948.475 1.754.648 2.417.173.758.346 1.825.519 3.199.173 1.374.345 2.772.518 4.193.26 1.706.519 3.507.778 5.403h88.678z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/size.svg b/ruoyi-ui/src/assets/icons/svg/size.svg
new file mode 100644
index 0000000..ddb25b8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/size.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/skill.svg b/ruoyi-ui/src/assets/icons/svg/skill.svg
new file mode 100644
index 0000000..a3b7312
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/skill.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M31.652 93.206h33.401c1.44 2.418 3.077 4.663 4.93 6.692h-38.33v-6.692zm0-10.586h28.914a44.8 44.8 0 0 1-1.264-6.688h-27.65v6.688zm0-17.27H59.39c.288-2.286.714-4.532 1.34-6.687H31.65v6.687h.003zm53.913 44.84v5.85c0 2.798-2.095 5.075-4.667 5.075h-70.07c-2.576 0-4.663-2.277-4.663-5.075V31.26l23.22-20.96v22.25H17.16v6.688h18.39V6.688h45.348c2.576 0 4.667 2.277 4.667 5.066v20.009c1.987-.675 4.053-1.128 6.17-1.445v-18.56C91.738 5.28 86.874 0 80.902 0H31.15L0 28.118v87.917c0 6.48 4.859 11.759 10.832 11.759h70.07c5.974 0 10.837-5.27 10.837-11.759v-4.41c-2.117-.312-4.183-.765-6.17-1.435h-.004zM23.279 58.667h-7.96v6.688h7.96v-6.688zm-7.956 41.23h7.96v-6.691h-7.96v6.692zm7.956-23.96h-7.96v6.687h7.96v-6.688zm89.718-15.042l-4.896-4.07-12.447 17.613-11.19-9.305-3.762 5.311 16.091 13.38 16.204-22.929zM128 70.978c0-18.632-13.97-33.782-31.147-33.782-17.168 0-31.135 15.155-31.135 33.782 0 18.628 13.97 33.783 31.135 33.783 17.172 0 31.143-15.15 31.143-33.783H128zm-6.17 0c0 14.933-11.203 27.1-24.981 27.1-13.77 0-24.987-12.158-24.987-27.1 0-14.941 11.195-27.099 24.987-27.099 13.778 0 24.982 12.158 24.982 27.1z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/star.svg b/ruoyi-ui/src/assets/icons/svg/star.svg
new file mode 100644
index 0000000..6cf86e6
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/star.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M70.66 4.328l14.01 29.693c1.088 2.29 3.177 3.882 5.603 4.25l31.347 4.76c6.087.926 8.528 8.756 4.117 13.247L103.05 79.395c-1.75 1.78-2.544 4.352-2.132 6.867l5.352 32.641c1.043 6.337-5.33 11.182-10.778 8.19l-28.039-15.409a7.13 7.13 0 0 0-6.91 0l-28.039 15.41c-5.448 2.99-11.821-1.854-10.777-8.19l5.352-32.642c.415-2.515-.387-5.088-2.136-6.867L2.264 56.278C-2.146 51.787.286 43.957 6.38 43.031l31.343-4.76c2.419-.368 4.51-1.96 5.595-4.25L57.334 4.328c2.728-5.77 10.605-5.77 13.325 0z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/swagger.svg b/ruoyi-ui/src/assets/icons/svg/swagger.svg
new file mode 100644
index 0000000..05d4e7b
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/swagger.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036776944" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6463" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M64 223.995345h168.001164v47.997673c0 26.428509 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.569164 41.984-47.997673v-47.997673h504.003491a32.004655 32.004655 0 0 0 0-64.009309H455.996509V111.988364c0-26.428509-18.878836-47.997673-41.984-47.997673H273.985164c-23.095855 0-41.984 21.569164-41.984 47.997673v47.997672H64a32.004655 32.004655 0 0 0 0 64.009309zM288.004655 128h111.997672V256H288.004655V128zM960 479.995345H791.998836v-47.997672c0-26.372655-18.878836-47.997673-41.984-47.997673H609.978182c-23.095855 0-41.984 21.634327-41.984 47.997673v47.997672H64a32.004655 32.004655 0 0 0 0 64.00931h504.003491v47.997672c0 26.363345 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.634327 41.984-47.997673v-47.997672h168.001164a32.004655 32.004655 0 1 0-0.009309-64.00931zM735.995345 576H623.997673v-128h111.997672v128zM960 800.293236v-0.288581H455.996509v-47.997673c0-26.363345-18.878836-47.997673-41.984-47.997673H274.050327c-23.105164 0-41.984 21.634327-41.984 47.997673v47.997673H64v0.288581a32.004655 32.004655 0 0 0 0 64.009309c0.986764 0 1.917673-0.195491 2.885818-0.288581h165.115346v47.997672c0 26.363345 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.634327 41.984-47.997673v-47.997672h501.108364c0.968145 0.093091 1.899055 0.288582 2.895127 0.288581a32.004655 32.004655 0 1 0-0.009309-64.009309zM400.002327 896H288.004655V768h111.997672v128z" fill="" p-id="6464"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/system.svg b/ruoyi-ui/src/assets/icons/svg/system.svg
new file mode 100644
index 0000000..86cb938
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/system.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827724451" class="icon" style="" viewBox="0 0 1084 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10233" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M1080.09609 434.500756c-4.216302-23.731757-26.9241-47.945376-50.595623-53.185637l-17.648235-4.095836a175.940257 175.940257 0 0 1-101.612877-80.832531 177.807476 177.807476 0 0 1-18.732427-129.801867l5.541425-16.684509c7.10748-23.129428-2.108151-54.992624-20.599646-70.833873 0 0-16.624276-14.094495-63.244529-41.199293-46.800951-26.984332-66.858502-34.513443-66.858502-34.513443-22.76803-8.372371-54.631227-0.361397-71.255503 17.407304l-12.287509 13.251234a173.470708 173.470708 0 0 1-120.465769 48.065842A174.13327 174.13327 0 0 1 421.329029 33.590675L409.583617 20.761071C393.140039 2.99237 361.096144-4.898138 338.267881 3.353767c0 0-20.358715 7.529111-67.099434 34.513443-46.800951 27.34573-63.244529 41.440225-63.244529 41.440225-18.431263 15.66055-27.646894 47.222582-20.539413 70.592941l5.059562 16.865207a178.048407 178.048407 0 0 1-18.672194 129.621169 174.916297 174.916297 0 0 1-102.275439 81.073463l-17.045906 3.854904c-23.310126 5.42096-46.258856 29.333415-50.595623 53.185637 0 0-3.854905 21.382674-3.854905 75.712737 0 54.330062 3.854905 75.712736 3.854905 75.712736 4.216302 23.972688 26.9241 47.945376 50.595623 53.185637l16.624276 3.854905a174.253736 174.253736 0 0 1 102.395904 81.314394c23.310126 40.837896 28.911785 87.337683 18.732427 129.801867l-4.81863 16.443578c-7.10748 23.129428 2.108151 54.992624 20.599646 70.833872 0 0 16.624276 14.094495 63.244529 41.199293 46.800951 27.104798 66.918735 34.513443 66.918735 34.513443 22.707798 8.372371 54.631227 0.361397 71.255503-17.407303l11.624947-12.588673a175.096996 175.096996 0 0 1 242.256662 0.120465l11.624947 12.648906c16.383345 17.708468 48.427239 25.598976 71.255503 17.347071 0 0 20.358715-7.529111 67.159666-34.513443 46.740719-27.104798 63.124063-41.199293 63.124064-41.199293 18.491496-15.600317 27.707127-47.463513 20.599646-70.833873l-5.059562-17.106139a176.723284 176.723284 0 0 1 18.672194-129.139305 176.060722 176.060722 0 0 1 102.395904-81.314394l16.68451-3.854905c23.310126-5.42096 46.258856-29.333415 50.595623-53.185637 0 0 3.854905-21.382674 3.854904-75.712737-0.240932-54.330062-4.095836-75.833202-4.095836-75.833202z m-537.819428 293.334149c-119.261112 0-216.175824-97.336342-216.175824-217.621412a216.657687 216.657687 0 0 1 216.236057-217.320249c119.200879 0 216.115591 97.276109 216.11559 217.56118-0.240932 120.044139-96.974945 217.320248-216.175823 217.320249z" p-id="10234" fill="#bfbfbf"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tab.svg b/ruoyi-ui/src/assets/icons/svg/tab.svg
new file mode 100644
index 0000000..b4b48e4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tab.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.921.052H49.08c-1.865 0-3.198 1.599-3.198 3.464v6.661c0 1.865 1.6 3.464 3.198 3.464h29.84c1.865 0 3.198-1.599 3.198-3.464V3.516C82.385 1.65 80.786.052 78.92.052zm45.563 0H94.642c-1.865 0-3.464 1.599-3.464 3.464v6.661c0 1.865 1.599 3.464 3.464 3.464h29.842c1.865-.266 3.464-1.599 3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464zm0 22.382H40.02c-1.866 0-3.464-1.599-3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464H3.516C1.65.052.052 1.651.052 3.516V124.75c0 1.598 1.599 3.197 3.464 3.197h120.968c1.865 0 3.464-1.599 3.464-3.464V25.898c0-1.865-1.599-3.464-3.464-3.464z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/table.svg b/ruoyi-ui/src/assets/icons/svg/table.svg
new file mode 100644
index 0000000..0e3dc9d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/table.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/theme.svg b/ruoyi-ui/src/assets/icons/svg/theme.svg
new file mode 100644
index 0000000..5982a2f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/theme.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M125.5 36.984L95.336 2.83C93.735 1.018 91.565 0 89.3 0c-2.263 0-4.433 1.018-6.033 2.83l-3.786 4.286c-1.6 1.812-3.77 2.83-6.032 2.831H54.553c-2.263 0-4.434-1.018-6.033-2.83L44.734 2.83C43.134 1.018 40.964 0 38.701 0c-2.263 0-4.434 1.018-6.034 2.83L2.5 36.984C.9 38.796 0 41.254 0 43.815c0 2.562.899 5.02 2.5 6.831L14.565 64.31c2.178 2.468 5.367 3.403 8.33 2.444 1.35-.435 2.709.592 2.709 2.18v49.407c0 5.313 3.84 9.66 8.532 9.66h59.726c4.693 0 8.532-4.347 8.532-9.66V68.934c0-1.59 1.36-2.616 2.71-2.181 2.962.96 6.15.024 8.329-2.444L125.5 50.646c1.6-1.811 2.499-4.269 2.499-6.83 0-2.563-.899-5.02-2.5-6.832z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tool.svg b/ruoyi-ui/src/assets/icons/svg/tool.svg
new file mode 100644
index 0000000..c813067
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tool.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1553828490559" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1684" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M898.831744 900.517641 103.816972 900.517641c-36.002982 0-65.363683-29.286-65.363683-65.313541l0-554.949184c0-36.041868 29.361725-65.326844 65.363683-65.326844l795.015795 0c36.002982 0 65.198931 29.284977 65.198931 65.326844l0 554.949184C964.030675 871.231641 934.834726 900.517641 898.831744 900.517641L898.831744 900.517641zM103.816972 255.593236c-13.576203 0-24.711821 11.085476-24.711821 24.662703l0 554.949184c0 13.576203 11.136641 24.662703 24.711821 24.662703l795.015795 0c13.577227 0 24.547069-11.086499 24.547069-24.662703l0-554.949184c0-13.577227-10.970866-24.662703-24.547069-24.662703L103.816972 255.593236 103.816972 255.593236zM664.346245 251.774257c-11.161201 0-20.332071-9.080819-20.332071-20.332071l0-101.278661c0-13.576203-11.047614-24.623817-24.699542-24.623817L383.181611 105.539708c-13.576203 0-24.712845 11.04659-24.712845 24.623817l0 101.278661c0 11.252275-9.041934 20.332071-20.332071 20.332071-11.20111 0-20.319791-9.080819-20.319791-20.332071l0-101.278661c0-35.989679 29.323862-65.275679 65.364707-65.275679l236.133022 0c36.06745 0 65.402569 29.284977 65.402569 65.275679l0 101.278661C684.717202 242.694461 675.636383 251.774257 664.346245 251.774257L664.346245 251.774257zM413.233044 521.725502 75.694471 521.725502c-11.163247 0-20.333094-9.117658-20.333094-20.35663 0-11.252275 9.169847-20.332071 20.333094-20.332071l337.538573 0c11.277858 0 20.319791 9.080819 20.319791 20.332071C433.552835 512.607844 424.510902 521.725502 413.233044 521.725502L413.233044 521.725502zM912.894018 521.725502 575.367725 521.725502c-11.213389 0-20.332071-9.117658-20.332071-20.35663 0-11.252275 9.118682-20.332071 20.332071-20.332071l337.526293 0c11.290137 0 20.332071 9.080819 20.332071 20.332071C933.226089 512.607844 924.184155 521.725502 912.894018 521.725502L912.894018 521.725502zM557.56322 634.217552 445.085496 634.217552c-11.213389 0-20.332071-9.079796-20.332071-20.331048l0-168.763658c0-11.251252 9.118682-20.332071 20.332071-20.332071l112.478747 0c11.290137 0 20.370956 9.080819 20.370956 20.332071l0 168.763658C577.934177 625.137757 568.853357 634.217552 557.56322 634.217552L557.56322 634.217552zM465.417567 593.514525l71.827909 0L537.245476 465.454918l-71.827909 0L465.417567 593.514525 465.417567 593.514525z" p-id="1685" fill="#bfbfbf"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tree-table.svg b/ruoyi-ui/src/assets/icons/svg/tree-table.svg
new file mode 100644
index 0000000..8aafdb8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tree-table.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M44.8 0h79.543C126.78 0 128 1.422 128 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H44.8c-2.438 0-3.657-1.422-3.657-4.267V4.267C41.143 1.422 42.362 0 44.8 0zm22.857 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 80 64 78.578 64 75.733V52.267C64 49.422 65.219 48 67.657 48zm0 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 128 64 126.578 64 123.733v-23.466C64 97.422 65.219 96 67.657 96zM50.286 68.267c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V32h6.4c2.02 0 3.658-1.91 3.658-4.267V4.267C27.429 1.91 25.79 0 23.77 0H3.657C1.637 0 0 1.91 0 4.267v23.466C0 30.09 1.637 32 3.657 32h6.4v80c0 2.356 1.638 4.267 3.657 4.267h36.572c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V68.267h32.915z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tree.svg b/ruoyi-ui/src/assets/icons/svg/tree.svg
new file mode 100644
index 0000000..dd4b7dd
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tree.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/user.svg b/ruoyi-ui/src/assets/icons/svg/user.svg
new file mode 100644
index 0000000..0ba0716
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/user.svg
@@ -0,0 +1 @@
+<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/validCode.svg b/ruoyi-ui/src/assets/icons/svg/validCode.svg
new file mode 100644
index 0000000..cfb1021
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/validCode.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569580729849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M513.3 958.5c-142.2 0-397.9-222.1-401.6-440.5V268c1.7-39.6 31.7-72.3 71.1-77.3 49-4.6 97.1-16.5 142.7-35.3 47.8-14 91.9-38.3 129.4-71.1 30.3-24.4 72.9-26.3 105.3-4.6 39.9 30.7 83.8 55.9 130.5 74.6 48.6 14.7 98.2 25.9 148.4 33.7 38.5 7.6 67.1 40.3 69.5 79.5 3.3 84.9 2.5 169.9-2.6 254.7-33.7 281.6-253.7 436.4-392.7 436.3z m-0.1-813.7c-7.2-0.2-14.3 2-20 6.4-39.7 35.2-86.8 61.1-137.7 75.7-46.8 19.2-96.2 31-146.6 35.2-11 3.2-18.8 13-19.5 24.4v230.1c3.5 180.3 223.3 361 323.9 361s287.3-120.2 317.6-360.5c7.3-142.7 0-228.6 0-229.6-1.3-13.3-11-24.3-24-27.3-49.6-7.7-98.6-19-146.5-33.7-46.3-19.5-89.7-45.3-129-76.7-5.8-3.8-12.7-5.5-19.5-4.9l1.3-0.1z" fill="#C6CCDA" p-id="1940"></path><path d="M750.1 428L490.7 673.2c-11.7 11.1-29.5 12.9-43.1 4.2l-6.8-5.8-141.2-149.4c-9.3-9.3-12.7-22.9-9-35.5 3.8-12.6 14.1-22.1 27-24.8 12.9-2.7 26.1 1.9 34.6 11.9L469 597.5l233.7-221c14.6-12.8 36.8-11.6 49.9 2.7 13.2 14.2 11.5 35.3-2.5 48.8" fill="#C6CCDA" p-id="1941"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/wechat.svg b/ruoyi-ui/src/assets/icons/svg/wechat.svg
new file mode 100644
index 0000000..c586e55
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/wechat.svg
@@ -0,0 +1 @@
+<svg width="128" height="110" xmlns="http://www.w3.org/2000/svg"><path d="M86.635 33.334c1.467 0 2.917.113 4.358.283C87.078 14.392 67.58.111 45.321.111 20.44.111.055 17.987.055 40.687c0 13.104 6.781 23.863 18.115 32.209l-4.527 14.352 15.82-8.364c5.666 1.182 10.207 2.395 15.858 2.395 1.42 0 2.829-.073 4.227-.189-.886-3.19-1.398-6.53-1.398-9.996 0-20.845 16.98-37.76 38.485-37.76zm-24.34-12.936c3.407 0 5.665 2.363 5.665 5.954 0 3.576-2.258 5.97-5.666 5.97-3.392 0-6.795-2.395-6.795-5.97 0-3.591 3.403-5.954 6.795-5.954zM30.616 32.323c-3.393 0-6.818-2.395-6.818-5.971 0-3.591 3.425-5.954 6.818-5.954 3.392 0 5.65 2.363 5.65 5.954 0 3.576-2.258 5.97-5.65 5.97z"/><path d="M127.945 70.52c0-19.075-18.108-34.623-38.448-34.623-21.537 0-38.5 15.548-38.5 34.623 0 19.108 16.963 34.622 38.5 34.622 4.508 0 9.058-1.2 13.584-2.395l12.414 7.167-3.404-11.923c9.087-7.184 15.854-16.712 15.854-27.471zm-50.928-5.97c-2.254 0-4.53-2.362-4.53-4.773 0-2.378 2.276-4.771 4.53-4.771 3.422 0 5.665 2.393 5.665 4.771 0 2.41-2.243 4.773-5.665 4.773zm24.897 0c-2.24 0-4.498-2.362-4.498-4.773 0-2.378 2.258-4.771 4.498-4.771 3.392 0 5.665 2.393 5.665 4.771 0 2.41-2.273 4.773-5.665 4.773z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/zip.svg b/ruoyi-ui/src/assets/icons/svg/zip.svg
new file mode 100644
index 0000000..f806fc4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/zip.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.527 116.793c.178.008.348.024.527.024h40.233c4.711-.005 8.53-3.677 8.534-8.21V18.895c-.004-4.532-3.823-8.204-8.534-8.209H79.054c-.179 0-.353.016-.527.024V0L0 10.082v107.406l78.527 10.342v-11.037zm0-101.362c.174-.024.348-.052.527-.052h40.233c2.018 0 3.659 1.578 3.659 3.52v89.713c-.003 1.942-1.64 3.517-3.659 3.519H79.054c-.179 0-.353-.028-.527-.052V15.431zM30.262 75.757l-18.721-.46V72.37l11.3-16.673v-.148l-10.266.164v-4.51l17.504-.44v3.264L18.696 70.76v.144l11.566.176v4.678zm9.419.231l-5.823-.144V50.671l5.823-.144v25.461zm22.255-11.632c-2.168 1.922-5.353 2.76-9.02 2.736-.702.004-1.402-.04-2.097-.131v9.303l-5.997-.148V50.743c1.852-.352 4.473-.647 8.218-.743 3.838-.096 6.608.539 8.48 1.913 1.807 1.306 3.032 3.5 3.032 6.112s-.926 4.833-2.612 6.331h-.004zM53.36 54.45c-.856-.01-1.71.083-2.541.275v7.682c.523.116 1.167.152 2.06.152 3.301-.004 5.36-1.614 5.36-4.314 0-2.425-1.772-3.843-4.875-3.791l-.004-.004zm39.847-37.066h9.564v3.795h-9.564v-3.795zm-9.568 5.68h9.564v3.8h-9.564v-3.8zm9.568 6.216h9.564v3.799h-9.564V29.28zm0 12h9.564v3.794h-9.564V41.28zm-9.568-6.096h9.564v3.795h-9.564v-3.795zm9.472 47.064c2.512 0 4.921-.96 6.697-2.67 1.776-1.708 2.773-4.026 2.772-6.442l-1.748-15.263c0-5.033-2.492-9.112-7.725-9.112-5.232 0-7.72 4.079-7.72 9.112l-1.752 15.263c-.001 2.417.996 4.735 2.773 6.444 1.777 1.71 4.187 2.669 6.7 2.668h.003zm-3.135-16.75h6.27v12.743h-6.27V65.5z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svgo.yml b/ruoyi-ui/src/assets/icons/svgo.yml
new file mode 100644
index 0000000..14f8f5c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svgo.yml
@@ -0,0 +1,22 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+  # - name
+  #
+  # or:
+  # - name: false
+  # - name: true
+  #
+  # or:
+  # - name:
+  #     param1: 1
+  #     param2: 2
+
+- removeAttrs:
+    attrs:
+      - 'fill'
+      - 'fill-rule'
diff --git a/ruoyi-ui/src/assets/image/login-background.jpg b/ruoyi-ui/src/assets/image/login-background.jpg
new file mode 100644
index 0000000..8a89eb8
--- /dev/null
+++ b/ruoyi-ui/src/assets/image/login-background.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/image/profile.jpg b/ruoyi-ui/src/assets/image/profile.jpg
new file mode 100644
index 0000000..b3a940b
--- /dev/null
+++ b/ruoyi-ui/src/assets/image/profile.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/logo/logo.png b/ruoyi-ui/src/assets/logo/logo.png
new file mode 100644
index 0000000..e263760
--- /dev/null
+++ b/ruoyi-ui/src/assets/logo/logo.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/styles/btn.scss b/ruoyi-ui/src/assets/styles/btn.scss
new file mode 100644
index 0000000..1ccb57d
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/btn.scss
@@ -0,0 +1,99 @@
+@import './variables.scss';
+
+@mixin colorBtn($color) {
+  background: $color;
+
+  &:hover {
+    color: $color;
+
+    &:before,
+    &:after {
+      background: $color;
+    }
+  }
+}
+
+.blue-btn {
+  @include colorBtn($blue)
+}
+
+.light-blue-btn {
+  @include colorBtn($light-blue)
+}
+
+.red-btn {
+  @include colorBtn($red)
+}
+
+.pink-btn {
+  @include colorBtn($pink)
+}
+
+.green-btn {
+  @include colorBtn($green)
+}
+
+.tiffany-btn {
+  @include colorBtn($tiffany)
+}
+
+.yellow-btn {
+  @include colorBtn($yellow)
+}
+
+.pan-btn {
+  font-size: 14px;
+  color: #fff;
+  padding: 14px 36px;
+  border-radius: 8px;
+  border: none;
+  outline: none;
+  transition: 600ms ease all;
+  position: relative;
+  display: inline-block;
+
+  &:hover {
+    background: #fff;
+
+    &:before,
+    &:after {
+      width: 100%;
+      transition: 600ms ease all;
+    }
+  }
+
+  &:before,
+  &:after {
+    content: '';
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 2px;
+    width: 0;
+    transition: 400ms ease all;
+  }
+
+  &::after {
+    right: inherit;
+    top: inherit;
+    left: 0;
+    bottom: 0;
+  }
+}
+
+.custom-button {
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  background: #fff;
+  color: #fff;
+  -webkit-appearance: none;
+  text-align: center;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  padding: 10px 15px;
+  font-size: 14px;
+  border-radius: 4px;
+}
diff --git a/ruoyi-ui/src/assets/styles/element-ui.scss b/ruoyi-ui/src/assets/styles/element-ui.scss
new file mode 100644
index 0000000..35c224e
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/element-ui.scss
@@ -0,0 +1,79 @@
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+  font-weight: 400 !important;
+}
+
+.el-upload {
+  input[type="file"] {
+    display: none !important;
+  }
+}
+
+.el-upload__input {
+  display: none;
+}
+
+.cell {
+  .el-tag {
+    margin-right: 0px;
+  }
+}
+
+.small-padding {
+  .cell {
+    padding-left: 5px;
+    padding-right: 5px;
+  }
+}
+
+.fixed-width {
+  .el-button--mini {
+    padding: 7px 10px;
+    width: 60px;
+  }
+}
+
+.status-col {
+  .cell {
+    padding: 0 10px;
+    text-align: center;
+
+    .el-tag {
+      margin-right: 0px;
+    }
+  }
+}
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+  transform: none;
+  left: 0;
+  position: relative;
+  margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+  .el-upload {
+    width: 100%;
+
+    .el-upload-dragger {
+      width: 100%;
+      height: 200px;
+    }
+  }
+}
+
+// dropdown
+.el-dropdown-menu {
+  a {
+    display: block
+  }
+}
+
+// fix date-picker ui bug in filter-item
+.el-range-editor.el-input__inner {
+  display: inline-flex !important;
+}
diff --git a/ruoyi-ui/src/assets/styles/element-variables.scss b/ruoyi-ui/src/assets/styles/element-variables.scss
new file mode 100644
index 0000000..bc7697e
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/element-variables.scss
@@ -0,0 +1,31 @@
+/**
+* I think element-ui's default theme color is too light for long-term use.
+* So I modified the default color and you can modify it to your liking.
+**/
+
+/* theme color */
+$--color-primary: #1890ff;
+$--color-success: #13ce66;
+$--color-warning: #FFBA00;
+$--color-danger: #ff4949;
+// $--color-info: #1E1E1E;
+
+$--button-font-weight: 400;
+
+// $--color-text-regular: #1f2d3d;
+
+$--border-color-light: #dfe4ed;
+$--border-color-lighter: #e6ebf5;
+
+$--table-border:1px solid#dfe6ec;
+
+/* icon font path, required */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+
+@import "~element-ui/packages/theme-chalk/src/index";
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  theme: $--color-primary;
+}
diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss
new file mode 100644
index 0000000..9f536ae
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/index.scss
@@ -0,0 +1,191 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+@import './btn.scss';
+
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+  font-weight: 700;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+*,
+*:before,
+*:after {
+  box-sizing: inherit;
+}
+
+.no-padding {
+  padding: 0px !important;
+}
+
+.padding-content {
+  padding: 4px 0;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+.fr {
+  float: right;
+}
+
+.fl {
+  float: left;
+}
+
+.pr-5 {
+  padding-right: 5px;
+}
+
+.pl-5 {
+  padding-left: 5px;
+}
+
+.block {
+  display: block;
+}
+
+.pointer {
+  cursor: pointer;
+}
+
+.inlineBlock {
+  display: block;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+aside {
+  background: #eef1f6;
+  padding: 8px 24px;
+  margin-bottom: 20px;
+  border-radius: 2px;
+  display: block;
+  line-height: 32px;
+  font-size: 16px;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+  color: #2c3e50;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+  a {
+    color: #337ab7;
+    cursor: pointer;
+
+    &:hover {
+      color: rgb(32, 160, 255);
+    }
+  }
+}
+
+//main-container鍏ㄥ眬鏍峰紡
+.app-container {
+  padding: 20px;
+}
+
+.components-container {
+  margin: 30px 50px;
+  position: relative;
+}
+
+.pagination-container {
+  margin-top: 30px;
+}
+
+.text-center {
+  text-align: center
+}
+
+.sub-navbar {
+  height: 50px;
+  line-height: 50px;
+  position: relative;
+  width: 100%;
+  text-align: right;
+  padding-right: 20px;
+  transition: 600ms ease position;
+  background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
+
+  .subtitle {
+    font-size: 20px;
+    color: #fff;
+  }
+
+  &.draft {
+    background: #d0d0d0;
+  }
+
+  &.deleted {
+    background: #d0d0d0;
+  }
+}
+
+.link-type,
+.link-type:focus {
+  color: #337ab7;
+  cursor: pointer;
+
+  &:hover {
+    color: rgb(32, 160, 255);
+  }
+}
+
+.filter-container {
+  padding-bottom: 10px;
+
+  .filter-item {
+    display: inline-block;
+    vertical-align: middle;
+    margin-bottom: 10px;
+  }
+}
+
+//refine vue-multiselect plugin
+.multiselect {
+  line-height: 16px;
+}
+
+.multiselect--active {
+  z-index: 1000 !important;
+}
diff --git a/ruoyi-ui/src/assets/styles/mixin.scss b/ruoyi-ui/src/assets/styles/mixin.scss
new file mode 100644
index 0000000..64d9cf6
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/mixin.scss
@@ -0,0 +1,66 @@
+@mixin clearfix {
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
+  }
+}
+
+@mixin scrollBar {
+  &::-webkit-scrollbar-track-piece {
+    background: #d3dce6;
+  }
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #99a9bf;
+    border-radius: 20px;
+  }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+@mixin pct($pct) {
+  width: #{$pct};
+  position: relative;
+  margin: 0 auto;
+}
+
+@mixin triangle($width, $height, $color, $direction) {
+  $width: $width/2;
+  $color-border-style: $height solid $color;
+  $transparent-border-style: $width solid transparent;
+  height: 0;
+  width: 0;
+
+  @if $direction==up {
+    border-bottom: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==right {
+    border-left: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+
+  @else if $direction==down {
+    border-top: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==left {
+    border-right: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+}
diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss
new file mode 100644
index 0000000..7c3aca1
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/ruoyi.scss
@@ -0,0 +1,126 @@
+ /**
+ * 閫氱敤css鏍峰紡甯冨眬澶勭悊
+ * Copyright (c) 2019 ruoyi
+ */
+
+.el-table .el-table__header-wrapper th {
+	word-break: break-word;
+	background-color: #f8f8f9;
+	color: #515a6e;
+	height: 40px;
+	font-size: 13px;
+}
+
+.pagination-container {
+	position: relative;
+	height: 25px;
+	margin-bottom: 10px;
+	margin-top: 15px;
+	padding: 10px 20px !important;
+}
+
+.pagination-container .el-pagination {
+	right: 0;
+	position: absolute;
+}
+
+.el-table .fixed-width .el-button--mini {
+	color: #409EFF;
+	padding-left: 0;
+	padding-right: 0;
+	width: inherit;
+}
+
+.el-tree-node__content > .el-checkbox {
+	margin-right: 8px;
+}
+
+.list-group-striped > .list-group-item {
+	border-left: 0;
+	border-right: 0;
+	border-radius: 0;
+	padding-left: 0;
+	padding-right: 0;
+}
+
+.list-group {
+	padding-left: 0px;
+	list-style: none;
+}
+
+.list-group-item {
+	border-bottom: 1px solid #e7eaec;
+	border-top: 1px solid #e7eaec;
+	margin-bottom: -1px;
+	padding: 11px 0px;
+	font-size: 13px;
+}
+
+.pull-right {
+	float: right !important;
+}
+
+.el-card__header {
+	padding: 14px 15px 7px;
+	min-height: 40px;
+}
+
+.el-card__body {
+	padding: 15px 20px 20px 20px;
+}
+
+.card-box {
+	padding-right: 15px;
+	padding-left: 15px;
+	margin-bottom: 10px;
+}
+  
+/* text color */
+.text-navy {
+	color: #1ab394;
+}
+
+.text-primary {
+	color: inherit;
+}
+
+.text-success {
+	color: #1c84c6;
+}
+
+.text-info {
+	color: #23c6c8;
+}
+
+.text-warning {
+	color: #f8ac59;
+}
+
+.text-danger {
+	color: #ed5565;
+}
+
+.text-muted {
+	color: #888888;
+}
+
+/* image */
+.img-circle {
+	border-radius: 50%;
+}
+
+.img-lg {
+	width: 120px;
+	height: 120px;
+}
+
+.avatar-upload-preview {
+	position: absolute;
+	top: 50%;
+	transform: translate(50%, -50%);
+	width: 180px;
+	height: 180px;
+	border-radius: 50%;
+	box-shadow: 0 0 4px #ccc;
+	overflow: hidden;
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/sidebar.scss b/ruoyi-ui/src/assets/styles/sidebar.scss
new file mode 100644
index 0000000..9fc13e2
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/sidebar.scss
@@ -0,0 +1,209 @@
+#app {
+
+  .main-container {
+    min-height: 100%;
+    transition: margin-left .28s;
+    margin-left: $sideBarWidth;
+    position: relative;
+  }
+
+  .sidebar-container {
+    transition: width 0.28s;
+    width: $sideBarWidth !important;
+    background-color: $menuBg;
+    height: 100%;
+    position: fixed;
+    font-size: 0px;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    overflow: hidden;
+
+    // reset element-ui css
+    .horizontal-collapse-transition {
+      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+    }
+
+    .scrollbar-wrapper {
+      overflow-x: hidden !important;
+    }
+
+    .el-scrollbar__bar.is-vertical {
+      right: 0px;
+    }
+
+    .el-scrollbar {
+      height: 100%;
+    }
+
+    &.has-logo {
+      .el-scrollbar {
+        height: calc(100% - 50px);
+      }
+    }
+
+    .is-horizontal {
+      display: none;
+    }
+
+    a {
+      display: inline-block;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .svg-icon {
+      margin-right: 16px;
+    }
+
+    .el-menu {
+      border: none;
+      height: 100%;
+      width: 100% !important;
+    }
+
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: $menuHover !important;
+      }
+    }
+
+    .is-active>.el-submenu__title {
+      color: $subMenuActiveText !important;
+    }
+
+    & .nest-menu .el-submenu>.el-submenu__title,
+    & .el-submenu .el-menu-item {
+      min-width: $sideBarWidth !important;
+      background-color: $subMenuBg !important;
+
+      &:hover {
+        background-color: $subMenuHover !important;
+      }
+    }
+  }
+
+  .hideSidebar {
+    .sidebar-container {
+      width: 54px !important;
+    }
+
+    .main-container {
+      margin-left: 54px;
+    }
+
+    .submenu-title-noDropdown {
+      padding: 0 !important;
+      position: relative;
+
+      .el-tooltip {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+      }
+    }
+
+    .el-submenu {
+      overflow: hidden;
+
+      &>.el-submenu__title {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+
+        .el-submenu__icon-arrow {
+          display: none;
+        }
+      }
+    }
+
+    .el-menu--collapse {
+      .el-submenu {
+        &>.el-submenu__title {
+          &>span {
+            height: 0;
+            width: 0;
+            overflow: hidden;
+            visibility: hidden;
+            display: inline-block;
+          }
+        }
+      }
+    }
+  }
+
+  .el-menu--collapse .el-menu .el-submenu {
+    min-width: $sideBarWidth !important;
+  }
+
+  // mobile responsive
+  .mobile {
+    .main-container {
+      margin-left: 0px;
+    }
+
+    .sidebar-container {
+      transition: transform .28s;
+      width: $sideBarWidth !important;
+    }
+
+    &.hideSidebar {
+      .sidebar-container {
+        pointer-events: none;
+        transition-duration: 0.3s;
+        transform: translate3d(-$sideBarWidth, 0, 0);
+      }
+    }
+  }
+
+  .withoutAnimation {
+
+    .main-container,
+    .sidebar-container {
+      transition: none;
+    }
+  }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+  &>.el-menu {
+    .svg-icon {
+      margin-right: 16px;
+    }
+  }
+
+  .nest-menu .el-submenu>.el-submenu__title,
+  .el-menu-item {
+    &:hover {
+      // you can use $subMenuHover
+      background-color: $menuHover !important;
+    }
+  }
+
+  // the scroll bar appears when the subMenu is too long
+  >.el-menu--popup {
+    max-height: 100vh;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar-track-piece {
+      background: #d3dce6;
+    }
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background: #99a9bf;
+      border-radius: 20px;
+    }
+  }
+}
diff --git a/ruoyi-ui/src/assets/styles/transition.scss b/ruoyi-ui/src/assets/styles/transition.scss
new file mode 100644
index 0000000..25e7e18
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/transition.scss
@@ -0,0 +1,48 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+  opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all .5s;
+}
+
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+  transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+  opacity: 0;
+  transform: translateX(20px);
+}
+
+.breadcrumb-move {
+  transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+  position: absolute;
+}
diff --git a/ruoyi-ui/src/assets/styles/variables.scss b/ruoyi-ui/src/assets/styles/variables.scss
new file mode 100644
index 0000000..d5f4e9f
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/variables.scss
@@ -0,0 +1,35 @@
+// base color
+$blue:#324157;
+$light-blue:#3A71A8;
+$red:#C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow:#FEC171;
+$panGreen: #30B08F;
+
+// sidebar
+$menuText:#bfcbd9;
+$menuActiveText:#409EFF;
+$subMenuActiveText:#f4f4f5; // https://github.com/ElemeFE/element/issues/12951
+
+$menuBg:#304156;
+$menuHover:#263445;
+
+$subMenuBg:#1f2d3d;
+$subMenuHover:#001528;
+
+$sideBarWidth: 200px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  menuText: $menuText;
+  menuActiveText: $menuActiveText;
+  subMenuActiveText: $subMenuActiveText;
+  menuBg: $menuBg;
+  menuHover: $menuHover;
+  subMenuBg: $subMenuBg;
+  subMenuHover: $subMenuHover;
+  sideBarWidth: $sideBarWidth;
+}
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
new file mode 100644
index 0000000..dec8bfe
--- /dev/null
+++ b/ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -0,0 +1,81 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item,index) in levelList" :key="item.path">
+        <span v-if="item.redirect==='noRedirect'||index==levelList.length-1" class="no-redirect">{{ item.meta.title }}</span>
+        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+import pathToRegexp from 'path-to-regexp'
+
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route(route) {
+      // if you go to the redirect page, do not update the breadcrumbs
+      if (route.path.startsWith('/redirect/')) {
+        return
+      }
+      this.getBreadcrumb()
+    }
+  },
+  created() {
+    this.getBreadcrumb()
+  },
+  methods: {
+    getBreadcrumb() {
+      // only show routes with meta.title
+      let matched = this.$route.matched.filter(item => item.meta && item.meta.title)
+      const first = matched[0]
+
+      if (!this.isDashboard(first)) {
+        matched = [{ path: '/index', meta: { title: '棣栭〉' }}].concat(matched)
+      }
+
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+    },
+    isDashboard(route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim() === '棣栭〉'
+    },
+    pathCompile(path) {
+      const { params } = this.$route
+      var toPath = pathToRegexp.compile(path)
+      return toPath(params)
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      this.$router.push(this.pathCompile(path))
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+
+  .no-redirect {
+    color: #97a8be;
+    cursor: text;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/Editor/index.vue b/ruoyi-ui/src/components/Editor/index.vue
new file mode 100644
index 0000000..2002908
--- /dev/null
+++ b/ruoyi-ui/src/components/Editor/index.vue
@@ -0,0 +1,226 @@
+<template>
+  <div>
+    <!-- 鍥剧墖涓婁紶缁勪欢杈呭姪 -->
+    <el-upload
+      class="avatar-uploader quill-img"
+      :action="uploadImgUrl"
+      name="file"
+      :headers="headers"
+      :show-file-list="false"
+      :on-success="quillImgSuccess"
+      :on-error="uploadError"
+      :before-upload="quillImgBefore"
+      accept='.jpg,.jpeg,.png,.gif'
+    ></el-upload>
+
+    <!-- 瀵屾枃鏈粍浠� -->
+    <quill-editor
+      class="editor"
+      v-model="content"
+      ref="quillEditor"
+      :options="editorOption"
+      @blur="onEditorBlur($event)"
+      @focus="onEditorFocus($event)"
+      @change="onEditorChange($event)"
+    ></quill-editor>
+  </div>
+</template>
+
+<script>
+import { getToken } from '@/utils/auth'
+
+// 宸ュ叿鏍忛厤缃�
+const toolbarOptions = [
+  ["bold", "italic", "underline", "strike"],       // 鍔犵矖 鏂滀綋 涓嬪垝绾� 鍒犻櫎绾�
+  ["blockquote", "code-block"],                    // 寮曠敤  浠g爜鍧�
+  [{ list: "ordered" }, { list: "bullet" }],       // 鏈夊簭銆佹棤搴忓垪琛�
+  [{ indent: "-1" }, { indent: "+1" }],            // 缂╄繘
+  [{ size: ["small", false, "large", "huge"] }],   // 瀛椾綋澶у皬
+  [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 鏍囬
+  [{ color: [] }, { background: [] }],             // 瀛椾綋棰滆壊銆佸瓧浣撹儗鏅鑹�
+  [{ align: [] }],                                 // 瀵归綈鏂瑰紡
+  ["clean"],                                       // 娓呴櫎鏂囨湰鏍煎紡
+  ["link", "image", "video"]                       // 閾炬帴銆佸浘鐗囥�佽棰�
+];
+
+import { quillEditor } from "vue-quill-editor";
+import "quill/dist/quill.core.css";
+import "quill/dist/quill.snow.css";
+import "quill/dist/quill.bubble.css";
+
+export default {
+  props: {
+    /* 缂栬緫鍣ㄧ殑鍐呭 */
+    value: {
+      type: String
+    },
+    /* 鍥剧墖澶у皬 */
+    maxSize: {
+      type: Number,
+      default: 4000 //kb
+    }
+  },
+  components: { quillEditor },
+  data() {
+    return {
+      content: this.value,
+      uploadImgUrl: "",
+      editorOption: {
+        placeholder: "",
+        theme: "snow", // or 'bubble'
+        placeholder: "璇疯緭鍏ュ唴瀹�",
+        modules: {
+          toolbar: {
+            container: toolbarOptions,
+            handlers: {
+              image: function(value) {
+                if (value) {
+                  // 瑙﹀彂input妗嗛�夋嫨鍥剧墖鏂囦欢
+                  document.querySelector(".quill-img input").click();
+                } else {
+                  this.quill.format("image", false);
+                }
+              }
+            }
+          }
+        }
+      },
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+      headers: {
+        Authorization: 'Bearer ' + getToken()
+      }
+    };
+  },
+  watch: {
+    value: function() {
+      this.content = this.value;
+    }
+  },
+  methods: {
+    onEditorBlur() {
+      //澶卞幓鐒︾偣浜嬩欢
+    },
+    onEditorFocus() {
+      //鑾峰緱鐒︾偣浜嬩欢
+    },
+    onEditorChange() {
+      //鍐呭鏀瑰彉浜嬩欢
+      this.$emit("input", this.content);
+    },
+
+    // 瀵屾枃鏈浘鐗囦笂浼犲墠
+    quillImgBefore(file) {
+      let fileType = file.type;
+			if(fileType === 'image/jpeg' || fileType === 'image/png'){
+				return true;
+			}else {
+				this.$message.error('璇锋彃鍏ュ浘鐗囩被鍨嬫枃浠�(jpg/jpeg/png)');
+				return false;
+			}
+    },
+
+    quillImgSuccess(res, file) {
+      // res涓哄浘鐗囨湇鍔″櫒杩斿洖鐨勬暟鎹�
+      // 鑾峰彇瀵屾枃鏈粍浠跺疄渚�
+      let quill = this.$refs.quillEditor.quill;
+      // 濡傛灉涓婁紶鎴愬姛
+      if (res.code == 200) {
+        // 鑾峰彇鍏夋爣鎵�鍦ㄤ綅缃�
+        let length = quill.getSelection().index;
+        // 鎻掑叆鍥剧墖  res.url涓烘湇鍔″櫒杩斿洖鐨勫浘鐗囧湴鍧�
+        quill.insertEmbed(length, "image", res.url);
+        // 璋冩暣鍏夋爣鍒版渶鍚�
+        quill.setSelection(length + 1);
+      } else {
+        this.$message.error("鍥剧墖鎻掑叆澶辫触");
+      }
+    },
+    // 瀵屾枃鏈浘鐗囦笂浼犲け璐�
+    uploadError() {
+      // loading鍔ㄧ敾娑堝け
+      this.$message.error("鍥剧墖鎻掑叆澶辫触");
+    }
+  }
+};
+</script> 
+
+<style>
+.editor {
+  line-height: normal !important;
+  height: 192px;
+}
+.el-upload {
+  display: none;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+  content: "璇疯緭鍏ラ摼鎺ュ湴鍧�:";
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+  border-right: 0px;
+  content: "淇濆瓨";
+  padding-right: 0px;
+}
+
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+  content: "璇疯緭鍏ヨ棰戝湴鍧�:";
+}
+
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+  content: "14px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+  content: "10px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+  content: "18px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+  content: "32px";
+}
+
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+  content: "鏂囨湰";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+  content: "鏍囬1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+  content: "鏍囬2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+  content: "鏍囬3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+  content: "鏍囬4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+  content: "鏍囬5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+  content: "鏍囬6";
+}
+
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+  content: "鏍囧噯瀛椾綋";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+  content: "琛嚎瀛椾綋";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+  content: "绛夊瀛椾綋";
+}
+</style>
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/Hamburger/index.vue b/ruoyi-ui/src/components/Hamburger/index.vue
new file mode 100644
index 0000000..c6a4359
--- /dev/null
+++ b/ruoyi-ui/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+    >
+      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    toggleClick() {
+      this.$emit('toggleClick')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>
diff --git a/ruoyi-ui/src/components/HeaderSearch/index.vue b/ruoyi-ui/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..8974171
--- /dev/null
+++ b/ruoyi-ui/src/components/HeaderSearch/index.vue
@@ -0,0 +1,180 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelect"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="item in options" :key="item.path" :value="item" :label="item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js'
+import path from 'path'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routes() {
+      return this.$store.getters.permission_routes
+    }
+  },
+  watch: {
+    routes() {
+      this.searchPool = this.generateRoutes(this.routes)
+    },
+    searchPool(list) {
+      this.initFuse(list)
+    },
+    show(value) {
+      if (value) {
+        document.body.addEventListener('click', this.close)
+      } else {
+        document.body.removeEventListener('click', this.close)
+      }
+    }
+  },
+  mounted() {
+    this.searchPool = this.generateRoutes(this.routes)
+  },
+  methods: {
+    click() {
+      this.show = !this.show
+      if (this.show) {
+        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+      }
+    },
+    close() {
+      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+      this.options = []
+      this.show = false
+    },
+    change(val) {
+      this.$router.push(val.path)
+      this.search = ''
+      this.options = []
+      this.$nextTick(() => {
+        this.show = false
+      })
+    },
+    initFuse(list) {
+      this.fuse = new Fuse(list, {
+        shouldSort: true,
+        threshold: 0.4,
+        location: 0,
+        distance: 100,
+        maxPatternLength: 32,
+        minMatchCharLength: 1,
+        keys: [{
+          name: 'title',
+          weight: 0.7
+        }, {
+          name: 'path',
+          weight: 0.3
+        }]
+      })
+    },
+    // Filter out the routes that can be displayed in the sidebar
+    // And generate the internationalized title
+    generateRoutes(routes, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: path.resolve(basePath, router.path),
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          data.title = [...data.title, router.meta.title]
+
+          if (router.redirect !== 'noRedirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        // recursive child routes
+        if (router.children) {
+          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+          if (tempRoutes.length >= 1) {
+            res = [...res, ...tempRoutes]
+          }
+        }
+      }
+      return res
+    },
+    querySearch(query) {
+      if (query !== '') {
+        this.options = this.fuse.search(query)
+      } else {
+        this.options = []
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+  font-size: 0 !important;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+  }
+
+  .header-search-select {
+    font-size: 18px;
+    transition: width 0.2s;
+    width: 0;
+    overflow: hidden;
+    background: transparent;
+    border-radius: 0;
+    display: inline-block;
+    vertical-align: middle;
+
+    /deep/ .el-input__inner {
+      border-radius: 0;
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+      border-bottom: 1px solid #d9d9d9;
+      vertical-align: middle;
+    }
+  }
+
+  &.show {
+    .header-search-select {
+      width: 210px;
+      margin-left: 10px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/IconSelect/index.vue b/ruoyi-ui/src/components/IconSelect/index.vue
new file mode 100644
index 0000000..ea4c1b6
--- /dev/null
+++ b/ruoyi-ui/src/components/IconSelect/index.vue
@@ -0,0 +1,69 @@
+<!-- @author zhengjie -->
+<template>
+  <div class="icon-body">
+    <el-input v-model="name" style="position: relative;" clearable placeholder="璇疯緭鍏ュ浘鏍囧悕绉�" @clear="filterIcons" @input.native="filterIcons">
+      <i slot="suffix" class="el-icon-search el-input__icon" />
+    </el-input>
+    <div class="icon-list">
+      <div v-for="(item, index) in iconList" :key="index" @click="selectedIcon(item)">
+        <svg-icon :icon-class="item" style="height: 30px;width: 16px;" />
+        <span>{{ item }}</span>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+  name: 'IconSelect',
+  data() {
+    return {
+      name: '',
+      iconList: icons
+    }
+  },
+  methods: {
+    filterIcons() {
+      if (this.name) {
+        this.iconList = this.iconList.filter(item => item.includes(this.name))
+      } else {
+        this.iconList = icons
+      }
+    },
+    selectedIcon(name) {
+      this.$emit('selected', name)
+      document.body.click()
+    },
+    reset() {
+      this.name = ''
+      this.iconList = icons
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .icon-body {
+    width: 100%;
+    padding: 10px;
+    .icon-list {
+      height: 200px;
+      overflow-y: scroll;
+      div {
+        height: 30px;
+        line-height: 30px;
+        margin-bottom: -5px;
+        cursor: pointer;
+        width: 33%;
+        float: left;
+      }
+      span {
+        display: inline-block;
+        vertical-align: -0.15em;
+        fill: currentColor;
+        overflow: hidden;
+      }
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/components/IconSelect/requireIcons.js b/ruoyi-ui/src/components/IconSelect/requireIcons.js
new file mode 100644
index 0000000..5d3005d
--- /dev/null
+++ b/ruoyi-ui/src/components/IconSelect/requireIcons.js
@@ -0,0 +1,11 @@
+
+const req = require.context('../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+  return i.match(re)[1]
+})
+
+export default icons
diff --git a/ruoyi-ui/src/components/Pagination/index.vue b/ruoyi-ui/src/components/Pagination/index.vue
new file mode 100644
index 0000000..08ff090
--- /dev/null
+++ b/ruoyi-ui/src/components/Pagination/index.vue
@@ -0,0 +1,101 @@
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 20, 30, 50]
+      }
+    },
+    layout: {
+      type: String,
+      default: 'total, sizes, prev, pager, next, jumper'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(val) {
+      this.$emit('pagination', { page: this.currentPage, limit: val })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(val) {
+      this.$emit('pagination', { page: val, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>
diff --git a/ruoyi-ui/src/components/PanThumb/index.vue b/ruoyi-ui/src/components/PanThumb/index.vue
new file mode 100644
index 0000000..796b01b
--- /dev/null
+++ b/ruoyi-ui/src/components/PanThumb/index.vue
@@ -0,0 +1,142 @@
+<template>
+  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+    <div class="pan-info">
+      <div class="pan-info-roles-container">
+        <slot />
+      </div>
+    </div>
+    <!-- eslint-disable-next-line -->
+    <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'PanThumb',
+  props: {
+    image: {
+      type: String,
+      required: true
+    },
+    zIndex: {
+      type: Number,
+      default: 1
+    },
+    width: {
+      type: String,
+      default: '150px'
+    },
+    height: {
+      type: String,
+      default: '150px'
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pan-item {
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  display: inline-block;
+  position: relative;
+  cursor: default;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+  padding: 20px;
+  text-align: center;
+}
+
+.pan-thumb {
+  width: 100%;
+  height: 100%;
+  background-position: center center;
+  background-size: cover;
+  border-radius: 50%;
+  overflow: hidden;
+  position: absolute;
+  transform-origin: 95% 40%;
+  transition: all 0.3s ease-in-out;
+}
+
+/* .pan-thumb:after {
+  content: '';
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  border-radius: 50%;
+  top: 40%;
+  left: 95%;
+  margin: -4px 0 0 -4px;
+  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+} */
+
+.pan-info {
+  position: absolute;
+  width: inherit;
+  height: inherit;
+  border-radius: 50%;
+  overflow: hidden;
+  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+  color: #fff;
+  text-transform: uppercase;
+  position: relative;
+  letter-spacing: 2px;
+  font-size: 18px;
+  margin: 0 60px;
+  padding: 22px 0 0 0;
+  height: 85px;
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+  color: #fff;
+  padding: 10px 5px;
+  font-style: italic;
+  margin: 0 30px;
+  font-size: 12px;
+  border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+  display: block;
+  color: #333;
+  width: 80px;
+  height: 80px;
+  background: rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  color: #fff;
+  font-style: normal;
+  font-weight: 700;
+  text-transform: uppercase;
+  font-size: 9px;
+  letter-spacing: 1px;
+  padding-top: 24px;
+  margin: 7px auto 0;
+  font-family: 'Open Sans', Arial, sans-serif;
+  opacity: 0;
+  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+  transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+  background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+  transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+  opacity: 1;
+  transform: translateX(0px) rotate(0deg);
+}
+</style>
diff --git a/ruoyi-ui/src/components/RightPanel/index.vue b/ruoyi-ui/src/components/RightPanel/index.vue
new file mode 100644
index 0000000..1534b9b
--- /dev/null
+++ b/ruoyi-ui/src/components/RightPanel/index.vue
@@ -0,0 +1,149 @@
+<template>
+  <div ref="rightPanel" :class="{show:show}" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import { addClass, removeClass } from '@/utils'
+
+export default {
+  name: 'RightPanel',
+  props: {
+    clickNotClose: {
+      default: false,
+      type: Boolean
+    },
+    buttonTop: {
+      default: 250,
+      type: Number
+    }
+  },
+  computed: {
+    show: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    },
+    theme() {
+      return this.$store.state.settings.theme
+    },
+  },
+  watch: {
+    show(value) {
+      if (value && !this.clickNotClose) {
+        this.addEventClick()
+      }
+      if (value) {
+        addClass(document.body, 'showRightPanel')
+      } else {
+        removeClass(document.body, 'showRightPanel')
+      }
+    }
+  },
+  mounted() {
+    this.insertToBody()
+    this.addEventClick()
+  },
+  beforeDestroy() {
+    const elx = this.$refs.rightPanel
+    elx.remove()
+  },
+  methods: {
+    addEventClick() {
+      window.addEventListener('click', this.closeSidebar)
+    },
+    closeSidebar(evt) {
+      const parent = evt.target.closest('.rightPanel')
+      if (!parent) {
+        this.show = false
+        window.removeEventListener('click', this.closeSidebar)
+      }
+    },
+    insertToBody() {
+      const elx = this.$refs.rightPanel
+      const body = document.querySelector('body')
+      body.insertBefore(elx, body.firstChild)
+    }
+  }
+}
+</script>
+
+<style>
+.showRightPanel {
+  overflow: hidden;
+  position: relative;
+  width: calc(100% - 15px);
+}
+</style>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.show {
+  transition: all .3s cubic-bezier(.7, .3, .1, 1);
+
+  .rightPanel-background {
+    z-index: 20000;
+    opacity: 1;
+    width: 100%;
+    height: 100%;
+  }
+
+  .rightPanel {
+    transform: translate(0);
+  }
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/RuoYi/index.vue b/ruoyi-ui/src/components/RuoYi/index.vue
new file mode 100644
index 0000000..530d57f
--- /dev/null
+++ b/ruoyi-ui/src/components/RuoYi/index.vue
@@ -0,0 +1,21 @@
+<template>
+  <div>
+    <svg-icon icon-class="download" @click="handleDownload"/>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RuoYi',
+  data() {
+    return {
+      url: 'https://gitee.com/y_project/RuoYi-Vue'
+    }
+  },
+  methods: {
+    handleDownload() {
+      window.open(this.url)
+    }
+  }
+}
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/Screenfull/index.vue b/ruoyi-ui/src/components/Screenfull/index.vue
new file mode 100644
index 0000000..099d74d
--- /dev/null
+++ b/ruoyi-ui/src/components/Screenfull/index.vue
@@ -0,0 +1,60 @@
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'Screenfull',
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  mounted() {
+    this.init()
+  },
+  beforeDestroy() {
+    this.destroy()
+  },
+  methods: {
+    click() {
+      if (!screenfull.enabled) {
+        this.$message({
+          message: 'you browser can not work',
+          type: 'warning'
+        })
+        return false
+      }
+      screenfull.toggle()
+    },
+    change() {
+      this.isFullscreen = screenfull.isFullscreen
+    },
+    init() {
+      if (screenfull.enabled) {
+        screenfull.on('change', this.change)
+      }
+    },
+    destroy() {
+      if (screenfull.enabled) {
+        screenfull.off('change', this.change)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>
diff --git a/ruoyi-ui/src/components/SizeSelect/index.vue b/ruoyi-ui/src/components/SizeSelect/index.vue
new file mode 100644
index 0000000..5503b97
--- /dev/null
+++ b/ruoyi-ui/src/components/SizeSelect/index.vue
@@ -0,0 +1,57 @@
+<template>
+  <el-dropdown trigger="click" @command="handleSetSize">
+    <div>
+      <svg-icon class-name="size-icon" icon-class="size" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+        {{
+          item.label }}
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      sizeOptions: [
+        { label: 'Default', value: 'default' },
+        { label: 'Medium', value: 'medium' },
+        { label: 'Small', value: 'small' },
+        { label: 'Mini', value: 'mini' }
+      ]
+    }
+  },
+  computed: {
+    size() {
+      return this.$store.getters.size
+    }
+  },
+  methods: {
+    handleSetSize(size) {
+      this.$ELEMENT.size = size
+      this.$store.dispatch('app/setSize', size)
+      this.refreshView()
+      this.$message({
+        message: 'Switch Size Success',
+        type: 'success'
+      })
+    },
+    refreshView() {
+      // In order to make the cached page re-rendered
+      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+      const { fullPath } = this.$route
+
+      this.$nextTick(() => {
+        this.$router.replace({
+          path: '/redirect' + fullPath
+        })
+      })
+    }
+  }
+
+}
+</script>
diff --git a/ruoyi-ui/src/components/SvgIcon/index.vue b/ruoyi-ui/src/components/SvgIcon/index.vue
new file mode 100644
index 0000000..340ace4
--- /dev/null
+++ b/ruoyi-ui/src/components/SvgIcon/index.vue
@@ -0,0 +1,61 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.iconClass)
+    },
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    },
+    styleExternalIcon() {
+      return {
+        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>
diff --git a/ruoyi-ui/src/components/ThemePicker/index.vue b/ruoyi-ui/src/components/ThemePicker/index.vue
new file mode 100644
index 0000000..9a77cd3
--- /dev/null
+++ b/ruoyi-ui/src/components/ThemePicker/index.vue
@@ -0,0 +1,175 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const version = require('element-ui/package.json').version // element-ui version from node_modules
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+  data() {
+    return {
+      chalk: '', // content of theme-chalk css
+      theme: ''
+    }
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    defaultTheme: {
+      handler: function(val, oldVal) {
+        this.theme = val
+      },
+      immediate: true
+    },
+    async theme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+      if (typeof val !== 'string') return
+      const themeCluster = this.getThemeCluster(val.replace('#', ''))
+      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+      console.log(themeCluster, originalCluster)
+
+      const $message = this.$message({
+        message: '  Compiling the theme',
+        customClass: 'theme-message',
+        type: 'success',
+        duration: 0,
+        iconClass: 'el-icon-loading'
+      })
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+          let styleTag = document.getElementById(id)
+          if (!styleTag) {
+            styleTag = document.createElement('style')
+            styleTag.setAttribute('id', id)
+            document.head.appendChild(styleTag)
+          }
+          styleTag.innerText = newStyle
+        }
+      }
+
+      if (!this.chalk) {
+        const url = `https://unpkg.com/element-ui@${version}/lib/theme-chalk/index.css`
+        await this.getCSSString(url, 'chalk')
+      }
+
+      const chalkHandler = getHandler('chalk', 'chalk-style')
+
+      chalkHandler()
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+        })
+      styles.forEach(style => {
+        const { innerText } = style
+        if (typeof innerText !== 'string') return
+        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+      })
+
+      this.$emit('change', val)
+
+      $message.close()
+    }
+  },
+
+  methods: {
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+      })
+      return newStyle
+    },
+
+    getCSSString(url, variable) {
+      return new Promise(resolve => {
+        const xhr = new XMLHttpRequest()
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+            resolve()
+          }
+        }
+        xhr.open('GET', url)
+        xhr.send()
+      })
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        if (tint === 0) { // when primary color is in its rgb space
+          return [red, green, blue].join(',')
+        } else {
+          red += Math.round(tint * (255 - red))
+          green += Math.round(tint * (255 - green))
+          blue += Math.round(tint * (255 - blue))
+
+          red = red.toString(16)
+          green = green.toString(16)
+          blue = blue.toString(16)
+
+          return `#${red}${green}${blue}`
+        }
+      }
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        red = Math.round((1 - shade) * red)
+        green = Math.round((1 - shade) * green)
+        blue = Math.round((1 - shade) * blue)
+
+        red = red.toString(16)
+        green = green.toString(16)
+        blue = blue.toString(16)
+
+        return `#${red}${green}${blue}`
+      }
+
+      const clusters = [theme]
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+      }
+      clusters.push(shadeColor(theme, 0.1))
+      return clusters
+    }
+  }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>
diff --git a/ruoyi-ui/src/directive/permission/hasPermi.js b/ruoyi-ui/src/directive/permission/hasPermi.js
new file mode 100644
index 0000000..74f9d32
--- /dev/null
+++ b/ruoyi-ui/src/directive/permission/hasPermi.js
@@ -0,0 +1,28 @@
+ /**
+ * 鎿嶄綔鏉冮檺澶勭悊
+ * Copyright (c) 2019 ruoyi
+ */
+ 
+import store from '@/store'
+
+export default {
+  inserted(el, binding, vnode) {
+    const { value } = binding
+    const all_permission = "*:*:*";
+    const permissions = store.getters && store.getters.permissions
+
+    if (value && value instanceof Array && value.length > 0) {
+      const permissionFlag = value
+
+      const hasPermissions = permissions.some(permission => {
+        return all_permission === permission || permissionFlag.includes(permission)
+      })
+
+      if (!hasPermissions) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    } else {
+      throw new Error(`璇疯缃搷浣滄潈闄愭爣绛惧�糮)
+    }
+  }
+}
diff --git a/ruoyi-ui/src/directive/permission/hasRole.js b/ruoyi-ui/src/directive/permission/hasRole.js
new file mode 100644
index 0000000..ea966a3
--- /dev/null
+++ b/ruoyi-ui/src/directive/permission/hasRole.js
@@ -0,0 +1,28 @@
+ /**
+ * 瑙掕壊鏉冮檺澶勭悊
+ * Copyright (c) 2019 ruoyi
+ */
+ 
+import store from '@/store'
+
+export default {
+  inserted(el, binding, vnode) {
+    const { value } = binding
+    const super_admin = "admin";
+    const roles = store.getters && store.getters.roles
+
+    if (value && value instanceof Array && value.length > 0) {
+      const roleFlag = value
+
+      const hasRole = roles.some(role => {
+        return super_admin === role || roleFlag.includes(role)
+      })
+
+      if (!hasRole) {
+        el.parentNode && el.parentNode.removeChild(el)
+      }
+    } else {
+      throw new Error(`璇疯缃鑹叉潈闄愭爣绛惧��"`)
+    }
+  }
+}
diff --git a/ruoyi-ui/src/directive/permission/index.js b/ruoyi-ui/src/directive/permission/index.js
new file mode 100644
index 0000000..d6f530d
--- /dev/null
+++ b/ruoyi-ui/src/directive/permission/index.js
@@ -0,0 +1,15 @@
+import hasRole from './hasRole'
+import hasPermi from './hasPermi'
+
+const install = function(Vue) {
+  Vue.directive('hasRole', hasRole)
+  Vue.directive('hasPermi', hasPermi)
+}
+
+if (window.Vue) {
+  window['hasRole'] = hasRole
+  window['hasPermi'] = hasPermi
+  Vue.use(install); // eslint-disable-line
+}
+
+export default install
diff --git a/ruoyi-ui/src/layout/components/AppMain.vue b/ruoyi-ui/src/layout/components/AppMain.vue
new file mode 100644
index 0000000..423437b
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/AppMain.vue
@@ -0,0 +1,57 @@
+<template>
+  <section class="app-main">
+    <transition name="fade-transform" mode="out-in">
+      <keep-alive :include="cachedViews">
+        <router-view :key="key" />
+      </keep-alive>
+    </transition>
+  </section>
+</template>
+
+<script>
+export default {
+  name: 'AppMain',
+  computed: {
+    cachedViews() {
+      return this.$store.state.tagsView.cachedViews
+    },
+    key() {
+      return this.$route.path
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-main {
+  /* 50= navbar  50  */
+  min-height: calc(100vh - 50px);
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+}
+
+.fixed-header+.app-main {
+  padding-top: 50px;
+}
+
+.hasTagsView {
+  .app-main {
+    /* 84 = navbar + tags-view = 50 + 34 */
+    min-height: calc(100vh - 84px);
+  }
+
+  .fixed-header+.app-main {
+    padding-top: 84px;
+  }
+}
+</style>
+
+<style lang="scss">
+// fix css style bug in open el-dialog
+.el-popup-parent--hidden {
+  .fixed-header {
+    padding-right: 15px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
new file mode 100644
index 0000000..bafb11a
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Navbar.vue
@@ -0,0 +1,181 @@
+<template>
+  <div class="navbar">
+    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+
+    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" />
+
+    <div class="right-menu">
+      <template v-if="device!=='mobile'">
+        <search id="header-search" class="right-menu-item" />
+        
+        <el-tooltip content="涓嬭浇婧愮爜" effect="dark" placement="bottom">
+          <ruo-yi id="ruoyi" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+        <screenfull id="screenfull" class="right-menu-item hover-effect" />
+
+        <el-tooltip content="甯冨眬澶у皬" effect="dark" placement="bottom">
+          <size-select id="size-select" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+      </template>
+
+      <el-dropdown class="avatar-container right-menu-item hover-effect" trigger="click">
+        <div class="avatar-wrapper">
+          <img :src="avatar" class="user-avatar">
+          <i class="el-icon-caret-bottom" />
+        </div>
+        <el-dropdown-menu slot="dropdown">
+          <router-link to="/user/profile">
+            <el-dropdown-item>涓汉涓績</el-dropdown-item>
+          </router-link>
+          <el-dropdown-item>
+            <span @click="setting = true">甯冨眬璁剧疆</span>
+          </el-dropdown-item>
+          <el-dropdown-item divided>
+            <span @click="logout">閫�鍑虹櫥褰�</span>
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Breadcrumb from '@/components/Breadcrumb'
+import Hamburger from '@/components/Hamburger'
+import Screenfull from '@/components/Screenfull'
+import SizeSelect from '@/components/SizeSelect'
+import Search from '@/components/HeaderSearch'
+import RuoYi from '@/components/RuoYi'
+
+export default {
+  components: {
+    Breadcrumb,
+    Hamburger,
+    Screenfull,
+    SizeSelect,
+    Search,
+    RuoYi
+  },
+  computed: {
+    ...mapGetters([
+      'sidebar',
+      'avatar',
+      'device'
+    ]),
+    setting: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    }
+  },
+  methods: {
+    toggleSideBar() {
+      this.$store.dispatch('app/toggleSideBar')
+    },
+    async logout() {
+      this.$confirm('纭畾娉ㄩ攢骞堕��鍑虹郴缁熷悧锛�', '鎻愮ず', {
+        confirmButtonText: '纭畾',
+        cancelButtonText: '鍙栨秷',
+        type: 'warning'
+      }).then(() => {
+        this.$store.dispatch('LogOut').then(() => {
+          location.reload()
+        })
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.navbar {
+  height: 50px;
+  overflow: hidden;
+  position: relative;
+  background: #fff;
+  box-shadow: 0 1px 4px rgba(0,21,41,.08);
+
+  .hamburger-container {
+    line-height: 46px;
+    height: 100%;
+    float: left;
+    cursor: pointer;
+    transition: background .3s;
+    -webkit-tap-highlight-color:transparent;
+
+    &:hover {
+      background: rgba(0, 0, 0, .025)
+    }
+  }
+
+  .breadcrumb-container {
+    float: left;
+  }
+
+  .errLog-container {
+    display: inline-block;
+    vertical-align: top;
+  }
+
+  .right-menu {
+    float: right;
+    height: 100%;
+    line-height: 50px;
+
+    &:focus {
+      outline: none;
+    }
+
+    .right-menu-item {
+      display: inline-block;
+      padding: 0 8px;
+      height: 100%;
+      font-size: 18px;
+      color: #5a5e66;
+      vertical-align: text-bottom;
+
+      &.hover-effect {
+        cursor: pointer;
+        transition: background .3s;
+
+        &:hover {
+          background: rgba(0, 0, 0, .025)
+        }
+      }
+    }
+
+    .avatar-container {
+      margin-right: 30px;
+
+      .avatar-wrapper {
+        margin-top: 5px;
+        position: relative;
+
+        .user-avatar {
+          cursor: pointer;
+          width: 40px;
+          height: 40px;
+          border-radius: 10px;
+        }
+
+        .el-icon-caret-bottom {
+          cursor: pointer;
+          position: absolute;
+          right: -20px;
+          top: 25px;
+          font-size: 12px;
+        }
+      }
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue
new file mode 100644
index 0000000..3a9ac4a
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Settings/index.vue
@@ -0,0 +1,108 @@
+<template>
+  <div class="drawer-container">
+    <div>
+      <h3 class="drawer-title">绯荤粺甯冨眬閰嶇疆</h3>
+
+      <div class="drawer-item">
+        <span>涓婚棰滆壊</span>
+        <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+      </div>
+
+      <div class="drawer-item">
+        <span>寮�鍚� Tags-Views</span>
+        <el-switch v-model="tagsView" class="drawer-switch" />
+      </div>
+
+      <div class="drawer-item">
+        <span>鍥哄畾 Header</span>
+        <el-switch v-model="fixedHeader" class="drawer-switch" />
+      </div>
+
+      <div class="drawer-item">
+        <span>鏄剧ず Logo</span>
+        <el-switch v-model="sidebarLogo" class="drawer-switch" />
+      </div>
+
+    </div>
+  </div>
+</template>
+
+<script>
+import ThemePicker from '@/components/ThemePicker'
+
+export default {
+  components: { ThemePicker },
+  data() {
+    return {}
+  },
+  computed: {
+    fixedHeader: {
+      get() {
+        return this.$store.state.settings.fixedHeader
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'fixedHeader',
+          value: val
+        })
+      }
+    },
+    tagsView: {
+      get() {
+        return this.$store.state.settings.tagsView
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'tagsView',
+          value: val
+        })
+      }
+    },
+    sidebarLogo: {
+      get() {
+        return this.$store.state.settings.sidebarLogo
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'sidebarLogo',
+          value: val
+        })
+      }
+    },
+  },
+  methods: {
+    themeChange(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'theme',
+        value: val
+      })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.drawer-container {
+  padding: 24px;
+  font-size: 14px;
+  line-height: 1.5;
+  word-wrap: break-word;
+
+  .drawer-title {
+    margin-bottom: 12px;
+    color: rgba(0, 0, 0, .85);
+    font-size: 14px;
+    line-height: 22px;
+  }
+
+  .drawer-item {
+    color: rgba(0, 0, 0, .65);
+    font-size: 14px;
+    padding: 12px 0;
+  }
+
+  .drawer-switch {
+    float: right
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js b/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
new file mode 100644
index 0000000..3d8cc21
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
@@ -0,0 +1,25 @@
+export default {
+  computed: {
+    device() {
+      return this.$store.state.app.device
+    }
+  },
+  mounted() {
+    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
+    this.fixBugIniOS()
+  },
+  methods: {
+    fixBugIniOS() {
+      const $subMenu = this.$refs.subMenu
+      if ($subMenu) {
+        const handleMouseleave = $subMenu.handleMouseleave
+        $subMenu.handleMouseleave = (e) => {
+          if (this.device === 'mobile') {
+            return
+          }
+          handleMouseleave(e)
+        }
+      }
+    }
+  }
+}
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Item.vue b/ruoyi-ui/src/layout/components/Sidebar/Item.vue
new file mode 100644
index 0000000..1a99d63
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Item.vue
@@ -0,0 +1,29 @@
+<script>
+export default {
+  name: 'MenuItem',
+  functional: true,
+  props: {
+    icon: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+  render(h, context) {
+    const { icon, title } = context.props
+    const vnodes = []
+
+    if (icon) {
+      vnodes.push(<svg-icon icon-class={icon}/>)
+    }
+
+    if (title) {
+      vnodes.push(<span slot='title'>{(title)}</span>)
+    }
+    return vnodes
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Link.vue b/ruoyi-ui/src/layout/components/Sidebar/Link.vue
new file mode 100644
index 0000000..6cd6e2c
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Link.vue
@@ -0,0 +1,36 @@
+
+<template>
+  <!-- eslint-disable vue/require-component-is -->
+  <component v-bind="linkProps(to)">
+    <slot />
+  </component>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  props: {
+    to: {
+      type: String,
+      required: true
+    }
+  },
+  methods: {
+    linkProps(url) {
+      if (isExternal(url)) {
+        return {
+          is: 'a',
+          href: url,
+          target: '_blank',
+          rel: 'noopener'
+        }
+      }
+      return {
+        is: 'router-link',
+        to: url
+      }
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
new file mode 100644
index 0000000..021de8e
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
@@ -0,0 +1,84 @@
+<template>
+  <div class="sidebar-logo-container" :class="{'collapse':collapse}">
+    <transition name="sidebarLogoFade">
+      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <h1 v-else class="sidebar-title">{{ title }} </h1>
+      </router-link>
+      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo">
+        <h1 class="sidebar-title">{{ title }} </h1>
+      </router-link>
+    </transition>
+  </div>
+</template>
+
+<script>
+import logoImg from '@/assets/logo/logo.png'
+
+export default {
+  name: 'SidebarLogo',
+  props: {
+    collapse: {
+      type: Boolean,
+      required: true
+    }
+  },
+  data() {
+    return {
+      title: '鑻ヤ緷绠$悊绯荤粺',
+      logo: logoImg
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.sidebarLogoFade-enter-active {
+  transition: opacity 1.5s;
+}
+
+.sidebarLogoFade-enter,
+.sidebarLogoFade-leave-to {
+  opacity: 0;
+}
+
+.sidebar-logo-container {
+  position: relative;
+  width: 100%;
+  height: 50px;
+  line-height: 50px;
+  background: #2b2f3a;
+  text-align: center;
+  overflow: hidden;
+
+  & .sidebar-logo-link {
+    height: 100%;
+    width: 100%;
+
+    & .sidebar-logo {
+      width: 32px;
+      height: 32px;
+      vertical-align: middle;
+      margin-right: 12px;
+    }
+
+    & .sidebar-title {
+      display: inline-block;
+      margin: 0;
+      color: #fff;
+      font-weight: 600;
+      line-height: 50px;
+      font-size: 14px;
+      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+      vertical-align: middle;
+    }
+  }
+
+  &.collapse {
+    .sidebar-logo {
+      margin-right: 0px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue b/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
new file mode 100644
index 0000000..1ca89d2
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
@@ -0,0 +1,93 @@
+<template>
+  <div v-if="!item.hidden" class="menu-wrapper">
+    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
+      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path)">
+        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
+        </el-menu-item>
+      </app-link>
+    </template>
+
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+      <template slot="title">
+        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+      </template>
+      <sidebar-item
+        v-for="child in item.children"
+        :key="child.path"
+        :is-nest="true"
+        :item="child"
+        :base-path="resolvePath(child.path)"
+        class="nest-menu"
+      />
+    </el-submenu>
+  </div>
+</template>
+
+<script>
+import path from 'path'
+import { isExternal } from '@/utils/validate'
+import Item from './Item'
+import AppLink from './Link'
+import FixiOSBug from './FixiOSBug'
+
+export default {
+  name: 'SidebarItem',
+  components: { Item, AppLink },
+  mixins: [FixiOSBug],
+  props: {
+    // route object
+    item: {
+      type: Object,
+      required: true
+    },
+    isNest: {
+      type: Boolean,
+      default: false
+    },
+    basePath: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    this.onlyOneChild = null
+    return {}
+  },
+  methods: {
+    hasOneShowingChild(children = [], parent) {
+      const showingChildren = children.filter(item => {
+        if (item.hidden) {
+          return false
+        } else {
+          // Temp set(will be used if only has one showing child)
+          this.onlyOneChild = item
+          return true
+        }
+      })
+
+      // When there is only one child router, the child router is displayed by default
+      if (showingChildren.length === 1) {
+        return true
+      }
+
+      // Show parent if there are no child router to display
+      if (showingChildren.length === 0) {
+        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
+        return true
+      }
+
+      return false
+    },
+    resolvePath(routePath) {
+      if (isExternal(routePath)) {
+        return routePath
+      }
+      if (isExternal(this.basePath)) {
+        return this.basePath
+      }
+      return path.resolve(this.basePath, routePath)
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/index.vue b/ruoyi-ui/src/layout/components/Sidebar/index.vue
new file mode 100644
index 0000000..4d0c6c9
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/index.vue
@@ -0,0 +1,54 @@
+<template>
+  <div :class="{'has-logo':showLogo}">
+    <logo v-if="showLogo" :collapse="isCollapse" />
+    <el-scrollbar wrap-class="scrollbar-wrapper">
+      <el-menu
+        :default-active="activeMenu"
+        :collapse="isCollapse"
+        :background-color="variables.menuBg"
+        :text-color="variables.menuText"
+        :unique-opened="true"
+        :active-text-color="variables.menuActiveText"
+        :collapse-transition="false"
+        mode="vertical"
+      >
+        <sidebar-item v-for="route in permission_routes" :key="route.path" :item="route" :base-path="route.path" />
+      </el-menu>
+    </el-scrollbar>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Logo from './Logo'
+import SidebarItem from './SidebarItem'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+  components: { SidebarItem, Logo },
+  computed: {
+    ...mapGetters([
+      'permission_routes',
+      'sidebar'
+    ]),
+    activeMenu() {
+      const route = this.$route
+      const { meta, path } = route
+      // if set path, the sidebar will highlight the path you set
+      if (meta.activeMenu) {
+        return meta.activeMenu
+      }
+      return path
+    },
+    showLogo() {
+      return this.$store.state.settings.sidebarLogo
+    },
+    variables() {
+      return variables
+    },
+    isCollapse() {
+      return !this.sidebar.opened
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
new file mode 100644
index 0000000..8be9c01
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
@@ -0,0 +1,85 @@
+<template>
+  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
+    <slot />
+  </el-scrollbar>
+</template>
+
+<script>
+const tagAndTagSpacing = 4 // tagAndTagSpacing
+
+export default {
+  name: 'ScrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  computed: {
+    scrollWrapper() {
+      return this.$refs.scrollContainer.$refs.wrap
+    }
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 40
+      const $scrollWrapper = this.scrollWrapper
+      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+    },
+    moveToTarget(currentTag) {
+      const $container = this.$refs.scrollContainer.$el
+      const $containerWidth = $container.offsetWidth
+      const $scrollWrapper = this.scrollWrapper
+      const tagList = this.$parent.$refs.tag
+
+      let firstTag = null
+      let lastTag = null
+
+      // find first tag and last tag
+      if (tagList.length > 0) {
+        firstTag = tagList[0]
+        lastTag = tagList[tagList.length - 1]
+      }
+
+      if (firstTag === currentTag) {
+        $scrollWrapper.scrollLeft = 0
+      } else if (lastTag === currentTag) {
+        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
+      } else {
+        // find preTag and nextTag
+        const currentIndex = tagList.findIndex(item => item === currentTag)
+        const prevTag = tagList[currentIndex - 1]
+        const nextTag = tagList[currentIndex + 1]
+
+        // the tag's offsetLeft after of nextTag
+        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+
+        // the tag's offsetLeft before of prevTag
+        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+
+        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
+        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  /deep/ {
+    .el-scrollbar__bar {
+      bottom: 0px;
+    }
+    .el-scrollbar__wrap {
+      height: 49px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue
new file mode 100644
index 0000000..9fc380f
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/TagsView/index.vue
@@ -0,0 +1,286 @@
+<template>
+  <div id="tags-view-container" class="tags-view-container">
+    <scroll-pane ref="scrollPane" class="tags-view-wrapper">
+      <router-link
+        v-for="tag in visitedViews"
+        ref="tag"
+        :key="tag.path"
+        :class="isActive(tag)?'active':''"
+        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+        tag="span"
+        class="tags-view-item"
+        @click.middle.native="closeSelectedTag(tag)"
+        @contextmenu.prevent.native="openMenu(tag,$event)"
+      >
+        {{ tag.title }}
+        <span v-if="!tag.meta.affix" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+      </router-link>
+    </scroll-pane>
+    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
+      <li @click="refreshSelectedTag(selectedTag)">鍒锋柊椤甸潰</li>
+      <li v-if="!(selectedTag.meta&&selectedTag.meta.affix)" @click="closeSelectedTag(selectedTag)">鍏抽棴褰撳墠</li>
+      <li @click="closeOthersTags">鍏抽棴鍏朵粬</li>
+      <li @click="closeAllTags(selectedTag)">鍏抽棴鎵�鏈�</li>
+    </ul>
+  </div>
+</template>
+
+<script>
+import ScrollPane from './ScrollPane'
+import path from 'path'
+
+export default {
+  components: { ScrollPane },
+  data() {
+    return {
+      visible: false,
+      top: 0,
+      left: 0,
+      selectedTag: {},
+      affixTags: []
+    }
+  },
+  computed: {
+    visitedViews() {
+      return this.$store.state.tagsView.visitedViews
+    },
+    routes() {
+      return this.$store.state.permission.routes
+    }
+  },
+  watch: {
+    $route() {
+      this.addTags()
+      this.moveToCurrentTag()
+    },
+    visible(value) {
+      if (value) {
+        document.body.addEventListener('click', this.closeMenu)
+      } else {
+        document.body.removeEventListener('click', this.closeMenu)
+      }
+    }
+  },
+  mounted() {
+    this.initTags()
+    this.addTags()
+  },
+  methods: {
+    isActive(route) {
+      return route.path === this.$route.path
+    },
+    filterAffixTags(routes, basePath = '/') {
+      let tags = []
+      routes.forEach(route => {
+        if (route.meta && route.meta.affix) {
+          const tagPath = path.resolve(basePath, route.path)
+          tags.push({
+            fullPath: tagPath,
+            path: tagPath,
+            name: route.name,
+            meta: { ...route.meta }
+          })
+        }
+        if (route.children) {
+          const tempTags = this.filterAffixTags(route.children, route.path)
+          if (tempTags.length >= 1) {
+            tags = [...tags, ...tempTags]
+          }
+        }
+      })
+      return tags
+    },
+    initTags() {
+      const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+      for (const tag of affixTags) {
+        // Must have tag name
+        if (tag.name) {
+          this.$store.dispatch('tagsView/addVisitedView', tag)
+        }
+      }
+    },
+    addTags() {
+      const { name } = this.$route
+      if (name) {
+        this.$store.dispatch('tagsView/addView', this.$route)
+      }
+      return false
+    },
+    moveToCurrentTag() {
+      const tags = this.$refs.tag
+      this.$nextTick(() => {
+        for (const tag of tags) {
+          if (tag.to.path === this.$route.path) {
+            this.$refs.scrollPane.moveToTarget(tag)
+            // when query is different then update
+            if (tag.to.fullPath !== this.$route.fullPath) {
+              this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+            }
+            break
+          }
+        }
+      })
+    },
+    refreshSelectedTag(view) {
+      this.$store.dispatch('tagsView/delCachedView', view).then(() => {
+        const { fullPath } = view
+        this.$nextTick(() => {
+          this.$router.replace({
+            path: '/redirect' + fullPath
+          })
+        })
+      })
+    },
+    closeSelectedTag(view) {
+      this.$store.dispatch('tagsView/delView', view).then(({ visitedViews }) => {
+        if (this.isActive(view)) {
+          this.toLastView(visitedViews, view)
+        }
+      })
+    },
+    closeOthersTags() {
+      this.$router.push(this.selectedTag)
+      this.$store.dispatch('tagsView/delOthersViews', this.selectedTag).then(() => {
+        this.moveToCurrentTag()
+      })
+    },
+    closeAllTags(view) {
+      this.$store.dispatch('tagsView/delAllViews').then(({ visitedViews }) => {
+        if (this.affixTags.some(tag => tag.path === view.path)) {
+          return
+        }
+        this.toLastView(visitedViews, view)
+      })
+    },
+    toLastView(visitedViews, view) {
+      const latestView = visitedViews.slice(-1)[0]
+      if (latestView) {
+        this.$router.push(latestView)
+      } else {
+        // now the default is to redirect to the home page if there is no tags-view,
+        // you can adjust it according to your needs.
+        if (view.name === 'Dashboard') {
+          // to reload home page
+          this.$router.replace({ path: '/redirect' + view.fullPath })
+        } else {
+          this.$router.push('/')
+        }
+      }
+    },
+    openMenu(tag, e) {
+      const menuMinWidth = 105
+      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
+      const offsetWidth = this.$el.offsetWidth // container width
+      const maxLeft = offsetWidth - menuMinWidth // left boundary
+      const left = e.clientX - offsetLeft + 15 // 15: margin right
+
+      if (left > maxLeft) {
+        this.left = maxLeft
+      } else {
+        this.left = left
+      }
+
+      this.top = e.clientY
+      this.visible = true
+      this.selectedTag = tag
+    },
+    closeMenu() {
+      this.visible = false
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.tags-view-container {
+  height: 34px;
+  width: 100%;
+  background: #fff;
+  border-bottom: 1px solid #d8dce5;
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+  .tags-view-wrapper {
+    .tags-view-item {
+      display: inline-block;
+      position: relative;
+      cursor: pointer;
+      height: 26px;
+      line-height: 26px;
+      border: 1px solid #d8dce5;
+      color: #495060;
+      background: #fff;
+      padding: 0 8px;
+      font-size: 12px;
+      margin-left: 5px;
+      margin-top: 4px;
+      &:first-of-type {
+        margin-left: 15px;
+      }
+      &:last-of-type {
+        margin-right: 15px;
+      }
+      &.active {
+        background-color: #42b983;
+        color: #fff;
+        border-color: #42b983;
+        &::before {
+          content: '';
+          background: #fff;
+          display: inline-block;
+          width: 8px;
+          height: 8px;
+          border-radius: 50%;
+          position: relative;
+          margin-right: 2px;
+        }
+      }
+    }
+  }
+  .contextmenu {
+    margin: 0;
+    background: #fff;
+    z-index: 3000;
+    position: absolute;
+    list-style-type: none;
+    padding: 5px 0;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 400;
+    color: #333;
+    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+    li {
+      margin: 0;
+      padding: 7px 16px;
+      cursor: pointer;
+      &:hover {
+        background: #eee;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+//reset element css of el-icon-close
+.tags-view-wrapper {
+  .tags-view-item {
+    .el-icon-close {
+      width: 16px;
+      height: 16px;
+      vertical-align: 2px;
+      border-radius: 50%;
+      text-align: center;
+      transition: all .3s cubic-bezier(.645, .045, .355, 1);
+      transform-origin: 100% 50%;
+      &:before {
+        transform: scale(.6);
+        display: inline-block;
+        vertical-align: -3px;
+      }
+      &:hover {
+        background-color: #b4bccc;
+        color: #fff;
+      }
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/index.js b/ruoyi-ui/src/layout/components/index.js
new file mode 100644
index 0000000..7f83004
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/index.js
@@ -0,0 +1,5 @@
+export { default as AppMain } from './AppMain'
+export { default as Navbar } from './Navbar'
+export { default as Settings } from './Settings'
+export { default as Sidebar } from './Sidebar/index.vue'
+export { default as TagsView } from './TagsView/index.vue'
diff --git a/ruoyi-ui/src/layout/index.vue b/ruoyi-ui/src/layout/index.vue
new file mode 100644
index 0000000..4e761ea
--- /dev/null
+++ b/ruoyi-ui/src/layout/index.vue
@@ -0,0 +1,102 @@
+<template>
+  <div :class="classObj" class="app-wrapper">
+    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside" />
+    <sidebar class="sidebar-container" />
+    <div :class="{hasTagsView:needTagsView}" class="main-container">
+      <div :class="{'fixed-header':fixedHeader}">
+        <navbar />
+        <tags-view v-if="needTagsView" />
+      </div>
+      <app-main />
+      <right-panel v-if="showSettings">
+        <settings />
+      </right-panel>
+    </div>
+  </div>
+</template>
+
+<script>
+import RightPanel from '@/components/RightPanel'
+import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+import { mapState } from 'vuex'
+
+export default {
+  name: 'Layout',
+  components: {
+    AppMain,
+    Navbar,
+    RightPanel,
+    Settings,
+    Sidebar,
+    TagsView
+  },
+  mixins: [ResizeMixin],
+  computed: {
+    ...mapState({
+      sidebar: state => state.app.sidebar,
+      device: state => state.app.device,
+      showSettings: state => state.settings.showSettings,
+      needTagsView: state => state.settings.tagsView,
+      fixedHeader: state => state.settings.fixedHeader
+    }),
+    classObj() {
+      return {
+        hideSidebar: !this.sidebar.opened,
+        openSidebar: this.sidebar.opened,
+        withoutAnimation: this.sidebar.withoutAnimation,
+        mobile: this.device === 'mobile'
+      }
+    }
+  },
+  methods: {
+    handleClickOutside() {
+      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "~@/assets/styles/mixin.scss";
+  @import "~@/assets/styles/variables.scss";
+
+  .app-wrapper {
+    @include clearfix;
+    position: relative;
+    height: 100%;
+    width: 100%;
+
+    &.mobile.openSidebar {
+      position: fixed;
+      top: 0;
+    }
+  }
+
+  .drawer-bg {
+    background: #000;
+    opacity: 0.3;
+    width: 100%;
+    top: 0;
+    height: 100%;
+    position: absolute;
+    z-index: 999;
+  }
+
+  .fixed-header {
+    position: fixed;
+    top: 0;
+    right: 0;
+    z-index: 9;
+    width: calc(100% - #{$sideBarWidth});
+    transition: width 0.28s;
+  }
+
+  .hideSidebar .fixed-header {
+    width: calc(100% - 54px)
+  }
+
+  .mobile .fixed-header {
+    width: 100%;
+  }
+</style>
diff --git a/ruoyi-ui/src/layout/mixin/ResizeHandler.js b/ruoyi-ui/src/layout/mixin/ResizeHandler.js
new file mode 100644
index 0000000..b3fc8b2
--- /dev/null
+++ b/ruoyi-ui/src/layout/mixin/ResizeHandler.js
@@ -0,0 +1,45 @@
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+export default {
+  watch: {
+    $route(route) {
+      if (this.device === 'mobile' && this.sidebar.opened) {
+        store.dispatch('app/closeSideBar', { withoutAnimation: false })
+      }
+    }
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.$_resizeHandler)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.$_resizeHandler)
+  },
+  mounted() {
+    const isMobile = this.$_isMobile()
+    if (isMobile) {
+      store.dispatch('app/toggleDevice', 'mobile')
+      store.dispatch('app/closeSideBar', { withoutAnimation: true })
+    }
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_isMobile() {
+      const rect = body.getBoundingClientRect()
+      return rect.width - 1 < WIDTH
+    },
+    $_resizeHandler() {
+      if (!document.hidden) {
+        const isMobile = this.$_isMobile()
+        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
+
+        if (isMobile) {
+          store.dispatch('app/closeSideBar', { withoutAnimation: true })
+        }
+      }
+    }
+  }
+}
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
new file mode 100644
index 0000000..c0056ee
--- /dev/null
+++ b/ruoyi-ui/src/main.js
@@ -0,0 +1,69 @@
+import Vue from 'vue'
+
+import Cookies from 'js-cookie'
+
+import 'normalize.css/normalize.css' // a modern alternative to CSS resets
+
+import Element from 'element-ui'
+import './assets/styles/element-variables.scss'
+
+import '@/assets/styles/index.scss' // global css
+import '@/assets/styles/ruoyi.scss' // ruoyi css
+import App from './App'
+import store from './store'
+import router from './router'
+import permission from './directive/permission'
+
+import './assets/icons' // icon
+import './permission' // permission control
+import { getDicts } from "@/api/system/dict/data";
+import { getConfigKey } from "@/api/system/config";
+import { dateFormat, resetForm, addDateRange, selectDictLabel } from "@/utils/ruoyi";
+import Pagination from "@/components/Pagination";
+
+// 鍏ㄥ眬鏂规硶鎸傝浇
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.dateFormat = dateFormat
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+
+Vue.prototype.msgSuccess = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "success" });
+}
+
+Vue.prototype.msgError = function (msg) {
+  this.$message({ showClose: true, message: msg, type: "error" });
+}
+
+Vue.prototype.msgInfo = function (msg) {
+  this.$message.info(msg);
+}
+
+// 鍏ㄥ眬缁勪欢鎸傝浇
+Vue.component('Pagination', Pagination)
+
+Vue.use(permission)
+
+/**
+ * If you don't want to use mock-server
+ * you want to use MockJs for mock api
+ * you can execute: mockXHR()
+ *
+ * Currently MockJs will be used in the production environment,
+ * please remove it before going online! ! !
+ */
+
+Vue.use(Element, {
+  size: Cookies.get('size') || 'medium' // set element-ui default size
+})
+
+Vue.config.productionTip = false
+
+new Vue({
+  el: '#app',
+  router,
+  store,
+  render: h => h(App)
+})
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
new file mode 100644
index 0000000..1813f42
--- /dev/null
+++ b/ruoyi-ui/src/permission.js
@@ -0,0 +1,64 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { getToken } from '@/utils/auth'
+
+NProgress.configure({ showSpinner: false })
+
+const whiteList = ['/login', '/auth-redirect', '/bind', '/register']
+
+router.beforeEach((to, from, next) => {
+  NProgress.start()
+  if (getToken()) {
+    /* has token*/
+    if (to.path === '/login') {
+      next({ path: '/' })
+      NProgress.done()
+    } else {
+      if (store.getters.roles.length === 0) {
+        // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
+        store.dispatch('GetInfo').then(res => {
+          // 鎷夊彇user_info
+          const roles = res.roles
+          store.dispatch('GenerateRoutes', { roles }).then(accessRoutes => {
+          // 娴嬭瘯 榛樿闈欐�侀〉闈�
+          // store.dispatch('permission/generateRoutes', { roles }).then(accessRoutes => {
+            // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+            router.addRoutes(accessRoutes) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+            next({ ...to, replace: true }) // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+          })
+        })
+          .catch(err => {
+            store.dispatch('FedLogOut').then(() => {
+              Message.error(err)
+              next({ path: '/' })
+            })
+          })
+      } else {
+        next()
+        // 娌℃湁鍔ㄦ�佹敼鍙樻潈闄愮殑闇�姹傚彲鐩存帴next() 鍒犻櫎涓嬫柟鏉冮檺鍒ゆ柇 鈫�
+        // if (hasPermission(store.getters.roles, to.meta.roles)) {
+        //   next()
+        // } else {
+        //   next({ path: '/401', replace: true, query: { noGoBack: true }})
+        // }
+        // 鍙垹 鈫�
+      }
+    }
+  } else {
+    // 娌℃湁token
+    if (whiteList.indexOf(to.path) !== -1) {
+      // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
+      next()
+    } else {
+      next(`/login?redirect=${to.path}`) // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
+      NProgress.done()
+    }
+  }
+})
+
+router.afterEach(() => {
+  NProgress.done()
+})
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
new file mode 100644
index 0000000..526d755
--- /dev/null
+++ b/ruoyi-ui/src/router/index.js
@@ -0,0 +1,101 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+
+/**
+ * Note: 璺敱閰嶇疆椤�
+ *
+ * hidden: true                   // 褰撹缃� true 鐨勬椂鍊欒璺敱涓嶄細鍐嶄晶杈规爮鍑虹幇 濡�401锛宭ogin绛夐〉闈紝鎴栬�呭涓�浜涚紪杈戦〉闈�/edit/1
+ * alwaysShow: true               // 褰撲綘涓�涓矾鐢变笅闈㈢殑 children 澹版槑鐨勮矾鐢卞ぇ浜�1涓椂锛岃嚜鍔ㄤ細鍙樻垚宓屽鐨勬ā寮�--濡傜粍浠堕〉闈�
+ *                                // 鍙湁涓�涓椂锛屼細灏嗛偅涓瓙璺敱褰撳仛鏍硅矾鐢辨樉绀哄湪渚ц竟鏍�--濡傚紩瀵奸〉闈�
+ *                                // 鑻ヤ綘鎯充笉绠¤矾鐢变笅闈㈢殑 children 澹版槑鐨勪釜鏁伴兘鏄剧ず浣犵殑鏍硅矾鐢�
+ *                                // 浣犲彲浠ヨ缃� alwaysShow: true锛岃繖鏍峰畠灏变細蹇界暐涔嬪墠瀹氫箟鐨勮鍒欙紝涓�鐩存樉绀烘牴璺敱
+ * redirect: noRedirect           // 褰撹缃� noRedirect 鐨勬椂鍊欒璺敱鍦ㄩ潰鍖呭睉瀵艰埅涓笉鍙鐐瑰嚮
+ * name:'router-name'             // 璁惧畾璺敱鐨勫悕瀛楋紝涓�瀹氳濉啓涓嶇劧浣跨敤<keep-alive>鏃朵細鍑虹幇鍚勭闂
+ * meta : {
+    roles: ['admin','editor']    // 璁剧疆璇ヨ矾鐢辫繘鍏ョ殑鏉冮檺锛屾敮鎸佸涓潈闄愬彔鍔�
+    title: 'title'               // 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+    icon: 'svg-name'             // 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/icons/svg
+    breadcrumb: false            // 濡傛灉璁剧疆涓篺alse锛屽垯涓嶄細鍦╞readcrumb闈㈠寘灞戜腑鏄剧ず
+  }
+ */
+
+// 鍏叡璺敱
+export const constantRoutes = [
+  {
+    path: '/redirect',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: '/redirect/:path*',
+        component: () => import('@/views/redirect')
+      }
+    ]
+  },
+  {
+    path: '/login',
+    component: () => import('@/views/login'),
+    hidden: true
+  },
+  {
+    path: '/404',
+    component: () => import('@/views/error/404'),
+    hidden: true
+  },
+  {
+    path: '/401',
+    component: () => import('@/views/error/401'),
+    hidden: true
+  },
+  {
+    path: '',
+    component: Layout,
+    redirect: 'index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/index'),
+        name: '棣栭〉',
+        meta: { title: '棣栭〉', icon: 'dashboard', noCache: true, affix: true }
+      }
+    ]
+  },
+  {
+    path: '/user',
+    component: Layout,
+    hidden: true,
+    redirect: 'noredirect',
+    children: [
+      {
+        path: 'profile',
+        component: () => import('@/views/system/user/profile/index'),
+        name: '涓汉涓績',
+        meta: { title: '涓汉涓績', icon: 'user' }
+      }
+    ]
+  },
+  {
+    path: '/dict',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: 'type/data/:dictId(\\d+)',
+        component: () => import('@/views/system/dict/data'),
+        name: '瀛楀吀鏁版嵁',
+        meta: { title: '瀛楀吀鏁版嵁', icon: '' }
+      }
+    ]
+  }
+]
+
+export default new Router({
+  mode: 'history', // 鍘绘帀url涓殑#
+  scrollBehavior: () => ({ y: 0 }),
+  routes: constantRoutes
+})
diff --git a/ruoyi-ui/src/settings.js b/ruoyi-ui/src/settings.js
new file mode 100644
index 0000000..ca6d00c
--- /dev/null
+++ b/ruoyi-ui/src/settings.js
@@ -0,0 +1,31 @@
+module.exports = {
+  title: '鑻ヤ緷绠$悊绯荤粺',
+
+  /**
+   * 鏄惁绯荤粺甯冨眬閰嶇疆
+   */
+  showSettings: false,
+
+  /**
+   * 鏄惁鏄剧ず tagsView
+   */
+  tagsView: true,
+
+  /**
+   * 鏄惁鍥哄畾澶撮儴
+   */
+  fixedHeader: false,
+
+  /**
+   * 鏄惁鏄剧ずlogo
+   */
+  sidebarLogo: true,
+
+  /**
+   * @type {string | array} 'production' | ['production', 'development']
+   * @description Need show err logs component.
+   * The default is only used in the production env
+   * If you want to also use it in dev, you can pass ['production', 'development']
+   */
+  errorLog: 'production'
+}
diff --git a/ruoyi-ui/src/store/getters.js b/ruoyi-ui/src/store/getters.js
new file mode 100644
index 0000000..b985521
--- /dev/null
+++ b/ruoyi-ui/src/store/getters.js
@@ -0,0 +1,15 @@
+const getters = {
+  sidebar: state => state.app.sidebar,
+  size: state => state.app.size,
+  device: state => state.app.device,
+  visitedViews: state => state.tagsView.visitedViews,
+  cachedViews: state => state.tagsView.cachedViews,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name,
+  introduction: state => state.user.introduction,
+  roles: state => state.user.roles,
+  permissions: state => state.user.permissions,
+  permission_routes: state => state.permission.routes
+}
+export default getters
diff --git a/ruoyi-ui/src/store/index.js b/ruoyi-ui/src/store/index.js
new file mode 100644
index 0000000..eceb2cd
--- /dev/null
+++ b/ruoyi-ui/src/store/index.js
@@ -0,0 +1,23 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import user from './modules/user'
+import tagsView from './modules/tagsView'
+import permission from './modules/permission'
+import settings from './modules/settings'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    app,
+    user,
+    tagsView,
+    permission,
+    settings
+  },
+  getters
+})
+
+export default store
diff --git a/ruoyi-ui/src/store/modules/app.js b/ruoyi-ui/src/store/modules/app.js
new file mode 100644
index 0000000..c8d8ee9
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/app.js
@@ -0,0 +1,56 @@
+import Cookies from 'js-cookie'
+
+const state = {
+  sidebar: {
+    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+    withoutAnimation: false
+  },
+  device: 'desktop',
+  size: Cookies.get('size') || 'medium'
+}
+
+const mutations = {
+  TOGGLE_SIDEBAR: state => {
+    state.sidebar.opened = !state.sidebar.opened
+    state.sidebar.withoutAnimation = false
+    if (state.sidebar.opened) {
+      Cookies.set('sidebarStatus', 1)
+    } else {
+      Cookies.set('sidebarStatus', 0)
+    }
+  },
+  CLOSE_SIDEBAR: (state, withoutAnimation) => {
+    Cookies.set('sidebarStatus', 0)
+    state.sidebar.opened = false
+    state.sidebar.withoutAnimation = withoutAnimation
+  },
+  TOGGLE_DEVICE: (state, device) => {
+    state.device = device
+  },
+  SET_SIZE: (state, size) => {
+    state.size = size
+    Cookies.set('size', size)
+  }
+}
+
+const actions = {
+  toggleSideBar({ commit }) {
+    commit('TOGGLE_SIDEBAR')
+  },
+  closeSideBar({ commit }, { withoutAnimation }) {
+    commit('CLOSE_SIDEBAR', withoutAnimation)
+  },
+  toggleDevice({ commit }, device) {
+    commit('TOGGLE_DEVICE', device)
+  },
+  setSize({ commit }, size) {
+    commit('SET_SIZE', size)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
new file mode 100644
index 0000000..da937ae
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/permission.js
@@ -0,0 +1,53 @@
+import { constantRoutes } from '@/router'
+import { getRouters } from '@/api/menu'
+import Layout from '@/layout/index'
+
+const permission = {
+  state: {
+    routes: [],
+    addRoutes: []
+  },
+  mutations: {
+    SET_ROUTES: (state, routes) => {
+      state.addRoutes = routes
+      state.routes = constantRoutes.concat(routes)
+    }
+  },
+  actions: {
+    // 鐢熸垚璺敱
+    GenerateRoutes({ commit }) {
+      return new Promise(resolve => {
+        // 鍚戝悗绔姹傝矾鐢辨暟鎹�
+        getRouters().then(res => {
+          const accessedRoutes = filterAsyncRouter(res.data)
+          commit('SET_ROUTES', accessedRoutes)
+          resolve(accessedRoutes)
+        })
+      })
+    }
+  }
+}
+
+// 閬嶅巻鍚庡彴浼犳潵鐨勮矾鐢卞瓧绗︿覆锛岃浆鎹负缁勪欢瀵硅薄
+function filterAsyncRouter(asyncRouterMap) {
+  return asyncRouterMap.filter(route => {
+    if (route.component) {
+      // Layout缁勪欢鐗规畩澶勭悊
+      if (route.component === 'Layout') {
+        route.component = Layout
+      } else {
+        route.component = loadView(route.component)
+      }
+    }
+    if (route.children != null && route.children && route.children.length) {
+      route.children = filterAsyncRouter(route.children)
+    }
+    return true
+  })
+}
+
+export const loadView = (view) => { // 璺敱鎳掑姞杞�
+  return () => import(`@/views/${view}`)
+}
+
+export default permission
diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js
new file mode 100644
index 0000000..30685e6
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/settings.js
@@ -0,0 +1,34 @@
+import variables from '@/assets/styles/element-variables.scss'
+import defaultSettings from '@/settings'
+
+const { showSettings, tagsView, fixedHeader, sidebarLogo } = defaultSettings
+
+const state = {
+  theme: variables.theme,
+  showSettings: showSettings,
+  tagsView: tagsView,
+  fixedHeader: fixedHeader,
+  sidebarLogo: sidebarLogo
+}
+
+const mutations = {
+  CHANGE_SETTING: (state, { key, value }) => {
+    if (state.hasOwnProperty(key)) {
+      state[key] = value
+    }
+  }
+}
+
+const actions = {
+  changeSetting({ commit }, data) {
+    commit('CHANGE_SETTING', data)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+
diff --git a/ruoyi-ui/src/store/modules/tagsView.js b/ruoyi-ui/src/store/modules/tagsView.js
new file mode 100644
index 0000000..e128d2a
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/tagsView.js
@@ -0,0 +1,165 @@
+const state = {
+  visitedViews: [],
+  cachedViews: []
+}
+
+const mutations = {
+  ADD_VISITED_VIEW: (state, view) => {
+    if (state.visitedViews.some(v => v.path === view.path)) return
+    state.visitedViews.push(
+      Object.assign({}, view, {
+        title: view.meta.title || 'no-name'
+      })
+    )
+  },
+  ADD_CACHED_VIEW: (state, view) => {
+    if (state.cachedViews.includes(view.name)) return
+    if (!view.meta.noCache) {
+      state.cachedViews.push(view.name)
+    }
+  },
+
+  DEL_VISITED_VIEW: (state, view) => {
+    for (const [i, v] of state.visitedViews.entries()) {
+      if (v.path === view.path) {
+        state.visitedViews.splice(i, 1)
+        break
+      }
+    }
+  },
+  DEL_CACHED_VIEW: (state, view) => {
+    for (const i of state.cachedViews) {
+      if (i === view.name) {
+        const index = state.cachedViews.indexOf(i)
+        state.cachedViews.splice(index, 1)
+        break
+      }
+    }
+  },
+
+  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+    state.visitedViews = state.visitedViews.filter(v => {
+      return v.meta.affix || v.path === view.path
+    })
+  },
+  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+    for (const i of state.cachedViews) {
+      if (i === view.name) {
+        const index = state.cachedViews.indexOf(i)
+        state.cachedViews = state.cachedViews.slice(index, index + 1)
+        break
+      }
+    }
+  },
+
+  DEL_ALL_VISITED_VIEWS: state => {
+    // keep affix tags
+    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+    state.visitedViews = affixTags
+  },
+  DEL_ALL_CACHED_VIEWS: state => {
+    state.cachedViews = []
+  },
+
+  UPDATE_VISITED_VIEW: (state, view) => {
+    for (let v of state.visitedViews) {
+      if (v.path === view.path) {
+        v = Object.assign(v, view)
+        break
+      }
+    }
+  }
+}
+
+const actions = {
+  addView({ dispatch }, view) {
+    dispatch('addVisitedView', view)
+    dispatch('addCachedView', view)
+  },
+  addVisitedView({ commit }, view) {
+    commit('ADD_VISITED_VIEW', view)
+  },
+  addCachedView({ commit }, view) {
+    commit('ADD_CACHED_VIEW', view)
+  },
+
+  delView({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delVisitedView', view)
+      dispatch('delCachedView', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delVisitedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_VISITED_VIEW', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delCachedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_CACHED_VIEW', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delOthersViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delOthersVisitedViews', view)
+      dispatch('delOthersCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delOthersVisitedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_VISITED_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delOthersCachedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_CACHED_VIEWS', view)
+      resolve([...state.cachedViews])
+    })
+  },
+
+  delAllViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delAllVisitedViews', view)
+      dispatch('delAllCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delAllVisitedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_VISITED_VIEWS')
+      resolve([...state.visitedViews])
+    })
+  },
+  delAllCachedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_CACHED_VIEWS')
+      resolve([...state.cachedViews])
+    })
+  },
+
+  updateVisitedView({ commit }, view) {
+    commit('UPDATE_VISITED_VIEW', view)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js
new file mode 100644
index 0000000..20f44bf
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/user.js
@@ -0,0 +1,96 @@
+import { login, logout, getInfo } from '@/api/login'
+import { getToken, setToken, removeToken } from '@/utils/auth'
+
+const user = {
+  state: {
+    token: getToken(),
+    name: '',
+    avatar: '',
+    roles: [],
+    permissions: []
+  },
+
+  mutations: {
+    SET_TOKEN: (state, token) => {
+      state.token = token
+    },
+    SET_NAME: (state, name) => {
+      state.name = name
+    },
+    SET_AVATAR: (state, avatar) => {
+      state.avatar = avatar
+    },
+    SET_ROLES: (state, roles) => {
+      state.roles = roles
+    },
+    SET_PERMISSIONS: (state, permissions) => {
+      state.permissions = permissions
+    }
+  },
+
+  actions: {
+    // 鐧诲綍
+    Login({ commit }, userInfo) {
+      const username = userInfo.username.trim()
+      const password = userInfo.password
+      const code = userInfo.code
+      const uuid = userInfo.uuid
+      return new Promise((resolve, reject) => {
+        login(username, password, code, uuid).then(res => {
+          setToken(res.token)
+          commit('SET_TOKEN', res.token)
+          resolve()
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 鑾峰彇鐢ㄦ埛淇℃伅
+    GetInfo({ commit, state }) {
+      return new Promise((resolve, reject) => {
+        getInfo(state.token).then(res => {
+          const user = res.user
+          const avatar = user.avatar == "" ? require("@/assets/image/profile.jpg") : process.env.VUE_APP_BASE_API + user.avatar;
+          if (res.roles && res.roles.length > 0) { // 楠岃瘉杩斿洖鐨剅oles鏄惁鏄竴涓潪绌烘暟缁�
+            commit('SET_ROLES', res.roles)
+            commit('SET_PERMISSIONS', res.permissions)
+          } else {
+            commit('SET_ROLES', ['ROLE_DEFAULT'])
+          }
+          commit('SET_NAME', user.username)
+          commit('SET_AVATAR', avatar)
+          resolve(res)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+    
+    // 閫�鍑虹郴缁�
+    LogOut({ commit, state }) {
+      return new Promise((resolve, reject) => {
+        logout(state.token).then(() => {
+          commit('SET_TOKEN', '')
+          commit('SET_ROLES', [])
+          commit('SET_PERMISSIONS', [])
+          removeToken()
+          resolve()
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 鍓嶇 鐧诲嚭
+    FedLogOut({ commit }) {
+      return new Promise(resolve => {
+        commit('SET_TOKEN', '')
+        removeToken()
+        resolve()
+      })
+    }
+  }
+}
+
+export default user
diff --git a/ruoyi-ui/src/utils/auth.js b/ruoyi-ui/src/utils/auth.js
new file mode 100644
index 0000000..88d7b6c
--- /dev/null
+++ b/ruoyi-ui/src/utils/auth.js
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+export function getToken() {
+  return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+  return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+  return Cookies.remove(TokenKey)
+}
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
new file mode 100644
index 0000000..9e171eb
--- /dev/null
+++ b/ruoyi-ui/src/utils/index.js
@@ -0,0 +1,317 @@
+/**
+ * 琛ㄦ牸鏃堕棿鏍煎紡鍖�
+ */
+export function formatDate(cellValue) {
+  if (cellValue == null || cellValue == "") return "";
+  var date = new Date(cellValue) 
+  var year = date.getFullYear()
+  var month = date.getMonth() + 1 < 10 ? '0' + (date.getMonth() + 1) : date.getMonth() + 1
+  var day = date.getDate() < 10 ? '0' + date.getDate() : date.getDate() 
+  var hours = date.getHours() < 10 ? '0' + date.getHours() : date.getHours() 
+  var minutes = date.getMinutes() < 10 ? '0' + date.getMinutes() : date.getMinutes() 
+  var seconds = date.getSeconds() < 10 ? '0' + date.getSeconds() : date.getSeconds()
+  return year + '-' + month + '-' + day + ' ' + hours + ':' + minutes + ':' + seconds
+}
+
+/**
+ * @param {number} time
+ * @param {string} option
+ * @returns {string}
+ */
+export function formatTime(time, option) {
+  if (('' + time).length === 10) {
+    time = parseInt(time) * 1000
+  } else {
+    time = +time
+  }
+  const d = new Date(time)
+  const now = Date.now()
+
+  const diff = (now - d) / 1000
+
+  if (diff < 30) {
+    return '鍒氬垰'
+  } else if (diff < 3600) {
+    // less 1 hour
+    return Math.ceil(diff / 60) + '鍒嗛挓鍓�'
+  } else if (diff < 3600 * 24) {
+    return Math.ceil(diff / 3600) + '灏忔椂鍓�'
+  } else if (diff < 3600 * 24 * 2) {
+    return '1澶╁墠'
+  }
+  if (option) {
+    return parseTime(time, option)
+  } else {
+    return (
+      d.getMonth() +
+      1 +
+      '鏈�' +
+      d.getDate() +
+      '鏃�' +
+      d.getHours() +
+      '鏃�' +
+      d.getMinutes() +
+      '鍒�'
+    )
+  }
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function getQueryObject(url) {
+  url = url == null ? window.location.href : url
+  const search = url.substring(url.lastIndexOf('?') + 1)
+  const obj = {}
+  const reg = /([^?&=]+)=([^?&=]*)/g
+  search.replace(reg, (rs, $1, $2) => {
+    const name = decodeURIComponent($1)
+    let val = decodeURIComponent($2)
+    val = String(val)
+    obj[name] = val
+    return rs
+  })
+  return obj
+}
+
+/**
+ * @param {string} input value
+ * @returns {number} output value
+ */
+export function byteLength(str) {
+  // returns the byte length of an utf8 string
+  let s = str.length
+  for (var i = str.length - 1; i >= 0; i--) {
+    const code = str.charCodeAt(i)
+    if (code > 0x7f && code <= 0x7ff) s++
+    else if (code > 0x7ff && code <= 0xffff) s += 2
+    if (code >= 0xDC00 && code <= 0xDFFF) i--
+  }
+  return s
+}
+
+/**
+ * @param {Array} actual
+ * @returns {Array}
+ */
+export function cleanArray(actual) {
+  const newArray = []
+  for (let i = 0; i < actual.length; i++) {
+    if (actual[i]) {
+      newArray.push(actual[i])
+    }
+  }
+  return newArray
+}
+
+/**
+ * @param {Object} json
+ * @returns {Array}
+ */
+export function param(json) {
+  if (!json) return ''
+  return cleanArray(
+    Object.keys(json).map(key => {
+      if (json[key] === undefined) return ''
+      return encodeURIComponent(key) + '=' + encodeURIComponent(json[key])
+    })
+  ).join('&')
+}
+
+/**
+ * @param {string} url
+ * @returns {Object}
+ */
+export function param2Obj(url) {
+  const search = url.split('?')[1]
+  if (!search) {
+    return {}
+  }
+  return JSON.parse(
+    '{"' +
+      decodeURIComponent(search)
+        .replace(/"/g, '\\"')
+        .replace(/&/g, '","')
+        .replace(/=/g, '":"')
+        .replace(/\+/g, ' ') +
+      '"}'
+  )
+}
+
+/**
+ * @param {string} val
+ * @returns {string}
+ */
+export function html2Text(val) {
+  const div = document.createElement('div')
+  div.innerHTML = val
+  return div.textContent || div.innerText
+}
+
+/**
+ * Merges two objects, giving the last one precedence
+ * @param {Object} target
+ * @param {(Object|Array)} source
+ * @returns {Object}
+ */
+export function objectMerge(target, source) {
+  if (typeof target !== 'object') {
+    target = {}
+  }
+  if (Array.isArray(source)) {
+    return source.slice()
+  }
+  Object.keys(source).forEach(property => {
+    const sourceProperty = source[property]
+    if (typeof sourceProperty === 'object') {
+      target[property] = objectMerge(target[property], sourceProperty)
+    } else {
+      target[property] = sourceProperty
+    }
+  })
+  return target
+}
+
+/**
+ * @param {HTMLElement} element
+ * @param {string} className
+ */
+export function toggleClass(element, className) {
+  if (!element || !className) {
+    return
+  }
+  let classString = element.className
+  const nameIndex = classString.indexOf(className)
+  if (nameIndex === -1) {
+    classString += '' + className
+  } else {
+    classString =
+      classString.substr(0, nameIndex) +
+      classString.substr(nameIndex + className.length)
+  }
+  element.className = classString
+}
+
+/**
+ * @param {string} type
+ * @returns {Date}
+ */
+export function getTime(type) {
+  if (type === 'start') {
+    return new Date().getTime() - 3600 * 1000 * 24 * 90
+  } else {
+    return new Date(new Date().toDateString())
+  }
+}
+
+/**
+ * @param {Function} func
+ * @param {number} wait
+ * @param {boolean} immediate
+ * @return {*}
+ */
+export function debounce(func, wait, immediate) {
+  let timeout, args, context, timestamp, result
+
+  const later = function() {
+    // 鎹笂涓�娆¤Е鍙戞椂闂撮棿闅�
+    const last = +new Date() - timestamp
+
+    // 涓婃琚寘瑁呭嚱鏁拌璋冪敤鏃堕棿闂撮殧 last 灏忎簬璁惧畾鏃堕棿闂撮殧 wait
+    if (last < wait && last > 0) {
+      timeout = setTimeout(later, wait - last)
+    } else {
+      timeout = null
+      // 濡傛灉璁惧畾涓篿mmediate===true锛屽洜涓哄紑濮嬭竟鐣屽凡缁忚皟鐢ㄨ繃浜嗘澶勬棤闇�璋冪敤
+      if (!immediate) {
+        result = func.apply(context, args)
+        if (!timeout) context = args = null
+      }
+    }
+  }
+
+  return function(...args) {
+    context = this
+    timestamp = +new Date()
+    const callNow = immediate && !timeout
+    // 濡傛灉寤舵椂涓嶅瓨鍦紝閲嶆柊璁惧畾寤舵椂
+    if (!timeout) timeout = setTimeout(later, wait)
+    if (callNow) {
+      result = func.apply(context, args)
+      context = args = null
+    }
+
+    return result
+  }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+  if (!source && typeof source !== 'object') {
+    throw new Error('error arguments', 'deepClone')
+  }
+  const targetObj = source.constructor === Array ? [] : {}
+  Object.keys(source).forEach(keys => {
+    if (source[keys] && typeof source[keys] === 'object') {
+      targetObj[keys] = deepClone(source[keys])
+    } else {
+      targetObj[keys] = source[keys]
+    }
+  })
+  return targetObj
+}
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+  return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+  const timestamp = +new Date() + ''
+  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+  return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+  if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+  if (hasClass(ele, cls)) {
+    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+    ele.className = ele.className.replace(reg, ' ')
+  }
+}
diff --git a/ruoyi-ui/src/utils/permission.js b/ruoyi-ui/src/utils/permission.js
new file mode 100644
index 0000000..efb4cc8
--- /dev/null
+++ b/ruoyi-ui/src/utils/permission.js
@@ -0,0 +1,24 @@
+import store from '@/store'
+
+/**
+ * @param {Array} value
+ * @returns {Boolean}
+ */
+export default function checkPermission(value) {
+  if (value && value instanceof Array && value.length > 0) {
+    const roles = store.getters && store.getters.roles
+    const permissionRoles = value
+
+    const hasPermission = roles.some(role => {
+      return permissionRoles.includes(role)
+    })
+
+    if (!hasPermission) {
+      return false
+    }
+    return true
+  } else {
+    console.error(`need roles! Like v-permission="['admin','editor']"`)
+    return false
+  }
+}
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
new file mode 100644
index 0000000..fd6e5f0
--- /dev/null
+++ b/ruoyi-ui/src/utils/request.js
@@ -0,0 +1,65 @@
+import axios from 'axios'
+import { Notification, MessageBox } from 'element-ui'
+import store from '@/store'
+import { getToken } from '@/utils/auth'
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+// 鍒涘缓axios瀹炰緥
+const service = axios.create({
+  // axios涓姹傞厤缃湁baseURL閫夐」锛岃〃绀鸿姹俇RL鍏叡閮ㄥ垎
+  baseURL: process.env.VUE_APP_BASE_API,
+  // 瓒呮椂
+  timeout: 10000
+})
+// request鎷︽埅鍣�
+service.interceptors.request.use(
+  config => {
+    if (getToken()) {
+      config.headers['Authorization'] = 'Bearer ' + getToken() // 璁╂瘡涓姹傛惡甯﹁嚜瀹氫箟token 璇锋牴鎹疄闄呮儏鍐佃嚜琛屼慨鏀�
+    }
+    return config
+  },
+  error => {
+    console.log(error)
+    Promise.reject(error)
+  }
+)
+
+// 鍝嶅簲鎷︽埅鍣�
+service.interceptors.response.use(res => {
+    const code = res.data.code
+    if (code === 401) {
+      MessageBox.confirm(
+        '鐧诲綍鐘舵�佸凡杩囨湡锛屾偍鍙互缁х画鐣欏湪璇ラ〉闈紝鎴栬�呴噸鏂扮櫥褰�',
+        '绯荤粺鎻愮ず',
+        {
+          confirmButtonText: '閲嶆柊鐧诲綍',
+          cancelButtonText: '鍙栨秷',
+          type: 'warning'
+        }
+      ).then(() => {
+        store.dispatch('LogOut').then(() => {
+          location.reload() // 涓轰簡閲嶆柊瀹炰緥鍖杤ue-router瀵硅薄 閬垮厤bug
+        })
+      })
+    } else if (code !== 200) {
+      Notification.error({
+        title: res.data.msg
+      })
+      return Promise.reject('error')
+    } else {
+      return res.data
+    }
+  },
+  error => {
+    console.log('err' + error)
+    Message({
+      message: error.message,
+      type: 'error',
+      duration: 5 * 1000
+    })
+    return Promise.reject(error)
+  }
+)
+
+export default service
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
new file mode 100644
index 0000000..acef7f9
--- /dev/null
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -0,0 +1,76 @@
+/**
+ * 閫氱敤js鏂规硶灏佽澶勭悊
+ * Copyright (c) 2019 ruoyi
+ */
+
+// 鏃ユ湡鏍煎紡鍖�
+export function dateFormat(date, pattern) {
+	var d = new Date(date).Format("yyyy-MM-dd hh:mm:ss");
+	if (pattern) {
+		d = new Date(date).Format(pattern);
+	}
+	return d.toLocaleString();
+}
+
+// 琛ㄥ崟閲嶇疆
+export function resetForm(refName) {
+	if (this.$refs[refName] !== undefined) {
+		this.$refs[refName].resetFields();
+	}
+}
+
+// 娣诲姞鏃ユ湡鑼冨洿
+export function addDateRange(params, dateRange) {
+	var search = params;
+	if (null != dateRange) {
+		search.params = {
+			beginTime: this.dateRange[0],
+			endTime: this.dateRange[1]
+		};
+	}
+	return search;
+}
+
+// 鍥炴樉鏁版嵁瀛楀吀
+export function selectDictLabel(datas, value) {
+	var actions = [];
+	Object.keys(datas).map((key) => {
+		if (datas[key].dictValue == ('' + value)) {
+			actions.push(datas[key].dictLabel);
+			return false;
+		}
+	})
+	return actions.join('');
+}
+
+// 瀛楃涓叉牸寮忓寲(%s )
+export function sprintf(str) {
+	var args = arguments, flag = true, i = 1;
+	str = str.replace(/%s/g, function () {
+		var arg = args[i++];
+		if (typeof arg === 'undefined') {
+			flag = false;
+			return '';
+		}
+		return arg;
+	});
+	return flag ? str : '';
+}
+
+Date.prototype.Format = function (fmt) {
+	var o = {
+		"M+": this.getMonth() + 1,                   // 鏈堜唤
+		"d+": this.getDate(),                        // 鏃�
+		"h+": this.getHours(),                       // 灏忔椂
+		"m+": this.getMinutes(),                     // 鍒�
+		"s+": this.getSeconds(),                     // 绉�
+		"q+": Math.floor((this.getMonth() + 3) / 3), // 瀛e害
+		"S": this.getMilliseconds()                  // 姣
+	};
+	if (/(y+)/.test(fmt))
+		fmt = fmt.replace(RegExp.$1, (this.getFullYear() + "").substr(4 - RegExp.$1.length));
+	for (var k in o)
+		if (new RegExp("(" + k + ")").test(fmt))
+			fmt = fmt.replace(RegExp.$1, (RegExp.$1.length == 1) ? (o[k]) : (("00" + o[k]).substr(("" + o[k]).length)));
+	return fmt;
+}  
\ No newline at end of file
diff --git a/ruoyi-ui/src/utils/scroll-to.js b/ruoyi-ui/src/utils/scroll-to.js
new file mode 100644
index 0000000..709fa57
--- /dev/null
+++ b/ruoyi-ui/src/utils/scroll-to.js
@@ -0,0 +1,58 @@
+Math.easeInOutQuad = function(t, b, c, d) {
+  t /= d / 2
+  if (t < 1) {
+    return c / 2 * t * t + b
+  }
+  t--
+  return -c / 2 * (t * (t - 2) - 1) + b
+}
+
+// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
+var requestAnimFrame = (function() {
+  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
+})()
+
+/**
+ * Because it's so fucking difficult to detect the scrolling element, just move them all
+ * @param {number} amount
+ */
+function move(amount) {
+  document.documentElement.scrollTop = amount
+  document.body.parentNode.scrollTop = amount
+  document.body.scrollTop = amount
+}
+
+function position() {
+  return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
+}
+
+/**
+ * @param {number} to
+ * @param {number} duration
+ * @param {Function} callback
+ */
+export function scrollTo(to, duration, callback) {
+  const start = position()
+  const change = to - start
+  const increment = 20
+  let currentTime = 0
+  duration = (typeof (duration) === 'undefined') ? 500 : duration
+  var animateScroll = function() {
+    // increment the time
+    currentTime += increment
+    // find the value with the quadratic in-out easing function
+    var val = Math.easeInOutQuad(currentTime, start, change, duration)
+    // move the document.body
+    move(val)
+    // do the animation unless its over
+    if (currentTime < duration) {
+      requestAnimFrame(animateScroll)
+    } else {
+      if (callback && typeof (callback) === 'function') {
+        // the animation is done so lets callback
+        callback()
+      }
+    }
+  }
+  animateScroll()
+}
diff --git a/ruoyi-ui/src/utils/validate.js b/ruoyi-ui/src/utils/validate.js
new file mode 100644
index 0000000..9c00400
--- /dev/null
+++ b/ruoyi-ui/src/utils/validate.js
@@ -0,0 +1,83 @@
+/**
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path) {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername(str) {
+  const valid_map = ['admin', 'editor']
+  return valid_map.indexOf(str.trim()) >= 0
+}
+
+/**
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function validURL(url) {
+  const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+  return reg.test(url)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validLowerCase(str) {
+  const reg = /^[a-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUpperCase(str) {
+  const reg = /^[A-Z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validAlphabets(str) {
+  const reg = /^[A-Za-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} email
+ * @returns {Boolean}
+ */
+export function validEmail(email) {
+  const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+  return reg.test(email)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function isString(str) {
+  if (typeof str === 'string' || str instanceof String) {
+    return true
+  }
+  return false
+}
+
+/**
+ * @param {Array} arg
+ * @returns {Boolean}
+ */
+export function isArray(arg) {
+  if (typeof Array.isArray === 'undefined') {
+    return Object.prototype.toString.call(arg) === '[object Array]'
+  }
+  return Array.isArray(arg)
+}
diff --git a/ruoyi-ui/src/views/components/icons/element-icons.js b/ruoyi-ui/src/views/components/icons/element-icons.js
new file mode 100644
index 0000000..d9fd628
--- /dev/null
+++ b/ruoyi-ui/src/views/components/icons/element-icons.js
@@ -0,0 +1,74 @@
+const elementIcons = [
+  'info',
+  'error',
+  'success',
+  'warning',
+  'question',
+  'back',
+  'arrow-left',
+  'arrow-down',
+  'arrow-right',
+  'arrow-up',
+  'caret-left',
+  'caret-bottom',
+  'caret-top',
+  'caret-right',
+  'd-arrow-left',
+  'd-arrow-right',
+  'minus',
+  'plus',
+  'remove',
+  'circle-plus',
+  'remove-outline',
+  'circle-plus-outline',
+  'close',
+  'check',
+  'circle-close',
+  'circle-check',
+  'circle-close-outline',
+  'circle-check-outline',
+  'zoom-out',
+  'zoom-in',
+  'd-caret',
+  'sort',
+  'sort-down',
+  'sort-up',
+  'tickets',
+  'document',
+  'goods',
+  'sold-out',
+  'news',
+  'message',
+  'date',
+  'printer',
+  'time',
+  'bell',
+  'mobile-phone',
+  'service',
+  'view',
+  'menu',
+  'more',
+  'more-outline',
+  'star-on',
+  'star-off',
+  'location',
+  'location-outline',
+  'phone',
+  'phone-outline',
+  'picture',
+  'picture-outline',
+  'delete',
+  'search',
+  'edit',
+  'edit-outline',
+  'rank',
+  'refresh',
+  'share',
+  'setting',
+  'upload',
+  'upload2',
+  'download',
+  'loading'
+]
+
+export default elementIcons
diff --git a/ruoyi-ui/src/views/components/icons/index.vue b/ruoyi-ui/src/views/components/icons/index.vue
new file mode 100644
index 0000000..f422eee
--- /dev/null
+++ b/ruoyi-ui/src/views/components/icons/index.vue
@@ -0,0 +1,87 @@
+<template>
+  <div class="icons-container">
+    <aside>
+      <a href="#" target="_blank">Add and use
+      </a>
+    </aside>
+    <el-tabs type="border-card">
+      <el-tab-pane label="Icons">
+        <div v-for="item of svgIcons" :key="item">
+          <el-tooltip placement="top">
+            <div slot="content">
+              {{ generateIconCode(item) }}
+            </div>
+            <div class="icon-item">
+              <svg-icon :icon-class="item" class-name="disabled" />
+              <span>{{ item }}</span>
+            </div>
+          </el-tooltip>
+        </div>
+      </el-tab-pane>
+      <el-tab-pane label="Element-UI Icons">
+        <div v-for="item of elementIcons" :key="item">
+          <el-tooltip placement="top">
+            <div slot="content">
+              {{ generateElementIconCode(item) }}
+            </div>
+            <div class="icon-item">
+              <i :class="'el-icon-' + item" />
+              <span>{{ item }}</span>
+            </div>
+          </el-tooltip>
+        </div>
+      </el-tab-pane>
+    </el-tabs>
+  </div>
+</template>
+
+<script>
+import svgIcons from './svg-icons'
+import elementIcons from './element-icons'
+
+export default {
+  name: 'Icons',
+  data() {
+    return {
+      svgIcons,
+      elementIcons
+    }
+  },
+  methods: {
+    generateIconCode(symbol) {
+      return `<svg-icon icon-class="${symbol}" />`
+    },
+    generateElementIconCode(symbol) {
+      return `<i class="el-icon-${symbol}" />`
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.icons-container {
+  margin: 10px 20px 0;
+  overflow: hidden;
+
+  .icon-item {
+    margin: 20px;
+    height: 85px;
+    text-align: center;
+    width: 100px;
+    float: left;
+    font-size: 30px;
+    color: #24292e;
+    cursor: pointer;
+  }
+
+  span {
+    display: block;
+    font-size: 16px;
+    margin-top: 10px;
+  }
+
+  .disabled {
+    pointer-events: none;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/components/icons/svg-icons.js b/ruoyi-ui/src/views/components/icons/svg-icons.js
new file mode 100644
index 0000000..9713fd8
--- /dev/null
+++ b/ruoyi-ui/src/views/components/icons/svg-icons.js
@@ -0,0 +1,10 @@
+const req = require.context('../../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const svgIcons = requireAll(req).map(i => {
+  return i.match(re)[1]
+})
+
+export default svgIcons
diff --git a/ruoyi-ui/src/views/dashboard/BarChart.vue b/ruoyi-ui/src/views/dashboard/BarChart.vue
new file mode 100644
index 0000000..6b464e1
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/BarChart.vue
@@ -0,0 +1,102 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 6000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
+            type: 'shadow' // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
+          }
+        },
+        grid: {
+          top: 10,
+          left: '2%',
+          right: '2%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: [{
+          type: 'category',
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          axisTick: {
+            alignWithLabel: true
+          }
+        }],
+        yAxis: [{
+          type: 'value',
+          axisTick: {
+            show: false
+          }
+        }],
+        series: [{
+          name: 'pageA',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [79, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageB',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [80, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageC',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [30, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/LineChart.vue b/ruoyi-ui/src/views/dashboard/LineChart.vue
new file mode 100644
index 0000000..4e30a37
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/LineChart.vue
@@ -0,0 +1,135 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '350px'
+    },
+    autoResize: {
+      type: Boolean,
+      default: true
+    },
+    chartData: {
+      type: Object,
+      required: true
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  watch: {
+    chartData: {
+      deep: true,
+      handler(val) {
+        this.setOptions(val)
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+      this.setOptions(this.chartData)
+    },
+    setOptions({ expectedData, actualData } = {}) {
+      this.chart.setOption({
+        xAxis: {
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          boundaryGap: false,
+          axisTick: {
+            show: false
+          }
+        },
+        grid: {
+          left: 10,
+          right: 10,
+          bottom: 20,
+          top: 30,
+          containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross'
+          },
+          padding: [5, 10]
+        },
+        yAxis: {
+          axisTick: {
+            show: false
+          }
+        },
+        legend: {
+          data: ['expected', 'actual']
+        },
+        series: [{
+          name: 'expected', itemStyle: {
+            normal: {
+              color: '#FF005A',
+              lineStyle: {
+                color: '#FF005A',
+                width: 2
+              }
+            }
+          },
+          smooth: true,
+          type: 'line',
+          data: expectedData,
+          animationDuration: 2800,
+          animationEasing: 'cubicInOut'
+        },
+        {
+          name: 'actual',
+          smooth: true,
+          type: 'line',
+          itemStyle: {
+            normal: {
+              color: '#3888fa',
+              lineStyle: {
+                color: '#3888fa',
+                width: 2
+              },
+              areaStyle: {
+                color: '#f3f8ff'
+              }
+            }
+          },
+          data: actualData,
+          animationDuration: 2800,
+          animationEasing: 'quadraticOut'
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/PanelGroup.vue b/ruoyi-ui/src/views/dashboard/PanelGroup.vue
new file mode 100644
index 0000000..8d3a73b
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/PanelGroup.vue
@@ -0,0 +1,181 @@
+<template>
+  <el-row :gutter="40" class="panel-group">
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
+        <div class="card-panel-icon-wrapper icon-people">
+          <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            璁垮
+          </div>
+          <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('messages')">
+        <div class="card-panel-icon-wrapper icon-message">
+          <svg-icon icon-class="message" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            娑堟伅
+          </div>
+          <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('purchases')">
+        <div class="card-panel-icon-wrapper icon-money">
+          <svg-icon icon-class="money" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            閲戦
+          </div>
+          <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('shoppings')">
+        <div class="card-panel-icon-wrapper icon-shopping">
+          <svg-icon icon-class="shopping" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            璁㈠崟
+          </div>
+          <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+  </el-row>
+</template>
+
+<script>
+import CountTo from 'vue-count-to'
+
+export default {
+  components: {
+    CountTo
+  },
+  methods: {
+    handleSetLineChartData(type) {
+      this.$emit('handleSetLineChartData', type)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.panel-group {
+  margin-top: 18px;
+
+  .card-panel-col {
+    margin-bottom: 32px;
+  }
+
+  .card-panel {
+    height: 108px;
+    cursor: pointer;
+    font-size: 12px;
+    position: relative;
+    overflow: hidden;
+    color: #666;
+    background: #fff;
+    box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+    border-color: rgba(0, 0, 0, .05);
+
+    &:hover {
+      .card-panel-icon-wrapper {
+        color: #fff;
+      }
+
+      .icon-people {
+        background: #40c9c6;
+      }
+
+      .icon-message {
+        background: #36a3f7;
+      }
+
+      .icon-money {
+        background: #f4516c;
+      }
+
+      .icon-shopping {
+        background: #34bfa3
+      }
+    }
+
+    .icon-people {
+      color: #40c9c6;
+    }
+
+    .icon-message {
+      color: #36a3f7;
+    }
+
+    .icon-money {
+      color: #f4516c;
+    }
+
+    .icon-shopping {
+      color: #34bfa3
+    }
+
+    .card-panel-icon-wrapper {
+      float: left;
+      margin: 14px 0 0 14px;
+      padding: 16px;
+      transition: all 0.38s ease-out;
+      border-radius: 6px;
+    }
+
+    .card-panel-icon {
+      float: left;
+      font-size: 48px;
+    }
+
+    .card-panel-description {
+      float: right;
+      font-weight: bold;
+      margin: 26px;
+      margin-left: 0px;
+
+      .card-panel-text {
+        line-height: 18px;
+        color: rgba(0, 0, 0, 0.45);
+        font-size: 16px;
+        margin-bottom: 12px;
+      }
+
+      .card-panel-num {
+        font-size: 20px;
+      }
+    }
+  }
+}
+
+@media (max-width:550px) {
+  .card-panel-description {
+    display: none;
+  }
+
+  .card-panel-icon-wrapper {
+    float: none !important;
+    width: 100%;
+    height: 100%;
+    margin: 0 !important;
+
+    .svg-icon {
+      display: block;
+      margin: 14px auto !important;
+      float: none !important;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/dashboard/PieChart.vue b/ruoyi-ui/src/views/dashboard/PieChart.vue
new file mode 100644
index 0000000..d0e4f50
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/PieChart.vue
@@ -0,0 +1,79 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b} : {c} ({d}%)'
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
+        },
+        series: [
+          {
+            name: 'WEEKLY WRITE ARTICLES',
+            type: 'pie',
+            roseType: 'radius',
+            radius: [15, 95],
+            center: ['50%', '38%'],
+            data: [
+              { value: 320, name: 'Industries' },
+              { value: 240, name: 'Technology' },
+              { value: 149, name: 'Forex' },
+              { value: 100, name: 'Gold' },
+              { value: 59, name: 'Forecasts' }
+            ],
+            animationEasing: 'cubicInOut',
+            animationDuration: 2600
+          }
+        ]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/RaddarChart.vue b/ruoyi-ui/src/views/dashboard/RaddarChart.vue
new file mode 100644
index 0000000..9831abf
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/RaddarChart.vue
@@ -0,0 +1,116 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 3000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
+            type: 'shadow' // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
+          }
+        },
+        radar: {
+          radius: '66%',
+          center: ['50%', '42%'],
+          splitNumber: 8,
+          splitArea: {
+            areaStyle: {
+              color: 'rgba(127,95,132,.3)',
+              opacity: 1,
+              shadowBlur: 45,
+              shadowColor: 'rgba(0,0,0,.5)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 15
+            }
+          },
+          indicator: [
+            { name: 'Sales', max: 10000 },
+            { name: 'Administration', max: 20000 },
+            { name: 'Information Techology', max: 20000 },
+            { name: 'Customer Support', max: 20000 },
+            { name: 'Development', max: 20000 },
+            { name: 'Marketing', max: 20000 }
+          ]
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
+        },
+        series: [{
+          type: 'radar',
+          symbolSize: 0,
+          areaStyle: {
+            normal: {
+              shadowBlur: 13,
+              shadowColor: 'rgba(0,0,0,.2)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 10,
+              opacity: 1
+            }
+          },
+          data: [
+            {
+              value: [5000, 7000, 12000, 11000, 15000, 14000],
+              name: 'Allocated Budget'
+            },
+            {
+              value: [4000, 9000, 15000, 15000, 13000, 11000],
+              name: 'Expected Spending'
+            },
+            {
+              value: [5500, 11000, 12000, 15000, 12000, 12000],
+              name: 'Actual Spending'
+            }
+          ],
+          animationDuration: animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/mixins/resize.js b/ruoyi-ui/src/views/dashboard/mixins/resize.js
new file mode 100644
index 0000000..5516794
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/mixins/resize.js
@@ -0,0 +1,52 @@
+import { debounce } from '@/utils'
+
+export default {
+  data() {
+    return {
+      $_sidebarElm: null
+    }
+  },
+  mounted() {
+    this.$_initResizeEvent()
+    this.$_initSidebarResizeEvent()
+  },
+  beforeDestroy() {
+    this.$_destroyResizeEvent()
+    this.$_destroySidebarResizeEvent()
+  },
+  activated() {
+    this.$_initResizeEvent()
+    this.$_initSidebarResizeEvent()
+  },
+  deactivated() {
+    this.$_destroyResizeEvent()
+    this.$_destroySidebarResizeEvent()
+  },
+  methods: {
+    $_resizeHandler() {
+      return debounce(() => {
+        if (this.chart) {
+          this.chart.resize()
+        }
+      }, 100)()
+    },
+    $_initResizeEvent() {
+      window.addEventListener('resize', this.$_resizeHandler)
+    },
+    $_destroyResizeEvent() {
+      window.removeEventListener('resize', this.$_resizeHandler)
+    },
+    $_sidebarResizeHandler(e) {
+      if (e.propertyName === 'width') {
+        this.$_resizeHandler()
+      }
+    },
+    $_initSidebarResizeEvent() {
+      this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
+      this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
+    },
+    $_destroySidebarResizeEvent() {
+      this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
+    }
+  }
+}
diff --git a/ruoyi-ui/src/views/error/401.vue b/ruoyi-ui/src/views/error/401.vue
new file mode 100644
index 0000000..8561150
--- /dev/null
+++ b/ruoyi-ui/src/views/error/401.vue
@@ -0,0 +1,99 @@
+<template>
+  <div class="errPage-container">
+    <el-button icon="arrow-left" class="pan-back-btn" @click="back">
+      杩斿洖
+    </el-button>
+    <el-row>
+      <el-col :span="12">
+        <h1 class="text-jumbo text-ginormous">
+          Oops!
+        </h1>
+        gif鏉ユ簮<a href="https://zh.airbnb.com/" target="_blank">airbnb</a> 椤甸潰
+        <h2>浣犳病鏈夋潈闄愬幓璇ラ〉闈�</h2>
+        <h6>濡傛湁涓嶆弧璇疯仈绯讳綘棰嗗</h6>
+        <ul class="list-unstyled">
+          <li>鎴栬�呬綘鍙互鍘�:</li>
+          <li class="link-type">
+            <router-link to="/dashboard">
+              鍥為椤�
+            </router-link>
+          </li>
+          <li class="link-type">
+            <a href="https://www.taobao.com/">闅忎究鐪嬬湅</a>
+          </li>
+          <li><a href="#" @click.prevent="dialogVisible=true">鐐规垜鐪嬪浘</a></li>
+        </ul>
+      </el-col>
+      <el-col :span="12">
+        <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
+      </el-col>
+    </el-row>
+    <el-dialog :visible.sync="dialogVisible" title="闅忎究鐪�">
+      <img :src="ewizardClap" class="pan-img">
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import errGif from '@/assets/401_images/401.gif'
+
+export default {
+  name: 'Page401',
+  data() {
+    return {
+      errGif: errGif + '?' + +new Date(),
+      ewizardClap: 'https://wpimg.wallstcn.com/007ef517-bafd-4066-aae4-6883632d9646',
+      dialogVisible: false
+    }
+  },
+  methods: {
+    back() {
+      if (this.$route.query.noGoBack) {
+        this.$router.push({ path: '/dashboard' })
+      } else {
+        this.$router.go(-1)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .errPage-container {
+    width: 800px;
+    max-width: 100%;
+    margin: 100px auto;
+    .pan-back-btn {
+      background: #008489;
+      color: #fff;
+      border: none!important;
+    }
+    .pan-gif {
+      margin: 0 auto;
+      display: block;
+    }
+    .pan-img {
+      display: block;
+      margin: 0 auto;
+      width: 100%;
+    }
+    .text-jumbo {
+      font-size: 60px;
+      font-weight: 700;
+      color: #484848;
+    }
+    .list-unstyled {
+      font-size: 14px;
+      li {
+        padding-bottom: 5px;
+      }
+      a {
+        color: #008489;
+        text-decoration: none;
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/views/error/404.vue b/ruoyi-ui/src/views/error/404.vue
new file mode 100644
index 0000000..c21ebce
--- /dev/null
+++ b/ruoyi-ui/src/views/error/404.vue
@@ -0,0 +1,228 @@
+<template>
+  <div class="wscn-http404-container">
+    <div class="wscn-http404">
+      <div class="pic-404">
+        <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
+        <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
+      </div>
+      <div class="bullshit">
+        <div class="bullshit__oops">OOPS!</div>
+        <div class="bullshit__info">All rights reserved
+          <a style="color:#20a0ff" href="https://wallstreetcn.com" target="_blank">wallstreetcn</a>
+        </div>
+        <div class="bullshit__headline">{{ message }}</div>
+        <div class="bullshit__info">Please check that the URL you entered is correct, or click the button below to return to the homepage.</div>
+        <a href="" class="bullshit__return-home">Back to home</a>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'Page404',
+  computed: {
+    message() {
+      return 'The webmaster said that you can not enter this page...'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.wscn-http404-container{
+  transform: translate(-50%,-50%);
+  position: absolute;
+  top: 40%;
+  left: 50%;
+}
+.wscn-http404 {
+  position: relative;
+  width: 1200px;
+  padding: 0 50px;
+  overflow: hidden;
+  .pic-404 {
+    position: relative;
+    float: left;
+    width: 600px;
+    overflow: hidden;
+    &__parent {
+      width: 100%;
+    }
+    &__child {
+      position: absolute;
+      &.left {
+        width: 80px;
+        top: 17px;
+        left: 220px;
+        opacity: 0;
+        animation-name: cloudLeft;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      &.mid {
+        width: 46px;
+        top: 10px;
+        left: 420px;
+        opacity: 0;
+        animation-name: cloudMid;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1.2s;
+      }
+      &.right {
+        width: 62px;
+        top: 100px;
+        left: 500px;
+        opacity: 0;
+        animation-name: cloudRight;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      @keyframes cloudLeft {
+        0% {
+          top: 17px;
+          left: 220px;
+          opacity: 0;
+        }
+        20% {
+          top: 33px;
+          left: 188px;
+          opacity: 1;
+        }
+        80% {
+          top: 81px;
+          left: 92px;
+          opacity: 1;
+        }
+        100% {
+          top: 97px;
+          left: 60px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudMid {
+        0% {
+          top: 10px;
+          left: 420px;
+          opacity: 0;
+        }
+        20% {
+          top: 40px;
+          left: 360px;
+          opacity: 1;
+        }
+        70% {
+          top: 130px;
+          left: 180px;
+          opacity: 1;
+        }
+        100% {
+          top: 160px;
+          left: 120px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudRight {
+        0% {
+          top: 100px;
+          left: 500px;
+          opacity: 0;
+        }
+        20% {
+          top: 120px;
+          left: 460px;
+          opacity: 1;
+        }
+        80% {
+          top: 180px;
+          left: 340px;
+          opacity: 1;
+        }
+        100% {
+          top: 200px;
+          left: 300px;
+          opacity: 0;
+        }
+      }
+    }
+  }
+  .bullshit {
+    position: relative;
+    float: left;
+    width: 300px;
+    padding: 30px 0;
+    overflow: hidden;
+    &__oops {
+      font-size: 32px;
+      font-weight: bold;
+      line-height: 40px;
+      color: #1482f0;
+      opacity: 0;
+      margin-bottom: 20px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-fill-mode: forwards;
+    }
+    &__headline {
+      font-size: 20px;
+      line-height: 24px;
+      color: #222;
+      font-weight: bold;
+      opacity: 0;
+      margin-bottom: 10px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.1s;
+      animation-fill-mode: forwards;
+    }
+    &__info {
+      font-size: 13px;
+      line-height: 21px;
+      color: grey;
+      opacity: 0;
+      margin-bottom: 30px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.2s;
+      animation-fill-mode: forwards;
+    }
+    &__return-home {
+      display: block;
+      float: left;
+      width: 110px;
+      height: 36px;
+      background: #1482f0;
+      border-radius: 100px;
+      text-align: center;
+      color: #ffffff;
+      opacity: 0;
+      font-size: 14px;
+      line-height: 36px;
+      cursor: pointer;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.3s;
+      animation-fill-mode: forwards;
+    }
+    @keyframes slideUp {
+      0% {
+        transform: translateY(60px);
+        opacity: 0;
+      }
+      100% {
+        transform: translateY(0);
+        opacity: 1;
+      }
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
new file mode 100644
index 0000000..4828d88
--- /dev/null
+++ b/ruoyi-ui/src/views/index.vue
@@ -0,0 +1,98 @@
+<template>
+  <div class="dashboard-editor-container">
+
+    <panel-group @handleSetLineChartData="handleSetLineChartData" />
+
+    <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
+      <line-chart :chart-data="lineChartData" />
+    </el-row>
+
+    <el-row :gutter="32">
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <raddar-chart />
+        </div>
+      </el-col>
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <pie-chart />
+        </div>
+      </el-col>
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <bar-chart />
+        </div>
+      </el-col>
+    </el-row>
+
+    
+  </div>
+</template>
+
+<script>
+import PanelGroup from './dashboard/PanelGroup'
+import LineChart from './dashboard/LineChart'
+import RaddarChart from './dashboard/RaddarChart'
+import PieChart from './dashboard/PieChart'
+import BarChart from './dashboard/BarChart'
+
+const lineChartData = {
+  newVisitis: {
+    expectedData: [100, 120, 161, 134, 105, 160, 165],
+    actualData: [120, 82, 91, 154, 162, 140, 145]
+  },
+  messages: {
+    expectedData: [200, 192, 120, 144, 160, 130, 140],
+    actualData: [180, 160, 151, 106, 145, 150, 130]
+  },
+  purchases: {
+    expectedData: [80, 100, 121, 104, 105, 90, 100],
+    actualData: [120, 90, 100, 138, 142, 130, 130]
+  },
+  shoppings: {
+    expectedData: [130, 140, 141, 142, 145, 150, 160],
+    actualData: [120, 82, 91, 154, 162, 140, 130]
+  }
+}
+
+export default {
+  name: 'Index',
+  components: {
+    PanelGroup,
+    LineChart,
+    RaddarChart,
+    PieChart,
+    BarChart
+  },
+  data() {
+    return {
+      lineChartData: lineChartData.newVisitis
+    }
+  },
+  methods: {
+    handleSetLineChartData(type) {
+      this.lineChartData = lineChartData[type]
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.dashboard-editor-container {
+  padding: 32px;
+  background-color: rgb(240, 242, 245);
+  position: relative;
+
+  .chart-wrapper {
+    background: #fff;
+    padding: 16px 16px 0;
+    margin-bottom: 32px;
+  }
+}
+
+@media (max-width:1024px) {
+  .chart-wrapper {
+    padding: 8px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
new file mode 100644
index 0000000..880af8d
--- /dev/null
+++ b/ruoyi-ui/src/views/login.vue
@@ -0,0 +1,203 @@
+<template>
+  <div class="login">
+    <el-form ref="loginForm" :model="loginForm" :rules="loginRules" class="login-form">
+      <h3 class="title">鑻ヤ緷鍚庡彴绠$悊绯荤粺</h3>
+      <el-form-item prop="username">
+        <el-input v-model="loginForm.username" type="text" auto-complete="off" placeholder="璐﹀彿">
+          <svg-icon slot="prefix" icon-class="user" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="password">
+        <el-input
+          v-model="loginForm.password"
+          type="password"
+          auto-complete="off"
+          placeholder="瀵嗙爜"
+          @keyup.enter.native="handleLogin"
+        >
+          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="code">
+        <el-input
+          v-model="loginForm.code"
+          auto-complete="off"
+          placeholder="楠岃瘉鐮�"
+          style="width: 63%"
+          @keyup.enter.native="handleLogin"
+        >
+          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+        </el-input>
+        <div class="login-code">
+          <img :src="codeUrl" @click="getCode" />
+        </div>
+      </el-form-item>
+      <el-checkbox v-model="loginForm.rememberMe" style="margin:0px 0px 25px 0px;">璁颁綇瀵嗙爜</el-checkbox>
+      <el-form-item style="width:100%;">
+        <el-button
+          :loading="loading"
+          size="medium"
+          type="primary"
+          style="width:100%;"
+          @click.native.prevent="handleLogin"
+        >
+          <span v-if="!loading">鐧� 褰�</span>
+          <span v-else>鐧� 褰� 涓�...</span>
+        </el-button>
+      </el-form-item>
+    </el-form>
+    <!--  搴曢儴  -->
+    <div class="el-login-footer">
+      <span>Copyright 漏 2018-2019 ruoyi.vip All Rights Reserved.</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getCodeImg } from "@/api/login";
+import Cookies from "js-cookie";
+
+export default {
+  name: "Login",
+  data() {
+    return {
+      codeUrl: "",
+      cookiePassword: "",
+      loginForm: {
+        username: "admin",
+        password: "admin123",
+        rememberMe: false,
+        code: "",
+        uuid: ""
+      },
+      loginRules: {
+        username: [
+          { required: true, trigger: "blur", message: "鐢ㄦ埛鍚嶄笉鑳戒负绌�" }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "瀵嗙爜涓嶈兘涓虹┖" }
+        ],
+        code: [{ required: true, trigger: "change", message: "楠岃瘉鐮佷笉鑳戒负绌�" }]
+      },
+      loading: false,
+      redirect: undefined
+    };
+  },
+  watch: {
+    $route: {
+      handler: function(route) {
+        this.redirect = route.query && route.query.redirect;
+      },
+      immediate: true
+    }
+  },
+  created() {
+    this.getCode();
+    this.getCookie();
+  },
+  methods: {
+    getCode() {
+      getCodeImg().then(res => {
+        this.codeUrl = "data:image/gif;base64," + res.img;
+        this.loginForm.uuid = res.uuid;
+      });
+    },
+    getCookie() {
+      const username = Cookies.get("username");
+      const password = Cookies.get("password");
+      const rememberMe = Cookies.get('rememberMe')
+      this.loginForm = {
+        username: username === undefined ? this.loginForm.username : username,
+        password: password === undefined ? this.loginForm.password : password,
+        rememberMe: rememberMe === undefined ? false : Boolean(rememberMe)
+      };
+    },
+    handleLogin() {
+      this.$refs.loginForm.validate(valid => {
+        if (valid) {
+          this.loading = true;
+          if (this.loginForm.rememberMe) {
+            Cookies.set("username", this.loginForm.username, { expires: 30 });
+            Cookies.set("password", this.loginForm.password, { expires: 30 });
+            Cookies.set('rememberMe', this.loginForm.rememberMe, { expires: 30 });
+          } else {
+            Cookies.remove("username");
+            Cookies.remove("password");
+            Cookies.remove('rememberMe');
+          }
+          this.$store
+            .dispatch("Login", this.loginForm)
+            .then(() => {
+              this.loading = false;
+              this.$router.push({ path: this.redirect || "/" });
+            })
+            .catch(() => {
+              this.loading = false;
+              this.getCode();
+            });
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.login {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background-image: url("../assets/image/login-background.jpg");
+  background-size: cover;
+}
+.title {
+  margin: 0px auto 30px auto;
+  text-align: center;
+  color: #707070;
+}
+
+.login-form {
+  border-radius: 6px;
+  background: #ffffff;
+  width: 400px;
+  padding: 25px 25px 5px 25px;
+  .el-input {
+    height: 38px;
+    input {
+      height: 38px;
+    }
+  }
+  .input-icon {
+    height: 39px;
+    width: 14px;
+    margin-left: 2px;
+  }
+}
+.login-tip {
+  font-size: 13px;
+  text-align: center;
+  color: #bfbfbf;
+}
+.login-code {
+  width: 33%;
+  height: 38px;
+  float: right;
+  img {
+    cursor: pointer;
+    vertical-align: middle;
+  }
+}
+.el-login-footer {
+  height: 40px;
+  line-height: 40px;
+  position: fixed;
+  bottom: 0;
+  width: 100%;
+  text-align: center;
+  color: #fff;
+  font-family: Arial;
+  font-size: 12px;
+  letter-spacing: 1px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/login/auth-redirect.vue b/ruoyi-ui/src/views/login/auth-redirect.vue
new file mode 100644
index 0000000..de7bbf3
--- /dev/null
+++ b/ruoyi-ui/src/views/login/auth-redirect.vue
@@ -0,0 +1,15 @@
+<script>
+export default {
+  name: 'AuthRedirect',
+  created() {
+    const hash = window.location.search.slice(1)
+    if (window.localStorage) {
+      window.localStorage.setItem('x-admin-oauth-code', hash)
+      window.close()
+    }
+  },
+  render: function(h) {
+    return h() // avoid warning message
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/login/components/SocialSignin.vue b/ruoyi-ui/src/views/login/components/SocialSignin.vue
new file mode 100644
index 0000000..17537ed
--- /dev/null
+++ b/ruoyi-ui/src/views/login/components/SocialSignin.vue
@@ -0,0 +1,72 @@
+<template>
+  <div class="social-signup-container">
+    <div class="sign-btn" @click="wechatHandleClick('wechat')">
+      <span class="wx-svg-container"><svg-icon icon-class="wechat" class="icon" /></span>
+      WeChat
+    </div>
+    <div class="sign-btn" @click="tencentHandleClick('tencent')">
+      <span class="qq-svg-container"><svg-icon icon-class="qq" class="icon" /></span>
+      QQ
+    </div>
+  </div>
+</template>
+
+<script>
+// import openWindow from '@/utils/open-window'
+
+export default {
+  name: 'SocialSignin',
+  methods: {
+    wechatHandleClick(thirdpart) {
+      alert('ok')
+      // this.$store.commit('SET_AUTH_TYPE', thirdpart)
+      // const appid = 'xxxxx'
+      // const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
+      // const url = 'https://open.weixin.qq.com/connect/qrconnect?appid=' + appid + '&redirect_uri=' + redirect_uri + '&response_type=code&scope=snsapi_login#wechat_redirect'
+      // openWindow(url, thirdpart, 540, 540)
+    },
+    tencentHandleClick(thirdpart) {
+      alert('ok')
+      // this.$store.commit('SET_AUTH_TYPE', thirdpart)
+      // const client_id = 'xxxxx'
+      // const redirect_uri = encodeURIComponent('xxx/redirect?redirect=' + window.location.origin + '/auth-redirect')
+      // const url = 'https://graph.qq.com/oauth2.0/authorize?response_type=code&client_id=' + client_id + '&redirect_uri=' + redirect_uri
+      // openWindow(url, thirdpart, 540, 540)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .social-signup-container {
+    margin: 20px 0;
+    .sign-btn {
+      display: inline-block;
+      cursor: pointer;
+    }
+    .icon {
+      color: #fff;
+      font-size: 24px;
+      margin-top: 8px;
+    }
+    .wx-svg-container,
+    .qq-svg-container {
+      display: inline-block;
+      width: 40px;
+      height: 40px;
+      line-height: 40px;
+      text-align: center;
+      padding-top: 1px;
+      border-radius: 4px;
+      margin-bottom: 20px;
+      margin-right: 5px;
+    }
+    .wx-svg-container {
+      background-color: #24da70;
+    }
+    .qq-svg-container {
+      background-color: #6BA2D6;
+      margin-left: 50px;
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/views/monitor/druid/index.vue b/ruoyi-ui/src/views/monitor/druid/index.vue
new file mode 100644
index 0000000..6ab35b2
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/druid/index.vue
@@ -0,0 +1,25 @@
+<template>
+  <div v-loading="loading" :style="'height:'+ height">
+    <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      src: process.env.VUE_APP_BASE_API + "/druid/index.html",
+      height: document.documentElement.clientHeight - 94.5 + "px;",
+      loading: true
+    };
+  },
+  mounted: function() {
+    setTimeout(() => {
+      this.loading = false;
+    }, 230);
+    const that = this;
+    window.onresize = function temp() {
+      that.height = document.documentElement.clientHeight - 94.5 + "px;";
+    };
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
new file mode 100644
index 0000000..2467772
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/job/index.vue
@@ -0,0 +1,5 @@
+<template>
+  <div class="app-container">
+   瀹氭椂浠诲姟
+  </div>
+</template>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue
new file mode 100644
index 0000000..7bc42aa
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -0,0 +1,138 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="鐧诲綍鍦板潃">
+        <el-input
+          v-model="queryParams.ipaddr"
+          placeholder="璇疯緭鍏ョ櫥褰曞湴鍧�"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐢ㄦ埛鍚嶇О">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="鐧诲綍鐘舵��"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鐧诲綍鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="list" style="width: 100%;">
+      <el-table-column label="璁块棶缂栧彿" align="center" prop="infoId" />
+      <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" prop="userName" />
+      <el-table-column label="鐧诲綍鍦板潃" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
+      <el-table-column label="鐧诲綍鍦扮偣" align="center" prop="loginLocation" />
+      <el-table-column label="娴忚鍣�" align="center" prop="browser" />
+      <el-table-column label="鎿嶄綔绯荤粺" align="center" prop="os" />
+      <el-table-column label="鐧诲綍鐘舵��" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="鎿嶄綔淇℃伅" align="center" prop="msg" />
+      <el-table-column label="鐧诲綍鏃ユ湡" align="center" prop="loginTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.loginTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { list } from "@/api/monitor/logininfor";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ牸鏁版嵁
+      list: [],
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        ipaddr: undefined,
+        userName: undefined,
+        status: undefined
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_common_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鐧诲綍鏃ュ織鍒楄〃 */
+    getList() {
+      this.loading = true;
+      list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.list = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鐧诲綍鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    }
+  }
+};
+</script>
+
diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/monitor/online/index.vue
new file mode 100644
index 0000000..764613a
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/online/index.vue
@@ -0,0 +1,5 @@
+<template>
+  <div class="app-container">
+   鍦ㄧ嚎鐢ㄦ埛
+  </div>
+</template>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/monitor/operlog/index.vue b/ruoyi-ui/src/views/monitor/operlog/index.vue
new file mode 100644
index 0000000..b7d4f99
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -0,0 +1,226 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="绯荤粺妯″潡">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="璇疯緭鍏ョ郴缁熸ā鍧�"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎿嶄綔浜哄憳">
+        <el-input
+          v-model="queryParams.operName"
+          placeholder="璇疯緭鍏ユ搷浣滀汉鍛�"
+          clearable
+          style="width: 240px;"
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绫诲瀷">
+        <el-select
+          v-model="queryParams.businessType"
+          placeholder="鎿嶄綔绫诲瀷"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="鎿嶄綔鐘舵��"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎿嶄綔鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="list" style="width: 100%;">
+      <el-table-column label="鏃ュ織缂栧彿" align="center" prop="operId" />
+      <el-table-column label="绯荤粺妯″潡" align="center" prop="title" />
+      <el-table-column label="鎿嶄綔绫诲瀷" align="center" prop="businessType" :formatter="typeFormat" />
+      <el-table-column label="璇锋眰鏂瑰紡" align="center" prop="requestMethod" />
+      <el-table-column label="鎿嶄綔浜哄憳" align="center" prop="operName" />
+      <el-table-column label="涓绘満" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
+      <el-table-column label="鎿嶄綔鍦扮偣" align="center" prop="operLocation" />
+      <el-table-column label="鎿嶄綔鐘舵��" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="鎿嶄綔鏃ユ湡" align="center" prop="operTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.operTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row,scope.index)"
+            v-hasPermi="['monitor:operlog:query']"
+          >璇︾粏</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 鎿嶄綔鏃ュ織璇︾粏 -->
+    <el-dialog title="鎿嶄綔鏃ュ織璇︾粏" :visible.sync="open" width="700px">
+      <el-form ref="form" :model="form" label-width="100px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鎿嶄綔妯″潡锛�">{{ form.title }} / 淇敼</el-form-item>
+            <el-form-item
+              label="鐧诲綍淇℃伅锛�"
+            >{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璇锋眰鍦板潃锛�">{{ form.operUrl }}</el-form-item>
+            <el-form-item label="璇锋眰鏂瑰紡锛�">{{ form.requestMethod }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鎿嶄綔鏂规硶锛�">{{ form.method }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="璇锋眰鍙傛暟锛�">{{ form.operParam }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="杩斿洖鍙傛暟锛�">{{ form.jsonResult }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎿嶄綔鐘舵�侊細">
+              <div v-if="form.status === 0">姝e父</div>
+              <div v-else-if="form.status === 1">澶辫触</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎿嶄綔鏃堕棿锛�">{{ dateFormat(form.operTime) }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="寮傚父淇℃伅锛�" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="open = false">鍏� 闂�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list } from "@/api/monitor/operlog";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ牸鏁版嵁
+      list: [],
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 绫诲瀷鏁版嵁瀛楀吀
+      typeOptions: [],
+      // 绫诲瀷鏁版嵁瀛楀吀
+      statusOptions: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        title: undefined,
+        operName: undefined,
+        businessType: undefined,
+        status: undefined
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_oper_type").then(response => {
+      this.typeOptions = response.data;
+    });
+    this.getDicts("sys_common_status").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鐧诲綍鏃ュ織 */
+    getList() {
+      this.loading = true;
+      list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {
+          this.list = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鎿嶄綔鏃ュ織鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鎿嶄綔鏃ュ織绫诲瀷瀛楀吀缈昏瘧
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.typeOptions, row.businessType);
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 璇︾粏鎸夐挳鎿嶄綔 */
+    handleView(row) {
+      this.open = true;
+      this.form = row;
+    }
+  }
+};
+</script>
+
diff --git a/ruoyi-ui/src/views/monitor/server/index.vue b/ruoyi-ui/src/views/monitor/server/index.vue
new file mode 100644
index 0000000..36c95e3
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/server/index.vue
@@ -0,0 +1,209 @@
+<template>
+  <div class="app-container">
+    <el-row>
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span>CPU</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="is-leaf"><div class="cell">灞炴��</div></th>
+                  <th class="is-leaf"><div class="cell">鍊�</div></th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td><div class="cell">鏍稿績鏁�</div></td>
+                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.cpuNum }}</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">鐢ㄦ埛浣跨敤鐜�</div></td>
+                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.used }}%</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">绯荤粺浣跨敤鐜�</div></td>
+                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.sys }}%</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">褰撳墠绌洪棽鐜�</div></td>
+                  <td><div class="cell" v-if="server.cpu">{{ server.cpu.free }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span>鍐呭瓨</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="is-leaf"><div class="cell">灞炴��</div></th>
+                  <th class="is-leaf"><div class="cell">鍐呭瓨</div></th>
+                  <th class="is-leaf"><div class="cell">JVM</div></th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td><div class="cell">鎬诲唴瀛�</div></td>
+                  <td><div class="cell" v-if="server.mem">{{ server.mem.total }}G</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">宸茬敤鍐呭瓨</div></td>
+                  <td><div class="cell" v-if="server.mem">{{ server.mem.used}}G</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">鍓╀綑鍐呭瓨</div></td>
+                  <td><div class="cell" v-if="server.mem">{{ server.mem.free }}G</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">浣跨敤鐜�</div></td>
+                  <td><div class="cell" v-if="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
+                  <td><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span>鏈嶅姟鍣ㄤ俊鎭�</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <tbody>
+                <tr>
+                  <td><div class="cell">鏈嶅姟鍣ㄥ悕绉�</div></td>
+                  <td><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</div></td>
+                  <td><div class="cell">鎿嶄綔绯荤粺</div></td>
+                  <td><div class="cell" v-if="server.sys">{{ server.sys.osName }}</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">鏈嶅姟鍣↖P</div></td>
+                  <td><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</div></td>
+                  <td><div class="cell">绯荤粺鏋舵瀯</div></td>
+                  <td><div class="cell" v-if="server.sys">{{ server.sys.osArch }}</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span>Java铏氭嫙鏈轰俊鎭�</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <tbody>
+                <tr>
+                  <td><div class="cell">Java鍚嶇О</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
+                  <td><div class="cell">Java鐗堟湰</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</div></td>
+                </tr>
+                <tr>
+                  <td><div class="cell">鍚姩鏃堕棿</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.startTime }}</div></td>
+                  <td><div class="cell">杩愯鏃堕暱</div></td>
+                  <td><div class="cell" v-if="server.jvm">{{ server.jvm.runTime }}</div></td>
+                </tr>
+                <tr>
+                  <td colspan="1"><div class="cell">瀹夎璺緞</div></td>
+                  <td colspan="3"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
+                </tr>
+                <tr>
+                  <td colspan="1"><div class="cell">椤圭洰璺緞</div></td>
+                  <td colspan="3"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span>纾佺洏鐘舵��</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="is-leaf"><div class="cell">鐩樼璺緞</div></th>
+                  <th class="is-leaf"><div class="cell">鏂囦欢绯荤粺</div></th>
+                  <th class="is-leaf"><div class="cell">鐩樼绫诲瀷</div></th>
+                  <th class="is-leaf"><div class="cell">鎬诲ぇ灏�</div></th>
+                  <th class="is-leaf"><div class="cell">鍙敤澶у皬</div></th>
+                  <th class="is-leaf"><div class="cell">宸茬敤澶у皬</div></th>
+                  <th class="is-leaf"><div class="cell">宸茬敤鐧惧垎姣�</div></th>
+                </tr>
+              </thead>
+              <tbody v-if="server.sysFiles">
+                <tr v-for="sysFile in server.sysFiles">
+                  <td><div class="cell">{{ sysFile.dirName }}</div></td>
+                  <td><div class="cell">{{ sysFile.sysTypeName }}</div></td>
+                  <td><div class="cell">{{ sysFile.typeName }}</div></td>
+                  <td><div class="cell">{{ sysFile.total }}</div></td>
+                  <td><div class="cell">{{ sysFile.free }}</div></td>
+                  <td><div class="cell">{{ sysFile.used }}</div></td>
+                  <td><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { getServer } from "@/api/monitor/server";
+
+export default {
+  data() {
+    return {
+      // 鍔犺浇灞備俊鎭�
+      loading: [],
+      // 鏈嶅姟鍣ㄤ俊鎭�
+      server: []
+    };
+  },
+  created() {
+    this.getList();
+    this.openLoading();
+  },
+  methods: {
+    /** 鏌ヨ鏈嶅姟鍣ㄤ俊鎭� */
+    getList() {
+      getServer().then(response => {
+        this.server = response.data;
+        this.loading.close();
+      });
+    },
+    // 鎵撳紑鍔犺浇灞�
+    openLoading() {
+      this.loading = this.$loading({
+        lock: true,
+        text: "鎷煎懡璇诲彇涓�",
+        spinner: "el-icon-loading",
+        background: "rgba(0, 0, 0, 0.7)"
+      });
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/redirect.vue b/ruoyi-ui/src/views/redirect.vue
new file mode 100644
index 0000000..6a62cb7
--- /dev/null
+++ b/ruoyi-ui/src/views/redirect.vue
@@ -0,0 +1,12 @@
+<script>
+export default {
+  created() {
+    const { params, query } = this.$route
+    const { path } = params
+    this.$router.replace({ path: '/' + path, query })
+  },
+  render: function(h) {
+    return h() // avoid warning message
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue
new file mode 100644
index 0000000..5e0046d
--- /dev/null
+++ b/ruoyi-ui/src/views/system/config/index.vue
@@ -0,0 +1,270 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="鍙傛暟鍚嶇О">
+        <el-input
+          v-model="queryParams.configName"
+          placeholder="璇疯緭鍏ュ弬鏁板悕绉�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍙傛暟閿悕">
+        <el-input
+          v-model="queryParams.configKey"
+          placeholder="璇疯緭鍏ュ弬鏁伴敭鍚�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绯荤粺鍐呯疆">
+        <el-select v-model="queryParams.configType" placeholder="绯荤粺鍐呯疆" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:config:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="configList">
+      <el-table-column label="鍙傛暟涓婚敭" align="center" prop="configId" />
+      <el-table-column label="鍙傛暟鍚嶇О" align="center" prop="configName" :show-overflow-tooltip="true" />
+      <el-table-column label="鍙傛暟閿悕" align="center" prop="configKey" :show-overflow-tooltip="true" />
+      <el-table-column label="鍙傛暟閿��" align="center" prop="configValue" />
+      <el-table-column label="绯荤粺鍐呯疆" align="center" prop="configType" :formatter="typeFormat" />
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:config:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:config:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="鍙傛暟鍚嶇О" prop="configName">
+          <el-input v-model="form.configName" placeholder="璇疯緭鍏ュ弬鏁板悕绉�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟閿悕" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="璇疯緭鍏ュ弬鏁伴敭鍚�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟閿��" prop="configValue">
+          <el-input v-model="form.configValue" placeholder="璇疯緭鍏ュ弬鏁伴敭鍊�" />
+        </el-form-item>
+        <el-form-item label="绯荤粺鍐呯疆" prop="configType">
+          <el-radio-group v-model="form.configType">
+            <el-radio
+              v-for="dict in typeOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listConfig, getConfig, delConfig, addConfig, updateConfig } from "@/api/system/config";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鍙傛暟琛ㄦ牸鏁版嵁
+      configList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 绫诲瀷鏁版嵁瀛楀吀
+      typeOptions: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        configName: undefined,
+        configKey: undefined,
+        configType: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        configName: [
+          { required: true, message: "鍙傛暟鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        configKey: [
+          { required: true, message: "鍙傛暟閿悕涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        configValue: [
+          { required: true, message: "鍙傛暟閿�间笉鑳戒负绌�", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_yes_no").then(response => {
+      this.typeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鍙傛暟鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listConfig(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.configList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鍙傛暟绯荤粺鍐呯疆瀛楀吀缈昏瘧
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.typeOptions, row.configType);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        configId: undefined,
+        configName: undefined,
+        configKey: undefined,
+        configValue: undefined,
+        configType: "Y",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞鍙傛暟";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getConfig(row.configId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鍙傛暟";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.configId != undefined) {
+            updateConfig(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addConfig(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.configName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delConfig(row.configId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue
new file mode 100644
index 0000000..c5bb197
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dept/index.vue
@@ -0,0 +1,307 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true">
+      <el-form-item label="閮ㄩ棬鍚嶇О">
+        <el-input
+          v-model="queryParams.deptName"
+          placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select v-model="queryParams.status" placeholder="閮ㄩ棬鐘舵��" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button
+          class="filter-item"
+          type="primary"
+          icon="el-icon-search"
+          size="mini"
+          @click="handleQuery"
+        >鎼滅储</el-button>
+        <el-button
+          class="filter-item"
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:dept:add']"
+        >鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table
+      v-loading="loading"
+      :data="deptList"
+      row-key="deptId"
+      default-expand-all
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column prop="deptName" label="閮ㄩ棬鍚嶇О" width="200"></el-table-column>
+      <el-table-column prop="orderNum" label="鎺掑簭" width="200"></el-table-column>
+      <el-table-column prop="status" label="鐘舵��" :formatter="statusFormat" width="100"></el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="200">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dept:edit']"
+          >淇敼</el-button>
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-plus" 
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['system:dept:add']"
+          >鏂板</el-button>
+          <el-button
+            v-if="scope.row.parentId != 0"
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dept:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀归儴闂ㄥ璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="24" v-if="form.parentId !== 0">
+            <el-form-item label="涓婄骇閮ㄩ棬" prop="parentId">
+              <treeselect v-model="form.parentId" :options="deptOptions" placeholder="閫夋嫨涓婄骇閮ㄩ棬" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閮ㄩ棬鍚嶇О" prop="deptName">
+              <el-input v-model="form.deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄剧ず鎺掑簭" prop="orderNum">
+              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璐熻矗浜�" prop="leader">
+              <el-input v-model="form.leader" placeholder="璇疯緭鍏ヨ礋璐d汉" maxlength="20" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴鐢佃瘽" prop="phone">
+              <el-input v-model="form.phone" placeholder="璇疯緭鍏ヨ仈绯荤數璇�" maxlength="11" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閭" prop="email">
+              <el-input v-model="form.email" placeholder="璇疯緭鍏ラ偖绠�" maxlength="50" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閮ㄩ棬鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{dict.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDept, getDept, treeselect, delDept, addDept, updateDept } from "@/api/system/dept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 琛ㄦ牸鏍戞暟鎹�
+      deptList: [],
+      // 閮ㄩ棬閮ㄩ棬鏍戦�夐」
+      deptOptions: undefined,
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        deptName: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        parentId: [
+          { required: true, message: "涓婄骇閮ㄩ棬涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        deptName: [
+          { required: true, message: "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        orderNum: [
+          { required: true, message: "鑿滃崟椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        email: [
+          {
+            type: "email",
+            message: "'璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phone: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ閮ㄩ棬鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listDept(this.queryParams).then(response => {
+        this.deptList = response.data;
+        this.loading = false;
+      });
+    },
+    /** 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 瀛楀吀鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        deptId: undefined,
+        parentId: 100,
+        deptName: undefined,
+        orderNum: undefined,
+        leader: undefined,
+        phone: undefined,
+        email: undefined,
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != undefined) {
+        this.form.parentId = row.deptId;
+      }
+      this.open = true;
+      this.title = "娣诲姞閮ㄩ棬";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      getDept(row.deptId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼閮ㄩ棬";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.deptId != undefined) {
+            updateDept(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addDept(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.deptName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delDept(row.deptId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
new file mode 100644
index 0000000..fe1b12d
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -0,0 +1,276 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true">
+      <el-form-item label="瀛楀吀鍚嶇О">
+        <el-select v-model="queryParams.dictType" size="small">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.dictId"
+            :label="item.dictName"
+            :value="item.dictType"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀛楀吀鏍囩">
+        <el-input
+          v-model="queryParams.dictLabel"
+          placeholder="璇疯緭鍏ュ瓧鍏告爣绛�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select v-model="queryParams.status" placeholder="鏁版嵁鐘舵��" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="dataList" style="width: 100%;">
+      <el-table-column label="瀛楀吀缂栫爜" align="center" prop="dictCode" />
+      <el-table-column label="瀛楀吀鏍囩" align="center" prop="dictLabel" />
+      <el-table-column label="瀛楀吀閿��" align="center" prop="dictValue" />
+      <el-table-column label="瀛楀吀鎺掑簭" align="center" prop="dictSort" />
+      <el-table-column label="鐘舵��" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dict:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dict:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="瀛楀吀绫诲瀷">
+          <el-input v-model="form.dictType" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏁版嵁鏍囩" prop="dictLabel">
+          <el-input v-model="form.dictLabel" placeholder="璇疯緭鍏ユ暟鎹爣绛�" />
+        </el-form-item>
+        <el-form-item label="鏁版嵁閿��" prop="dictValue">
+          <el-input v-model="form.dictValue" placeholder="璇疯緭鍏ユ暟鎹敭鍊�" />
+        </el-form-item>
+        <el-form-item label="鏄剧ず鎺掑簭" prop="dictSort">
+          <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
+import { listType, getType } from "@/api/system/dict/type";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瀛楀吀琛ㄦ牸鏁版嵁
+      dataList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 绫诲瀷鏁版嵁瀛楀吀
+      typeOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictName: undefined,
+        dictType: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        dictLabel: [
+          { required: true, message: "鏁版嵁鏍囩涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        dictValue: [
+          { required: true, message: "鏁版嵁閿�间笉鑳戒负绌�", trigger: "blur" }
+        ],
+        dictSort: [
+          { required: true, message: "鏁版嵁椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    const dictId = this.$route.params && this.$route.params.dictId;
+    this.getType(dictId);
+    this.getTypeList();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ瀛楀吀绫诲瀷璇︾粏 */
+    getType(dictId) {
+      getType(dictId).then(response => {
+        this.queryParams.dictType = response.data.dictType;
+        this.getList();
+      });
+    },
+    /** 鏌ヨ瀛楀吀绫诲瀷鍒楄〃 */
+    getTypeList() {
+      listType().then(response => {
+        this.typeOptions = response.rows;
+      });
+    },
+    /** 鏌ヨ瀛楀吀鏁版嵁鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listData(this.queryParams).then(response => {
+        this.dataList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鏁版嵁鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        dictCode: undefined,
+        dictLabel: undefined,
+        dictValue: undefined,
+        dictSort: 0,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞瀛楀吀鏁版嵁";
+      this.form.dictType = this.queryParams.dictType;
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getData(row.dictCode).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼瀛楀吀鏁版嵁";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.dictCode != undefined) {
+            updateData(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addData(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.dictLabel + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delData(row.dictCode);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dict/index.vue b/ruoyi-ui/src/views/system/dict/index.vue
new file mode 100644
index 0000000..f9e5d17
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dict/index.vue
@@ -0,0 +1,275 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="瀛楀吀鍚嶇О">
+        <el-input
+          v-model="queryParams.dictName"
+          placeholder="璇疯緭鍏ュ瓧鍏稿悕绉�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="瀛楀吀绫诲瀷">
+        <el-input
+          v-model="queryParams.dictType"
+          placeholder="璇疯緭鍏ュ瓧鍏哥被鍨�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="瀛楀吀鐘舵��"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="queryParams.createTime"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:dict:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="typeList" style="width: 100%;">
+      <el-table-column label="瀛楀吀涓婚敭" align="center" prop="dictId" />
+      <el-table-column label="瀛楀吀鍚嶇О" align="center" prop="dictName" :show-overflow-tooltip="true" />
+      <el-table-column label="瀛楀吀绫诲瀷" align="center">
+        <template slot-scope="scope">
+          <router-link :to="'/dict/type/data/' + scope.row.dictId" class="link-type">
+            <span>{{ scope.row.dictType }}</span>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="鐘舵��" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dict:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dict:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="瀛楀吀鍚嶇О" prop="dictName">
+          <el-input v-model="form.dictName" placeholder="璇疯緭鍏ュ瓧鍏稿悕绉�" />
+        </el-form-item>
+        <el-form-item label="瀛楀吀绫诲瀷" prop="dictType">
+          <el-input v-model="form.dictType" placeholder="璇疯緭鍏ュ瓧鍏哥被鍨�" />
+        </el-form-item>
+        <el-form-item label="鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listType, getType, delType, addType, updateType } from "@/api/system/dict/type";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瀛楀吀琛ㄦ牸鏁版嵁
+      typeList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictName: undefined,
+        dictType: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        dictName: [
+          { required: true, message: "瀛楀吀鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        dictType: [
+          { required: true, message: "瀛楀吀绫诲瀷涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ瀛楀吀绫诲瀷鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listType(this.addDateRange(this.queryParams, this.dateRange)).then(
+        response => {
+          this.typeList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 瀛楀吀鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        dictId: undefined,
+        dictName: undefined,
+        dictType: undefined,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞瀛楀吀绫诲瀷";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getType(row.dictId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼瀛楀吀绫诲瀷";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.dictId != undefined) {
+            updateType(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addType(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.dictName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delType(row.dictId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/log/index.vue b/ruoyi-ui/src/views/system/log/index.vue
new file mode 100644
index 0000000..ad6360c
--- /dev/null
+++ b/ruoyi-ui/src/views/system/log/index.vue
@@ -0,0 +1,3 @@
+<template >
+  <router-view />
+</template>
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
new file mode 100644
index 0000000..d8d163e
--- /dev/null
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -0,0 +1,337 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true">
+      <el-form-item label="鑿滃崟鍚嶇О">
+        <el-input
+          v-model="queryParams.menuName"
+          placeholder="璇疯緭鍏ヨ彍鍗曞悕绉�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select v-model="queryParams.visible" placeholder="鑿滃崟鐘舵��" clearable size="small">
+          <el-option
+            v-for="dict in visibleOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:menu:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table
+      v-loading="loading"
+      :data="menuList"
+      row-key="menuId"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column prop="menuName" label="鑿滃崟鍚嶇О" :show-overflow-tooltip="true" width="130px"></el-table-column>
+      <el-table-column prop="icon" label="鍥炬爣" align="center" width="100px">
+        <template slot-scope="scope">
+          <svg-icon :icon-class="scope.row.icon" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="orderNum" label="鎺掑簭" width="60px"></el-table-column>
+      <el-table-column prop="perms" label="鏉冮檺鏍囪瘑" width="130px" :show-overflow-tooltip="true"></el-table-column>
+      <el-table-column prop="component" label="缁勪欢璺緞" width="180px" :show-overflow-tooltip="true"></el-table-column>
+      <el-table-column prop="visible" label="	鍙" :formatter="visibleFormat" width="80px"></el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" width="180" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:menu:edit']"
+          >淇敼</el-button>
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-plus" 
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['system:menu:add']"
+          >鏂板</el-button>
+          <el-button
+            v-if="scope.row.parentId != 0"
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:menu:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀硅彍鍗曞璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="24" v-if="form.parentId !== 0">
+            <el-form-item label="涓婄骇鑿滃崟" prop="parentId">
+              <treeselect
+                v-model="form.parentId"
+                :options="menuOptions"
+                :show-count="true"
+                placeholder="閫夋嫨涓婄骇鑿滃崟"
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鑿滃崟绫诲瀷" prop="menuType">
+              <el-radio-group v-model="form.menuType">
+                <el-radio label="M">鐩綍</el-radio>
+                <el-radio label="C">鑿滃崟</el-radio>
+                <el-radio label="F">鎸夐挳</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item v-if="form.menuType != 'F'" label="鑿滃崟鍥炬爣">
+              <el-popover
+                placement="bottom-start"
+                width="460"
+                trigger="click"
+                @show="$refs['iconSelect'].reset()"
+              >
+                <IconSelect ref="iconSelect" @selected="selected" />
+                <el-input slot="reference" v-model="form.icon" placeholder="鐐瑰嚮閫夋嫨鍥炬爣" readonly>
+                  <svg-icon
+                    v-if="form.icon"
+                    slot="prefix"
+                    :icon-class="form.icon"
+                    class="el-input__icon"
+                    style="height: 32px;width: 16px;"
+                  />
+                  <i v-else slot="prefix" class="el-icon-search el-input__icon" />
+                </el-input>
+              </el-popover>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鑿滃崟鍚嶇О" prop="menuName">
+              <el-input v-model="form.menuName" placeholder="璇疯緭鍏ヨ彍鍗曞悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄剧ず鎺掑簭" prop="orderNum">
+              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item v-if="form.menuType != 'F'" label="鏄惁澶栭摼">
+              <el-radio-group v-model="form.isFrame">
+                <el-radio label="0">鏄�</el-radio>
+                <el-radio label="1">鍚�</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item v-if="form.menuType != 'F'" label="璺敱鍦板潃" prop="path">
+              <el-input v-model="form.path" placeholder="璇疯緭鍏ヨ矾鐢卞湴鍧�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item label="缁勪欢璺緞" prop="component">
+              <el-input v-model="form.component" placeholder="璇疯緭鍏ョ粍浠惰矾寰�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item v-if="form.menuType == 'C'" label="鏉冮檺鏍囪瘑">
+              <el-input v-model="form.perms" placeholder="璇锋潈闄愭爣璇�" maxlength="50" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item v-if="form.menuType != 'F'" label="鑿滃崟鐘舵��">
+              <el-radio-group v-model="form.visible">
+                <el-radio
+                  v-for="dict in visibleOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{dict.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listMenu, getMenu, treeselect, delMenu, addMenu, updateMenu } from "@/api/system/menu";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import IconSelect from "@/components/IconSelect";
+
+export default {
+  components: { Treeselect, IconSelect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鑿滃崟琛ㄦ牸鏍戞暟鎹�
+      menuList: [],
+      // 鑿滃崟鏍戦�夐」
+      menuOptions: undefined,
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鑿滃崟鐘舵�佹暟鎹瓧鍏�
+      visibleOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        menuName: undefined,
+        visible: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        parentId: [
+          { required: true, message: "涓婄骇鑿滃崟涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        menuName: [
+          { required: true, message: "鑿滃崟鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        orderNum: [
+          { required: true, message: "鑿滃崟椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_show_hide").then(response => {
+      this.visibleOptions = response.data;
+    });
+  },
+  methods: {
+    // 閫夋嫨鍥炬爣
+    selected(name) {
+      this.form.icon = name;
+    },
+    /** 鏌ヨ鑿滃崟鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listMenu(this.queryParams).then(response => {
+        this.menuList = response.data;
+        this.loading = false;
+      });
+    },
+    /** 鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.menuOptions = response.data;
+      });
+    },
+    // 鑿滃崟鏄剧ず鐘舵�佸瓧鍏哥炕璇�
+    visibleFormat(row, column) {
+      if (row.menuType == "F") {
+        return "";
+      }
+      return this.selectDictLabel(this.visibleOptions, row.visible);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        menuId: undefined,
+        parentId: 0,
+        menuName: undefined,
+        icon: undefined,
+        menuType: "M",
+        orderNum: undefined,
+        isFrame: "1",
+        visible: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null) {
+        this.form.parentId = row.menuId;
+      }
+      this.open = true;
+      this.title = "娣诲姞鑿滃崟";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      getMenu(row.menuId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鑿滃崟";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.menuId != undefined) {
+            updateMenu(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addMenu(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.menuName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delMenu(row.menuId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/notice/index.vue b/ruoyi-ui/src/views/system/notice/index.vue
new file mode 100644
index 0000000..6aa32bd
--- /dev/null
+++ b/ruoyi-ui/src/views/system/notice/index.vue
@@ -0,0 +1,292 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="鍏憡鏍囬">
+        <el-input
+          v-model="queryParams.noticeTitle"
+          placeholder="璇疯緭鍏ュ叕鍛婃爣棰�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎿嶄綔浜哄憳">
+        <el-input
+          v-model="queryParams.createBy"
+          placeholder="璇疯緭鍏ユ搷浣滀汉鍛�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绫诲瀷">
+        <el-select v-model="queryParams.noticeType" placeholder="鍏憡绫诲瀷" clearable size="small">
+          <el-option
+            v-for="dict in typeOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:notice:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="noticeList">
+      <el-table-column label="搴忓彿" align="center" prop="noticeId" width="100" />
+      <el-table-column
+        label="鍏憡鏍囬"
+        align="center"
+        prop="noticeTitle"
+        :show-overflow-tooltip="true"
+      />
+      <el-table-column
+        label="鍏憡绫诲瀷"
+        align="center"
+        prop="noticeType"
+        :formatter="typeFormat"
+        width="100"
+      />
+      <el-table-column
+        label="鐘舵��"
+        align="center"
+        prop="status"
+        :formatter="statusFormat"
+        width="100"
+      />
+      <el-table-column label="鍒涘缓鑰�" align="center" prop="createBy" width="100" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="100">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime, 'yyyy-MM-dd') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:notice:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:notice:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰叕鍛婂璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="780px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鍏憡鏍囬" prop="noticeTitle">
+              <el-input v-model="form.noticeTitle" placeholder="璇疯緭鍏ュ叕鍛婃爣棰�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏憡绫诲瀷" prop="noticeType">
+              <el-select v-model="form.noticeType" placeholder="璇烽�夋嫨">
+                <el-option
+                  v-for="dict in typeOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{dict.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鍐呭">
+               <Editor v-model="form.noticeContent"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer" style="padding-top:20px">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
+import Editor from '@/components/Editor';
+
+export default {
+  components: {
+    Editor
+  },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鍏憡琛ㄦ牸鏁版嵁
+      noticeList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 绫诲瀷鏁版嵁瀛楀吀
+      statusOptions: [],
+      // 鐘舵�佹暟鎹瓧鍏�
+      typeOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        noticeTitle: undefined,
+        createBy: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        noticeTitle: [
+          { required: true, message: "鍏憡鏍囬涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        noticeType: [
+          { required: true, message: "鍏憡绫诲瀷涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_notice_status").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_notice_type").then(response => {
+      this.typeOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鍏憡鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listNotice(this.queryParams).then(response => {
+        this.noticeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍏憡鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鍏憡鐘舵�佸瓧鍏哥炕璇�
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.typeOptions, row.noticeType);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        noticeId: undefined,
+        noticeTitle: undefined,
+        noticeType: undefined,
+        noticeContent: undefined,
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞鍏憡";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getNotice(row.noticeId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鍏憡";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.noticeId != undefined) {
+            updateNotice(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addNotice(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍏憡鏍囬涓�"' + row.noticeTitle + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delNotice(row.noticeId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/post/index.vue b/ruoyi-ui/src/views/system/post/index.vue
new file mode 100644
index 0000000..b1f0c9f
--- /dev/null
+++ b/ruoyi-ui/src/views/system/post/index.vue
@@ -0,0 +1,252 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true" label-width="68px">
+      <el-form-item label="宀椾綅缂栫爜">
+        <el-input
+          v-model="queryParams.postCode"
+          placeholder="璇疯緭鍏ュ矖浣嶇紪鐮�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="宀椾綅鍚嶇О">
+        <el-input
+          v-model="queryParams.postName"
+          placeholder="璇疯緭鍏ュ矖浣嶅悕绉�"
+          clearable
+          size="small"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select v-model="queryParams.status" placeholder="宀椾綅鐘舵��" clearable size="small">
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:post:add']">鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="postList">
+      <el-table-column label="宀椾綅缂栧彿" align="center" prop="postId" />
+      <el-table-column label="宀椾綅缂栫爜" align="center" prop="postCode" />
+      <el-table-column label="宀椾綅鍚嶇О" align="center" prop="postName" />
+      <el-table-column label="宀椾綅鎺掑簭" align="center" prop="postSort" />
+      <el-table-column label="鐘舵��" align="center" prop="status" :formatter="statusFormat" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button 
+            size="mini" 
+            type="text" 
+            icon="el-icon-edit" 
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:post:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:post:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰矖浣嶅璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="宀椾綅鍚嶇О" prop="postName">
+          <el-input v-model="form.postName" placeholder="璇疯緭鍏ュ矖浣嶅悕绉�" />
+        </el-form-item>
+        <el-form-item label="宀椾綅缂栫爜" prop="postCode">
+          <el-input v-model="form.postCode" placeholder="璇疯緭鍏ョ紪鐮佸悕绉�" />
+        </el-form-item>
+        <el-form-item label="宀椾綅椤哄簭" prop="postSort">
+          <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="宀椾綅鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 宀椾綅琛ㄦ牸鏁版嵁
+      postList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        postCode: undefined,
+        postName: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        postName: [
+          { required: true, message: "宀椾綅鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        postCode: [
+          { required: true, message: "宀椾綅缂栫爜涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        postSort: [
+          { required: true, message: "宀椾綅椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ宀椾綅鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listPost(this.queryParams).then(response => {
+        this.postList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 宀椾綅鐘舵�佸瓧鍏哥炕璇�
+    statusFormat(row, column) {
+      return this.selectDictLabel(this.statusOptions, row.status);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        postId: undefined,
+        postCode: undefined,
+        postName: undefined,
+        postSort: 0,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞宀椾綅";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getPost(row.postId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼宀椾綅";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.postId != undefined) {
+            updatePost(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addPost(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎宀椾綅鍚嶇О涓�"' + row.postName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delPost(row.postId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
new file mode 100644
index 0000000..332dc8f
--- /dev/null
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -0,0 +1,478 @@
+<template>
+  <div class="app-container">
+    <el-form :inline="true">
+      <el-form-item label="瑙掕壊鍚嶇О">
+        <el-input
+          v-model="queryParams.roleName"
+          placeholder="璇疯緭鍏ヨ鑹插悕绉�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鏉冮檺瀛楃">
+        <el-input
+          v-model="queryParams.roleKey"
+          placeholder="璇疯緭鍏ユ潈闄愬瓧绗�"
+          clearable
+          size="small"
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="瑙掕壊鐘舵��"
+          clearable
+          size="small"
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in statusOptions"
+            :key="dict.dictValue"
+            :label="dict.dictLabel"
+            :value="dict.dictValue"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          size="small"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button
+          type="primary"
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['system:role:add']"
+        >鏂板</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-table v-loading="loading" :data="roleList">
+      <el-table-column label="瑙掕壊缂栧彿" prop="roleId" width="120" />
+      <el-table-column label="瑙掕壊鍚嶇О" prop="roleName" :show-overflow-tooltip="true" width="150" />
+      <el-table-column label="鏉冮檺瀛楃" prop="roleKey" :show-overflow-tooltip="true" width="180" />
+      <el-table-column label="鏄剧ず椤哄簭" prop="roleSort" width="120" />
+      <el-table-column label="鐘舵��" align="center" width="120">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            active-value="0"
+            inactive-value="1"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ dateFormat(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:role:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-circle-check"
+            @click="handleDataScope(scope.row)"
+            v-hasPermi="['system:role:edit']"
+          >鏁版嵁鏉冮檺</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:role:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀硅鑹查厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="瑙掕壊鍚嶇О" prop="roleName">
+          <el-input v-model="form.roleName" placeholder="璇疯緭鍏ヨ鑹插悕绉�" />
+        </el-form-item>
+        <el-form-item label="鏉冮檺瀛楃" prop="roleKey">
+          <el-input v-model="form.roleKey" placeholder="璇疯緭鍏ユ潈闄愬瓧绗�" />
+        </el-form-item>
+        <el-form-item label="瑙掕壊椤哄簭" prop="roleSort">
+          <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="鐘舵��">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in statusOptions"
+              :key="dict.dictValue"
+              :label="dict.dictValue"
+            >{{dict.dictLabel}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="鑿滃崟鏉冮檺">
+          <el-tree
+            :data="menuOptions"
+            show-checkbox
+            ref="menu"
+            node-key="id"
+            empty-text="鍔犺浇涓紝璇风◢鍚�"
+            :props="defaultProps"
+          ></el-tree>
+        </el-form-item>
+        <el-form-item label="澶囨敞">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鍒嗛厤瑙掕壊鏁版嵁鏉冮檺瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="openDataScope" width="500px">
+      <el-form :model="form" label-width="80px">
+        <el-form-item label="瑙掕壊鍚嶇О">
+          <el-input v-model="form.roleName" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏉冮檺瀛楃">
+          <el-input v-model="form.roleKey" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏉冮檺鑼冨洿">
+          <el-select v-model="form.dataScope">
+            <el-option
+              v-for="item in dataScopeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鏁版嵁鏉冮檺" v-show="form.dataScope == 2">
+          <el-tree
+            :data="deptOptions"
+            show-checkbox
+            default-expand-all
+            ref="dept"
+            node-key="id"
+            empty-text="鍔犺浇涓紝璇风◢鍚�"
+            :props="defaultProps"
+          ></el-tree>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitDataScope">纭� 瀹�</el-button>
+        <el-button @click="cancelDataScope">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus } from "@/api/system/role";
+import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
+import { treeselect as deptTreeselect, roleDeptTreeselect } from "@/api/system/dept";
+
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瑙掕壊琛ㄦ牸鏁版嵁
+      roleList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁鏄剧ず寮瑰嚭灞傦紙鏁版嵁鏉冮檺锛�
+      openDataScope: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鏁版嵁鑼冨洿閫夐」
+      dataScopeOptions: [
+        {
+          value: "1",
+          label: "鍏ㄩ儴鏁版嵁鏉冮檺"
+        },
+        {
+          value: "2",
+          label: "鑷畾鏁版嵁鏉冮檺"
+        },
+        {
+          value: "3",
+          label: "鏈儴闂ㄦ暟鎹潈闄�"
+        },
+        {
+          value: "4",
+          label: "鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺"
+        },
+        {
+          value: "5",
+          label: "浠呮湰浜烘暟鎹潈闄�"
+        }
+      ],
+      // 鑿滃崟鍒楄〃
+      menuOptions: [],
+      // 閮ㄩ棬鍒楄〃
+      deptOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleName: undefined,
+        roleKey: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      defaultProps: {
+        children: "children",
+        label: "label"
+      },
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        roleName: [
+          { required: true, message: "瑙掕壊鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        roleKey: [
+          { required: true, message: "鏉冮檺瀛楃涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        roleSort: [
+          { required: true, message: "瑙掕壊椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ瑙掕壊鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(
+        response => {
+          this.roleList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鏌ヨ鑿滃崟鏍戠粨鏋� */
+    getMenuTreeselect() {
+      menuTreeselect().then(response => {
+        this.menuOptions = response.data;
+      });
+    },
+    /** 鏌ヨ閮ㄩ棬鏍戠粨鏋� */
+    getDeptTreeselect() {
+      deptTreeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 鎵�鏈夎彍鍗曡妭鐐规暟鎹�
+    getMenuAllCheckedKeys() {
+      // 鐩墠琚�変腑鐨勮彍鍗曡妭鐐�
+      let checkedKeys = this.$refs.menu.getHalfCheckedKeys();
+      // 鍗婇�変腑鐨勮彍鍗曡妭鐐�
+      let halfCheckedKeys = this.$refs.menu.getCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      return checkedKeys;
+    },
+    // 鎵�鏈夐儴闂ㄨ妭鐐规暟鎹�
+    getDeptAllCheckedKeys() {
+      // 鐩墠琚�変腑鐨勯儴闂ㄨ妭鐐�
+      let checkedKeys = this.$refs.dept.getHalfCheckedKeys();
+      // 鍗婇�変腑鐨勯儴闂ㄨ妭鐐�
+      let halfCheckedKeys = this.$refs.dept.getCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      return checkedKeys;
+    },
+    /** 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戠粨鏋� */
+    getRoleMenuTreeselect(roleId) {
+      roleMenuTreeselect(roleId).then(response => {
+        this.getMenuTreeselect();
+        this.$refs.menu.setCheckedKeys(response.data);
+      });
+    },
+    /** 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戠粨鏋� */
+    getRoleDeptTreeselect(roleId) {
+      roleDeptTreeselect(roleId).then(response => {
+        this.getDeptTreeselect();
+        this.$refs.dept.setCheckedKeys(response.data);
+      });
+    },
+    // 瑙掕壊鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$confirm('纭瑕�"' + text + '""' + row.roleName + '"瑙掕壊鍚�?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return changeRoleStatus(row.roleId, row.status);
+        }).then(() => {
+          this.msgSuccess(text + "鎴愬姛");
+        }).catch(function() {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 鍙栨秷鎸夐挳锛堟暟鎹潈闄愶級
+    cancelDataScope() {
+      this.openDataScope = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      if (this.$refs.tree != undefined) {
+        this.$refs.tree.setCheckedKeys([]);
+      }
+      this.form = {
+        roleId: undefined,
+        roleName: undefined,
+        roleKey: undefined,
+        roleSort: 0,
+        status: "0",
+        menuIds: [],
+        deptIds: [],
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.getMenuTreeselect();
+      this.open = true;
+      this.title = "娣诲姞瑙掕壊";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.$nextTick(() => {
+        this.getRoleMenuTreeselect(row.roleId);
+      });
+      getRole(row.roleId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼瑙掕壊";
+      });
+    },
+    /** 鍒嗛厤鏁版嵁鏉冮檺鎿嶄綔 */
+    handleDataScope(row) {
+      this.reset();
+      this.$nextTick(() => {
+        this.getRoleDeptTreeselect(row.roleId);
+      });
+      getRole(row.roleId).then(response => {
+        this.form = response.data;
+        this.openDataScope = true;
+        this.title = "鍒嗛厤鏁版嵁鏉冮檺";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.roleId != undefined) {
+            this.form.menuIds = this.getMenuAllCheckedKeys();
+            updateRole(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            this.form.menuIds = this.getMenuAllCheckedKeys();
+            addRole(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鎻愪氦鎸夐挳锛堟暟鎹潈闄愶級 */
+    submitDataScope: function() {
+      if (this.form.roleId != undefined) {
+        this.form.deptIds = this.getDeptAllCheckedKeys();
+        dataScope(this.form).then(response => {
+          if (response.code === 200) {
+            this.msgSuccess("淇敼鎴愬姛");
+            this.openDataScope = false;
+            this.getList();
+          } else {
+            this.msgError(response.msg);
+          }
+        });
+      }
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.roleName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delRole(row.roleId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
new file mode 100644
index 0000000..c340d74
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -0,0 +1,515 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <!--閮ㄩ棬鏁版嵁-->
+      <el-col :span="4" :xs="24">
+        <div class="head-container">
+          <el-input
+            v-model="deptName"
+            placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+            clearable
+            size="small"
+            prefix-icon="el-icon-search"
+            style="margin-bottom: 20px"
+          />
+        </div>
+        <div class="head-container">
+          <el-tree
+            :data="deptOptions"
+            :props="defaultProps"
+            :expand-on-click-node="false"
+            :filter-node-method="filterNode"
+            ref="tree"
+            default-expand-all
+            @node-click="handleNodeClick"
+          />
+        </div>
+      </el-col>
+      <!--鐢ㄦ埛鏁版嵁-->
+      <el-col :span="20" :xs="24">
+        <el-form :inline="true" label-width="68px">
+          <el-form-item label="鐢ㄦ埛鍚嶇О">
+            <el-input
+              v-model="queryParams.userName"
+              placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+              clearable
+              size="small"
+              style="width: 240px"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="鎵嬫満鍙风爜">
+            <el-input
+              v-model="queryParams.phonenumber"
+              placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�"
+              clearable
+              size="small"
+              style="width: 240px"
+              @keyup.enter.native="handleQuery"
+            />
+          </el-form-item>
+          <el-form-item label="鐘舵��">
+            <el-select
+              v-model="queryParams.status"
+              placeholder="鐢ㄦ埛鐘舵��"
+              clearable
+              size="small"
+              style="width: 240px"
+            >
+              <el-option
+                v-for="dict in statusOptions"
+                :key="dict.dictValue"
+                :label="dict.dictLabel"
+                :value="dict.dictValue"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item label="鍒涘缓鏃堕棿">
+            <el-date-picker
+              v-model="dateRange"
+              size="small"
+              style="width: 240px"
+              value-format="yyyy-MM-dd"
+              type="daterange"
+              range-separator="-"
+              start-placeholder="寮�濮嬫棩鏈�"
+              end-placeholder="缁撴潫鏃ユ湡"
+            ></el-date-picker>
+          </el-form-item>
+          <el-form-item>
+            <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd" v-hasPermi="['system:user:add']">鏂板</el-button>
+          </el-form-item>
+        </el-form>
+
+        <el-table v-loading="loading" :data="userList">
+          <el-table-column label="鐢ㄦ埛缂栧彿" align="center" prop="userId" />
+          <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" prop="userName" />
+          <el-table-column label="鐢ㄦ埛鏄电О" align="center" prop="nickName" />
+          <el-table-column label="閮ㄩ棬" align="center" prop="dept.deptName" />
+          <el-table-column label="鎵嬫満鍙风爜" align="center" prop="phonenumber" width="120" />
+          <el-table-column label="鐘舵��" align="center">
+            <template slot-scope="scope">
+              <el-switch
+                v-model="scope.row.status"
+                active-value="0"
+                inactive-value="1"
+                @change="handleStatusChange(scope.row)"
+              ></el-switch>
+            </template>
+          </el-table-column>
+          <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="160">
+            <template slot-scope="scope">
+              <span>{{ dateFormat(scope.row.createTime) }}</span>
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="鎿嶄綔"
+            align="center"
+            width="180"
+            class-name="small-padding fixed-width"
+          >
+            <template slot-scope="scope">
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-edit"
+                @click="handleUpdate(scope.row)"
+                v-hasPermi="['system:user:edit']"
+              >淇敼</el-button>
+              <el-button
+                v-if="scope.row.userId !== 1"
+                size="mini"
+                type="text"
+                icon="el-icon-delete"
+                @click="handleDelete(scope.row)"
+                v-hasPermi="['system:user:remove']"
+              >鍒犻櫎</el-button>
+              <el-button
+                size="mini"
+                type="text"
+                icon="el-icon-key"
+                @click="handleResetPwd(scope.row)"
+                v-hasPermi="['system:user:resetPwd']"
+              >閲嶇疆</el-button>
+            </template>
+          </el-table-column>
+        </el-table>
+
+        <pagination
+          v-show="total>0"
+          :total="total"
+          :page.sync="queryParams.pageNum"
+          :limit.sync="queryParams.pageSize"
+          @pagination="getList"
+        />
+      </el-col>
+    </el-row>
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px">
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName">
+              <el-input v-model="form.nickName" placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+              <treeselect v-model="form.deptId" :options="deptOptions" placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+              <el-input v-model="form.phonenumber" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" maxlength="11" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閭" prop="email">
+              <el-input v-model="form.email" placeholder="璇疯緭鍏ラ偖绠�" maxlength="50" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+              <el-input v-model="form.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item v-if="form.userId == undefined" label="鐢ㄦ埛瀵嗙爜" prop="password">
+              <el-input v-model="form.password" placeholder="璇疯緭鍏ョ敤鎴峰瘑鐮�" type="password" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐢ㄦ埛鎬у埆">
+              <el-select v-model="form.sex" placeholder="璇烽�夋嫨">
+                <el-option
+                  v-for="dict in sexOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictLabel"
+                  :value="dict.dictValue"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in statusOptions"
+                  :key="dict.dictValue"
+                  :label="dict.dictValue"
+                >{{dict.dictLabel}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+
+          <el-col :span="12">
+            <el-form-item label="宀椾綅">
+              <el-select v-model="form.postIds" multiple placeholder="璇烽�夋嫨">
+                <el-option
+                  v-for="item in postOptions"
+                  :key="item.postId"
+                  :label="item.postName"
+                  :value="item.postId"
+                  :disabled="item.status == 1"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瑙掕壊">
+              <el-select v-model="form.roleIds" multiple placeholder="璇烽�夋嫨">
+                <el-option
+                  v-for="item in roleOptions"
+                  :key="item.roleId"
+                  :label="item.roleName"
+                  :value="item.roleId"
+                  :disabled="item.status == 1"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="澶囨敞">
+              <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus } from "@/api/system/user";
+import { treeselect } from "@/api/system/dept";
+import { listPost } from "@/api/system/post";
+import { listRole } from "@/api/system/role";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 閮ㄩ棬鏍戦�夐」
+      deptOptions: undefined,
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鐘舵�佹暟鎹瓧鍏�
+      statusOptions: [],
+      // 鎬у埆鐘舵�佸瓧鍏�
+      sexOptions: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      defaultProps: {
+        children: "children",
+        label: "label"
+      },
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        phonenumber: undefined,
+        status: undefined,
+        deptId: undefined
+      },
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        deptId: [
+          { required: true, message: "褰掑睘閮ㄩ棬涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        email: [
+          {
+            type: "email",
+            message: "'璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  watch: {
+    // 鏍规嵁鍚嶇О绛涢�夐儴闂ㄦ爲
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  created() {
+    this.getList();
+    this.getTreeselect();
+    this.getDicts("sys_normal_disable").then(response => {
+      this.statusOptions = response.data;
+    });
+    this.getDicts("sys_user_sex").then(response => {
+      this.sexOptions = response.data;
+    });
+    this.getConfigKey("sys.user.initPassword").then(response => {
+      this.initPassword = response.data;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鐢ㄦ埛鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      treeselect().then(response => {
+        this.deptOptions = response.data;
+      });
+    },
+    // 绛涢�夎妭鐐�
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    // 鑺傜偣鍗曞嚮浜嬩欢
+    handleNodeClick(data) {
+      this.queryParams.deptId = data.id;
+      this.getList();
+    },
+    /** 鏌ヨ宀椾綅鍒楄〃 */
+    getPosts() {
+      listPost().then(response => {
+        this.postOptions = response.rows;
+      });
+    },
+    /** 鏌ヨ瑙掕壊鍒楄〃 */
+    getRoles() {
+      listRole().then(response => {
+        this.roleOptions = response.rows;
+      });
+    },
+    // 鐢ㄦ埛鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚�?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return changeUserStatus(row.userId, row.status);
+        }).then(() => {
+          this.msgSuccess(text + "鎴愬姛");
+        }).catch(function() {
+          row.status = row.status === "0" ? "1" : "0";
+        });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: 100,
+        userName: undefined,
+        nickName: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: []
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.page = 1;
+      this.getList();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.getTreeselect();
+      this.getPosts();
+      this.getRoles();
+      this.open = true;
+      this.title = "娣诲姞鐢ㄦ埛";
+      this.form.password = this.initPassword;
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      this.getPosts();
+      this.getRoles();
+      getUser(row.userId).then(response => {
+        this.form = response.data;
+        this.form.postIds = response.postIds;
+        this.form.roleIds = response.roleIds;
+        this.open = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷"
+      }).then(({ value }) => {
+          resetUserPwd(row.userId, value).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+            } else {
+              this.msgError(response.msg);
+            }
+          });
+        }).catch(() => {});
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          } else {
+            addUser(this.form).then(response => {
+              if (response.code === 200) {
+                this.msgSuccess("鏂板鎴愬姛");
+                this.open = false;
+                this.getList();
+              } else {
+                this.msgError(response.msg);
+              }
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.userName + '"鐨勬暟鎹」?', "璀﹀憡", {
+          confirmButtonText: "纭畾",
+          cancelButtonText: "鍙栨秷",
+          type: "warning"
+        }).then(function() {
+          return delUser(row.userId);
+        }).then(() => {
+          this.getList();
+          this.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(function() {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/profile/index.vue b/ruoyi-ui/src/views/system/user/profile/index.vue
new file mode 100644
index 0000000..3b7a117
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/index.vue
@@ -0,0 +1,101 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <el-col :span="6" :xs="24">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>涓汉淇℃伅</span>
+          </div>
+          <div>
+            <div class="text-center">
+              <userAvatar :user="user" />
+            </div>
+            <ul class="list-group list-group-striped">
+              <li class="list-group-item">
+                <svg-icon icon-class="user" />鐢ㄦ埛鍚嶇О
+                <div class="pull-right">{{ user.userName }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="phone" />鎵嬫満鍙风爜
+                <div class="pull-right">{{ user.phonenumber }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="email" />鐢ㄦ埛閭
+                <div class="pull-right">{{ user.email }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="tree" />鎵�灞為儴闂�
+                <div class="pull-right" v-if="user.dept">{{ user.dept.deptName }} / {{ postGroup }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="peoples" />鎵�灞炶鑹�
+                <div class="pull-right">{{ roleGroup }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="date" />鍒涘缓鏃ユ湡
+                <div class="pull-right">2018-08-23 09:11:56</div>
+              </li>
+            </ul>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="18" :xs="24">
+        <el-card>
+          <div slot="header" class="clearfix">
+            <span>鍩烘湰璧勬枡</span>
+          </div>
+          <el-tabs v-model="activeTab">
+            <el-tab-pane label="鍩烘湰璧勬枡" name="userinfo">
+              <userInfo :user="user" />
+            </el-tab-pane>
+            <el-tab-pane label="淇敼瀵嗙爜" name="resetPwd">
+              <resetPwd :user="user" />
+            </el-tab-pane>
+          </el-tabs>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import userAvatar from "./userAvatar";
+import userInfo from "./userInfo";
+import resetPwd from "./resetPwd";
+import { getUserProfile } from "@/api/system/user";
+
+export default {
+  name: "Profile",
+  components: { userAvatar, userInfo, resetPwd },
+  data() {
+    return {
+      user: {},
+      roleGroup: {},
+      postGroup: {},
+      activeTab: "userinfo"
+    };
+  },
+  created() {
+    this.getUser();
+  },
+  methods: {
+    getUser() {
+      getUserProfile().then(response => {
+        this.user = response.data;
+        this.roleGroup = response.roleGroup;
+        this.postGroup = response.postGroup;
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.avatar-uploader-icon {
+  font-size: 28px;
+  width: 120px;
+  height: 120px;
+  line-height: 120px;
+  text-align: center;
+}
+</style>
diff --git a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
new file mode 100644
index 0000000..380e168
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -0,0 +1,76 @@
+<template>
+  <el-form ref="form" :model="user" :rules="rules" label-width="80px">
+    <el-form-item label="鏃у瘑鐮�" prop="oldPassword">
+      <el-input v-model="user.oldPassword" placeholder="璇疯緭鍏ユ棫瀵嗙爜" type="password" />
+    </el-form-item>
+    <el-form-item label="鏂板瘑鐮�" prop="newPassword">
+      <el-input v-model="user.newPassword" placeholder="璇疯緭鍏ユ柊瀵嗙爜" type="password" />
+    </el-form-item>
+    <el-form-item label="纭瀵嗙爜" prop="confirmPassword">
+      <el-input v-model="user.confirmPassword" placeholder="璇风‘璁ゅ瘑鐮�" type="password" />
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" size="mini" @click="submit">淇濆瓨</el-button>
+      <el-button type="danger" size="mini" @click="close">鍏抽棴</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import { updateUserPwd } from "@/api/system/user";
+
+export default {
+  data() {
+    const equalToPassword = (rule, value, callback) => {
+      if (this.user.newPassword !== value) {
+        callback(new Error("涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�"));
+      } else {
+        callback();
+      }
+    };
+    return {
+      test: "1test",
+      user: {
+        oldPassword: undefined,
+        newPassword: undefined,
+        confirmPassword: undefined
+      },
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        oldPassword: [
+          { required: true, message: "鏃у瘑鐮佷笉鑳戒负绌�", trigger: "blur" }
+        ],
+        newPassword: [
+          { required: true, message: "鏂板瘑鐮佷笉鑳戒负绌�", trigger: "blur" },
+          { min: 6, max: 20, message: "闀垮害鍦� 6 鍒� 20 涓瓧绗�", trigger: "blur" }
+        ],
+        confirmPassword: [
+          { required: true, message: "纭瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          { required: true, validator: equalToPassword, trigger: "blur" }
+        ]
+      }
+    };
+  },
+  methods: {
+    submit() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(
+            response => {
+              if (response.code === 200) {
+                this.msgSuccess("淇敼鎴愬姛");
+              } else {
+                this.msgError(response.msg);
+              }
+            }
+          );
+        }
+      });
+    },
+    close() {
+      this.$store.dispatch("tagsView/delView", this.$route);
+      this.$router.push({ path: "/index" });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
new file mode 100644
index 0000000..bca0493
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
@@ -0,0 +1,135 @@
+<template>
+  <div>
+    <img v-bind:src="options.img" @click="editCropper()" title="鐐瑰嚮涓婁紶澶村儚" class="img-circle img-lg" />
+    <el-dialog :title="title" :visible.sync="open" width="800px">
+      <el-row>
+        <el-col :xs="24" :md="12" :style="{height: '350px'}">
+          <vue-cropper
+            ref="cropper"
+            :img="options.img"
+            :info="true"
+            :autoCrop="options.autoCrop"
+            :autoCropWidth="options.autoCropWidth"
+            :autoCropHeight="options.autoCropHeight"
+            :fixedBox="options.fixedBox"
+            @realTime="realTime"
+          />
+        </el-col>
+        <el-col :xs="24" :md="12" :style="{height: '350px'}">
+          <div class="avatar-upload-preview">
+            <img :src="previews.url" :style="previews.img" />
+          </div>
+        </el-col>
+      </el-row>
+      <br />
+      <el-row>
+        <el-col :lg="2" :md="2">
+          <el-upload :show-file-list="false" :before-upload="beforeUpload">
+            <el-button size="small">
+              涓婁紶
+              <i class="el-icon-upload el-icon--right"></i>
+            </el-button>
+          </el-upload>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 2}" :md="2">
+          <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :md="2">
+          <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :md="2">
+          <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :md="2">
+          <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
+        </el-col>
+        <el-col :lg="{span: 2, offset: 6}" :md="2">
+          <el-button type="primary" size="small" @click="uploadImg()">涓� 浼�</el-button>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import store from "@/store";
+import { VueCropper } from "vue-cropper";
+import { uploadAvatar } from "@/api/system/user";
+
+export default {
+  components: { VueCropper },
+  props: {
+    user: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 寮瑰嚭灞傛爣棰�
+      title: "淇敼澶村儚",
+      options: {
+        img: store.getters.avatar, //瑁佸壀鍥剧墖鐨勫湴鍧�
+        autoCrop: true, // 鏄惁榛樿鐢熸垚鎴浘妗�
+        autoCropWidth: 200, // 榛樿鐢熸垚鎴浘妗嗗搴�
+        autoCropHeight: 200, // 榛樿鐢熸垚鎴浘妗嗛珮搴�
+        fixedBox: true // 鍥哄畾鎴浘妗嗗ぇ灏� 涓嶅厑璁告敼鍙�
+      },
+      previews: {}
+    };
+  },
+  methods: {
+    // 缂栬緫澶村儚
+    editCropper() {
+      this.open = true;
+    },
+    // 鍚戝乏鏃嬭浆
+    rotateLeft() {
+      this.$refs.cropper.rotateLeft();
+    },
+    // 鍚戝彸鏃嬭浆
+    rotateRight() {
+      this.$refs.cropper.rotateRight();
+    },
+    // 鍥剧墖缂╂斁
+    changeScale(num) {
+      num = num || 1;
+      this.$refs.cropper.changeScale(num);
+    },
+    // 涓婁紶棰勫鐞�
+    beforeUpload(file) {
+      if (file.type.indexOf("image/") == -1) {
+        this.msgError("鏂囦欢鏍煎紡閿欒锛岃涓婁紶鍥剧墖绫诲瀷,濡傦細JPG锛孭NG鍚庣紑鐨勬枃浠躲��");
+      } else {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        reader.onload = () => {
+          this.options.img = reader.result;
+        };
+      }
+    },
+    // 涓婁紶鍥剧墖
+    uploadImg() {
+      this.$refs.cropper.getCropBlob(data => {
+        let formData = new FormData();
+        formData.append("avatarfile", data);
+        uploadAvatar(formData).then(response => {
+          if (response.code === 200) {
+            this.open = false;
+            this.options.img = process.env.VUE_APP_BASE_API + response.imgUrl;
+            this.msgSuccess("淇敼鎴愬姛");
+          } else {
+            this.msgError(response.msg);
+          }
+          this.$refs.cropper.clearCrop();
+        });
+      });
+    },
+    // 瀹炴椂棰勮
+    realTime(data) {
+      this.previews = data;
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/profile/userInfo.vue b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
new file mode 100644
index 0000000..2e8ef99
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
@@ -0,0 +1,80 @@
+<template>
+  <el-form ref="form" :model="user" :rules="rules" label-width="80px">
+    <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName">
+      <el-input v-model="user.nickName" />
+    </el-form-item> 
+    <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+      <el-input v-model="user.phonenumber" maxlength="11" />
+    </el-form-item>
+    <el-form-item label="閭" prop="email">
+      <el-input v-model="user.email" maxlength="50" />
+    </el-form-item>
+    <el-form-item label="鎬у埆">
+      <el-radio-group v-model="user.sex">
+        <el-radio label="0">鐢�</el-radio>
+        <el-radio label="1">濂�</el-radio>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" size="mini" @click="submit">淇濆瓨</el-button>
+      <el-button type="danger" size="mini" @click="close">鍏抽棴</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import { updateUserProfile } from "@/api/system/user";
+
+export default {
+  props: {
+    user: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        email: [
+          { required: true, message: "閭鍦板潃涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            type: "email",
+            message: "'璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phonenumber: [
+          { required: true, message: "鎵嬫満鍙风爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  methods: {
+    submit() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          updateUserProfile(this.user).then(response => {
+            if (response.code === 200) {
+              this.msgSuccess("淇敼鎴愬姛");
+            } else {
+              this.msgError(response.msg);
+            }
+          });
+        }
+      });
+    },
+    close() {
+      this.$store.dispatch("tagsView/delView", this.$route);
+      this.$router.push({ path: "/index" });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue
new file mode 100644
index 0000000..9d4496e
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/index.vue
@@ -0,0 +1,5 @@
+<template>
+  <div class="app-container">
+   鏋勫缓宸ュ叿
+  </div>
+</template>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue
new file mode 100644
index 0000000..c0c0673
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/index.vue
@@ -0,0 +1,5 @@
+<template>
+  <div class="app-container">
+   浠g爜鐢熸垚
+  </div>
+</template>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/tool/swagger/index.vue b/ruoyi-ui/src/views/tool/swagger/index.vue
new file mode 100644
index 0000000..00484e2
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/swagger/index.vue
@@ -0,0 +1,25 @@
+<template>
+  <div v-loading="loading" :style="'height:'+ height">
+    <iframe :src="src" frameborder="no" style="width: 100%;height: 100%" scrolling="auto" />
+  </div>
+</template>
+<script>
+export default {
+  data() {
+    return {
+      src: process.env.VUE_APP_BASE_API + "/swagger-ui.html",
+      height: document.documentElement.clientHeight - 94.5 + "px;",
+      loading: true
+    };
+  },
+  mounted: function() {
+    setTimeout(() => {
+      this.loading = false;
+    }, 230);
+    const that = this;
+    window.onresize = function temp() {
+      that.height = document.documentElement.clientHeight - 94.5 + "px;";
+    };
+  }
+};
+</script>
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
new file mode 100644
index 0000000..62589f0
--- /dev/null
+++ b/ruoyi-ui/vue.config.js
@@ -0,0 +1,130 @@
+'use strict'
+const path = require('path')
+const defaultSettings = require('./src/settings.js')
+
+function resolve(dir) {
+  return path.join(__dirname, dir)
+}
+
+const name = defaultSettings.title || '鑻ヤ緷绠$悊绯荤粺' // 鏍囬
+
+const port = process.env.port || process.env.npm_config_port || 80 // 绔彛
+
+// vue.config.js 閰嶇疆璇存槑
+//瀹樻柟vue.config.js 鍙傝�冩枃妗� https://cli.vuejs.org/zh/config/#css-loaderoptions
+// 杩欓噷鍙垪涓�閮ㄥ垎锛屽叿浣撻厤缃弬鑰冩枃妗�
+module.exports = {
+  // 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
+  // 榛樿鎯呭喌涓嬶紝Vue CLI 浼氬亣璁句綘鐨勫簲鐢ㄦ槸琚儴缃插湪涓�涓煙鍚嶇殑鏍硅矾寰勪笂
+  // 渚嬪 https://www.ruoyi.vip/銆傚鏋滃簲鐢ㄨ閮ㄧ讲鍦ㄤ竴涓瓙璺緞涓婏紝浣犲氨闇�瑕佺敤杩欎釜閫夐」鎸囧畾杩欎釜瀛愯矾寰勩�備緥濡傦紝濡傛灉浣犵殑搴旂敤琚儴缃插湪 https://www.ruoyi.vip/admin/锛屽垯璁剧疆 baseUrl 涓� /admin/銆�
+  publicPath: process.env.NODE_ENV === "production" ? "./" : "/",
+  // 鍦╪pm run build 鎴� yarn build 鏃� 锛岀敓鎴愭枃浠剁殑鐩綍鍚嶇О锛堣鍜宐aseUrl鐨勭敓浜х幆澧冭矾寰勪竴鑷达級锛堥粯璁ist锛�
+  outputDir: 'dist',
+  // 鐢ㄤ簬鏀剧疆鐢熸垚鐨勯潤鎬佽祫婧� (js銆乧ss銆乮mg銆乫onts) 鐨勶紱锛堥」鐩墦鍖呬箣鍚庯紝闈欐�佽祫婧愪細鏀惧湪杩欎釜鏂囦欢澶逛笅锛�
+  assetsDir: 'static',
+  // 鏄惁寮�鍚痚slint淇濆瓨妫�娴嬶紝鏈夋晥鍊硷細ture | false | 'error'
+  lintOnSave: process.env.NODE_ENV === 'development',
+  // 濡傛灉浣犱笉闇�瑕佺敓浜х幆澧冪殑 source map锛屽彲浠ュ皢鍏惰缃负 false 浠ュ姞閫熺敓浜х幆澧冩瀯寤恒��
+  productionSourceMap: false,
+  // webpack-dev-server 鐩稿叧閰嶇疆
+  devServer: {
+    host: '0.0.0.0',
+    port: port,
+    proxy: {
+      // detail: https://cli.vuejs.org/config/#devserver-proxy
+      [process.env.VUE_APP_BASE_API]: {
+        target: `http://localhost:8080`,
+        changeOrigin: true,
+        pathRewrite: {
+          ['^' + process.env.VUE_APP_BASE_API]: ''
+        }
+      }
+    },
+    disableHostCheck: true
+  },
+  configureWebpack: {
+    name: name,
+    resolve: {
+      alias: {
+        '@': resolve('src')
+      }
+    }
+  },
+  chainWebpack(config) {
+    config.plugins.delete('preload') // TODO: need test
+    config.plugins.delete('prefetch') // TODO: need test
+
+    // set svg-sprite-loader
+    config.module
+      .rule('svg')
+      .exclude.add(resolve('src/assets/icons'))
+      .end()
+    config.module
+      .rule('icons')
+      .test(/\.svg$/)
+      .include.add(resolve('src/assets/icons'))
+      .end()
+      .use('svg-sprite-loader')
+      .loader('svg-sprite-loader')
+      .options({
+        symbolId: 'icon-[name]'
+      })
+      .end()
+
+    // set preserveWhitespace
+    config.module
+      .rule('vue')
+      .use('vue-loader')
+      .loader('vue-loader')
+      .tap(options => {
+        options.compilerOptions.preserveWhitespace = true
+        return options
+      })
+      .end()
+
+    config
+      // https://webpack.js.org/configuration/devtool/#development
+      .when(process.env.NODE_ENV === 'development',
+        config => config.devtool('cheap-source-map')
+      )
+
+    config
+      .when(process.env.NODE_ENV !== 'development',
+        config => {
+          config
+            .plugin('ScriptExtHtmlWebpackPlugin')
+            .after('html')
+            .use('script-ext-html-webpack-plugin', [{
+            // `runtime` must same as runtimeChunk name. default is `runtime`
+              inline: /runtime\..*\.js$/
+            }])
+            .end()
+          config
+            .optimization.splitChunks({
+              chunks: 'all',
+              cacheGroups: {
+                libs: {
+                  name: 'chunk-libs',
+                  test: /[\\/]node_modules[\\/]/,
+                  priority: 10,
+                  chunks: 'initial' // only package third parties that are initially dependent
+                },
+                elementUI: {
+                  name: 'chunk-elementUI', // split elementUI into a single package
+                  priority: 20, // the weight needs to be larger than libs and app or it will be packaged into libs or app
+                  test: /[\\/]node_modules[\\/]_?element-ui(.*)/ // in order to adapt to cnpm
+                },
+                commons: {
+                  name: 'chunk-commons',
+                  test: resolve('src/components'), // can customize your rules
+                  minChunks: 3, //  minimum common number
+                  priority: 5,
+                  reuseExistingChunk: true
+                }
+              }
+            })
+          config.optimization.runtimeChunk('single')
+        }
+      )
+  }
+}
diff --git a/ruoyi/.gitignore b/ruoyi/.gitignore
new file mode 100644
index 0000000..4916f7a
--- /dev/null
+++ b/ruoyi/.gitignore
@@ -0,0 +1,43 @@
+######################################################################
+# Build Tools
+
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
\ No newline at end of file
diff --git a/ruoyi/bin/clean.bat b/ruoyi/bin/clean.bat
new file mode 100644
index 0000000..e144025
--- /dev/null
+++ b/ruoyi/bin/clean.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 清理生成路径。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean
+
+pause
\ No newline at end of file
diff --git a/ruoyi/bin/package.bat b/ruoyi/bin/package.bat
new file mode 100644
index 0000000..af8af8e
--- /dev/null
+++ b/ruoyi/bin/package.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成war/jar包文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean package -Dmaven.test.skip=true
+
+pause
\ No newline at end of file
diff --git a/ruoyi/bin/run-tomcat.bat b/ruoyi/bin/run-tomcat.bat
new file mode 100644
index 0000000..5d38ad0
--- /dev/null
+++ b/ruoyi/bin/run-tomcat.bat
@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [信息] 使用 Spring Boot Tomcat 运行 Web 工程。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+title %cd%
+set MAVEN_OPTS=%MAVEN_OPTS% -Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+call mvn clean spring-boot:run -Dmaven.test.skip=true -U
+
+pause
\ No newline at end of file
diff --git a/ruoyi/pom.xml b/ruoyi/pom.xml
new file mode 100644
index 0000000..0e04df7
--- /dev/null
+++ b/ruoyi/pom.xml
@@ -0,0 +1,267 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+		 xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+	<groupId>com.ruoyi</groupId>
+	<artifactId>ruoyi</artifactId>
+	<version>1.0</version>
+	<packaging>jar</packaging>
+
+	<name>ruoyi</name>
+	<url>http://www.ruoyi.vip</url>
+	<description>鑻ヤ緷绠$悊绯荤粺</description>
+
+	<parent>
+		<groupId>org.springframework.boot</groupId>
+		<artifactId>spring-boot-starter-parent</artifactId>
+		<version>2.1.1.RELEASE</version>
+		<relativePath />
+	</parent>
+
+	<properties>
+		<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+		<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+		<java.version>1.8</java.version>
+		<mybatis.spring.boot.starter.version>1.3.2</mybatis.spring.boot.starter.version>
+		<pagehelper.spring.boot.starter.version>1.2.5</pagehelper.spring.boot.starter.version>
+		<fastjson.version>1.2.47</fastjson.version>
+		<druid.version>1.1.14</druid.version>
+		<commons.io.version>2.5</commons.io.version>
+		<commons.fileupload.version>1.3.3</commons.fileupload.version>
+		<bitwalker.version>1.19</bitwalker.version>
+		<jwt.version>0.9.0</jwt.version>
+		<swagger.version>2.9.2</swagger.version>
+		<oshi.version>3.9.1</oshi.version>
+	</properties>
+
+	<dependencies>
+
+		<!-- SpringBoot 鏍稿績鍖� -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter</artifactId>
+			<!--
+			 <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-tomcat</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+             -->
+		</dependency>
+
+		<!-- SpringBoot 娴嬭瘯 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-test</artifactId>
+			<scope>test</scope>
+		</dependency>
+
+		<!-- SpringBoot 鎷︽埅鍣� -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+
+		<!-- SpringBoot Web瀹瑰櫒 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		
+		<!-- spring-boot-devtools -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-devtools</artifactId>
+			<optional>true</optional> <!-- 琛ㄧず渚濊禆涓嶄細浼犻�� -->
+		</dependency>
+		
+		<!-- spring security 瀹夊叏璁よ瘉 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-security</artifactId>
+		</dependency>
+		
+		<!-- redis 缂撳瓨鎿嶄綔 -->
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-redis</artifactId>
+		</dependency>
+		
+		<!-- pool 瀵硅薄姹� -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-pool2</artifactId>
+		</dependency>
+
+		<!-- Mysql椹卞姩鍖� -->
+		<dependency>
+			<groupId>mysql</groupId>
+			<artifactId>mysql-connector-java</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+
+		<!-- SpringBoot闆嗘垚mybatis妗嗘灦 -->
+		<dependency>
+			<groupId>org.mybatis.spring.boot</groupId>
+			<artifactId>mybatis-spring-boot-starter</artifactId>
+			<version>${mybatis.spring.boot.starter.version}</version>
+		</dependency>
+		
+		<!-- pagehelper 鍒嗛〉鎻掍欢 -->
+		<dependency>
+			<groupId>com.github.pagehelper</groupId>
+			<artifactId>pagehelper-spring-boot-starter</artifactId>
+			<version>${pagehelper.spring.boot.starter.version}</version>
+		</dependency>
+
+		<!--闃块噷鏁版嵁搴撹繛鎺ユ睜 -->
+		<dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${druid.version}</version>
+        </dependency>
+
+		<!--甯哥敤宸ュ叿绫� -->
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+
+		<!--io甯哥敤宸ュ叿绫� -->
+		<dependency>
+			<groupId>commons-io</groupId>
+			<artifactId>commons-io</artifactId>
+			<version>${commons.io.version}</version>
+		</dependency>
+		
+		<!--鏂囦欢涓婁紶宸ュ叿绫� -->
+		<dependency>
+			<groupId>commons-fileupload</groupId>
+			<artifactId>commons-fileupload</artifactId>
+			<version>${commons.fileupload.version}</version>
+		</dependency>
+		
+		<!-- 瑙f瀽瀹㈡埛绔搷浣滅郴缁熴�佹祻瑙堝櫒绛� -->
+		<dependency>
+			<groupId>eu.bitwalker</groupId>
+			<artifactId>UserAgentUtils</artifactId>
+			<version>${bitwalker.version}</version>
+		</dependency>
+
+		<!-- 闃块噷JSON瑙f瀽鍣� -->
+		<dependency>
+			<groupId>com.alibaba</groupId>
+			<artifactId>fastjson</artifactId>
+			<version>${fastjson.version}</version>
+		</dependency>
+
+		<!--Spring妗嗘灦鍩烘湰鐨勬牳蹇冨伐鍏�-->
+		<dependency>
+			<groupId>org.springframework</groupId>
+			<artifactId>spring-context-support</artifactId>
+		</dependency>
+		
+        <!--Token鐢熸垚涓庤В鏋�-->
+		<dependency>
+			<groupId>io.jsonwebtoken</groupId>
+			<artifactId>jjwt</artifactId>
+			<version>${jwt.version}</version>
+		</dependency>
+		
+		<!-- swagger2-->
+		<dependency>
+			<groupId>io.springfox</groupId>
+			<artifactId>springfox-swagger2</artifactId>
+			<version>${swagger.version}</version>
+			<exclusions>
+			    <exclusion>
+			        <groupId>io.swagger</groupId>
+			        <artifactId>swagger-annotations</artifactId>
+			    </exclusion>
+			    <exclusion>
+			        <groupId>io.swagger</groupId>
+			        <artifactId>swagger-models</artifactId>
+			    </exclusion>
+			</exclusions>
+		</dependency>
+		
+		<!--闃叉杩涘叆swagger椤甸潰鎶ョ被鍨嬭浆鎹㈤敊璇紝鎺掗櫎2.9.2涓殑寮曠敤锛屾墜鍔ㄥ鍔�1.5.21鐗堟湰-->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.5.21</version>
+        </dependency>
+        
+		<!-- swagger2-UI-->
+		<dependency>
+			<groupId>io.springfox</groupId>
+			<artifactId>springfox-swagger-ui</artifactId>
+			<version>${swagger.version}</version>
+		</dependency>
+		
+        <!-- 鑾峰彇绯荤粺淇℃伅 -->
+		<dependency>
+			<groupId>com.github.oshi</groupId>
+			<artifactId>oshi-core</artifactId>
+			<version>${oshi.version}</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>net.java.dev.jna</groupId>
+			<artifactId>jna</artifactId>
+		</dependency>
+		
+		<dependency>
+			<groupId>net.java.dev.jna</groupId>
+			<artifactId>jna-platform</artifactId>
+		</dependency>
+
+	</dependencies>
+
+	<build>
+		<finalName>${project.artifactId}</finalName>
+		<plugins>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<configuration>
+					<fork>true</fork> <!-- 濡傛灉娌℃湁璇ラ厤缃紝devtools涓嶄細鐢熸晥 -->
+				</configuration>
+			</plugin>
+		</plugins>
+	</build>
+
+	<repositories>
+		<repository>
+			<id>public</id>
+			<name>aliyun nexus</name>
+			<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+		</repository>
+	</repositories>
+
+	<pluginRepositories>
+		<pluginRepository>
+			<id>public</id>
+			<name>aliyun nexus</name>
+			<url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+			<releases>
+				<enabled>true</enabled>
+			</releases>
+			<snapshots>
+				<enabled>false</enabled>
+			</snapshots>
+		</pluginRepository>
+	</pluginRepositories>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi/ry.sh b/ruoyi/ry.sh
new file mode 100644
index 0000000..52f80bd
--- /dev/null
+++ b/ruoyi/ry.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+
+AppName=ruoyi.jar
+
+#JVM鍙傛暟
+JVM_OPTS="-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512M -Xmx512M -XX:PermSize=256M -XX:MaxPermSize=512M -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
+APP_HOME=`pwd`
+LOG_PATH=$APP_HOME/logs/$AppName.log
+
+if [ "$1" = "" ];
+then
+    echo -e "\033[0;31m 鏈緭鍏ユ搷浣滃悕 \033[0m  \033[0;34m {start|stop|restart|status} \033[0m"
+    exit 1
+fi
+
+if [ "$AppName" = "" ];
+then
+    echo -e "\033[0;31m 鏈緭鍏ュ簲鐢ㄥ悕 \033[0m"
+    exit 1
+fi
+
+function start()
+{
+    PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
+
+	if [ x"$PID" != x"" ]; then
+	    echo "$AppName is running..."
+	else
+		nohup java -jar  $JVM_OPTS target/$AppName > /dev/null 2>&1 &
+		echo "Start $AppName success..."
+	fi
+}
+
+function stop()
+{
+    echo "Stop $AppName"
+	
+	PID=""
+	query(){
+		PID=`ps -ef |grep java|grep $AppName|grep -v grep|awk '{print $2}'`
+	}
+
+	query
+	if [ x"$PID" != x"" ]; then
+		kill -TERM $PID
+		echo "$AppName (pid:$PID) exiting..."
+		while [ x"$PID" != x"" ]
+		do
+			sleep 1
+			query
+		done
+		echo "$AppName exited."
+	else
+		echo "$AppName already stopped."
+	fi
+}
+
+function restart()
+{
+    stop
+    sleep 2
+    start
+}
+
+function status()
+{
+    PID=`ps -ef |grep java|grep $AppName|grep -v grep|wc -l`
+    if [ $PID != 0 ];then
+        echo "$AppName is running..."
+    else
+        echo "$AppName is not running..."
+    fi
+}
+
+case $1 in
+    start)
+    start;;
+    stop)
+    stop;;
+    restart)
+    restart;;
+    status)
+    status;;
+    *)
+
+esac
diff --git a/ruoyi/sql/ry_20191008.sql b/ruoyi/sql/ry_20191008.sql
new file mode 100644
index 0000000..7d75501
--- /dev/null
+++ b/ruoyi/sql/ry_20191008.sql
@@ -0,0 +1,693 @@
+-- ----------------------------
+-- 1銆侀儴闂ㄨ〃
+-- ----------------------------
+drop table if exists sys_dept;
+create table sys_dept (
+  dept_id           bigint(20)      not null auto_increment    comment '閮ㄩ棬id',
+  parent_id         bigint(20)      default 0                  comment '鐖堕儴闂╥d',
+  ancestors         varchar(50)     default ''                 comment '绁栫骇鍒楄〃',
+  dept_name         varchar(30)     default ''                 comment '閮ㄩ棬鍚嶇О',
+  order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+  leader            varchar(20)     default null               comment '璐熻矗浜�',
+  phone             varchar(11)     default null               comment '鑱旂郴鐢佃瘽',
+  email             varchar(50)     default null               comment '閭',
+  status            char(1)         default '0'                comment '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  primary key (dept_id)
+) engine=innodb auto_increment=200 comment = '閮ㄩ棬琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-閮ㄩ棬琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_dept values(100,  0,   '0',          '鑻ヤ緷绉戞妧',   0, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(101,  100, '0,100',      '娣卞湷鎬诲叕鍙�', 1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(102,  100, '0,100',      '闀挎矙鍒嗗叕鍙�', 2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(103,  101, '0,100,101',  '鐮斿彂閮ㄩ棬',   1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(104,  101, '0,100,101',  '甯傚満閮ㄩ棬',   2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(105,  101, '0,100,101',  '娴嬭瘯閮ㄩ棬',   3, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(106,  101, '0,100,101',  '璐㈠姟閮ㄩ棬',   4, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(107,  101, '0,100,101',  '杩愮淮閮ㄩ棬',   5, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(108,  102, '0,100,102',  '甯傚満閮ㄩ棬',   1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+insert into sys_dept values(109,  102, '0,100,102',  '璐㈠姟閮ㄩ棬',   2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00');
+
+
+-- ----------------------------
+-- 2銆佺敤鎴蜂俊鎭〃
+-- ----------------------------
+drop table if exists sys_user;
+create table sys_user (
+  user_id           bigint(20)      not null auto_increment    comment '鐢ㄦ埛ID',
+  dept_id           bigint(20)      default null               comment '閮ㄩ棬ID',
+  user_name         varchar(30)     not null                   comment '鐢ㄦ埛璐﹀彿',
+  nick_name         varchar(30)     not null                   comment '鐢ㄦ埛鏄电О',
+  user_type         varchar(2)      default '00'               comment '鐢ㄦ埛绫诲瀷锛�00绯荤粺鐢ㄦ埛锛�',
+  email             varchar(50)     default ''                 comment '鐢ㄦ埛閭',
+  phonenumber       varchar(11)     default ''                 comment '鎵嬫満鍙风爜',
+  sex               char(1)         default '0'                comment '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�',
+  avatar            varchar(100)    default ''                 comment '澶村儚鍦板潃',
+  password          varchar(100)    default ''                 comment '瀵嗙爜',
+  status            char(1)         default '0'                comment '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  login_ip          varchar(50)     default ''                 comment '鏈�鍚庣櫥闄咺P',
+  login_date        datetime                                   comment '鏈�鍚庣櫥闄嗘椂闂�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (user_id)
+) engine=innodb auto_increment=100 comment = '鐢ㄦ埛淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_user values(1,  103, 'admin', '鑻ヤ緷', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绠$悊鍛�');
+insert into sys_user values(2,  105, 'ry',    '鑻ヤ緷', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', '2018-03-16 11-33-00', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '娴嬭瘯鍛�');
+
+
+-- ----------------------------
+-- 3銆佸矖浣嶄俊鎭〃
+-- ----------------------------
+drop table if exists sys_post;
+create table sys_post
+(
+  post_id       bigint(20)      not null auto_increment    comment '宀椾綅ID',
+  post_code     varchar(64)     not null                   comment '宀椾綅缂栫爜',
+  post_name     varchar(50)     not null                   comment '宀椾綅鍚嶇О',
+  post_sort     int(4)          not null                   comment '鏄剧ず椤哄簭',
+  status        char(1)         not null                   comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by     varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time   datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by     varchar(64)     default ''			       comment '鏇存柊鑰�',
+  update_time   datetime                                   comment '鏇存柊鏃堕棿',
+  remark        varchar(500)    default null               comment '澶囨敞',
+  primary key (post_id)
+) engine=innodb comment = '宀椾綅淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-宀椾綅淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_post values(1, 'ceo',  '钁d簨闀�',    1, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_post values(2, 'se',   '椤圭洰缁忕悊',  2, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_post values(3, 'hr',   '浜哄姏璧勬簮',  3, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_post values(4, 'user', '鏅�氬憳宸�',  4, '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+
+
+-- ----------------------------
+-- 4銆佽鑹蹭俊鎭〃
+-- ----------------------------
+drop table if exists sys_role;
+create table sys_role (
+  role_id           bigint(20)      not null auto_increment    comment '瑙掕壊ID',
+  role_name         varchar(30)     not null                   comment '瑙掕壊鍚嶇О',
+  role_key          varchar(100)    not null                   comment '瑙掕壊鏉冮檺瀛楃涓�',
+  role_sort         int(4)          not null                   comment '鏄剧ず椤哄簭',
+  data_scope        char(1)         default '1'                comment '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級',
+  status            char(1)         not null                   comment '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (role_id)
+) engine=innodb auto_increment=100 comment = '瑙掕壊淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_role values('1', '绠$悊鍛�',   'admin',  1, 1, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绠$悊鍛�');
+insert into sys_role values('2', '鏅�氳鑹�', 'common', 2, 2, '0', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏅�氳鑹�');
+
+
+-- ----------------------------
+-- 5銆佽彍鍗曟潈闄愯〃
+-- ----------------------------
+drop table if exists sys_menu;
+create table sys_menu (
+  menu_id           bigint(20)      not null auto_increment    comment '鑿滃崟ID',
+  menu_name         varchar(50)     not null                   comment '鑿滃崟鍚嶇О',
+  parent_id         bigint(20)      default 0                  comment '鐖惰彍鍗旾D',
+  order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+  path              varchar(200)    default ''                 comment '璺敱鍦板潃',
+  component         varchar(255)    default null               comment '缁勪欢璺緞',
+  is_frame          int(1)          default 1                  comment '鏄惁涓哄閾撅紙0鏄� 1鍚︼級',
+  menu_type         char(1)         default ''                 comment '鑿滃崟绫诲瀷锛�0鐩綍 1鑿滃崟 2鎸夐挳锛�',
+  visible           char(1)         default 0                  comment '鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛�',
+  perms             varchar(100)    default null               comment '鏉冮檺鏍囪瘑',
+  icon              varchar(100)    default '#'                comment '鑿滃崟鍥炬爣',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default ''                 comment '澶囨敞',
+  primary key (menu_id)
+) engine=innodb auto_increment=2000 comment = '鑿滃崟鏉冮檺琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鑿滃崟淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+-- 涓�绾ц彍鍗�
+insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',   null,  1, 'M', '0', '', 'system',   'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺绠$悊鐩綍');
+insert into sys_menu values('2', '绯荤粺鐩戞帶', '0', '2', 'monitor',  null,  1, 'M', '0', '', 'monitor',  'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺鐩戞帶鐩綍');
+insert into sys_menu values('3', '绯荤粺宸ュ叿', '0', '3', 'tool',     null,  1, 'M', '0', '', 'tool',     'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺宸ュ叿鐩綍');
+INSERT INTO sys_menu VALUES('4', '鑻ヤ緷瀹樼綉', '0', '4', 'http://ruoyi.vip',  NULL ,  0, 'M', '0', '', 'guide',     'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鑻ヤ緷瀹樼綉');
+-- 浜岀骇鑿滃崟
+insert into sys_menu values('100',  '鐢ㄦ埛绠$悊', '1',   '1', 'user',       'system/user/index',        1, 'C', '0', 'system:user:list',        'user',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鐢ㄦ埛绠$悊鑿滃崟');
+insert into sys_menu values('101',  '瑙掕壊绠$悊', '1',   '2', 'role',       'system/role/index',        1, 'C', '0', 'system:role:list',        'peoples',       'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '瑙掕壊绠$悊鑿滃崟');
+insert into sys_menu values('102',  '鑿滃崟绠$悊', '1',   '3', 'menu',       'system/menu/index',        1, 'C', '0', 'system:menu:list',        'tree-table',    'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鑿滃崟绠$悊鑿滃崟');
+insert into sys_menu values('103',  '閮ㄩ棬绠$悊', '1',   '4', 'dept',       'system/dept/index',        1, 'C', '0', 'system:dept:list',        'tree',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '閮ㄩ棬绠$悊鑿滃崟');
+insert into sys_menu values('104',  '宀椾綅绠$悊', '1',   '5', 'post',       'system/post/index',        1, 'C', '0', 'system:post:list',        'post',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '宀椾綅绠$悊鑿滃崟');
+insert into sys_menu values('105',  '瀛楀吀绠$悊', '1',   '6', 'dict',       'system/dict/index',        1, 'C', '0', 'system:dict:list',        'dict',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '瀛楀吀绠$悊鑿滃崟');
+insert into sys_menu values('106',  '鍙傛暟璁剧疆', '1',   '7', 'config',     'system/config/index',      1, 'C', '0', 'system:config:list',      'edit',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍙傛暟璁剧疆鑿滃崟');
+insert into sys_menu values('107',  '閫氱煡鍏憡', '1',   '8', 'notice',     'system/notice/index',      1, 'C', '0', 'system:notice:list',      'message',       'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '閫氱煡鍏憡鑿滃崟');
+insert into sys_menu values('108',  '鏃ュ織绠$悊', '1',   '9', 'log',        'system/log/index',         1, 'M', '0', '',                        'log',           'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏃ュ織绠$悊鑿滃崟');
+insert into sys_menu values('109',  '鍦ㄧ嚎鐢ㄦ埛', '2',   '1', 'online',     'monitor/online/index',     1, 'C', '0', 'monitor:online:list',     'online',        'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+insert into sys_menu values('110',  '瀹氭椂浠诲姟', '2',   '2', 'job',        'monitor/job/index',        1, 'C', '0', 'monitor:job:list',        'job',           'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '瀹氭椂浠诲姟鑿滃崟');
+insert into sys_menu values('111',  '鏁版嵁鐩戞帶', '2',   '3', 'druid',      'monitor/druid/index',      1, 'C', '0', 'monitor:druid:list',      'druid',         'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏁版嵁鐩戞帶鑿滃崟');
+insert into sys_menu values('112',  '鏈嶅姟鐩戞帶', '2',   '4', 'server',     'monitor/server/index',     1, 'C', '0', 'monitor:server:list',     'server',        'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏈嶅姟鐩戞帶鑿滃崟');
+insert into sys_menu values('113',  '琛ㄥ崟鏋勫缓', '3',   '1', 'build',      'tool/build/index',         1 ,'C', '0', 'tool:build:list',         'build',         'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '琛ㄥ崟鏋勫缓鑿滃崟');
+insert into sys_menu values('114',  '浠g爜鐢熸垚', '3',   '2', 'server',     'tool/gen/index',           1, 'C', '0', 'tool:gen:list',           'code',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '浠g爜鐢熸垚鑿滃崟');
+insert into sys_menu values('115',  '绯荤粺鎺ュ彛', '3',   '3', 'swagger',    'tool/swagger/index',       1, 'C', '0', 'tool:swagger:list',       'swagger',       'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺鎺ュ彛鑿滃崟');
+-- 涓夌骇鑿滃崟
+insert into sys_menu values('500',  '鎿嶄綔鏃ュ織', '108', '1', 'operlog',    'monitor/operlog/index',    1, 'C', '0', 'monitor:operlog:list',    'form',          'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎿嶄綔鏃ュ織鑿滃崟');
+insert into sys_menu values('501',  '鐧诲綍鏃ュ織', '108', '2', 'logininfor', 'monitor/logininfor/index', 1, 'C', '0', 'monitor:logininfor:list', 'logininfor',    'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鐧诲綍鏃ュ織鑿滃崟');
+-- 鐢ㄦ埛绠$悊鎸夐挳
+insert into sys_menu values('1001', '鐢ㄦ埛鏌ヨ', '100', '1',  '', '', 1, 'F', '0', 'system:user:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1002', '鐢ㄦ埛鏂板', '100', '2',  '', '', 1, 'F', '0', 'system:user:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1003', '鐢ㄦ埛淇敼', '100', '3',  '', '', 1, 'F', '0', 'system:user:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1004', '鐢ㄦ埛鍒犻櫎', '100', '4',  '', '', 1, 'F', '0', 'system:user:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1005', '鐢ㄦ埛瀵煎嚭', '100', '5',  '', '', 1, 'F', '0', 'system:user:export',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1006', '鐢ㄦ埛瀵煎叆', '100', '6',  '', '', 1, 'F', '0', 'system:user:import',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1007', '閲嶇疆瀵嗙爜', '100', '7',  '', '', 1, 'F', '0', 'system:user:resetPwd',       '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 瑙掕壊绠$悊鎸夐挳
+insert into sys_menu values('1008', '瑙掕壊鏌ヨ', '101', '1',  '', '', 1, 'F', '0', 'system:role:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1009', '瑙掕壊鏂板', '101', '2',  '', '', 1, 'F', '0', 'system:role:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1010', '瑙掕壊淇敼', '101', '3',  '', '', 1, 'F', '0', 'system:role:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1011', '瑙掕壊鍒犻櫎', '101', '4',  '', '', 1, 'F', '0', 'system:role:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1012', '瑙掕壊瀵煎嚭', '101', '5',  '', '', 1, 'F', '0', 'system:role:export',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 鑿滃崟绠$悊鎸夐挳
+insert into sys_menu values('1013', '鑿滃崟鏌ヨ', '102', '1',  '', '', 1, 'F', '0', 'system:menu:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1014', '鑿滃崟鏂板', '102', '2',  '', '', 1, 'F', '0', 'system:menu:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1015', '鑿滃崟淇敼', '102', '3',  '', '', 1, 'F', '0', 'system:menu:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1016', '鑿滃崟鍒犻櫎', '102', '4',  '', '', 1, 'F', '0', 'system:menu:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 閮ㄩ棬绠$悊鎸夐挳
+insert into sys_menu values('1017', '閮ㄩ棬鏌ヨ', '103', '1',  '', '', 1, 'F', '0', 'system:dept:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1018', '閮ㄩ棬鏂板', '103', '2',  '', '', 1, 'F', '0', 'system:dept:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1019', '閮ㄩ棬淇敼', '103', '3',  '', '', 1, 'F', '0', 'system:dept:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1020', '閮ㄩ棬鍒犻櫎', '103', '4',  '', '', 1, 'F', '0', 'system:dept:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 宀椾綅绠$悊鎸夐挳
+insert into sys_menu values('1021', '宀椾綅鏌ヨ', '104', '1',  '', '', 1, 'F', '0', 'system:post:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1022', '宀椾綅鏂板', '104', '2',  '', '', 1, 'F', '0', 'system:post:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1023', '宀椾綅淇敼', '104', '3',  '', '', 1, 'F', '0', 'system:post:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1024', '宀椾綅鍒犻櫎', '104', '4',  '', '', 1, 'F', '0', 'system:post:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1025', '宀椾綅瀵煎嚭', '104', '5',  '', '', 1, 'F', '0', 'system:post:export',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 瀛楀吀绠$悊鎸夐挳
+insert into sys_menu values('1026', '瀛楀吀鏌ヨ', '105', '1', '#', '', 1, 'F', '0', 'system:dict:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1027', '瀛楀吀鏂板', '105', '2', '#', '', 1, 'F', '0', 'system:dict:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1028', '瀛楀吀淇敼', '105', '3', '#', '', 1, 'F', '0', 'system:dict:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1029', '瀛楀吀鍒犻櫎', '105', '4', '#', '', 1, 'F', '0', 'system:dict:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1030', '瀛楀吀瀵煎嚭', '105', '5', '#', '', 1, 'F', '0', 'system:dict:export',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 鍙傛暟璁剧疆鎸夐挳
+insert into sys_menu values('1031', '鍙傛暟鏌ヨ', '106', '1', '#', '', 1, 'F', '0', 'system:config:query',        '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1032', '鍙傛暟鏂板', '106', '2', '#', '', 1, 'F', '0', 'system:config:add',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1033', '鍙傛暟淇敼', '106', '3', '#', '', 1, 'F', '0', 'system:config:edit',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1034', '鍙傛暟鍒犻櫎', '106', '4', '#', '', 1, 'F', '0', 'system:config:remove',       '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1035', '鍙傛暟瀵煎嚭', '106', '5', '#', '', 1, 'F', '0', 'system:config:export',       '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 閫氱煡鍏憡鎸夐挳
+insert into sys_menu values('1036', '鍏憡鏌ヨ', '107', '1', '#', '', 1, 'F', '0', 'system:notice:query',        '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1037', '鍏憡鏂板', '107', '2', '#', '', 1, 'F', '0', 'system:notice:add',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1038', '鍏憡淇敼', '107', '3', '#', '', 1, 'F', '0', 'system:notice:edit',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1039', '鍏憡鍒犻櫎', '107', '4', '#', '', 1, 'F', '0', 'system:notice:remove',       '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 鎿嶄綔鏃ュ織鎸夐挳
+insert into sys_menu values('1040', '鎿嶄綔鏌ヨ', '500', '1', '#', '', 1, 'F', '0', 'monitor:operlog:query',      '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1041', '鎿嶄綔鍒犻櫎', '500', '2', '#', '', 1, 'F', '0', 'monitor:operlog:remove',     '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1042', '鏃ュ織瀵煎嚭', '500', '4', '#', '', 1, 'F', '0', 'monitor:operlog:export',     '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 鐧诲綍鏃ュ織鎸夐挳
+insert into sys_menu values('1043', '鐧诲綍鏌ヨ', '501', '1', '#', '', 1, 'F', '0', 'monitor:logininfor:query',   '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1044', '鐧诲綍鍒犻櫎', '501', '2', '#', '', 1, 'F', '0', 'monitor:logininfor:remove',  '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1045', '鏃ュ織瀵煎嚭', '501', '3', '#', '', 1, 'F', '0', 'monitor:logininfor:export',  '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 鍦ㄧ嚎鐢ㄦ埛鎸夐挳
+insert into sys_menu values('1046', '鍦ㄧ嚎鏌ヨ', '109', '1', '#', '', 1, 'F', '0', 'monitor:online:query',       '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1047', '鎵归噺寮洪��', '109', '2', '#', '', 1, 'F', '0', 'monitor:online:batchLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1048', '鍗曟潯寮洪��', '109', '3', '#', '', 1, 'F', '0', 'monitor:online:forceLogout', '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 瀹氭椂浠诲姟鎸夐挳
+insert into sys_menu values('1049', '浠诲姟鏌ヨ', '110', '1', '#', '', 1, 'F', '0', 'monitor:job:query',          '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1050', '浠诲姟鏂板', '110', '2', '#', '', 1, 'F', '0', 'monitor:job:add',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1051', '浠诲姟淇敼', '110', '3', '#', '', 1, 'F', '0', 'monitor:job:edit',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1052', '浠诲姟鍒犻櫎', '110', '4', '#', '', 1, 'F', '0', 'monitor:job:remove',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1053', '鐘舵�佷慨鏀�', '110', '5', '#', '', 1, 'F', '0', 'monitor:job:changeStatus',   '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1054', '浠诲姟瀵煎嚭', '110', '7', '#', '', 1, 'F', '0', 'monitor:job:export',         '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+-- 浠g爜鐢熸垚鎸夐挳
+insert into sys_menu values('1055', '鐢熸垚鏌ヨ', '114', '1', '#', '', 1, 'F', '0', 'tool:gen:query',             '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1056', '鐢熸垚淇敼', '114', '2', '#', '', 1, 'F', '0', 'tool:gen:edit',              '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1057', '鐢熸垚鍒犻櫎', '114', '3', '#', '', 1, 'F', '0', 'tool:gen:remove',            '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1058', '棰勮浠g爜', '114', '4', '#', '', 1, 'F', '0', 'tool:gen:preview',           '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_menu values('1059', '鐢熸垚浠g爜', '114', '5', '#', '', 1, 'F', '0', 'tool:gen:code',              '#', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+
+
+-- ----------------------------
+-- 6銆佺敤鎴峰拰瑙掕壊鍏宠仈琛�  鐢ㄦ埛N-1瑙掕壊
+-- ----------------------------
+drop table if exists sys_user_role;
+create table sys_user_role (
+  user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  primary key(user_id, role_id)
+) engine=innodb comment = '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛鍜岃鑹插叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_role values ('1', '1');
+insert into sys_user_role values ('2', '2');
+
+
+-- ----------------------------
+-- 7銆佽鑹插拰鑿滃崟鍏宠仈琛�  瑙掕壊1-N鑿滃崟
+-- ----------------------------
+drop table if exists sys_role_menu;
+create table sys_role_menu (
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  menu_id   bigint(20) not null comment '鑿滃崟ID',
+  primary key(role_id, menu_id)
+) engine=innodb comment = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_menu values ('2', '1');
+insert into sys_role_menu values ('2', '2');
+insert into sys_role_menu values ('2', '3');
+insert into sys_role_menu values ('2', '4');
+insert into sys_role_menu values ('2', '100');
+insert into sys_role_menu values ('2', '101');
+insert into sys_role_menu values ('2', '102');
+insert into sys_role_menu values ('2', '103');
+insert into sys_role_menu values ('2', '104');
+insert into sys_role_menu values ('2', '105');
+insert into sys_role_menu values ('2', '106');
+insert into sys_role_menu values ('2', '107');
+insert into sys_role_menu values ('2', '108');
+insert into sys_role_menu values ('2', '109');
+insert into sys_role_menu values ('2', '110');
+insert into sys_role_menu values ('2', '111');
+insert into sys_role_menu values ('2', '112');
+insert into sys_role_menu values ('2', '113');
+insert into sys_role_menu values ('2', '114');
+insert into sys_role_menu values ('2', '115');
+insert into sys_role_menu values ('2', '500');
+insert into sys_role_menu values ('2', '501');
+insert into sys_role_menu values ('2', '1000');
+insert into sys_role_menu values ('2', '1001');
+insert into sys_role_menu values ('2', '1002');
+insert into sys_role_menu values ('2', '1003');
+insert into sys_role_menu values ('2', '1004');
+insert into sys_role_menu values ('2', '1005');
+insert into sys_role_menu values ('2', '1006');
+insert into sys_role_menu values ('2', '1007');
+insert into sys_role_menu values ('2', '1008');
+insert into sys_role_menu values ('2', '1009');
+insert into sys_role_menu values ('2', '1010');
+insert into sys_role_menu values ('2', '1011');
+insert into sys_role_menu values ('2', '1012');
+insert into sys_role_menu values ('2', '1013');
+insert into sys_role_menu values ('2', '1014');
+insert into sys_role_menu values ('2', '1015');
+insert into sys_role_menu values ('2', '1016');
+insert into sys_role_menu values ('2', '1017');
+insert into sys_role_menu values ('2', '1018');
+insert into sys_role_menu values ('2', '1019');
+insert into sys_role_menu values ('2', '1020');
+insert into sys_role_menu values ('2', '1021');
+insert into sys_role_menu values ('2', '1022');
+insert into sys_role_menu values ('2', '1023');
+insert into sys_role_menu values ('2', '1024');
+insert into sys_role_menu values ('2', '1025');
+insert into sys_role_menu values ('2', '1026');
+insert into sys_role_menu values ('2', '1027');
+insert into sys_role_menu values ('2', '1028');
+insert into sys_role_menu values ('2', '1029');
+insert into sys_role_menu values ('2', '1030');
+insert into sys_role_menu values ('2', '1031');
+insert into sys_role_menu values ('2', '1032');
+insert into sys_role_menu values ('2', '1033');
+insert into sys_role_menu values ('2', '1034');
+insert into sys_role_menu values ('2', '1035');
+insert into sys_role_menu values ('2', '1036');
+insert into sys_role_menu values ('2', '1037');
+insert into sys_role_menu values ('2', '1038');
+insert into sys_role_menu values ('2', '1039');
+insert into sys_role_menu values ('2', '1040');
+insert into sys_role_menu values ('2', '1041');
+insert into sys_role_menu values ('2', '1042');
+insert into sys_role_menu values ('2', '1043');
+insert into sys_role_menu values ('2', '1044');
+insert into sys_role_menu values ('2', '1045');
+insert into sys_role_menu values ('2', '1046');
+insert into sys_role_menu values ('2', '1047');
+insert into sys_role_menu values ('2', '1048');
+insert into sys_role_menu values ('2', '1049');
+insert into sys_role_menu values ('2', '1050');
+insert into sys_role_menu values ('2', '1051');
+insert into sys_role_menu values ('2', '1052');
+insert into sys_role_menu values ('2', '1053');
+insert into sys_role_menu values ('2', '1054');
+insert into sys_role_menu values ('2', '1055');
+insert into sys_role_menu values ('2', '1056');
+insert into sys_role_menu values ('2', '1057');
+insert into sys_role_menu values ('2', '1058');
+insert into sys_role_menu values ('2', '1059');
+
+-- ----------------------------
+-- 8銆佽鑹插拰閮ㄩ棬鍏宠仈琛�  瑙掕壊1-N閮ㄩ棬
+-- ----------------------------
+drop table if exists sys_role_dept;
+create table sys_role_dept (
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  dept_id   bigint(20) not null comment '閮ㄩ棬ID',
+  primary key(role_id, dept_id)
+) engine=innodb comment = '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_dept values ('2', '100');
+insert into sys_role_dept values ('2', '101');
+insert into sys_role_dept values ('2', '105');
+
+
+-- ----------------------------
+-- 9銆佺敤鎴蜂笌宀椾綅鍏宠仈琛�  鐢ㄦ埛1-N宀椾綅
+-- ----------------------------
+drop table if exists sys_user_post;
+create table sys_user_post
+(
+  user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+  post_id   bigint(20) not null comment '宀椾綅ID',
+  primary key (user_id, post_id)
+) engine=innodb comment = '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_post values ('1', '1');
+insert into sys_user_post values ('2', '2');
+
+
+-- ----------------------------
+-- 10銆佹搷浣滄棩蹇楄褰�
+-- ----------------------------
+drop table if exists sys_oper_log;
+create table sys_oper_log (
+  oper_id           bigint(20)      not null auto_increment    comment '鏃ュ織涓婚敭',
+  title             varchar(50)     default ''                 comment '妯″潡鏍囬',
+  business_type     int(2)          default 0                  comment '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�',
+  method            varchar(100)    default ''                 comment '鏂规硶鍚嶇О',
+  request_method    varchar(10)     default ''                 comment '璇锋眰鏂瑰紡',
+  operator_type     int(1)          default 0                  comment '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級',
+  oper_name         varchar(50)     default ''                 comment '鎿嶄綔浜哄憳',
+  dept_name         varchar(50)     default ''                 comment '閮ㄩ棬鍚嶇О',
+  oper_url          varchar(255)    default ''                 comment '璇锋眰URL',
+  oper_ip           varchar(50)     default ''                 comment '涓绘満鍦板潃',
+  oper_location     varchar(255)    default ''                 comment '鎿嶄綔鍦扮偣',
+  oper_param        varchar(2000)   default ''                 comment '璇锋眰鍙傛暟',
+  json_result       varchar(2000)   default ''                 comment '杩斿洖鍙傛暟',
+  status            int(1)          default 0                  comment '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�',
+  error_msg         varchar(2000)   default ''                 comment '閿欒娑堟伅',
+  oper_time         datetime                                   comment '鎿嶄綔鏃堕棿',
+  primary key (oper_id)
+) engine=innodb auto_increment=100 comment = '鎿嶄綔鏃ュ織璁板綍';
+
+
+-- ----------------------------
+-- 11銆佸瓧鍏哥被鍨嬭〃
+-- ----------------------------
+drop table if exists sys_dict_type;
+create table sys_dict_type
+(
+  dict_id          bigint(20)      not null auto_increment    comment '瀛楀吀涓婚敭',
+  dict_name        varchar(100)    default ''                 comment '瀛楀吀鍚嶇О',
+  dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+  status           char(1)         default '0'                comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by        varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by        varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time      datetime                                   comment '鏇存柊鏃堕棿',
+  remark           varchar(500)    default null               comment '澶囨敞',
+  primary key (dict_id),
+  unique (dict_type)
+) engine=innodb auto_increment=100 comment = '瀛楀吀绫诲瀷琛�';
+
+insert into sys_dict_type values(1,  '鐢ㄦ埛鎬у埆', 'sys_user_sex',        '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鐢ㄦ埛鎬у埆鍒楄〃');
+insert into sys_dict_type values(2,  '鑿滃崟鐘舵��', 'sys_show_hide',       '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鑿滃崟鐘舵�佸垪琛�');
+insert into sys_dict_type values(3,  '绯荤粺寮�鍏�', 'sys_normal_disable',  '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺寮�鍏冲垪琛�');
+insert into sys_dict_type values(4,  '浠诲姟鐘舵��', 'sys_job_status',      '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '浠诲姟鐘舵�佸垪琛�');
+insert into sys_dict_type values(5,  '浠诲姟鍒嗙粍', 'sys_job_group',       '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '浠诲姟鍒嗙粍鍒楄〃');
+insert into sys_dict_type values(6,  '绯荤粺鏄惁', 'sys_yes_no',          '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺鏄惁鍒楄〃');
+insert into sys_dict_type values(7,  '閫氱煡绫诲瀷', 'sys_notice_type',     '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '閫氱煡绫诲瀷鍒楄〃');
+insert into sys_dict_type values(8,  '閫氱煡鐘舵��', 'sys_notice_status',   '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '閫氱煡鐘舵�佸垪琛�');
+insert into sys_dict_type values(9,  '鎿嶄綔绫诲瀷', 'sys_oper_type',       '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎿嶄綔绫诲瀷鍒楄〃');
+insert into sys_dict_type values(10, '绯荤粺鐘舵��', 'sys_common_status',   '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鐧诲綍鐘舵�佸垪琛�');
+
+
+-- ----------------------------
+-- 12銆佸瓧鍏告暟鎹〃
+-- ----------------------------
+drop table if exists sys_dict_data;
+create table sys_dict_data
+(
+  dict_code        bigint(20)      not null auto_increment    comment '瀛楀吀缂栫爜',
+  dict_sort        int(4)          default 0                  comment '瀛楀吀鎺掑簭',
+  dict_label       varchar(100)    default ''                 comment '瀛楀吀鏍囩',
+  dict_value       varchar(100)    default ''                 comment '瀛楀吀閿��',
+  dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+  css_class        varchar(100)    default null               comment '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�',
+  list_class       varchar(100)    default null               comment '琛ㄦ牸鍥炴樉鏍峰紡',
+  is_default       char(1)         default 'N'                comment '鏄惁榛樿锛圷鏄� N鍚︼級',
+  status           char(1)         default '0'                comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by        varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by        varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time      datetime                                   comment '鏇存柊鏃堕棿',
+  remark           varchar(500)    default null               comment '澶囨敞',
+  primary key (dict_code)
+) engine=innodb auto_increment=100 comment = '瀛楀吀鏁版嵁琛�';
+
+insert into sys_dict_data values(1,  1,  '鐢�',       '0',       'sys_user_sex',        '',   '',        'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎬у埆鐢�');
+insert into sys_dict_data values(2,  2,  '濂�',       '1',       'sys_user_sex',        '',   '',        'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎬у埆濂�');
+insert into sys_dict_data values(3,  3,  '鏈煡',     '2',       'sys_user_sex',        '',   '',        'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎬у埆鏈煡');
+insert into sys_dict_data values(4,  1,  '鏄剧ず',     '0',       'sys_show_hide',       '',   'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏄剧ず鑿滃崟');
+insert into sys_dict_data values(5,  2,  '闅愯棌',     '1',       'sys_show_hide',       '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '闅愯棌鑿滃崟');
+insert into sys_dict_data values(6,  1,  '姝e父',     '0',       'sys_normal_disable',  '',   'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '姝e父鐘舵��');
+insert into sys_dict_data values(7,  2,  '鍋滅敤',     '1',       'sys_normal_disable',  '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍋滅敤鐘舵��');
+insert into sys_dict_data values(8,  1,  '姝e父',     '0',       'sys_job_status',      '',   'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '姝e父鐘舵��');
+insert into sys_dict_data values(9,  2,  '鏆傚仠',     '1',       'sys_job_status',      '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍋滅敤鐘舵��');
+insert into sys_dict_data values(10, 1,  '榛樿',     'DEFAULT', 'sys_job_group',       '',   '',        'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '榛樿鍒嗙粍');
+insert into sys_dict_data values(11, 2,  '绯荤粺',     'SYSTEM',  'sys_job_group',       '',   '',        'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺鍒嗙粍');
+insert into sys_dict_data values(12, 1,  '鏄�',       'Y',       'sys_yes_no',          '',   'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺榛樿鏄�');
+insert into sys_dict_data values(13, 2,  '鍚�',       'N',       'sys_yes_no',          '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绯荤粺榛樿鍚�');
+insert into sys_dict_data values(14, 1,  '閫氱煡',     '1',       'sys_notice_type',     '',   'warning', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '閫氱煡');
+insert into sys_dict_data values(15, 2,  '鍏憡',     '2',       'sys_notice_type',     '',   'success', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍏憡');
+insert into sys_dict_data values(16, 1,  '姝e父',     '0',       'sys_notice_status',   '',   'primary', 'Y', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '姝e父鐘舵��');
+insert into sys_dict_data values(17, 2,  '鍏抽棴',     '1',       'sys_notice_status',   '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍏抽棴鐘舵��');
+insert into sys_dict_data values(18, 1,  '鏂板',     '1',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鏂板鎿嶄綔');
+insert into sys_dict_data values(19, 2,  '淇敼',     '2',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '淇敼鎿嶄綔');
+insert into sys_dict_data values(20, 3,  '鍒犻櫎',     '3',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍒犻櫎鎿嶄綔');
+insert into sys_dict_data values(21, 4,  '鎺堟潈',     '4',       'sys_oper_type',       '',   'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鎺堟潈鎿嶄綔');
+insert into sys_dict_data values(22, 5,  '瀵煎嚭',     '5',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '瀵煎嚭鎿嶄綔');
+insert into sys_dict_data values(23, 6,  '瀵煎叆',     '6',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '瀵煎叆鎿嶄綔');
+insert into sys_dict_data values(24, 7,  '寮洪��',     '7',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '寮洪��鎿嶄綔');
+insert into sys_dict_data values(25, 8,  '鐢熸垚浠g爜', '8',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鐢熸垚鎿嶄綔');
+insert into sys_dict_data values(26, 9,  '娓呯┖鏁版嵁', '9',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '娓呯┖鎿嶄綔');
+insert into sys_dict_data values(27, 1,  '鎴愬姛',     '0',       'sys_common_status',   '',   'primary', 'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '姝e父鐘舵��');
+insert into sys_dict_data values(28, 2,  '澶辫触',     '1',       'sys_common_status',   '',   'danger',  'N', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍋滅敤鐘舵��');
+
+
+-- ----------------------------
+-- 13銆佸弬鏁伴厤缃〃
+-- ----------------------------
+drop table if exists sys_config;
+create table sys_config (
+  config_id         int(5)          not null auto_increment    comment '鍙傛暟涓婚敭',
+  config_name       varchar(100)    default ''                 comment '鍙傛暟鍚嶇О',
+  config_key        varchar(100)    default ''                 comment '鍙傛暟閿悕',
+  config_value      varchar(500)    default ''                 comment '鍙傛暟閿��',
+  config_type       char(1)         default 'N'                comment '绯荤粺鍐呯疆锛圷鏄� N鍚︼級',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (config_id)
+) engine=innodb auto_increment=100 comment = '鍙傛暟閰嶇疆琛�';
+
+insert into sys_config values(1, '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О', 'sys.index.skinName',     'skin-blue',     'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',     'sys.user.initPassword',  '123456',        'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '涓绘鏋堕〉-渚ц竟鏍忎富棰�',       'sys.index.sideTheme',    'theme-dark',    'Y', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+
+
+-- ----------------------------
+-- 14銆佺郴缁熻闂褰�
+-- ----------------------------
+drop table if exists sys_logininfor;
+create table sys_logininfor (
+  info_id        bigint(20)     not null auto_increment   comment '璁块棶ID',
+  user_name      varchar(50)    default ''                comment '鐢ㄦ埛璐﹀彿',
+  ipaddr         varchar(50)    default ''                comment '鐧诲綍IP鍦板潃',
+  login_location varchar(255)   default ''                comment '鐧诲綍鍦扮偣',
+  browser        varchar(50)    default ''                comment '娴忚鍣ㄧ被鍨�',
+  os             varchar(50)    default ''                comment '鎿嶄綔绯荤粺',
+  status         char(1)        default '0'               comment '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�',
+  msg            varchar(255)   default ''                comment '鎻愮ず娑堟伅',
+  login_time     datetime                                 comment '璁块棶鏃堕棿',
+  primary key (info_id)
+) engine=innodb auto_increment=100 comment = '绯荤粺璁块棶璁板綍';
+
+
+-- ----------------------------
+-- 15銆佸湪绾跨敤鎴疯褰�
+-- ----------------------------
+drop table if exists sys_user_online;
+create table sys_user_online (
+  sessionId         varchar(50)   default ''                comment '鐢ㄦ埛浼氳瘽id',
+  user_name         varchar(50)   default ''                comment '鐢ㄦ埛璐﹀彿',
+  dept_name         varchar(50)   default ''                comment '閮ㄩ棬鍚嶇О',
+  ipaddr            varchar(50)   default ''                comment '鐧诲綍IP鍦板潃',
+  login_location    varchar(255)  default ''                comment '鐧诲綍鍦扮偣',
+  browser           varchar(50)   default ''                comment '娴忚鍣ㄧ被鍨�',
+  os                varchar(50)   default ''                comment '鎿嶄綔绯荤粺',
+  status            varchar(10)   default ''                comment '鍦ㄧ嚎鐘舵�乷n_line鍦ㄧ嚎off_line绂荤嚎',
+  start_timestamp   datetime                                comment 'session鍒涘缓鏃堕棿',
+  last_access_time  datetime                                comment 'session鏈�鍚庤闂椂闂�',
+  expire_time       int(5)        default 0                 comment '瓒呮椂鏃堕棿锛屽崟浣嶄负鍒嗛挓',
+  primary key (sessionId)
+) engine=innodb comment = '鍦ㄧ嚎鐢ㄦ埛璁板綍';
+
+
+-- ----------------------------
+-- 16銆佸畾鏃朵换鍔¤皟搴﹁〃
+-- ----------------------------
+drop table if exists sys_job;
+create table sys_job (
+  job_id              bigint(20)    not null auto_increment    comment '浠诲姟ID',
+  job_name            varchar(64)   default ''                 comment '浠诲姟鍚嶇О',
+  job_group           varchar(64)   default 'DEFAULT'          comment '浠诲姟缁勫悕',
+  invoke_target       varchar(500)  not null                   comment '璋冪敤鐩爣瀛楃涓�',
+  cron_expression     varchar(255)  default ''                 comment 'cron鎵ц琛ㄨ揪寮�',
+  misfire_policy      varchar(20)   default '3'                comment '璁″垝鎵ц閿欒绛栫暐锛�1绔嬪嵆鎵ц 2鎵ц涓�娆� 3鏀惧純鎵ц锛�',
+  concurrent          char(1)       default '1'                comment '鏄惁骞跺彂鎵ц锛�0鍏佽 1绂佹锛�',
+  status              char(1)       default '0'                comment '鐘舵�侊紙0姝e父 1鏆傚仠锛�',
+  create_by           varchar(64)   default ''                 comment '鍒涘缓鑰�',
+  create_time         datetime                                 comment '鍒涘缓鏃堕棿',
+  update_by           varchar(64)   default ''                 comment '鏇存柊鑰�',
+  update_time         datetime                                 comment '鏇存柊鏃堕棿',
+  remark              varchar(500)  default ''                 comment '澶囨敞淇℃伅',
+  primary key (job_id, job_name, job_group)
+) engine=innodb auto_increment=100 comment = '瀹氭椂浠诲姟璋冨害琛�';
+
+insert into sys_job values(1, '绯荤粺榛樿锛堟棤鍙傦級', 'DEFAULT', 'ryTask.ryNoParams',        '0/10 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_job values(2, '绯荤粺榛樿锛堟湁鍙傦級', 'DEFAULT', 'ryTask.ryParams(\'ry\')',  '0/15 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+insert into sys_job values(3, '绯荤粺榛樿锛堝鍙傦級', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)',  '0/20 * * * * ?', '3', '1', '1', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '');
+
+
+-- ----------------------------
+-- 17銆佸畾鏃朵换鍔¤皟搴︽棩蹇楄〃
+-- ----------------------------
+drop table if exists sys_job_log;
+create table sys_job_log (
+  job_log_id          bigint(20)     not null auto_increment    comment '浠诲姟鏃ュ織ID',
+  job_name            varchar(64)    not null                   comment '浠诲姟鍚嶇О',
+  job_group           varchar(64)    not null                   comment '浠诲姟缁勫悕',
+  invoke_target       varchar(500)   not null                   comment '璋冪敤鐩爣瀛楃涓�',
+  job_message         varchar(500)                              comment '鏃ュ織淇℃伅',
+  status              char(1)        default '0'                comment '鎵ц鐘舵�侊紙0姝e父 1澶辫触锛�',
+  exception_info      varchar(2000)  default ''                 comment '寮傚父淇℃伅',
+  create_time         datetime                                  comment '鍒涘缓鏃堕棿',
+  primary key (job_log_id)
+) engine=innodb comment = '瀹氭椂浠诲姟璋冨害鏃ュ織琛�';
+
+
+-- ----------------------------
+-- 18銆侀�氱煡鍏憡琛�
+-- ----------------------------
+drop table if exists sys_notice;
+create table sys_notice (
+  notice_id         int(4)          not null auto_increment    comment '鍏憡ID',
+  notice_title      varchar(50)     not null                   comment '鍏憡鏍囬',
+  notice_type       char(1)         not null                   comment '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
+  notice_content    varchar(2000)   default null               comment '鍏憡鍐呭',
+  status            char(1)         default '0'                comment '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(255)    default null               comment '澶囨敞',
+  primary key (notice_id)
+) engine=innodb auto_increment=10 comment = '閫氱煡鍏憡琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鍏憡淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_notice values('1', '娓╅Θ鎻愰啋锛�2018-07-01 鑻ヤ緷鏂扮増鏈彂甯冨暒', '2', '鏂扮増鏈唴瀹�', '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绠$悊鍛�');
+insert into sys_notice values('2', '缁存姢閫氱煡锛�2018-07-01 鑻ヤ緷绯荤粺鍑屾櫒缁存姢', '1', '缁存姢鍐呭',   '0', 'admin', '2018-03-16 11-33-00', 'ry', '2018-03-16 11-33-00', '绠$悊鍛�');
+
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+drop table if exists gen_table;
+create table gen_table (
+  table_id          bigint(20)      not null auto_increment    comment '缂栧彿',
+  table_name        varchar(200)    default ''                 comment '琛ㄥ悕绉�',
+  table_comment     varchar(500)    default ''                 comment '琛ㄦ弿杩�',
+  class_name        varchar(100)    default ''                 comment '瀹炰綋绫诲悕绉�',
+  tpl_category      varchar(200)    default 'crud'             comment '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�',
+  package_name      varchar(100)                               comment '鐢熸垚鍖呰矾寰�',
+  module_name       varchar(30)                                comment '鐢熸垚妯″潡鍚�',
+  business_name     varchar(30)                                comment '鐢熸垚涓氬姟鍚�',
+  function_name     varchar(50)                                comment '鐢熸垚鍔熻兘鍚�',
+  function_author   varchar(50)                                comment '鐢熸垚鍔熻兘浣滆��',
+  options           varchar(1000)                              comment '鍏跺畠鐢熸垚閫夐」',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (table_id)
+) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛�';
+
+
+-- ----------------------------
+-- 20銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+drop table if exists gen_table_column;
+create table gen_table_column (
+  column_id         bigint(20)      not null auto_increment    comment '缂栧彿',
+  table_id          varchar(64)                                comment '褰掑睘琛ㄧ紪鍙�',
+  column_name       varchar(200)                               comment '鍒楀悕绉�',
+  column_comment    varchar(500)                               comment '鍒楁弿杩�',
+  column_type       varchar(100)                               comment '鍒楃被鍨�',
+  java_type         varchar(500)                               comment 'JAVA绫诲瀷',
+  java_field        varchar(200)                               comment 'JAVA瀛楁鍚�',
+  is_pk             char(1)                                    comment '鏄惁涓婚敭锛�1鏄級',
+  is_increment      char(1)                                    comment '鏄惁鑷锛�1鏄級',
+  is_required       char(1)                                    comment '鏄惁蹇呭~锛�1鏄級',
+  is_insert         char(1)                                    comment '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級',
+  is_edit           char(1)                                    comment '鏄惁缂栬緫瀛楁锛�1鏄級',
+  is_list           char(1)                                    comment '鏄惁鍒楄〃瀛楁锛�1鏄級',
+  is_query          char(1)                                    comment '鏄惁鏌ヨ瀛楁锛�1鏄級',
+  query_type        varchar(200)    default 'EQ'               comment '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級',
+  html_type         varchar(200)                               comment '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級',
+  dict_type         varchar(200)    default ''                 comment '瀛楀吀绫诲瀷',
+  sort              int                                        comment '鎺掑簭',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  primary key (column_id)
+) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi/src/main/java/com/ruoyi/RuoYiApplication.java
new file mode 100644
index 0000000..e3c56ee
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -0,0 +1,30 @@
+package com.ruoyi;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 鍚姩绋嬪簭
+ * 
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+public class RuoYiApplication
+{
+    public static void main(String[] args)
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(RuoYiApplication.class, args);
+        System.out.println("(鈾モ棤鈥库棤)锞夛緸  鑻ヤ緷鍚姩鎴愬姛   醿�(麓凇`醿�)锞�  \n" +
+                " .-------.       ____     __        \n" +
+                " |  _ _   \\      \\   \\   /  /    \n" +
+                " | ( ' )  |       \\  _. /  '       \n" +
+                " |(_ o _) /        _( )_ .'         \n" +
+                " | (_,_).' __  ___(_ o _)'          \n" +
+                " |  |\\ \\  |  ||   |(_,_)'         \n" +
+                " |  | \\ `'   /|   `-'  /           \n" +
+                " |  |  \\    /  \\      /           \n" +
+                " ''-'   `'-'    `-..-'              ");
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/ruoyi/src/main/java/com/ruoyi/RuoYiServletInitializer.java
new file mode 100644
index 0000000..9d82a23
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/RuoYiServletInitializer.java
@@ -0,0 +1,18 @@
+package com.ruoyi;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web瀹瑰櫒涓繘琛岄儴缃�
+ * 
+ * @author ruoyi
+ */
+public class RuoYiServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(RuoYiApplication.class);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi/src/main/java/com/ruoyi/common/constant/Constants.java
new file mode 100644
index 0000000..ed4e471
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -0,0 +1,96 @@
+package com.ruoyi.common.constant;
+
+import io.jsonwebtoken.Claims;
+
+/**
+ * 閫氱敤甯搁噺淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Constants
+{
+    /**
+     * 閫氱敤鎴愬姛鏍囪瘑
+     */
+    public static final String SUCCESS = "0";
+
+    /**
+     * 閫氱敤澶辫触鏍囪瘑
+     */
+    public static final String FAIL = "1";
+
+    /**
+     * 鐧诲綍鎴愬姛
+     */
+    public static final String LOGIN_SUCCESS = "Success";
+
+    /**
+     * 娉ㄩ攢
+     */
+    public static final String LOGOUT = "Logout";
+
+    /**
+     * 鐧诲綍澶辫触
+     */
+    public static final String LOGIN_FAIL = "Error";
+
+    /**
+     * 楠岃瘉鐮� redis key
+     */
+    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    /**
+     * 鐧诲綍鐢ㄦ埛 redis key
+     */
+    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 楠岃瘉鐮佹湁鏁堟湡锛堝垎閽燂級
+     */
+    public static final Integer CAPTCHA_EXPIRATION = 2;
+
+    /**
+     * 浠ょ墝
+     */
+    public static final String TOKEN = "token";
+
+    /**
+     * 浠ょ墝鍓嶇紑
+     */
+    public static final String TOKEN_PREFIX = "Bearer ";
+
+    /**
+     * 浠ょ墝鍓嶇紑
+     */
+    public static final String LOGIN_USER_KEY = "login_user_key";
+
+    /**
+     * 鐢ㄦ埛ID
+     */
+    public static final String JWT_USERID = "userid";
+
+    /**
+     * 鐢ㄦ埛鍚嶇О
+     */
+    public static final String JWT_USERNAME = Claims.SUBJECT;
+
+    /**
+     * 鐢ㄦ埛澶村儚
+     */
+    public static final String JWT_AVATAR = "avatar";
+
+    /**
+     * 鍒涘缓鏃堕棿
+     */
+    public static final String JWT_CREATED = "created";
+
+    /**
+     * 鐢ㄦ埛鏉冮檺
+     */
+    public static final String JWT_AUTHORITIES = "authorities";
+
+    /**
+     * 璧勬簮鏄犲皠璺緞 鍓嶇紑
+     */
+    public static final String RESOURCE_PREFIX = "/profile";
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/ruoyi/src/main/java/com/ruoyi/common/constant/HttpStatus.java
new file mode 100644
index 0000000..ffdb56d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/constant/HttpStatus.java
@@ -0,0 +1,89 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 杩斿洖鐘舵�佺爜
+ * 
+ * @author ruoyi
+ */
+public interface HttpStatus
+{
+    /**
+     * 鎿嶄綔鎴愬姛
+     */
+    public static final int SUCCESS = 200;
+
+    /**
+     * 瀵硅薄鍒涘缓鎴愬姛
+     */
+    public static final int CREATED = 201;
+
+    /**
+     * 璇锋眰宸茬粡琚帴鍙�
+     */
+    public static final int ACCEPTED = 202;
+
+    /**
+     * 鎿嶄綔宸茬粡鎵ц鎴愬姛锛屼絾鏄病鏈夎繑鍥炴暟鎹�
+     */
+    public static final int NO_CONTENT = 204;
+
+    /**
+     * 璧勬簮宸茶绉婚櫎
+     */
+    public static final int MOVED_PERM = 301;
+
+    /**
+     * 閲嶅畾鍚�
+     */
+    public static final int SEE_OTHER = 303;
+
+    /**
+     * 璧勬簮娌℃湁琚慨鏀�
+     */
+    public static final int NOT_MODIFIED = 304;
+
+    /**
+     * 鍙傛暟鍒楄〃閿欒锛堢己灏戯紝鏍煎紡涓嶅尮閰嶏級
+     */
+    public static final int BAD_REQUEST = 400;
+
+    /**
+     * 鏈巿鏉�
+     */
+    public static final int UNAUTHORIZED = 401;
+
+    /**
+     * 璁块棶鍙楅檺锛屾巿鏉冭繃鏈�
+     */
+    public static final int FORBIDDEN = 403;
+
+    /**
+     * 璧勬簮锛屾湇鍔℃湭鎵惧埌
+     */
+    public static final int NOT_FOUND = 404;
+
+    /**
+     * 涓嶅厑璁哥殑http鏂规硶
+     */
+    public static final int BAD_METHOD = 405;
+
+    /**
+     * 璧勬簮鍐茬獊锛屾垨鑰呰祫婧愯閿�
+     */
+    public static final int CONFLICT = 409;
+
+    /**
+     * 涓嶆敮鎸佺殑鏁版嵁锛屽獟浣撶被鍨�
+     */
+    public static final int UNSUPPORTED_TYPE = 415;
+
+    /**
+     * 绯荤粺鍐呴儴閿欒
+     */
+    public static final int ERROR = 500;
+
+    /**
+     * 鎺ュ彛鏈疄鐜�
+     */
+    public static final int NOT_IMPLEMENTED = 501;
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/constant/UserConstants.java b/ruoyi/src/main/java/com/ruoyi/common/constant/UserConstants.java
new file mode 100644
index 0000000..9164cd2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -0,0 +1,39 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 鐢ㄦ埛甯搁噺淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class UserConstants
+{
+    /**
+     * 骞冲彴鍐呯郴缁熺敤鎴风殑鍞竴鏍囧織
+     */
+    public static final String SYS_USER = "SYS_USER";
+
+    /** 姝e父鐘舵�� */
+    public static final String NORMAL = "0";
+
+    /** 寮傚父鐘舵�� */
+    public static final String EXCEPTION = "1";
+
+    /** 鐢ㄦ埛灏佺鐘舵�� */
+    public static final String USER_BLOCKED = "1";
+
+    /** 瑙掕壊灏佺鐘舵�� */
+    public static final String ROLE_BLOCKED = "1";
+
+    /** 閮ㄩ棬姝e父鐘舵�� */
+    public static final String DEPT_NORMAL = "0";
+
+    /** 瀛楀吀姝e父鐘舵�� */
+    public static final String DICT_NORMAL = "0";
+
+    /** 鏄惁涓虹郴缁熼粯璁わ紙鏄級 */
+    public static final String YES = "Y";
+
+    /** 鏍¢獙杩斿洖缁撴灉鐮� */
+    public final static String UNIQUE = "0";
+    public final static String NOT_UNIQUE = "1";
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/lang/UUID.java b/ruoyi/src/main/java/com/ruoyi/common/core/lang/UUID.java
new file mode 100644
index 0000000..9e1bbeb
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/core/lang/UUID.java
@@ -0,0 +1,481 @@
+package com.ruoyi.common.core.lang;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import com.ruoyi.common.exception.UtilException;
+
+/**
+ * 鎻愪緵閫氱敤鍞竴璇嗗埆鐮侊紙universally unique identifier锛夛紙UUID锛夊疄鐜�
+ *
+ * @author ruoyi
+ */
+public final class UUID implements java.io.Serializable, Comparable<UUID>
+{
+    private static final long serialVersionUID = -1185015143654744140L;
+
+    /**
+     * SecureRandom 鐨勫崟渚�
+     *
+     */
+    private static class Holder
+    {
+        static final SecureRandom numberGenerator = getSecureRandom();
+    }
+
+    /** 姝UID鐨勬渶楂�64鏈夋晥浣� */
+    private final long mostSigBits;
+
+    /** 姝UID鐨勬渶浣�64鏈夋晥浣� */
+    private final long leastSigBits;
+
+    /**
+     * 绉佹湁鏋勯��
+     * 
+     * @param data 鏁版嵁
+     */
+    private UUID(byte[] data)
+    {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i = 0; i < 8; i++)
+        {
+            msb = (msb << 8) | (data[i] & 0xff);
+        }
+        for (int i = 8; i < 16; i++)
+        {
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        }
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * 浣跨敤鎸囧畾鐨勬暟鎹瀯閫犳柊鐨� UUID銆�
+     *
+     * @param mostSigBits 鐢ㄤ簬 {@code UUID} 鐨勬渶楂樻湁鏁� 64 浣�
+     * @param leastSigBits 鐢ㄤ簬 {@code UUID} 鐨勬渶浣庢湁鏁� 64 浣�
+     */
+    public UUID(long mostSigBits, long leastSigBits)
+    {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘�� 浣跨敤鍔犲瘑鐨勬湰鍦扮嚎绋嬩吉闅忔満鏁扮敓鎴愬櫒鐢熸垚璇� UUID銆�
+     * 
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID fastUUID()
+    {
+        return randomUUID(false);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘�� 浣跨敤鍔犲瘑鐨勫己浼殢鏈烘暟鐢熸垚鍣ㄧ敓鎴愯 UUID銆�
+     * 
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID randomUUID()
+    {
+        return randomUUID(true);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘�� 浣跨敤鍔犲瘑鐨勫己浼殢鏈烘暟鐢熸垚鍣ㄧ敓鎴愯 UUID銆�
+     * 
+     * @param isSecure 鏄惁浣跨敤{@link SecureRandom}濡傛灉鏄彲浠ヨ幏寰楁洿瀹夊叏鐨勯殢鏈虹爜锛屽惁鍒欏彲浠ュ緱鍒版洿濂界殑鎬ц兘
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID randomUUID(boolean isSecure)
+    {
+        final Random ng = isSecure ? Holder.numberGenerator : getRandom();
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6] &= 0x0f; /* clear version */
+        randomBytes[6] |= 0x40; /* set to version 4 */
+        randomBytes[8] &= 0x3f; /* clear variant */
+        randomBytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * 鏍规嵁鎸囧畾鐨勫瓧鑺傛暟缁勮幏鍙栫被鍨� 3锛堝熀浜庡悕绉扮殑锛塙UID 鐨勯潤鎬佸伐鍘傘��
+     *
+     * @param name 鐢ㄤ簬鏋勯�� UUID 鐨勫瓧鑺傛暟缁勩��
+     *
+     * @return 鏍规嵁鎸囧畾鏁扮粍鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID nameUUIDFromBytes(byte[] name)
+    {
+        MessageDigest md;
+        try
+        {
+            md = MessageDigest.getInstance("MD5");
+        }
+        catch (NoSuchAlgorithmException nsae)
+        {
+            throw new InternalError("MD5 not supported");
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6] &= 0x0f; /* clear version */
+        md5Bytes[6] |= 0x30; /* set to version 3 */
+        md5Bytes[8] &= 0x3f; /* clear variant */
+        md5Bytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(md5Bytes);
+    }
+
+    /**
+     * 鏍规嵁 {@link #toString()} 鏂规硶涓弿杩扮殑瀛楃涓叉爣鍑嗚〃绀哄舰寮忓垱寤簕@code UUID}銆�
+     *
+     * @param name 鎸囧畾 {@code UUID} 瀛楃涓�
+     * @return 鍏锋湁鎸囧畾鍊肩殑 {@code UUID}
+     * @throws IllegalArgumentException 濡傛灉 name 涓� {@link #toString} 涓弿杩扮殑瀛楃涓茶〃绀哄舰寮忎笉绗︽姏鍑烘寮傚父
+     *
+     */
+    public static UUID fromString(String name)
+    {
+        String[] components = name.split("-");
+        if (components.length != 5)
+        {
+            throw new IllegalArgumentException("Invalid UUID string: " + name);
+        }
+        for (int i = 0; i < 5; i++)
+        {
+            components[i] = "0x" + components[i];
+        }
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    /**
+     * 杩斿洖姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶浣庢湁鏁� 64 浣嶃��
+     *
+     * @return 姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶浣庢湁鏁� 64 浣嶃��
+     */
+    public long getLeastSignificantBits()
+    {
+        return leastSigBits;
+    }
+
+    /**
+     * 杩斿洖姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶楂樻湁鏁� 64 浣嶃��
+     *
+     * @return 姝� UUID 鐨� 128 浣嶅�间腑鏈�楂樻湁鏁� 64 浣嶃��
+     */
+    public long getMostSignificantBits()
+    {
+        return mostSigBits;
+    }
+
+    /**
+     * 涓庢 {@code UUID} 鐩稿叧鑱旂殑鐗堟湰鍙�. 鐗堟湰鍙锋弿杩版 {@code UUID} 鏄浣曠敓鎴愮殑銆�
+     * <p>
+     * 鐗堟湰鍙峰叿鏈変互涓嬪惈鎰�:
+     * <ul>
+     * <li>1 鍩轰簬鏃堕棿鐨� UUID
+     * <li>2 DCE 瀹夊叏 UUID
+     * <li>3 鍩轰簬鍚嶇О鐨� UUID
+     * <li>4 闅忔満鐢熸垚鐨� UUID
+     * </ul>
+     *
+     * @return 姝� {@code UUID} 鐨勭増鏈彿
+     */
+    public int version()
+    {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int) ((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * 涓庢 {@code UUID} 鐩稿叧鑱旂殑鍙樹綋鍙枫�傚彉浣撳彿鎻忚堪 {@code UUID} 鐨勫竷灞�銆�
+     * <p>
+     * 鍙樹綋鍙峰叿鏈変互涓嬪惈鎰忥細
+     * <ul>
+     * <li>0 涓� NCS 鍚戝悗鍏煎淇濈暀
+     * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 鐢ㄤ簬姝ょ被
+     * <li>6 淇濈暀锛屽井杞悜鍚庡吋瀹�
+     * <li>7 淇濈暀渚涗互鍚庡畾涔変娇鐢�
+     * </ul>
+     *
+     * @return 姝� {@code UUID} 鐩稿叧鑱旂殑鍙樹綋鍙�
+     */
+    public int variant()
+    {
+        // This field is composed of a varying number of bits.
+        // 0 - - Reserved for NCS backward compatibility
+        // 1 0 - The IETF aka Leach-Salz variant (used by this class)
+        // 1 1 0 Reserved, Microsoft backward compatibility
+        // 1 1 1 Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鑱旂殑鏃堕棿鎴冲�笺��
+     *
+     * <p>
+     * 60 浣嶇殑鏃堕棿鎴冲�兼牴鎹 {@code UUID} 鐨� time_low銆乼ime_mid 鍜� time_hi 瀛楁鏋勯�犮��<br>
+     * 鎵�寰楀埌鐨勬椂闂存埑浠� 100 姣井绉掍负鍗曚綅锛屼粠 UTC锛堥�氱敤鍗忚皟鏃堕棿锛� 1582 骞� 10 鏈� 15 鏃ラ浂鏃跺紑濮嬨��
+     *
+     * <p>
+     * 鏃堕棿鎴冲�间粎鍦ㄥ湪鍩轰簬鏃堕棿鐨� UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆�<br>
+     * 濡傛灉姝� {@code UUID} 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑� UnsupportedOperationException銆�
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� {@code UUID} 涓嶆槸 version 涓� 1 鐨� UUID銆�
+     */
+    public long timestamp() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return (mostSigBits & 0x0FFFL) << 48//
+                | ((mostSigBits >> 16) & 0x0FFFFL) << 32//
+                | mostSigBits >>> 32;
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鑱旂殑鏃堕挓搴忓垪鍊笺��
+     *
+     * <p>
+     * 14 浣嶇殑鏃堕挓搴忓垪鍊兼牴鎹 UUID 鐨� clock_seq 瀛楁鏋勯�犮�俢lock_seq 瀛楁鐢ㄤ簬淇濊瘉鍦ㄥ熀浜庢椂闂寸殑 UUID 涓殑鏃堕棿鍞竴鎬с��
+     * <p>
+     * {@code clockSequence} 鍊间粎鍦ㄥ熀浜庢椂闂寸殑 UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆� 濡傛灉姝� UUID 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑�
+     * UnsupportedOperationException銆�
+     *
+     * @return 姝� {@code UUID} 鐨勬椂閽熷簭鍒�
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� UUID 鐨� version 涓嶄负 1
+     */
+    public int clockSequence() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鐨勮妭鐐瑰�笺��
+     *
+     * <p>
+     * 48 浣嶇殑鑺傜偣鍊兼牴鎹 UUID 鐨� node 瀛楁鏋勯�犮�傛瀛楁鏃ㄥ湪鐢ㄤ簬淇濆瓨鏈哄櫒鐨� IEEE 802 鍦板潃锛岃鍦板潃鐢ㄤ簬鐢熸垚姝� UUID 浠ヤ繚璇佺┖闂村敮涓�鎬с��
+     * <p>
+     * 鑺傜偣鍊间粎鍦ㄥ熀浜庢椂闂寸殑 UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆�<br>
+     * 濡傛灉姝� UUID 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑� UnsupportedOperationException銆�
+     *
+     * @return 姝� {@code UUID} 鐨勮妭鐐瑰��
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� UUID 鐨� version 涓嶄负 1
+     */
+    public long node() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    /**
+     * 杩斿洖姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡銆�
+     *
+     * <p>
+     * UUID 鐨勫瓧绗︿覆琛ㄧず褰㈠紡鐢辨 BNF 鎻忚堪锛�
+     * 
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     * 
+     * </blockquote>
+     *
+     * @return 姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡
+     * @see #toString(boolean)
+     */
+    @Override
+    public String toString()
+    {
+        return toString(false);
+    }
+
+    /**
+     * 杩斿洖姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡銆�
+     *
+     * <p>
+     * UUID 鐨勫瓧绗︿覆琛ㄧず褰㈠紡鐢辨 BNF 鎻忚堪锛�
+     * 
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     * 
+     * </blockquote>
+     *
+     * @param isSimple 鏄惁绠�鍗曟ā寮忥紝绠�鍗曟ā寮忎负涓嶅甫'-'鐨刄UID瀛楃涓�
+     * @return 姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡
+     */
+    public String toString(boolean isSimple)
+    {
+        final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
+        // time_low
+        builder.append(digits(mostSigBits >> 32, 8));
+        if (false == isSimple)
+        {
+            builder.append('-');
+        }
+        // time_mid
+        builder.append(digits(mostSigBits >> 16, 4));
+        if (false == isSimple)
+        {
+            builder.append('-');
+        }
+        // time_high_and_version
+        builder.append(digits(mostSigBits, 4));
+        if (false == isSimple)
+        {
+            builder.append('-');
+        }
+        // variant_and_sequence
+        builder.append(digits(leastSigBits >> 48, 4));
+        if (false == isSimple)
+        {
+            builder.append('-');
+        }
+        // node
+        builder.append(digits(leastSigBits, 12));
+
+        return builder.toString();
+    }
+
+    /**
+     * 杩斿洖姝� UUID 鐨勫搱甯岀爜銆�
+     *
+     * @return UUID 鐨勫搱甯岀爜鍊笺��
+     */
+    public int hashCode()
+    {
+        long hilo = mostSigBits ^ leastSigBits;
+        return ((int) (hilo >> 32)) ^ (int) hilo;
+    }
+
+    /**
+     * 灏嗘瀵硅薄涓庢寚瀹氬璞℃瘮杈冦��
+     * <p>
+     * 褰撲笖浠呭綋鍙傛暟涓嶄负 {@code null}銆佽�屾槸涓�涓� UUID 瀵硅薄銆佸叿鏈変笌姝� UUID 鐩稿悓鐨� varriant銆佸寘鍚浉鍚岀殑鍊硷紙姣忎竴浣嶅潎鐩稿悓锛夋椂锛岀粨鏋滄墠涓� {@code true}銆�
+     *
+     * @param obj 瑕佷笌涔嬫瘮杈冪殑瀵硅薄
+     *
+     * @return 濡傛灉瀵硅薄鐩稿悓锛屽垯杩斿洖 {@code true}锛涘惁鍒欒繑鍥� {@code false}
+     */
+    public boolean equals(Object obj)
+    {
+        if ((null == obj) || (obj.getClass() != UUID.class))
+        {
+            return false;
+        }
+        UUID id = (UUID) obj;
+        return (mostSigBits == id.mostSigBits && leastSigBits == id.leastSigBits);
+    }
+
+    // Comparison Operations
+
+    /**
+     * 灏嗘 UUID 涓庢寚瀹氱殑 UUID 姣旇緝銆�
+     *
+     * <p>
+     * 濡傛灉涓や釜 UUID 涓嶅悓锛屼笖绗竴涓� UUID 鐨勬渶楂樻湁鏁堝瓧娈靛ぇ浜庣浜屼釜 UUID 鐨勫搴斿瓧娈碉紝鍒欑涓�涓� UUID 澶т簬绗簩涓� UUID銆�
+     *
+     * @param val 涓庢 UUID 姣旇緝鐨� UUID
+     *
+     * @return 鍦ㄦ UUID 灏忎簬銆佺瓑浜庢垨澶т簬 val 鏃讹紝鍒嗗埆杩斿洖 -1銆�0 鎴� 1銆�
+     *
+     */
+    public int compareTo(UUID val)
+    {
+        // The ordering is intentionally set up so that the UUIDs
+        // can simply be numerically compared as two numbers
+        return (this.mostSigBits < val.mostSigBits ? -1 : //
+                (this.mostSigBits > val.mostSigBits ? 1 : //
+                        (this.leastSigBits < val.leastSigBits ? -1 : //
+                                (this.leastSigBits > val.leastSigBits ? 1 : //
+                                        0))));
+    }
+
+    // -------------------------------------------------------------------------------------------------------------------
+    // Private method start
+    /**
+     * 杩斿洖鎸囧畾鏁板瓧瀵瑰簲鐨刪ex鍊�
+     * 
+     * @param val 鍊�
+     * @param digits 浣�
+     * @return 鍊�
+     */
+    private static String digits(long val, int digits)
+    {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * 妫�鏌ユ槸鍚︿负time-based鐗堟湰UUID
+     */
+    private void checkTimeBase()
+    {
+        if (version() != 1)
+        {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+    }
+
+    /**
+     * 鑾峰彇{@link SecureRandom}锛岀被鎻愪緵鍔犲瘑鐨勫己闅忔満鏁扮敓鎴愬櫒 (RNG)
+     * 
+     * @return {@link SecureRandom}
+     */
+    public static SecureRandom getSecureRandom()
+    {
+        try
+        {
+            return SecureRandom.getInstance("SHA1PRNG");
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new UtilException(e);
+        }
+    }
+
+    /**
+     * 鑾峰彇闅忔満鏁扮敓鎴愬櫒瀵硅薄<br>
+     * ThreadLocalRandom鏄疛DK 7涔嬪悗鎻愪緵骞跺彂浜х敓闅忔満鏁帮紝鑳藉瑙e喅澶氫釜绾跨▼鍙戠敓鐨勭珵浜変簤澶恒��
+     * 
+     * @return {@link ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom getRandom()
+    {
+        return ThreadLocalRandom.current();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/text/CharsetKit.java b/ruoyi/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
new file mode 100644
index 0000000..8297661
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
@@ -0,0 +1,86 @@
+package com.ruoyi.common.core.text;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 瀛楃闆嗗伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class CharsetKit
+{
+    /** ISO-8859-1 */
+    public static final String ISO_8859_1 = "ISO-8859-1";
+    /** UTF-8 */
+    public static final String UTF_8 = "UTF-8";
+    /** GBK */
+    public static final String GBK = "GBK";
+
+    /** ISO-8859-1 */
+    public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
+    /** UTF-8 */
+    public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
+    /** GBK */
+    public static final Charset CHARSET_GBK = Charset.forName(GBK);
+
+    /**
+     * 杞崲涓篊harset瀵硅薄
+     * 
+     * @param charset 瀛楃闆嗭紝涓虹┖鍒欒繑鍥為粯璁ゅ瓧绗﹂泦
+     * @return Charset
+     */
+    public static Charset charset(String charset)
+    {
+        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
+    }
+
+    /**
+     * 杞崲瀛楃涓茬殑瀛楃闆嗙紪鐮�
+     * 
+     * @param source 瀛楃涓�
+     * @param srcCharset 婧愬瓧绗﹂泦锛岄粯璁SO-8859-1
+     * @param destCharset 鐩爣瀛楃闆嗭紝榛樿UTF-8
+     * @return 杞崲鍚庣殑瀛楃闆�
+     */
+    public static String convert(String source, String srcCharset, String destCharset)
+    {
+        return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
+    }
+
+    /**
+     * 杞崲瀛楃涓茬殑瀛楃闆嗙紪鐮�
+     * 
+     * @param source 瀛楃涓�
+     * @param srcCharset 婧愬瓧绗﹂泦锛岄粯璁SO-8859-1
+     * @param destCharset 鐩爣瀛楃闆嗭紝榛樿UTF-8
+     * @return 杞崲鍚庣殑瀛楃闆�
+     */
+    public static String convert(String source, Charset srcCharset, Charset destCharset)
+    {
+        if (null == srcCharset)
+        {
+            srcCharset = StandardCharsets.ISO_8859_1;
+        }
+
+        if (null == destCharset)
+        {
+            srcCharset = StandardCharsets.UTF_8;
+        }
+
+        if (StringUtils.isEmpty(source) || srcCharset.equals(destCharset))
+        {
+            return source;
+        }
+        return new String(source.getBytes(srcCharset), destCharset);
+    }
+
+    /**
+     * @return 绯荤粺瀛楃闆嗙紪鐮�
+     */
+    public static String systemCharset()
+    {
+        return Charset.defaultCharset().name();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/text/Convert.java b/ruoyi/src/main/java/com/ruoyi/common/core/text/Convert.java
new file mode 100644
index 0000000..9dd076d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/core/text/Convert.java
@@ -0,0 +1,999 @@
+package com.ruoyi.common.core.text;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.NumberFormat;
+import java.util.Set;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 绫诲瀷杞崲鍣�
+ * 
+ * @author ruoyi
+ */
+public class Convert
+{
+    /**
+     * 杞崲涓哄瓧绗︿覆<br>
+     * 濡傛灉缁欏畾鐨勫�间负null锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static String toStr(Object value, String defaultValue)
+    {
+        if (null == value)
+        {
+            return defaultValue;
+        }
+        if (value instanceof String)
+        {
+            return (String) value;
+        }
+        return value.toString();
+    }
+
+    /**
+     * 杞崲涓哄瓧绗︿覆<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static String toStr(Object value)
+    {
+        return toStr(value, null);
+    }
+
+    /**
+     * 杞崲涓哄瓧绗�<br>
+     * 濡傛灉缁欏畾鐨勫�间负null锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Character toChar(Object value, Character defaultValue)
+    {
+        if (null == value)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Character)
+        {
+            return (Character) value;
+        }
+
+        final String valueStr = toStr(value, null);
+        return StringUtils.isEmpty(valueStr) ? defaultValue : valueStr.charAt(0);
+    }
+
+    /**
+     * 杞崲涓哄瓧绗�<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Character toChar(Object value)
+    {
+        return toChar(value, null);
+    }
+
+    /**
+     * 杞崲涓篵yte<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Byte toByte(Object value, Byte defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Byte)
+        {
+            return (Byte) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Byte.parseByte(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篵yte<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Byte toByte(Object value)
+    {
+        return toByte(value, null);
+    }
+
+    /**
+     * 杞崲涓篠hort<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Short toShort(Object value, Short defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Short)
+        {
+            return (Short) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Short.parseShort(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篠hort<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Short toShort(Object value)
+    {
+        return toShort(value, null);
+    }
+
+    /**
+     * 杞崲涓篘umber<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Number toNumber(Object value, Number defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Number)
+        {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return NumberFormat.getInstance().parse(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篘umber<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Number toNumber(Object value)
+    {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 杞崲涓篿nt<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Integer toInt(Object value, Integer defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Integer)
+        {
+            return (Integer) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Integer.parseInt(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篿nt<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer toInt(Object value)
+    {
+        return toInt(value, null);
+    }
+
+    /**
+     * 杞崲涓篒nteger鏁扮粍<br>
+     * 
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer[] toIntArray(String str)
+    {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篖ong鏁扮粍<br>
+     * 
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long[] toLongArray(String str)
+    {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篒nteger鏁扮粍<br>
+     * 
+     * @param split 鍒嗛殧绗�
+     * @param split 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer[] toIntArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Integer[] {};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 杞崲涓篖ong鏁扮粍<br>
+     * 
+     * @param split 鍒嗛殧绗�
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long[] toLongArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Long[] {};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 杞崲涓篠tring鏁扮粍<br>
+     * 
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static String[] toStrArray(String str)
+    {
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篠tring鏁扮粍<br>
+     * 
+     * @param split 鍒嗛殧绗�
+     * @param split 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static String[] toStrArray(String split, String str)
+    {
+        return str.split(split);
+    }
+
+    /**
+     * 杞崲涓簂ong<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Long toLong(Object value, Long defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Long)
+        {
+            return (Long) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 鏀寔绉戝璁℃暟娉�
+            return new BigDecimal(valueStr.trim()).longValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓簂ong<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long toLong(Object value)
+    {
+        return toLong(value, null);
+    }
+
+    /**
+     * 杞崲涓篸ouble<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Double toDouble(Object value, Double defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Double)
+        {
+            return (Double) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 鏀寔绉戝璁℃暟娉�
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篸ouble<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Double toDouble(Object value)
+    {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 杞崲涓篎loat<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Float toFloat(Object value, Float defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Float)
+        {
+            return (Float) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Float.parseFloat(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篎loat<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Float toFloat(Object value)
+    {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 杞崲涓篵oolean<br>
+     * String鏀寔鐨勫�间负锛歵rue銆乫alse銆亂es銆乷k銆乶o锛�1,0 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Boolean)
+        {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        switch (valueStr)
+        {
+            case "true":
+                return true;
+            case "false":
+                return false;
+            case "yes":
+                return true;
+            case "ok":
+                return true;
+            case "no":
+                return false;
+            case "1":
+                return true;
+            case "0":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篵oolean<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Boolean toBool(Object value)
+    {
+        return toBool(value, null);
+    }
+
+    /**
+     * 杞崲涓篍num瀵硅薄<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 
+     * @param clazz Enum鐨凜lass
+     * @param value 鍊�
+     * @param defaultValue 榛樿鍊�
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass()))
+        {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Enum.valueOf(clazz, valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篍num瀵硅薄<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 
+     * @param clazz Enum鐨凜lass
+     * @param value 鍊�
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
+    {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 杞崲涓築igInteger<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger)
+        {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long)
+        {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return new BigInteger(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓築igInteger<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static BigInteger toBigInteger(Object value)
+    {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 杞崲涓築igDecimal<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal)
+        {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long)
+        {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double)
+        {
+            return new BigDecimal((Double) value);
+        }
+        if (value instanceof Integer)
+        {
+            return new BigDecimal((Integer) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return new BigDecimal(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓築igDecimal<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     * 
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static BigDecimal toBigDecimal(Object value)
+    {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     * 
+     * @param obj 瀵硅薄
+     * @return 瀛楃涓�
+     */
+    public static String utf8Str(Object obj)
+    {
+        return str(obj, CharsetKit.CHARSET_UTF_8);
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     * 
+     * @param obj 瀵硅薄
+     * @param charsetName 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(Object obj, String charsetName)
+    {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     * 
+     * @param obj 瀵硅薄
+     * @param charset 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(Object obj, Charset charset)
+    {
+        if (null == obj)
+        {
+            return null;
+        }
+
+        if (obj instanceof String)
+        {
+            return (String) obj;
+        }
+        else if (obj instanceof byte[] || obj instanceof Byte[])
+        {
+            return str((Byte[]) obj, charset);
+        }
+        else if (obj instanceof ByteBuffer)
+        {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 灏哹yte鏁扮粍杞负瀛楃涓�
+     * 
+     * @param bytes byte鏁扮粍
+     * @param charset 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(byte[] bytes, String charset)
+    {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 瑙g爜瀛楄妭鐮�
+     * 
+     * @param data 瀛楃涓�
+     * @param charset 瀛楃闆嗭紝濡傛灉姝ゅ瓧娈典负绌猴紝鍒欒В鐮佺殑缁撴灉鍙栧喅浜庡钩鍙�
+     * @return 瑙g爜鍚庣殑瀛楃涓�
+     */
+    public static String str(byte[] data, Charset charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        if (null == charset)
+        {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 灏嗙紪鐮佺殑byteBuffer鏁版嵁杞崲涓哄瓧绗︿覆
+     * 
+     * @param data 鏁版嵁
+     * @param charset 瀛楃闆嗭紝濡傛灉涓虹┖浣跨敤褰撳墠绯荤粺瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(ByteBuffer data, String charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 灏嗙紪鐮佺殑byteBuffer鏁版嵁杞崲涓哄瓧绗︿覆
+     * 
+     * @param data 鏁版嵁
+     * @param charset 瀛楃闆嗭紝濡傛灉涓虹┖浣跨敤褰撳墠绯荤粺瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(ByteBuffer data, Charset charset)
+    {
+        if (null == charset)
+        {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    // ----------------------------------------------------------------------- 鍏ㄨ鍗婅杞崲
+    /**
+     * 鍗婅杞叏瑙�
+     * 
+     * @param input String.
+     * @return 鍏ㄨ瀛楃涓�.
+     */
+    public static String toSBC(String input)
+    {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 鍗婅杞叏瑙�
+     * 
+     * @param input String
+     * @param notConvertSet 涓嶆浛鎹㈢殑瀛楃闆嗗悎
+     * @return 鍏ㄨ瀛楃涓�.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet)
+    {
+        char c[] = input.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 璺宠繃涓嶆浛鎹㈢殑瀛楃
+                continue;
+            }
+
+            if (c[i] == ' ')
+            {
+                c[i] = '\u3000';
+            }
+            else if (c[i] < '\177')
+            {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 鍏ㄨ杞崐瑙�
+     * 
+     * @param input String.
+     * @return 鍗婅瀛楃涓�
+     */
+    public static String toDBC(String input)
+    {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 鏇挎崲鍏ㄨ涓哄崐瑙�
+     * 
+     * @param text 鏂囨湰
+     * @param notConvertSet 涓嶆浛鎹㈢殑瀛楃闆嗗悎
+     * @return 鏇挎崲鍚庣殑瀛楃
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet)
+    {
+        char c[] = text.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 璺宠繃涓嶆浛鎹㈢殑瀛楃
+                continue;
+            }
+
+            if (c[i] == '\u3000')
+            {
+                c[i] = ' ';
+            }
+            else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
+            {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        String returnString = new String(c);
+
+        return returnString;
+    }
+
+    /**
+     * 鏁板瓧閲戦澶у啓杞崲 鍏堝啓涓畬鏁寸殑鐒跺悗灏嗗闆舵嬀鏇挎崲鎴愰浂
+     * 
+     * @param n 鏁板瓧
+     * @return 涓枃澶у啓鏁板瓧
+     */
+    public static String digitUppercase(double n)
+    {
+        String[] fraction = { "瑙�", "鍒�" };
+        String[] digit = { "闆�", "澹�", "璐�", "鍙�", "鑲�", "浼�", "闄�", "鏌�", "鎹�", "鐜�" };
+        String[][] unit = { { "鍏�", "涓�", "浜�" }, { "", "鎷�", "浣�", "浠�" } };
+
+        String head = n < 0 ? "璐�" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++)
+        {
+            s += (digit[(int) (Math.floor(n * 10 * Math.pow(10, i)) % 10)] + fraction[i]).replaceAll("(闆�.)+", "");
+        }
+        if (s.length() < 1)
+        {
+            s = "鏁�";
+        }
+        int integerPart = (int) Math.floor(n);
+
+        for (int i = 0; i < unit[0].length && integerPart > 0; i++)
+        {
+            String p = "";
+            for (int j = 0; j < unit[1].length && n > 0; j++)
+            {
+                p = digit[integerPart % 10] + unit[1][j] + p;
+                integerPart = integerPart / 10;
+            }
+            s = p.replaceAll("(闆�.)*闆�$", "").replaceAll("^$", "闆�") + unit[0][i] + s;
+        }
+        return head + s.replaceAll("(闆�.)*闆跺厓", "鍏�").replaceFirst("(闆�.)+", "").replaceAll("(闆�.)+", "闆�").replaceAll("^鏁�$", "闆跺厓鏁�");
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/core/text/StrFormatter.java b/ruoyi/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
new file mode 100644
index 0000000..dbf3e23
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
@@ -0,0 +1,92 @@
+package com.ruoyi.common.core.text;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 瀛楃涓叉牸寮忓寲
+ * 
+ * @author ruoyi
+ */
+public class StrFormatter
+{
+    public static final String EMPTY_JSON = "{}";
+    public static final char C_BACKSLASH = '\\';
+    public static final char C_DELIM_START = '{';
+    public static final char C_DELIM_END = '}';
+
+    /**
+     * 鏍煎紡鍖栧瓧绗︿覆<br>
+     * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br>
+     * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br>
+     * 渚嬶細<br>
+     * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     * 
+     * @param strPattern 瀛楃涓叉ā鏉�
+     * @param argArray 鍙傛暟鍒楄〃
+     * @return 缁撴灉
+     */
+    public static String format(final String strPattern, final Object... argArray)
+    {
+        if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
+        {
+            return strPattern;
+        }
+        final int strPatternLength = strPattern.length();
+
+        // 鍒濆鍖栧畾涔夊ソ鐨勯暱搴︿互鑾峰緱鏇村ソ鐨勬�ц兘
+        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
+
+        int handledPosition = 0;
+        int delimIndex;// 鍗犱綅绗︽墍鍦ㄤ綅缃�
+        for (int argIndex = 0; argIndex < argArray.length; argIndex++)
+        {
+            delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
+            if (delimIndex == -1)
+            {
+                if (handledPosition == 0)
+                {
+                    return strPattern;
+                }
+                else
+                { // 瀛楃涓叉ā鏉垮墿浣欓儴鍒嗕笉鍐嶅寘鍚崰浣嶇锛屽姞鍏ュ墿浣欓儴鍒嗗悗杩斿洖缁撴灉
+                    sbuf.append(strPattern, handledPosition, strPatternLength);
+                    return sbuf.toString();
+                }
+            }
+            else
+            {
+                if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
+                {
+                    if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
+                    {
+                        // 杞箟绗︿箣鍓嶈繕鏈変竴涓浆涔夌锛屽崰浣嶇渚濇棫鏈夋晥
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                        handledPosition = delimIndex + 2;
+                    }
+                    else
+                    {
+                        // 鍗犱綅绗﹁杞箟
+                        argIndex--;
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(C_DELIM_START);
+                        handledPosition = delimIndex + 1;
+                    }
+                }
+                else
+                {
+                    // 姝e父鍗犱綅绗�
+                    sbuf.append(strPattern, handledPosition, delimIndex);
+                    sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                    handledPosition = delimIndex + 2;
+                }
+            }
+        }
+        // 鍔犲叆鏈�鍚庝竴涓崰浣嶇鍚庢墍鏈夌殑瀛楃
+        sbuf.append(strPattern, handledPosition, strPattern.length());
+
+        return sbuf.toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/enums/HttpMethod.java b/ruoyi/src/main/java/com/ruoyi/common/enums/HttpMethod.java
new file mode 100644
index 0000000..2fa9f86
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/enums/HttpMethod.java
@@ -0,0 +1,36 @@
+package com.ruoyi.common.enums;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.lang.Nullable;
+
+/**
+ * 璇锋眰鏂瑰紡
+ *
+ * @author ruoyi
+ */
+public enum HttpMethod
+{
+    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
+
+    private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
+
+    static
+    {
+        for (HttpMethod httpMethod : values())
+        {
+            mappings.put(httpMethod.name(), httpMethod);
+        }
+    }
+
+    @Nullable
+    public static HttpMethod resolve(@Nullable String method)
+    {
+        return (method != null ? mappings.get(method) : null);
+    }
+
+    public boolean matches(String method)
+    {
+        return (this == resolve(method));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/enums/UserStatus.java b/ruoyi/src/main/java/com/ruoyi/common/enums/UserStatus.java
new file mode 100644
index 0000000..a4613ff
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/enums/UserStatus.java
@@ -0,0 +1,30 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 鐢ㄦ埛鐘舵��
+ * 
+ * @author ruoyi
+ */
+public enum UserStatus
+{
+    OK("0", "姝e父"), DISABLE("1", "鍋滅敤"), DELETED("2", "鍒犻櫎");
+
+    private final String code;
+    private final String info;
+
+    UserStatus(String code, String info)
+    {
+        this.code = code;
+        this.info = info;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public String getInfo()
+    {
+        return info;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/BaseException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/BaseException.java
new file mode 100644
index 0000000..c1e55c1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/BaseException.java
@@ -0,0 +1,97 @@
+package com.ruoyi.common.exception;
+
+import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 鍩虹寮傚父
+ * 
+ * @author ruoyi
+ */
+public class BaseException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鎵�灞炴ā鍧�
+     */
+    private String module;
+
+    /**
+     * 閿欒鐮�
+     */
+    private String code;
+
+    /**
+     * 閿欒鐮佸搴旂殑鍙傛暟
+     */
+    private Object[] args;
+
+    /**
+     * 閿欒娑堟伅
+     */
+    private String defaultMessage;
+
+    public BaseException(String module, String code, Object[] args, String defaultMessage)
+    {
+        this.module = module;
+        this.code = code;
+        this.args = args;
+        this.defaultMessage = defaultMessage;
+    }
+
+    public BaseException(String module, String code, Object[] args)
+    {
+        this(module, code, args, null);
+    }
+
+    public BaseException(String module, String defaultMessage)
+    {
+        this(module, null, null, defaultMessage);
+    }
+
+    public BaseException(String code, Object[] args)
+    {
+        this(null, code, args, null);
+    }
+
+    public BaseException(String defaultMessage)
+    {
+        this(null, null, null, defaultMessage);
+    }
+
+    @Override
+    public String getMessage()
+    {
+        String message = null;
+        if (!StringUtils.isEmpty(code))
+        {
+            message = MessageUtils.message(code, args);
+        }
+        if (message == null)
+        {
+            message = defaultMessage;
+        }
+        return message;
+    }
+
+    public String getModule()
+    {
+        return module;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public Object[] getArgs()
+    {
+        return args;
+    }
+
+    public String getDefaultMessage()
+    {
+        return defaultMessage;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/CustomException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/CustomException.java
new file mode 100644
index 0000000..a99a100
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/CustomException.java
@@ -0,0 +1,43 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 鑷畾涔夊紓甯�
+ * 
+ * @author ruoyi
+ */
+public class CustomException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    private Integer code;
+
+    private String message;
+
+    public CustomException(String message)
+    {
+        this.message = message;
+    }
+
+    public CustomException(String message, Integer code)
+    {
+        this.message = message;
+        this.code = code;
+    }
+
+    public CustomException(String message, Throwable e)
+    {
+        super(message, e);
+        this.message = message;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/DemoModeException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/DemoModeException.java
new file mode 100644
index 0000000..57bffc4
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/DemoModeException.java
@@ -0,0 +1,15 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 婕旂ず妯″紡寮傚父
+ * 
+ * @author ruoyi
+ */
+public class DemoModeException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    public DemoModeException()
+    {
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/UtilException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/UtilException.java
new file mode 100644
index 0000000..a544fb6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/UtilException.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 宸ュ叿绫诲紓甯�
+ * 
+ * @author ruoyi
+ */
+public class UtilException extends RuntimeException
+{
+    private static final long serialVersionUID = 8247610319171014183L;
+
+    public UtilException(Throwable e)
+    {
+        super(e.getMessage(), e);
+    }
+
+    public UtilException(String message)
+    {
+        super(message);
+    }
+
+    public UtilException(String message, Throwable throwable)
+    {
+        super(message, throwable);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileException.java
new file mode 100644
index 0000000..f0ae563
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileException.java
@@ -0,0 +1,19 @@
+package com.ruoyi.common.exception.file;
+
+import com.ruoyi.common.exception.BaseException;
+
+/**
+ * 鏂囦欢淇℃伅寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class FileException extends BaseException
+{
+    private static final long serialVersionUID = 1L;
+
+    public FileException(String code, Object[] args)
+    {
+        super("file", code, args, null);
+    }
+
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
new file mode 100644
index 0000000..44941b8
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.file;
+
+/**
+ * 鏂囦欢鍚嶇О瓒呴暱闄愬埗寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class FileNameLengthLimitExceededException extends FileException
+{
+    private static final long serialVersionUID = 1L;
+
+    public FileNameLengthLimitExceededException(int defaultFileNameLength)
+    {
+        super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
new file mode 100644
index 0000000..f855e72
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.file;
+
+/**
+ * 鏂囦欢鍚嶅ぇ灏忛檺鍒跺紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class FileSizeLimitExceededException extends FileException
+{
+    private static final long serialVersionUID = 1L;
+
+    public FileSizeLimitExceededException(long defaultMaxSize)
+    {
+        super("upload.exceed.maxSize", new Object[] { defaultMaxSize });
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
new file mode 100644
index 0000000..81cd78b
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
@@ -0,0 +1,71 @@
+package com.ruoyi.common.exception.file;
+
+import java.util.Arrays;
+import org.apache.commons.fileupload.FileUploadException;
+
+/**
+ * 鏂囦欢涓婁紶 璇紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class InvalidExtensionException extends FileUploadException
+{
+    private static final long serialVersionUID = 1L;
+
+    private String[] allowedExtension;
+    private String extension;
+    private String filename;
+
+    public InvalidExtensionException(String[] allowedExtension, String extension, String filename)
+    {
+        super("filename : [" + filename + "], extension : [" + extension + "], allowed extension : [" + Arrays.toString(allowedExtension) + "]");
+        this.allowedExtension = allowedExtension;
+        this.extension = extension;
+        this.filename = filename;
+    }
+
+    public String[] getAllowedExtension()
+    {
+        return allowedExtension;
+    }
+
+    public String getExtension()
+    {
+        return extension;
+    }
+
+    public String getFilename()
+    {
+        return filename;
+    }
+
+    public static class InvalidImageExtensionException extends InvalidExtensionException
+    {
+        private static final long serialVersionUID = 1L;
+
+        public InvalidImageExtensionException(String[] allowedExtension, String extension, String filename)
+        {
+            super(allowedExtension, extension, filename);
+        }
+    }
+
+    public static class InvalidFlashExtensionException extends InvalidExtensionException
+    {
+        private static final long serialVersionUID = 1L;
+
+        public InvalidFlashExtensionException(String[] allowedExtension, String extension, String filename)
+        {
+            super(allowedExtension, extension, filename);
+        }
+    }
+
+    public static class InvalidMediaExtensionException extends InvalidExtensionException
+    {
+        private static final long serialVersionUID = 1L;
+
+        public InvalidMediaExtensionException(String[] allowedExtension, String extension, String filename)
+        {
+            super(allowedExtension, extension, filename);
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
new file mode 100644
index 0000000..e3334ae
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 楠岃瘉鐮侀敊璇紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class CaptchaException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaException()
+    {
+        super("user.jcaptcha.error", null);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
new file mode 100644
index 0000000..5e6fd0f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 楠岃瘉鐮佸け鏁堝紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class CaptchaExpireException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaExpireException()
+    {
+        super("user.jcaptcha.expire", null);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserException.java
new file mode 100644
index 0000000..b85dab6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserException.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.exception.user;
+
+import com.ruoyi.common.exception.BaseException;
+
+/**
+ * 鐢ㄦ埛淇℃伅寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class UserException extends BaseException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserException(String code, Object[] args)
+    {
+        super("user", code, args, null);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java b/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
new file mode 100644
index 0000000..71449e2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 鐢ㄦ埛瀵嗙爜涓嶆纭垨涓嶇鍚堣鑼冨紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class UserPasswordNotMatchException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserPasswordNotMatchException()
+    {
+        super("user.password.not.match", null);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/Arith.java b/ruoyi/src/main/java/com/ruoyi/common/utils/Arith.java
new file mode 100644
index 0000000..8668319
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/Arith.java
@@ -0,0 +1,114 @@
+package com.ruoyi.common.utils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * 绮剧‘鐨勬诞鐐规暟杩愮畻
+ * 
+ * @author ruoyi
+ */
+public class Arith
+{
+
+    /** 榛樿闄ゆ硶杩愮畻绮惧害 */
+    private static final int DEF_DIV_SCALE = 10;
+
+    /** 杩欎釜绫讳笉鑳藉疄渚嬪寲 */
+    private Arith()
+    {
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫姞娉曡繍绠椼��
+     * @param v1 琚姞鏁�
+     * @param v2 鍔犳暟
+     * @return 涓や釜鍙傛暟鐨勫拰
+     */
+    public static double add(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.add(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫噺娉曡繍绠椼��
+     * @param v1 琚噺鏁�
+     * @param v2 鍑忔暟
+     * @return 涓や釜鍙傛暟鐨勫樊
+     */
+    public static double sub(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.subtract(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勪箻娉曡繍绠椼��
+     * @param v1 琚箻鏁�
+     * @param v2 涔樻暟
+     * @return 涓や釜鍙傛暟鐨勭Н
+     */
+    public static double mul(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.multiply(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠楋紝褰撳彂鐢熼櫎涓嶅敖鐨勬儏鍐垫椂锛岀簿纭埌
+     * 灏忔暟鐐逛互鍚�10浣嶏紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2)
+    {
+        return div(v1, v2, DEF_DIV_SCALE);
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠椼�傚綋鍙戠敓闄や笉灏界殑鎯呭喌鏃讹紝鐢眘cale鍙傛暟鎸�
+     * 瀹氱簿搴︼紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @param scale 琛ㄧず琛ㄧず闇�瑕佺簿纭埌灏忔暟鐐逛互鍚庡嚑浣嶃��
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        if (b1.compareTo(BigDecimal.ZERO) == 0)
+        {
+            return BigDecimal.ZERO.doubleValue();
+        }
+        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫皬鏁颁綅鍥涜垗浜斿叆澶勭悊銆�
+     * @param v 闇�瑕佸洓鑸嶄簲鍏ョ殑鏁板瓧
+     * @param scale 灏忔暟鐐瑰悗淇濈暀鍑犱綅
+     * @return 鍥涜垗浜斿叆鍚庣殑缁撴灉
+     */
+    public static double round(double v, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b = new BigDecimal(Double.toString(v));
+        BigDecimal one = new BigDecimal("1");
+        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/DateUtils.java
new file mode 100644
index 0000000..8ff95f1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -0,0 +1,155 @@
+package com.ruoyi.common.utils;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+/**
+ * 鏃堕棿宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class DateUtils extends org.apache.commons.lang3.time.DateUtils
+{
+    public static String YYYY = "yyyy";
+
+    public static String YYYY_MM = "yyyy-MM";
+
+    public static String YYYY_MM_DD = "yyyy-MM-dd";
+
+    public static String YYYYMMDDHHMMSS = "yyyyMMddHHmmss";
+
+    public static String YYYY_MM_DD_HH_MM_SS = "yyyy-MM-dd HH:mm:ss";
+    
+    private static String[] parsePatterns = {
+            "yyyy-MM-dd", "yyyy-MM-dd HH:mm:ss", "yyyy-MM-dd HH:mm", "yyyy-MM", 
+            "yyyy/MM/dd", "yyyy/MM/dd HH:mm:ss", "yyyy/MM/dd HH:mm", "yyyy/MM",
+            "yyyy.MM.dd", "yyyy.MM.dd HH:mm:ss", "yyyy.MM.dd HH:mm", "yyyy.MM"};
+
+    /**
+     * 鑾峰彇褰撳墠Date鍨嬫棩鏈�
+     * 
+     * @return Date() 褰撳墠鏃ユ湡
+     */
+    public static Date getNowDate()
+    {
+        return new Date();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     * 
+     * @return String
+     */
+    public static String getDate()
+    {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static final String getTime()
+    {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static final String dateTimeNow()
+    {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static final String dateTimeNow(final String format)
+    {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static final String dateTime(final Date date)
+    {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static final String parseDateToStr(final String format, final Date date)
+    {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static final Date dateTime(final String format, final String ts)
+    {
+        try
+        {
+            return new SimpleDateFormat(format).parse(ts);
+        }
+        catch (ParseException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
+     */
+    public static final String datePath()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
+     */
+    public static final String dateTime()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     */
+    public static Date parseDate(Object str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        try
+        {
+            return parseDate(str.toString(), parsePatterns);
+        }
+        catch (ParseException e)
+        {
+            return null;
+        }
+    }
+    
+    /**
+     * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     */
+    public static Date getServerStartDate()
+    {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 璁$畻涓や釜鏃堕棿宸�
+     */
+    public static String getDatePoor(Date endDate, Date nowDate)
+    {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 鑾峰緱涓や釜鏃堕棿鐨勬绉掓椂闂村樊寮�
+        long diff = endDate.getTime() - nowDate.getTime();
+        // 璁$畻宸灏戝ぉ
+        long day = diff / nd;
+        // 璁$畻宸灏戝皬鏃�
+        long hour = diff % nd / nh;
+        // 璁$畻宸灏戝垎閽�
+        long min = diff % nd % nh / nm;
+        // 璁$畻宸灏戠//杈撳嚭缁撴灉
+        // long sec = diff % nd % nh % nm / ns;
+        return day + "澶�" + hour + "灏忔椂" + min + "鍒嗛挓";
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/IdUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/IdUtils.java
new file mode 100644
index 0000000..45d8ac9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/IdUtils.java
@@ -0,0 +1,51 @@
+package com.ruoyi.common.utils;
+
+import com.ruoyi.common.core.lang.UUID;
+
+/**
+ * ID鐢熸垚鍣ㄥ伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class IdUtils
+{
+    /**
+     * 鑾峰彇闅忔満UUID
+     * 
+     * @return 闅忔満UUID
+     */
+    public static String randomUUID()
+    {
+        return UUID.randomUUID().toString();
+    }
+
+    /**
+     * 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎
+     * 
+     * @return 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎
+     */
+    public static String simpleUUID()
+    {
+        return UUID.randomUUID().toString(true);
+    }
+
+    /**
+     * 鑾峰彇闅忔満UUID锛屼娇鐢ㄦ�ц兘鏇村ソ鐨凾hreadLocalRandom鐢熸垚UUID
+     * 
+     * @return 闅忔満UUID
+     */
+    public static String fastUUID()
+    {
+        return UUID.fastUUID().toString();
+    }
+
+    /**
+     * 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎锛屼娇鐢ㄦ�ц兘鏇村ソ鐨凾hreadLocalRandom鐢熸垚UUID
+     * 
+     * @return 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎
+     */
+    public static String fastSimpleUUID()
+    {
+        return UUID.fastUUID().toString(true);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/LogUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/LogUtils.java
new file mode 100644
index 0000000..e415c9c
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/LogUtils.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.utils;
+
+/**
+ * 澶勭悊骞惰褰曟棩蹇楁枃浠�
+ * 
+ * @author ruoyi
+ */
+public class LogUtils
+{
+    public static String getBlock(Object msg)
+    {
+        if (msg == null)
+        {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/MessageUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/MessageUtils.java
new file mode 100644
index 0000000..5f2d9ea
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/MessageUtils.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.utils;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+import com.ruoyi.common.utils.spring.SpringUtils;
+
+/**
+ * 鑾峰彇i18n璧勬簮鏂囦欢
+ * 
+ * @author ruoyi
+ */
+public class MessageUtils
+{
+    /**
+     * 鏍规嵁娑堟伅閿拰鍙傛暟 鑾峰彇娑堟伅 濮旀墭缁檚pring messageSource
+     *
+     * @param code 娑堟伅閿�
+     * @param args 鍙傛暟
+     * @return 鑾峰彇鍥介檯鍖栫炕璇戝��
+     */
+    public static String message(String code, Object... args)
+    {
+        MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
+        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
new file mode 100644
index 0000000..c8d1783
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -0,0 +1,90 @@
+package com.ruoyi.common.utils;
+
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.framework.security.LoginUser;
+
+/**
+ * 瀹夊叏鏈嶅姟宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class SecurityUtils
+{
+    /**
+     * 鑾峰彇鐢ㄦ埛璐︽埛
+     **/
+    public static String getUsername()
+    {
+        try
+        {
+            return getLoginUser().getUsername();
+        }
+        catch (Exception e)
+        {
+            throw new CustomException("鑾峰彇鐢ㄦ埛璐︽埛寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛
+     **/
+    public static LoginUser getLoginUser()
+    {
+        try
+        {
+            return (LoginUser) getAuthentication().getPrincipal();
+        }
+        catch (Exception e)
+        {
+            throw new CustomException("鑾峰彇鐢ㄦ埛淇℃伅寮傚父", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 鑾峰彇Authentication
+     */
+    public static Authentication getAuthentication()
+    {
+        return SecurityContextHolder.getContext().getAuthentication();
+    }
+
+    /**
+     * 鐢熸垚BCryptPasswordEncoder瀵嗙爜
+     *
+     * @param password 瀵嗙爜
+     * @return 鍔犲瘑瀛楃涓�
+     */
+    public static String encryptPassword(String password)
+    {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.encode(password);
+    }
+
+    /**
+     * 鍒ゆ柇瀵嗙爜鏄惁鐩稿悓
+     *
+     * @param rawPassword 鐪熷疄瀵嗙爜
+     * @param encodedPassword 鍔犲瘑鍚庡瓧绗�
+     * @return 缁撴灉
+     */
+    public static boolean matchesPassword(String rawPassword, String encodedPassword)
+    {
+        BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
+        return passwordEncoder.matches(rawPassword, encodedPassword);
+    }
+
+    /**
+     * 鏄惁涓虹鐞嗗憳
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public static boolean isAdmin(Long userId)
+    {
+        return userId != null && 1L == userId;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/ServletUtils.java
new file mode 100644
index 0000000..9e6fd59
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/ServletUtils.java
@@ -0,0 +1,136 @@
+package com.ruoyi.common.utils;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 瀹㈡埛绔伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class ServletUtils
+{
+    /**
+     * 鑾峰彇String鍙傛暟
+     */
+    public static String getParameter(String name)
+    {
+        return getRequest().getParameter(name);
+    }
+
+    /**
+     * 鑾峰彇String鍙傛暟
+     */
+    public static String getParameter(String name, String defaultValue)
+    {
+        return Convert.toStr(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 鑾峰彇Integer鍙傛暟
+     */
+    public static Integer getParameterToInt(String name)
+    {
+        return Convert.toInt(getRequest().getParameter(name));
+    }
+
+    /**
+     * 鑾峰彇Integer鍙傛暟
+     */
+    public static Integer getParameterToInt(String name, Integer defaultValue)
+    {
+        return Convert.toInt(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 鑾峰彇request
+     */
+    public static HttpServletRequest getRequest()
+    {
+        return getRequestAttributes().getRequest();
+    }
+
+    /**
+     * 鑾峰彇response
+     */
+    public static HttpServletResponse getResponse()
+    {
+        return getRequestAttributes().getResponse();
+    }
+
+    /**
+     * 鑾峰彇session
+     */
+    public static HttpSession getSession()
+    {
+        return getRequest().getSession();
+    }
+
+    public static ServletRequestAttributes getRequestAttributes()
+    {
+        RequestAttributes attributes = RequestContextHolder.getRequestAttributes();
+        return (ServletRequestAttributes) attributes;
+    }
+
+    /**
+     * 灏嗗瓧绗︿覆娓叉煋鍒板鎴风
+     * 
+     * @param response 娓叉煋瀵硅薄
+     * @param string 寰呮覆鏌撶殑瀛楃涓�
+     * @return null
+     */
+    public static String renderString(HttpServletResponse response, String string)
+    {
+        try
+        {
+            response.setStatus(200);
+            response.setContentType("application/json");
+            response.setCharacterEncoding("utf-8");
+            response.getWriter().print(string);
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 鏄惁鏄疉jax寮傛璇锋眰
+     * 
+     * @param request
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request)
+    {
+        String accept = request.getHeader("accept");
+        if (accept != null && accept.indexOf("application/json") != -1)
+        {
+            return true;
+        }
+
+        String xRequestedWith = request.getHeader("X-Requested-With");
+        if (xRequestedWith != null && xRequestedWith.indexOf("XMLHttpRequest") != -1)
+        {
+            return true;
+        }
+
+        String uri = request.getRequestURI();
+        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
+        {
+            return true;
+        }
+
+        String ajax = request.getParameter("__ajax");
+        if (StringUtils.inStringIgnoreCase(ajax, "json", "xml"))
+        {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/StringUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/StringUtils.java
new file mode 100644
index 0000000..a865c35
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -0,0 +1,453 @@
+package com.ruoyi.common.utils;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import com.ruoyi.common.core.text.StrFormatter;
+
+/**
+ * 瀛楃涓插伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils
+{
+    /** 绌哄瓧绗︿覆 */
+    private static final String NULLSTR = "";
+
+    /** 涓嬪垝绾� */
+    private static final char SEPARATOR = '_';
+
+    /**
+     * 鑾峰彇鍙傛暟涓嶄负绌哄��
+     * 
+     * @param value defaultValue 瑕佸垽鏂殑value
+     * @return value 杩斿洖鍊�
+     */
+    public static <T> T nvl(T value, T defaultValue)
+    {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狢ollection鏄惁涓虹┖锛� 鍖呭惈List锛孲et锛孮ueue
+     * 
+     * @param coll 瑕佸垽鏂殑Collection
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Collection<?> coll)
+    {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狢ollection鏄惁闈炵┖锛屽寘鍚獿ist锛孲et锛孮ueue
+     * 
+     * @param coll 瑕佸垽鏂殑Collection
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Collection<?> coll)
+    {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚︿负绌�
+     * 
+     * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+     ** @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Object[] objects)
+    {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚﹂潪绌�
+     * 
+     * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Object[] objects)
+    {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+     * 
+     * @param map 瑕佸垽鏂殑Map
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Map<?, ?> map)
+    {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+     * 
+     * @param map 瑕佸垽鏂殑Map
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Map<?, ?> map)
+    {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓虹┖涓�
+     * 
+     * @param str String
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(String str)
+    {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓洪潪绌轰覆
+     * 
+     * @param str String
+     * @return true锛氶潪绌轰覆 false锛氱┖涓�
+     */
+    public static boolean isNotEmpty(String str)
+    {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚︿负绌�
+     * 
+     * @param object Object
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isNull(Object object)
+    {
+        return object == null;
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚﹂潪绌�
+     * 
+     * @param object Object
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotNull(Object object)
+    {
+        return !isNull(object);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚︽槸鏁扮粍绫诲瀷锛圝ava鍩烘湰鍨嬪埆鐨勬暟缁勶級
+     * 
+     * @param object 瀵硅薄
+     * @return true锛氭槸鏁扮粍 false锛氫笉鏄暟缁�
+     */
+    public static boolean isArray(Object object)
+    {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 鍘荤┖鏍�
+     */
+    public static String trim(String str)
+    {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 鎴彇瀛楃涓�
+     * 
+     * @param str 瀛楃涓�
+     * @param start 寮�濮�
+     * @return 缁撴灉
+     */
+    public static String substring(final String str, int start)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (start > str.length())
+        {
+            return NULLSTR;
+        }
+
+        return str.substring(start);
+    }
+
+    /**
+     * 鎴彇瀛楃涓�
+     * 
+     * @param str 瀛楃涓�
+     * @param start 寮�濮�
+     * @param end 缁撴潫
+     * @return 缁撴灉
+     */
+    public static String substring(final String str, int start, int end)
+    {
+        if (str == null)
+        {
+            return NULLSTR;
+        }
+
+        if (end < 0)
+        {
+            end = str.length() + end;
+        }
+        if (start < 0)
+        {
+            start = str.length() + start;
+        }
+
+        if (end > str.length())
+        {
+            end = str.length();
+        }
+
+        if (start > end)
+        {
+            return NULLSTR;
+        }
+
+        if (start < 0)
+        {
+            start = 0;
+        }
+        if (end < 0)
+        {
+            end = 0;
+        }
+
+        return str.substring(start, end);
+    }
+
+    /**
+     * 鏍煎紡鍖栨枃鏈�, {} 琛ㄧず鍗犱綅绗�<br>
+     * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br>
+     * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br>
+     * 渚嬶細<br>
+     * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     * 
+     * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {} 琛ㄧず
+     * @param params 鍙傛暟鍊�
+     * @return 鏍煎紡鍖栧悗鐨勬枃鏈�
+     */
+    public static String format(String template, Object... params)
+    {
+        if (isEmpty(params) || isEmpty(template))
+        {
+            return template;
+        }
+        return StrFormatter.format(template, params);
+    }
+
+    /**
+     * 瀛楃涓茶浆set
+     * 
+     * @param str 瀛楃涓�
+     * @param sep 鍒嗛殧绗�
+     * @return set闆嗗悎
+     */
+    public static final Set<String> str2Set(String str, String sep)
+    {
+        return new HashSet<String>(str2List(str, sep, true, false));
+    }
+
+    /**
+     * 瀛楃涓茶浆list
+     * 
+     * @param str 瀛楃涓�
+     * @param sep 鍒嗛殧绗�
+     * @param filterBlank 杩囨护绾┖鐧�
+     * @param trim 鍘绘帀棣栧熬绌虹櫧
+     * @return list闆嗗悎
+     */
+    public static final List<String> str2List(String str, String sep, boolean filterBlank, boolean trim)
+    {
+        List<String> list = new ArrayList<String>();
+        if (StringUtils.isEmpty(str))
+        {
+            return list;
+        }
+
+        // 杩囨护绌虹櫧瀛楃涓�
+        if (filterBlank && StringUtils.isBlank(str))
+        {
+            return list;
+        }
+        String[] split = str.split(sep);
+        for (String string : split)
+        {
+            if (filterBlank && StringUtils.isBlank(string))
+            {
+                continue;
+            }
+            if (trim)
+            {
+                string = string.trim();
+            }
+            list.add(string);
+        }
+
+        return list;
+    }
+
+    /**
+     * 涓嬪垝绾胯浆椹煎嘲鍛藉悕
+     */
+    public static String toUnderScoreCase(String str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        StringBuilder sb = new StringBuilder();
+        // 鍓嶇疆瀛楃鏄惁澶у啓
+        boolean preCharIsUpperCase = true;
+        // 褰撳墠瀛楃鏄惁澶у啓
+        boolean curreCharIsUpperCase = true;
+        // 涓嬩竴瀛楃鏄惁澶у啓
+        boolean nexteCharIsUpperCase = true;
+        for (int i = 0; i < str.length(); i++)
+        {
+            char c = str.charAt(i);
+            if (i > 0)
+            {
+                preCharIsUpperCase = Character.isUpperCase(str.charAt(i - 1));
+            }
+            else
+            {
+                preCharIsUpperCase = false;
+            }
+
+            curreCharIsUpperCase = Character.isUpperCase(c);
+
+            if (i < (str.length() - 1))
+            {
+                nexteCharIsUpperCase = Character.isUpperCase(str.charAt(i + 1));
+            }
+
+            if (preCharIsUpperCase && curreCharIsUpperCase && !nexteCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            else if ((i != 0 && !preCharIsUpperCase) && curreCharIsUpperCase)
+            {
+                sb.append(SEPARATOR);
+            }
+            sb.append(Character.toLowerCase(c));
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * 鏄惁鍖呭惈瀛楃涓�
+     * 
+     * @param str 楠岃瘉瀛楃涓�
+     * @param strs 瀛楃涓茬粍
+     * @return 鍖呭惈杩斿洖true
+     */
+    public static boolean inStringIgnoreCase(String str, String... strs)
+    {
+        if (str != null && strs != null)
+        {
+            for (String s : strs)
+            {
+                if (str.equalsIgnoreCase(trim(s)))
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 灏嗕笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆杞崲涓洪┘宄板紡銆傚鏋滆浆鎹㈠墠鐨勪笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆涓虹┖锛屽垯杩斿洖绌哄瓧绗︿覆銆� 渚嬪锛欻ELLO_WORLD->HelloWorld
+     * 
+     * @param name 杞崲鍓嶇殑涓嬪垝绾垮ぇ鍐欐柟寮忓懡鍚嶇殑瀛楃涓�
+     * @return 杞崲鍚庣殑椹煎嘲寮忓懡鍚嶇殑瀛楃涓�
+     */
+    public static String convertToCamelCase(String name)
+    {
+        StringBuilder result = new StringBuilder();
+        // 蹇�熸鏌�
+        if (name == null || name.isEmpty())
+        {
+            // 娌″繀瑕佽浆鎹�
+            return "";
+        }
+        else if (!name.contains("_"))
+        {
+            // 涓嶅惈涓嬪垝绾匡紝浠呭皢棣栧瓧姣嶅ぇ鍐�
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 鐢ㄤ笅鍒掔嚎灏嗗師濮嬪瓧绗︿覆鍒嗗壊
+        String[] camels = name.split("_");
+        for (String camel : camels)
+        {
+            // 璺宠繃鍘熷瀛楃涓蹭腑寮�澶淬�佺粨灏剧殑涓嬫崲绾挎垨鍙岄噸涓嬪垝绾�
+            if (camel.isEmpty())
+            {
+                continue;
+            }
+            // 棣栧瓧姣嶅ぇ鍐�
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 椹煎嘲寮忓懡鍚嶆硶 渚嬪锛歶ser_name->userName
+     */
+    public static String toCamelCase(String s)
+    {
+        if (s == null)
+        {
+            return null;
+        }
+        s = s.toLowerCase();
+        StringBuilder sb = new StringBuilder(s.length());
+        boolean upperCase = false;
+        for (int i = 0; i < s.length(); i++)
+        {
+            char c = s.charAt(i);
+
+            if (c == SEPARATOR)
+            {
+                upperCase = true;
+            }
+            else if (upperCase)
+            {
+                sb.append(Character.toUpperCase(c));
+                upperCase = false;
+            }
+            else
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/Threads.java b/ruoyi/src/main/java/com/ruoyi/common/utils/Threads.java
new file mode 100644
index 0000000..395920a
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/Threads.java
@@ -0,0 +1,99 @@
+package com.ruoyi.common.utils;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 绾跨▼鐩稿叧宸ュ叿绫�.
+ * 
+ * @author ruoyi
+ */
+public class Threads
+{
+    private static final Logger logger = LoggerFactory.getLogger(Threads.class);
+
+    /**
+     * sleep绛夊緟,鍗曚綅涓烘绉�
+     */
+    public static void sleep(long milliseconds)
+    {
+        try
+        {
+            Thread.sleep(milliseconds);
+        }
+        catch (InterruptedException e)
+        {
+            return;
+        }
+    }
+
+    /**
+     * 鍋滄绾跨▼姹�
+     * 鍏堜娇鐢╯hutdown, 鍋滄鎺ユ敹鏂颁换鍔″苟灏濊瘯瀹屾垚鎵�鏈夊凡瀛樺湪浠诲姟.
+     * 濡傛灉瓒呮椂, 鍒欒皟鐢╯hutdownNow, 鍙栨秷鍦╳orkQueue涓璓ending鐨勪换鍔�,骞朵腑鏂墍鏈夐樆濉炲嚱鏁�.
+     * 濡傛灉浠嶄汉瓒呮檪锛屽墖寮峰埗閫�鍑�.
+     * 鍙﹀鍦╯hutdown鏃剁嚎绋嬫湰韬璋冪敤涓柇鍋氫簡澶勭悊.
+     */
+    public static void shutdownAndAwaitTermination(ExecutorService pool)
+    {
+        if (pool != null && !pool.isShutdown())
+        {
+            pool.shutdown();
+            try
+            {
+                if (!pool.awaitTermination(120, TimeUnit.SECONDS))
+                {
+                    pool.shutdownNow();
+                    if (!pool.awaitTermination(120, TimeUnit.SECONDS))
+                    {
+                        logger.info("Pool did not terminate");
+                    }
+                }
+            }
+            catch (InterruptedException ie)
+            {
+                pool.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * 鎵撳嵃绾跨▼寮傚父淇℃伅
+     */
+    public static void printException(Runnable r, Throwable t)
+    {
+        if (t == null && r instanceof Future<?>)
+        {
+            try
+            {
+                Future<?> future = (Future<?>) r;
+                if (future.isDone())
+                {
+                    future.get();
+                }
+            }
+            catch (CancellationException ce)
+            {
+                t = ce;
+            }
+            catch (ExecutionException ee)
+            {
+                t = ee.getCause();
+            }
+            catch (InterruptedException ie)
+            {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (t != null)
+        {
+            logger.error(t.getMessage(), t);
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java
new file mode 100644
index 0000000..80b8c84
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/VerifyCodeUtils.java
@@ -0,0 +1,226 @@
+package com.ruoyi.common.utils;
+
+import java.awt.Color;
+import java.awt.Font;
+import java.awt.Graphics;
+import java.awt.Graphics2D;
+import java.awt.RenderingHints;
+import java.awt.geom.AffineTransform;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.security.SecureRandom;
+import java.util.Arrays;
+import java.util.Random;
+import javax.imageio.ImageIO;
+
+/**
+ * 楠岃瘉鐮佸伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class VerifyCodeUtils
+{
+    // 浣跨敤鍒癆lgerian瀛椾綋锛岀郴缁熼噷娌℃湁鐨勮瘽闇�瑕佸畨瑁呭瓧浣擄紝瀛椾綋鍙樉绀哄ぇ鍐欙紝鍘绘帀浜�1,0,i,o鍑犱釜瀹规槗娣锋穯鐨勫瓧绗�
+    public static final String VERIFY_CODES = "123456789ABCDEFGHJKLMNPQRSTUVWXYZ";
+
+    private static Random random = new SecureRandom();
+
+    /**
+     * 浣跨敤绯荤粺榛樿瀛楃婧愮敓鎴愰獙璇佺爜
+     * 
+     * @param verifySize 楠岃瘉鐮侀暱搴�
+     * @return
+     */
+    public static String generateVerifyCode(int verifySize)
+    {
+        return generateVerifyCode(verifySize, VERIFY_CODES);
+    }
+
+    /**
+     * 浣跨敤鎸囧畾婧愮敓鎴愰獙璇佺爜
+     * 
+     * @param verifySize 楠岃瘉鐮侀暱搴�
+     * @param sources 楠岃瘉鐮佸瓧绗︽簮
+     * @return
+     */
+    public static String generateVerifyCode(int verifySize, String sources)
+    {
+        if (sources == null || sources.length() == 0)
+        {
+            sources = VERIFY_CODES;
+        }
+        int codesLen = sources.length();
+        Random rand = new Random(System.currentTimeMillis());
+        StringBuilder verifyCode = new StringBuilder(verifySize);
+        for (int i = 0; i < verifySize; i++)
+        {
+            verifyCode.append(sources.charAt(rand.nextInt(codesLen - 1)));
+        }
+        return verifyCode.toString();
+    }
+
+    /**
+     * 杈撳嚭鎸囧畾楠岃瘉鐮佸浘鐗囨祦
+     * 
+     * @param w
+     * @param h
+     * @param os
+     * @param code
+     * @throws IOException
+     */
+    public static void outputImage(int w, int h, OutputStream os, String code) throws IOException
+    {
+        int verifySize = code.length();
+        BufferedImage image = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
+        Random rand = new Random();
+        Graphics2D g2 = image.createGraphics();
+        g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
+        Color[] colors = new Color[5];
+        Color[] colorSpaces = new Color[] { Color.WHITE, Color.CYAN, Color.GRAY, Color.LIGHT_GRAY, Color.MAGENTA,
+                Color.ORANGE, Color.PINK, Color.YELLOW };
+        float[] fractions = new float[colors.length];
+        for (int i = 0; i < colors.length; i++)
+        {
+            colors[i] = colorSpaces[rand.nextInt(colorSpaces.length)];
+            fractions[i] = rand.nextFloat();
+        }
+        Arrays.sort(fractions);
+
+        g2.setColor(Color.GRAY);// 璁剧疆杈规鑹�
+        g2.fillRect(0, 0, w, h);
+
+        Color c = getRandColor(200, 250);
+        g2.setColor(c);// 璁剧疆鑳屾櫙鑹�
+        g2.fillRect(0, 2, w, h - 4);
+
+        // 缁樺埗骞叉壈绾�
+        Random random = new Random();
+        g2.setColor(getRandColor(160, 200));// 璁剧疆绾挎潯鐨勯鑹�
+        for (int i = 0; i < 20; i++)
+        {
+            int x = random.nextInt(w - 1);
+            int y = random.nextInt(h - 1);
+            int xl = random.nextInt(6) + 1;
+            int yl = random.nextInt(12) + 1;
+            g2.drawLine(x, y, x + xl + 40, y + yl + 20);
+        }
+
+        // 娣诲姞鍣偣
+        float yawpRate = 0.05f;// 鍣0鐜�
+        int area = (int) (yawpRate * w * h);
+        for (int i = 0; i < area; i++)
+        {
+            int x = random.nextInt(w);
+            int y = random.nextInt(h);
+            int rgb = getRandomIntColor();
+            image.setRGB(x, y, rgb);
+        }
+
+        shear(g2, w, h, c);// 浣垮浘鐗囨壄鏇�
+
+        g2.setColor(getRandColor(100, 160));
+        int fontSize = h - 4;
+        Font font = new Font("Algerian", Font.ITALIC, fontSize);
+        g2.setFont(font);
+        char[] chars = code.toCharArray();
+        for (int i = 0; i < verifySize; i++)
+        {
+            AffineTransform affine = new AffineTransform();
+            affine.setToRotation(Math.PI / 4 * rand.nextDouble() * (rand.nextBoolean() ? 1 : -1),
+                    (w / verifySize) * i + fontSize / 2, h / 2);
+            g2.setTransform(affine);
+            g2.drawChars(chars, i, 1, ((w - 10) / verifySize) * i + 5, h / 2 + fontSize / 2 - 10);
+        }
+
+        g2.dispose();
+        ImageIO.write(image, "jpg", os);
+    }
+
+    private static Color getRandColor(int fc, int bc)
+    {
+        if (fc > 255)
+            fc = 255;
+        if (bc > 255)
+            bc = 255;
+        int r = fc + random.nextInt(bc - fc);
+        int g = fc + random.nextInt(bc - fc);
+        int b = fc + random.nextInt(bc - fc);
+        return new Color(r, g, b);
+    }
+
+    private static int getRandomIntColor()
+    {
+        int[] rgb = getRandomRgb();
+        int color = 0;
+        for (int c : rgb)
+        {
+            color = color << 8;
+            color = color | c;
+        }
+        return color;
+    }
+
+    private static int[] getRandomRgb()
+    {
+        int[] rgb = new int[3];
+        for (int i = 0; i < 3; i++)
+        {
+            rgb[i] = random.nextInt(255);
+        }
+        return rgb;
+    }
+
+    private static void shear(Graphics g, int w1, int h1, Color color)
+    {
+        shearX(g, w1, h1, color);
+        shearY(g, w1, h1, color);
+    }
+
+    private static void shearX(Graphics g, int w1, int h1, Color color)
+    {
+
+        int period = random.nextInt(2);
+
+        boolean borderGap = true;
+        int frames = 1;
+        int phase = random.nextInt(2);
+
+        for (int i = 0; i < h1; i++)
+        {
+            double d = (double) (period >> 1)
+                    * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(0, i, w1, 1, (int) d, 0);
+            if (borderGap)
+            {
+                g.setColor(color);
+                g.drawLine((int) d, i, 0, i);
+                g.drawLine((int) d + w1, i, w1, i);
+            }
+        }
+
+    }
+
+    private static void shearY(Graphics g, int w1, int h1, Color color)
+    {
+
+        int period = random.nextInt(40) + 10; // 50;
+
+        boolean borderGap = true;
+        int frames = 20;
+        int phase = 7;
+        for (int i = 0; i < w1; i++)
+        {
+            double d = (double) (period >> 1)
+                    * Math.sin((double) i / (double) period + (6.2831853071795862D * (double) phase) / (double) frames);
+            g.copyArea(i, 0, 1, h1, 0, (int) d);
+            if (borderGap)
+            {
+                g.setColor(color);
+                g.drawLine(i, (int) d, i, 0);
+                g.drawLine(i, (int) d + h1, i, h1);
+            }
+
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
new file mode 100644
index 0000000..48d3ada
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
@@ -0,0 +1,243 @@
+package com.ruoyi.common.utils.file;
+
+import java.io.File;
+import java.io.IOException;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.exception.file.FileNameLengthLimitExceededException;
+import com.ruoyi.common.exception.file.FileSizeLimitExceededException;
+import com.ruoyi.common.exception.file.InvalidExtensionException;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.security.Md5Utils;
+import com.ruoyi.framework.config.RuoYiConfig;
+
+/**
+ * 鏂囦欢涓婁紶宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class FileUploadUtils
+{
+    /**
+     * 榛樿澶у皬 50M
+     */
+    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024;
+
+    /**
+     * 榛樿鐨勬枃浠跺悕鏈�澶ч暱搴� 100
+     */
+    public static final int DEFAULT_FILE_NAME_LENGTH = 100;
+
+    /**
+     * 榛樿涓婁紶鐨勫湴鍧�
+     */
+    private static String defaultBaseDir = RuoYiConfig.getProfile();
+
+    private static int counter = 0;
+
+    public static void setDefaultBaseDir(String defaultBaseDir)
+    {
+        FileUploadUtils.defaultBaseDir = defaultBaseDir;
+    }
+
+    public static String getDefaultBaseDir()
+    {
+        return defaultBaseDir;
+    }
+
+    /**
+     * 浠ラ粯璁ら厤缃繘琛屾枃浠朵笂浼�
+     *
+     * @param file 涓婁紶鐨勬枃浠�
+     * @return 鏂囦欢鍚嶇О
+     * @throws Exception
+     */
+    public static final String upload(MultipartFile file) throws IOException
+    {
+        try
+        {
+            return upload(getDefaultBaseDir(), file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+        }
+        catch (Exception e)
+        {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 鏍规嵁鏂囦欢璺緞涓婁紶
+     *
+     * @param baseDir 鐩稿搴旂敤鐨勫熀鐩綍
+     * @param file 涓婁紶鐨勬枃浠�
+     * @return 鏂囦欢鍚嶇О
+     * @throws IOException
+     */
+    public static final String upload(String baseDir, MultipartFile file) throws IOException
+    {
+        try
+        {
+            return upload(baseDir, file, MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION);
+        }
+        catch (Exception e)
+        {
+            throw new IOException(e.getMessage(), e);
+        }
+    }
+
+    /**
+     * 鏂囦欢涓婁紶
+     *
+     * @param baseDir 鐩稿搴旂敤鐨勫熀鐩綍
+     * @param file 涓婁紶鐨勬枃浠�
+     * @param extension 涓婁紶鏂囦欢绫诲瀷
+     * @return 杩斿洖涓婁紶鎴愬姛鐨勬枃浠跺悕
+     * @throws FileSizeLimitExceededException 濡傛灉瓒呭嚭鏈�澶уぇ灏�
+     * @throws FileNameLengthLimitExceededException 鏂囦欢鍚嶅お闀�
+     * @throws IOException 姣斿璇诲啓鏂囦欢鍑洪敊鏃�
+     * @throws InvalidExtensionException 鏂囦欢鏍¢獙寮傚父
+     */
+    public static final String upload(String baseDir, MultipartFile file, String[] allowedExtension)
+            throws FileSizeLimitExceededException, IOException, FileNameLengthLimitExceededException,
+            InvalidExtensionException
+    {
+        int fileNamelength = file.getOriginalFilename().length();
+        if (fileNamelength > FileUploadUtils.DEFAULT_FILE_NAME_LENGTH)
+        {
+            throw new FileNameLengthLimitExceededException(FileUploadUtils.DEFAULT_FILE_NAME_LENGTH);
+        }
+
+        assertAllowed(file, allowedExtension);
+
+        String fileName = extractFilename(file);
+
+        File desc = getAbsoluteFile(baseDir, fileName);
+        file.transferTo(desc);
+        String pathFileName = getPathFileName(baseDir, fileName);
+        return pathFileName;
+    }
+
+    /**
+     * 缂栫爜鏂囦欢鍚�
+     */
+    public static final String extractFilename(MultipartFile file)
+    {
+        String fileName = file.getOriginalFilename();
+        String extension = getExtension(file);
+        fileName = DateUtils.datePath() + "/" + encodingFilename(fileName) + "." + extension;
+        return fileName;
+    }
+
+    private static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
+    {
+        File desc = new File(uploadDir + File.separator + fileName);
+
+        if (!desc.getParentFile().exists())
+        {
+            desc.getParentFile().mkdirs();
+        }
+        if (!desc.exists())
+        {
+            desc.createNewFile();
+        }
+        return desc;
+    }
+
+    private static final String getPathFileName(String uploadDir, String fileName) throws IOException
+    {
+        int dirLastIndex = uploadDir.lastIndexOf("/") + 1;
+        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
+        String pathFileName = Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + fileName;
+        return pathFileName;
+    }
+
+    /**
+     * 缂栫爜鏂囦欢鍚�
+     */
+    private static final String encodingFilename(String fileName)
+    {
+        fileName = fileName.replace("_", " ");
+        fileName = Md5Utils.hash(fileName + System.nanoTime() + counter++);
+        return fileName;
+    }
+
+    /**
+     * 鏂囦欢澶у皬鏍¢獙
+     *
+     * @param file 涓婁紶鐨勬枃浠�
+     * @return
+     * @throws FileSizeLimitExceededException 濡傛灉瓒呭嚭鏈�澶уぇ灏�
+     * @throws InvalidExtensionException
+     */
+    public static final void assertAllowed(MultipartFile file, String[] allowedExtension)
+            throws FileSizeLimitExceededException, InvalidExtensionException
+    {
+        long size = file.getSize();
+        if (DEFAULT_MAX_SIZE != -1 && size > DEFAULT_MAX_SIZE)
+        {
+            throw new FileSizeLimitExceededException(DEFAULT_MAX_SIZE / 1024 / 1024);
+        }
+
+        String fileName = file.getOriginalFilename();
+        String extension = getExtension(file);
+        if (allowedExtension != null && !isAllowedExtension(extension, allowedExtension))
+        {
+            if (allowedExtension == MimeTypeUtils.IMAGE_EXTENSION)
+            {
+                throw new InvalidExtensionException.InvalidImageExtensionException(allowedExtension, extension,
+                        fileName);
+            }
+            else if (allowedExtension == MimeTypeUtils.FLASH_EXTENSION)
+            {
+                throw new InvalidExtensionException.InvalidFlashExtensionException(allowedExtension, extension,
+                        fileName);
+            }
+            else if (allowedExtension == MimeTypeUtils.MEDIA_EXTENSION)
+            {
+                throw new InvalidExtensionException.InvalidMediaExtensionException(allowedExtension, extension,
+                        fileName);
+            }
+            else
+            {
+                throw new InvalidExtensionException(allowedExtension, extension, fileName);
+            }
+        }
+
+    }
+
+    /**
+     * 鍒ゆ柇MIME绫诲瀷鏄惁鏄厑璁哥殑MIME绫诲瀷
+     *
+     * @param extension
+     * @param allowedExtension
+     * @return
+     */
+    public static final boolean isAllowedExtension(String extension, String[] allowedExtension)
+    {
+        for (String str : allowedExtension)
+        {
+            if (str.equalsIgnoreCase(extension))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 鑾峰彇鏂囦欢鍚嶇殑鍚庣紑
+     * 
+     * @param file 琛ㄥ崟鏂囦欢
+     * @return 鍚庣紑鍚�
+     */
+    public static final String getExtension(MultipartFile file)
+    {
+        String extension = FilenameUtils.getExtension(file.getOriginalFilename());
+        if (StringUtils.isEmpty(extension))
+        {
+            extension = MimeTypeUtils.getExtension(file.getContentType());
+        }
+        return extension;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
new file mode 100644
index 0000000..03f5aa2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -0,0 +1,142 @@
+package com.ruoyi.common.utils.file;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 鏂囦欢澶勭悊宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class FileUtils
+{
+    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
+
+    /**
+     * 杈撳嚭鎸囧畾鏂囦欢鐨刡yte鏁扮粍
+     * 
+     * @param filePath 鏂囦欢璺緞
+     * @param os 杈撳嚭娴�
+     * @return
+     */
+    public static void writeBytes(String filePath, OutputStream os) throws IOException
+    {
+        FileInputStream fis = null;
+        try
+        {
+            File file = new File(filePath);
+            if (!file.exists())
+            {
+                throw new FileNotFoundException(filePath);
+            }
+            fis = new FileInputStream(file);
+            byte[] b = new byte[1024];
+            int length;
+            while ((length = fis.read(b)) > 0)
+            {
+                os.write(b, 0, length);
+            }
+        }
+        catch (IOException e)
+        {
+            throw e;
+        }
+        finally
+        {
+            if (os != null)
+            {
+                try
+                {
+                    os.close();
+                }
+                catch (IOException e1)
+                {
+                    e1.printStackTrace();
+                }
+            }
+            if (fis != null)
+            {
+                try
+                {
+                    fis.close();
+                }
+                catch (IOException e1)
+                {
+                    e1.printStackTrace();
+                }
+            }
+        }
+    }
+
+    /**
+     * 鍒犻櫎鏂囦欢
+     * 
+     * @param filePath 鏂囦欢
+     * @return
+     */
+    public static boolean deleteFile(String filePath)
+    {
+        boolean flag = false;
+        File file = new File(filePath);
+        // 璺緞涓烘枃浠朵笖涓嶄负绌哄垯杩涜鍒犻櫎
+        if (file.isFile() && file.exists())
+        {
+            file.delete();
+            flag = true;
+        }
+        return flag;
+    }
+
+    /**
+     * 鏂囦欢鍚嶇О楠岃瘉
+     * 
+     * @param filename 鏂囦欢鍚嶇О
+     * @return true 姝e父 false 闈炴硶
+     */
+    public static boolean isValidFilename(String filename)
+    {
+        return filename.matches(FILENAME_PATTERN);
+    }
+
+    /**
+     * 涓嬭浇鏂囦欢鍚嶉噸鏂扮紪鐮�
+     * 
+     * @param request 璇锋眰瀵硅薄
+     * @param fileName 鏂囦欢鍚�
+     * @return 缂栫爜鍚庣殑鏂囦欢鍚�
+     */
+    public static String setFileDownloadHeader(HttpServletRequest request, String fileName)
+            throws UnsupportedEncodingException
+    {
+        final String agent = request.getHeader("USER-AGENT");
+        String filename = fileName;
+        if (agent.contains("MSIE"))
+        {
+            // IE娴忚鍣�
+            filename = URLEncoder.encode(filename, "utf-8");
+            filename = filename.replace("+", " ");
+        }
+        else if (agent.contains("Firefox"))
+        {
+            // 鐏嫄娴忚鍣�
+            filename = new String(fileName.getBytes(), "ISO8859-1");
+        }
+        else if (agent.contains("Chrome"))
+        {
+            // google娴忚鍣�
+            filename = URLEncoder.encode(filename, "utf-8");
+        }
+        else
+        {
+            // 鍏跺畠娴忚鍣�
+            filename = URLEncoder.encode(filename, "utf-8");
+        }
+        return filename;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
new file mode 100644
index 0000000..d179a91
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
@@ -0,0 +1,55 @@
+package com.ruoyi.common.utils.file;
+
+/**
+ * 濯掍綋绫诲瀷宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class MimeTypeUtils
+{
+    public static final String IMAGE_PNG = "image/png";
+
+    public static final String IMAGE_JPG = "image/jpg";
+
+    public static final String IMAGE_JPEG = "image/jpeg";
+
+    public static final String IMAGE_BMP = "image/bmp";
+
+    public static final String IMAGE_GIF = "image/gif";
+    
+    public static final String[] IMAGE_EXTENSION = { "bmp", "gif", "jpg", "jpeg", "png" };
+
+    public static final String[] FLASH_EXTENSION = { "swf", "flv" };
+
+    public static final String[] MEDIA_EXTENSION = { "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg",
+            "asf", "rm", "rmvb" };
+
+    public static final String[] DEFAULT_ALLOWED_EXTENSION = {
+            // 鍥剧墖
+            "bmp", "gif", "jpg", "jpeg", "png",
+            // word excel powerpoint
+            "doc", "docx", "xls", "xlsx", "ppt", "pptx", "html", "htm", "txt",
+            // 鍘嬬缉鏂囦欢
+            "rar", "zip", "gz", "bz2",
+            // pdf
+            "pdf" };
+
+    public static String getExtension(String prefix)
+    {
+        switch (prefix)
+        {
+            case IMAGE_PNG:
+                return "png";
+            case IMAGE_JPG:
+                return "jpg";
+            case IMAGE_JPEG:
+                return "jpeg";
+            case IMAGE_BMP:
+                return "bmp";
+            case IMAGE_GIF:
+                return "gif";
+            default:
+                return "";
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java b/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
new file mode 100644
index 0000000..f6754c4
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
@@ -0,0 +1,152 @@
+package com.ruoyi.common.utils.html;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 杞箟鍜屽弽杞箟宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class EscapeUtil
+{
+    public static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
+
+    private static final char[][] TEXT = new char[64][];
+
+    static
+    {
+        for (int i = 0; i < 64; i++)
+        {
+            TEXT[i] = new char[] { (char) i };
+        }
+
+        // special HTML characters
+        TEXT['\''] = "&#039;".toCharArray(); // 鍗曞紩鍙�
+        TEXT['"'] = "&#34;".toCharArray(); // 鍗曞紩鍙�
+        TEXT['&'] = "&#38;".toCharArray(); // &绗�
+        TEXT['<'] = "&#60;".toCharArray(); // 灏忎簬鍙�
+        TEXT['>'] = "&#62;".toCharArray(); // 澶т簬鍙�
+    }
+
+    /**
+     * 杞箟鏂囨湰涓殑HTML瀛楃涓哄畨鍏ㄧ殑瀛楃
+     * 
+     * @param text 琚浆涔夌殑鏂囨湰
+     * @return 杞箟鍚庣殑鏂囨湰
+     */
+    public static String escape(String text)
+    {
+        return encode(text);
+    }
+
+    /**
+     * 杩樺師琚浆涔夌殑HTML鐗规畩瀛楃
+     * 
+     * @param content 鍖呭惈杞箟绗︾殑HTML鍐呭
+     * @return 杞崲鍚庣殑瀛楃涓�
+     */
+    public static String unescape(String content)
+    {
+        return decode(content);
+    }
+
+    /**
+     * 娓呴櫎鎵�鏈塇TML鏍囩锛屼絾鏄笉鍒犻櫎鏍囩鍐呯殑鍐呭
+     * 
+     * @param content 鏂囨湰
+     * @return 娓呴櫎鏍囩鍚庣殑鏂囨湰
+     */
+    public static String clean(String content)
+    {
+        return content.replaceAll(RE_HTML_MARK, "");
+    }
+
+    /**
+     * Escape缂栫爜
+     * 
+     * @param text 琚紪鐮佺殑鏂囨湰
+     * @return 缂栫爜鍚庣殑瀛楃
+     */
+    private static String encode(String text)
+    {
+        int len;
+        if ((text == null) || ((len = text.length()) == 0))
+        {
+            return StringUtils.EMPTY;
+        }
+        StringBuilder buffer = new StringBuilder(len + (len >> 2));
+        char c;
+        for (int i = 0; i < len; i++)
+        {
+            c = text.charAt(i);
+            if (c < 64)
+            {
+                buffer.append(TEXT[c]);
+            }
+            else
+            {
+                buffer.append(c);
+            }
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Escape瑙g爜
+     * 
+     * @param content 琚浆涔夌殑鍐呭
+     * @return 瑙g爜鍚庣殑瀛楃涓�
+     */
+    public static String decode(String content)
+    {
+        if (StringUtils.isEmpty(content))
+        {
+            return content;
+        }
+
+        StringBuilder tmp = new StringBuilder(content.length());
+        int lastPos = 0, pos = 0;
+        char ch;
+        while (lastPos < content.length())
+        {
+            pos = content.indexOf("%", lastPos);
+            if (pos == lastPos)
+            {
+                if (content.charAt(pos + 1) == 'u')
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 6;
+                }
+                else
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 3;
+                }
+            }
+            else
+            {
+                if (pos == -1)
+                {
+                    tmp.append(content.substring(lastPos));
+                    lastPos = content.length();
+                }
+                else
+                {
+                    tmp.append(content.substring(lastPos, pos));
+                    lastPos = pos;
+                }
+            }
+        }
+        return tmp.toString();
+    }
+
+    public static void main(String[] args)
+    {
+        String html = "<script>alert(1);</script>";
+        System.out.println(EscapeUtil.clean(html));
+        System.out.println(EscapeUtil.escape(html));
+        System.out.println(EscapeUtil.unescape(html));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
new file mode 100644
index 0000000..323dbc1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -0,0 +1,248 @@
+package com.ruoyi.common.utils.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ConnectException;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.security.cert.X509Certificate;
+import javax.net.ssl.HostnameVerifier;
+import javax.net.ssl.HttpsURLConnection;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSession;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 閫氱敤http鍙戦�佹柟娉�
+ * 
+ * @author ruoyi
+ */
+public class HttpUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丟ET鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @param param 璇锋眰鍙傛暟锛岃姹傚弬鏁板簲璇ユ槸 name1=value1&name2=value2 鐨勫舰寮忋��
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendGet(String url, String param)
+    {
+        StringBuilder result = new StringBuilder();
+        BufferedReader in = null;
+        try
+        {
+            String urlNameString = url + "?" + param;
+            log.info("sendGet - {}", urlNameString);
+            URL realUrl = new URL(urlNameString);
+            URLConnection connection = realUrl.openConnection();
+            connection.setRequestProperty("accept", "*/*");
+            connection.setRequestProperty("connection", "Keep-Alive");
+            connection.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            connection.connect();
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream()));
+            String line;
+            while ((line = in.readLine()) != null)
+            {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        }
+        catch (ConnectException e)
+        {
+            log.error("璋冪敤HttpUtils.sendGet ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("璋冪敤HttpUtils.sendGet SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("璋冪敤HttpUtils.sendGet IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("璋冪敤HttpsUtil.sendGet Exception, url=" + url + ",param=" + param, e);
+        }
+        finally
+        {
+            try
+            {
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (Exception ex)
+            {
+                log.error("璋冪敤in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丳OST鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @param param 璇锋眰鍙傛暟锛岃姹傚弬鏁板簲璇ユ槸 name1=value1&name2=value2 鐨勫舰寮忋��
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendPost(String url, String param)
+    {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            String urlNameString = url + "?" + param;
+            log.info("sendPost - {}", urlNameString);
+            URL realUrl = new URL(urlNameString);
+            URLConnection conn = realUrl.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            out = new PrintWriter(conn.getOutputStream());
+            out.print(param);
+            out.flush();
+            in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "utf-8"));
+            String line;
+            while ((line = in.readLine()) != null)
+            {
+                result.append(line);
+            }
+            log.info("recv - {}", result);
+        }
+        catch (ConnectException e)
+        {
+            log.error("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("璋冪敤HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("璋冪敤HttpUtils.sendPost IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("璋冪敤HttpsUtil.sendPost Exception, url=" + url + ",param=" + param, e);
+        }
+        finally
+        {
+            try
+            {
+                if (out != null)
+                {
+                    out.close();
+                }
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (IOException ex)
+            {
+                log.error("璋冪敤in.close Exception, url=" + url + ",param=" + param, ex);
+            }
+        }
+        return result.toString();
+    }
+
+    public static String sendSSLPost(String url, String param)
+    {
+        StringBuilder result = new StringBuilder();
+        String urlNameString = url + "?" + param;
+        try
+        {
+            log.info("sendSSLPost - {}", urlNameString);
+            SSLContext sc = SSLContext.getInstance("SSL");
+            sc.init(null, new TrustManager[] { new TrustAnyTrustManager() }, new java.security.SecureRandom());
+            URL console = new URL(urlNameString);
+            HttpsURLConnection conn = (HttpsURLConnection) console.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");
+            conn.setRequestProperty("Accept-Charset", "utf-8");
+            conn.setRequestProperty("contentType", "utf-8");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+
+            conn.setSSLSocketFactory(sc.getSocketFactory());
+            conn.setHostnameVerifier(new TrustAnyHostnameVerifier());
+            conn.connect();
+            InputStream is = conn.getInputStream();
+            BufferedReader br = new BufferedReader(new InputStreamReader(is));
+            String ret = "";
+            while ((ret = br.readLine()) != null)
+            {
+                if (ret != null && !ret.trim().equals(""))
+                {
+                    result.append(new String(ret.getBytes("ISO-8859-1"), "utf-8"));
+                }
+            }
+            log.info("recv - {}", result);
+            conn.disconnect();
+            br.close();
+        }
+        catch (ConnectException e)
+        {
+            log.error("璋冪敤HttpUtils.sendSSLPost ConnectException, url=" + url + ",param=" + param, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("璋冪敤HttpUtils.sendSSLPost SocketTimeoutException, url=" + url + ",param=" + param, e);
+        }
+        catch (IOException e)
+        {
+            log.error("璋冪敤HttpUtils.sendSSLPost IOException, url=" + url + ",param=" + param, e);
+        }
+        catch (Exception e)
+        {
+            log.error("璋冪敤HttpsUtil.sendSSLPost Exception, url=" + url + ",param=" + param, e);
+        }
+        return result.toString();
+    }
+
+    private static class TrustAnyTrustManager implements X509TrustManager
+    {
+        @Override
+        public void checkClientTrusted(X509Certificate[] chain, String authType)
+        {
+        }
+
+        @Override
+        public void checkServerTrusted(X509Certificate[] chain, String authType)
+        {
+        }
+
+        @Override
+        public X509Certificate[] getAcceptedIssuers()
+        {
+            return new X509Certificate[] {};
+        }
+    }
+
+    private static class TrustAnyHostnameVerifier implements HostnameVerifier
+    {
+        @Override
+        public boolean verify(String hostname, SSLSession session)
+        {
+            return true;
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
new file mode 100644
index 0000000..d70351f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
@@ -0,0 +1,41 @@
+package com.ruoyi.common.utils.ip;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.alibaba.fastjson.JSONObject;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.http.HttpUtils;
+
+/**
+ * 鑾峰彇鍦板潃绫�
+ * 
+ * @author ruoyi
+ */
+public class AddressUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
+
+    public static final String IP_URL = "http://ip.taobao.com/service/getIpInfo.php";
+
+    public static String getRealAddressByIP(String ip)
+    {
+        String address = "XX XX";
+        // 鍐呯綉涓嶆煡璇�
+        if (IpUtils.internalIp(ip))
+        {
+            return "鍐呯綉IP";
+        }
+        String rspStr = HttpUtils.sendPost(IP_URL, "ip=" + ip);
+        if (StringUtils.isEmpty(rspStr))
+        {
+            log.error("鑾峰彇鍦扮悊浣嶇疆寮傚父 {}", ip);
+            return address;
+        }
+        JSONObject obj = JSONObject.parseObject(rspStr);
+        JSONObject data = obj.getObject("data", JSONObject.class);
+        String region = data.getString("region");
+        String city = data.getString("city");
+        address = region + " " + city;
+        return address;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
new file mode 100644
index 0000000..9e050e9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
@@ -0,0 +1,189 @@
+package com.ruoyi.common.utils.ip;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.servlet.http.HttpServletRequest;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 鑾峰彇IP鏂规硶
+ * 
+ * @author ruoyi
+ */
+public class IpUtils
+{
+    public static String getIpAddr(HttpServletRequest request)
+    {
+        if (request == null)
+        {
+            return "unknown";
+        }
+        String ip = request.getHeader("x-forwarded-for");
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Forwarded-For");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("WL-Proxy-Client-IP");
+        }
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getHeader("X-Real-IP");
+        }
+
+        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip))
+        {
+            ip = request.getRemoteAddr();
+        }
+
+        return "0:0:0:0:0:0:0:1".equals(ip) ? "127.0.0.1" : ip;
+    }
+
+    public static boolean internalIp(String ip)
+    {
+        byte[] addr = textToNumericFormatV4(ip);
+        return internalIp(addr) || "127.0.0.1".equals(ip);
+    }
+
+    private static boolean internalIp(byte[] addr)
+    {
+        if (StringUtils.isNull(addr) || addr.length < 2)
+        {
+            return true;
+        }
+        final byte b0 = addr[0];
+        final byte b1 = addr[1];
+        // 10.x.x.x/8
+        final byte SECTION_1 = 0x0A;
+        // 172.16.x.x/12
+        final byte SECTION_2 = (byte) 0xAC;
+        final byte SECTION_3 = (byte) 0x10;
+        final byte SECTION_4 = (byte) 0x1F;
+        // 192.168.x.x/16
+        final byte SECTION_5 = (byte) 0xC0;
+        final byte SECTION_6 = (byte) 0xA8;
+        switch (b0)
+        {
+            case SECTION_1:
+                return true;
+            case SECTION_2:
+                if (b1 >= SECTION_3 && b1 <= SECTION_4)
+                {
+                    return true;
+                }
+            case SECTION_5:
+                switch (b1)
+                {
+                    case SECTION_6:
+                        return true;
+                }
+            default:
+                return false;
+        }
+    }
+
+    /**
+     * 灏咺Pv4鍦板潃杞崲鎴愬瓧鑺�
+     * 
+     * @param text IPv4鍦板潃
+     * @return byte 瀛楄妭
+     */
+    public static byte[] textToNumericFormatV4(String text)
+    {
+        if (text.length() == 0)
+        {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try
+        {
+            long l;
+            int i;
+            switch (elements.length)
+            {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L))
+                        return null;
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L))
+                        return null;
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L))
+                        return null;
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                            return null;
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L))
+                        return null;
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                            return null;
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        }
+        catch (NumberFormatException e)
+        {
+            return null;
+        }
+        return bytes;
+    }
+
+    public static String getHostIp()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostAddress();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "127.0.0.1";
+    }
+
+    public static String getHostName()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostName();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "鏈煡";
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/security/Md5Utils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/security/Md5Utils.java
new file mode 100644
index 0000000..40e8030
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/security/Md5Utils.java
@@ -0,0 +1,66 @@
+package com.ruoyi.common.utils.security;
+
+import java.security.MessageDigest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Md5鍔犲瘑鏂规硶
+ * 
+ * @author ruoyi
+ */
+public class Md5Utils
+{
+    private static final Logger log = LoggerFactory.getLogger(Md5Utils.class);
+
+    private static byte[] md5(String s)
+    {
+        MessageDigest algorithm;
+        try
+        {
+            algorithm = MessageDigest.getInstance("MD5");
+            algorithm.reset();
+            algorithm.update(s.getBytes("UTF-8"));
+            byte[] messageDigest = algorithm.digest();
+            return messageDigest;
+        }
+        catch (Exception e)
+        {
+            log.error("MD5 Error...", e);
+        }
+        return null;
+    }
+
+    private static final String toHex(byte hash[])
+    {
+        if (hash == null)
+        {
+            return null;
+        }
+        StringBuffer buf = new StringBuffer(hash.length * 2);
+        int i;
+
+        for (i = 0; i < hash.length; i++)
+        {
+            if ((hash[i] & 0xff) < 0x10)
+            {
+                buf.append("0");
+            }
+            buf.append(Long.toString(hash[i] & 0xff, 16));
+        }
+        return buf.toString();
+    }
+
+    public static String hash(String s)
+    {
+        try
+        {
+            return new String(toHex(md5(s)).getBytes("UTF-8"), "UTF-8");
+        }
+        catch (Exception e)
+        {
+            log.error("not supported charset...{}", e);
+            return s;
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/sign/Base64.java b/ruoyi/src/main/java/com/ruoyi/common/utils/sign/Base64.java
new file mode 100644
index 0000000..f2c1bfe
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/sign/Base64.java
@@ -0,0 +1,291 @@
+package com.ruoyi.common.utils.sign;
+
+/**
+ * Base64宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public final class Base64
+{
+    static private final int     BASELENGTH           = 128;
+    static private final int     LOOKUPLENGTH         = 64;
+    static private final int     TWENTYFOURBITGROUP   = 24;
+    static private final int     EIGHTBIT             = 8;
+    static private final int     SIXTEENBIT           = 16;
+    static private final int     FOURBYTE             = 4;
+    static private final int     SIGN                 = -128;
+    static private final char    PAD                  = '=';
+    static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
+    static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];
+
+    static
+    {
+        for (int i = 0; i < BASELENGTH; ++i)
+        {
+            base64Alphabet[i] = -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i >= 'a'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+
+        for (int i = '9'; i >= '0'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+'] = 62;
+        base64Alphabet['/'] = 63;
+
+        for (int i = 0; i <= 25; i++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('A' + i);
+        }
+
+        for (int i = 26, j = 0; i <= 51; i++, j++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('a' + j);
+        }
+
+        for (int i = 52, j = 0; i <= 61; i++, j++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('0' + j);
+        }
+        lookUpBase64Alphabet[62] = (char) '+';
+        lookUpBase64Alphabet[63] = (char) '/';
+    }
+
+    private static boolean isWhiteSpace(char octect)
+    {
+        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
+    }
+
+    private static boolean isPad(char octect)
+    {
+        return (octect == PAD);
+    }
+
+    private static boolean isData(char octect)
+    {
+        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
+    }
+
+    /**
+     * Encodes hex octects into Base64
+     *
+     * @param binaryData Array containing binaryData
+     * @return Encoded Base64 array
+     */
+    public static String encode(byte[] binaryData)
+    {
+        if (binaryData == null)
+        {
+            return null;
+        }
+
+        int lengthDataBits = binaryData.length * EIGHTBIT;
+        if (lengthDataBits == 0)
+        {
+            return "";
+        }
+
+        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
+        char encodedData[] = null;
+
+        encodedData = new char[numberQuartet * 4];
+
+        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+
+        for (int i = 0; i < numberTriplets; i++)
+        {
+            b1 = binaryData[dataIndex++];
+            b2 = binaryData[dataIndex++];
+            b3 = binaryData[dataIndex++];
+
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
+        }
+
+        // form integral number of 6-bit groups
+        if (fewerThan24bits == EIGHTBIT)
+        {
+            b1 = binaryData[dataIndex];
+            k = (byte) (b1 & 0x03);
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
+            encodedData[encodedIndex++] = PAD;
+            encodedData[encodedIndex++] = PAD;
+        }
+        else if (fewerThan24bits == SIXTEENBIT)
+        {
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
+            encodedData[encodedIndex++] = PAD;
+        }
+        return new String(encodedData);
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param encoded string containing Base64 data
+     * @return Array containind decoded data.
+     */
+    public static byte[] decode(String encoded)
+    {
+        if (encoded == null)
+        {
+            return null;
+        }
+
+        char[] base64Data = encoded.toCharArray();
+        // remove white spaces
+        int len = removeWhiteSpace(base64Data);
+
+        if (len % FOURBYTE != 0)
+        {
+            return null;// should be divisible by four
+        }
+
+        int numberQuadruple = (len / FOURBYTE);
+
+        if (numberQuadruple == 0)
+        {
+            return new byte[0];
+        }
+
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
+
+        int i = 0;
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        decodedData = new byte[(numberQuadruple) * 3];
+
+        for (; i < numberQuadruple - 1; i++)
+        {
+
+            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
+                    || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
+            {
+                return null;
+            } // if found "no data" just return null
+
+            b1 = base64Alphabet[d1];
+            b2 = base64Alphabet[d2];
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+        }
+
+        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])))
+        {
+            return null;// if found "no data" just return null
+        }
+
+        b1 = base64Alphabet[d1];
+        b2 = base64Alphabet[d2];
+
+        d3 = base64Data[dataIndex++];
+        d4 = base64Data[dataIndex++];
+        if (!isData((d3)) || !isData((d4)))
+        {// Check if they are PAD characters
+            if (isPad(d3) && isPad(d4))
+            {
+                if ((b2 & 0xf) != 0)// last 4 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 1];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                return tmp;
+            }
+            else if (!isPad(d3) && isPad(d4))
+            {
+                b3 = base64Alphabet[d3];
+                if ((b3 & 0x3) != 0)// last 2 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 2];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                return tmp;
+            }
+            else
+            {
+                return null;
+            }
+        }
+        else
+        { // No PAD e.g 3cQl
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+
+        }
+        return decodedData;
+    }
+
+    /**
+     * remove WhiteSpace from MIME containing encoded Base64 data.
+     *
+     * @param data the byte array of base64 data (with WS)
+     * @return the new length
+     */
+    private static int removeWhiteSpace(char[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        // count characters that's not whitespace
+        int newSize = 0;
+        int len = data.length;
+        for (int i = 0; i < len; i++)
+        {
+            if (!isWhiteSpace(data[i]))
+            {
+                data[newSize++] = data[i];
+            }
+        }
+        return newSize;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java b/ruoyi/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
new file mode 100644
index 0000000..e031159
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
@@ -0,0 +1,114 @@
+package com.ruoyi.common.utils.spring;
+
+import org.springframework.aop.framework.AopContext;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.NoSuchBeanDefinitionException;
+import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
+import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring宸ュ叿绫� 鏂逛究鍦ㄩ潪spring绠$悊鐜涓幏鍙朾ean
+ * 
+ * @author ruoyi
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor
+{
+    /** Spring搴旂敤涓婁笅鏂囩幆澧� */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException
+    {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    /**
+     * 鑾峰彇瀵硅薄
+     *
+     * @param name
+     * @return Object 涓�涓互鎵�缁欏悕瀛楁敞鍐岀殑bean鐨勫疄渚�
+     * @throws org.springframework.beans.BeansException
+     *
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getBean(String name) throws BeansException
+    {
+        return (T) beanFactory.getBean(name);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷涓簉equiredType鐨勫璞�
+     *
+     * @param clz
+     * @return
+     * @throws org.springframework.beans.BeansException
+     *
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException
+    {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 濡傛灉BeanFactory鍖呭惈涓�涓笌鎵�缁欏悕绉板尮閰嶇殑bean瀹氫箟锛屽垯杩斿洖true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name)
+    {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 鍒ゆ柇浠ョ粰瀹氬悕瀛楁敞鍐岀殑bean瀹氫箟鏄竴涓猻ingleton杩樻槸涓�涓猵rototype銆� 濡傛灉涓庣粰瀹氬悕瀛楃浉搴旂殑bean瀹氫箟娌℃湁琚壘鍒帮紝灏嗕細鎶涘嚭涓�涓紓甯革紙NoSuchBeanDefinitionException锛�
+     *
+     * @param name
+     * @return boolean
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 娉ㄥ唽瀵硅薄鐨勭被鍨�
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 濡傛灉缁欏畾鐨刡ean鍚嶅瓧鍦╞ean瀹氫箟涓湁鍒悕锛屽垯杩斿洖杩欎簺鍒悕
+     *
+     * @param name
+     * @return
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 鑾峰彇aop浠g悊瀵硅薄
+     * 
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker)
+    {
+        return (T) AopContext.currentProxy();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/ruoyi/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
new file mode 100644
index 0000000..b8aeaa1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
@@ -0,0 +1,36 @@
+package com.ruoyi.common.utils.sql;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * sql鎿嶄綔宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public class SqlUtil
+{
+    /**
+     * 浠呮敮鎸佸瓧姣嶃�佹暟瀛椼�佷笅鍒掔嚎銆佺┖鏍笺�侀�楀彿锛堟敮鎸佸涓瓧娈垫帓搴忥級
+     */
+    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,]+";
+
+    /**
+     * 妫�鏌ュ瓧绗︼紝闃叉娉ㄥ叆缁曡繃
+     */
+    public static String escapeOrderBySql(String value)
+    {
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
+        {
+            return StringUtils.EMPTY;
+        }
+        return value;
+    }
+
+    /**
+     * 楠岃瘉 order by 璇硶鏄惁绗﹀悎瑙勮寖
+     */
+    public static boolean isValidOrderBySql(String value)
+    {
+        return value.matches(SQL_PATTERN);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/common/xss/XssFilter.java b/ruoyi/src/main/java/com/ruoyi/common/xss/XssFilter.java
new file mode 100644
index 0000000..d307fbc
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/xss/XssFilter.java
@@ -0,0 +1,97 @@
+package com.ruoyi.common.xss;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.FilterConfig;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 闃叉XSS鏀诲嚮鐨勮繃婊ゅ櫒
+ * 
+ * @author ruoyi
+ */
+public class XssFilter implements Filter
+{
+    /**
+     * 鎺掗櫎閾炬帴
+     */
+    public List<String> excludes = new ArrayList<>();
+
+    /**
+     * xss杩囨护寮�鍏�
+     */
+    public boolean enabled = false;
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+        String tempExcludes = filterConfig.getInitParameter("excludes");
+        String tempEnabled = filterConfig.getInitParameter("enabled");
+        if (StringUtils.isNotEmpty(tempExcludes))
+        {
+            String[] url = tempExcludes.split(",");
+            for (int i = 0; url != null && i < url.length; i++)
+            {
+                excludes.add(url[i]);
+            }
+        }
+        if (StringUtils.isNotEmpty(tempEnabled))
+        {
+            enabled = Boolean.valueOf(tempEnabled);
+        }
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException
+    {
+        HttpServletRequest req = (HttpServletRequest) request;
+        HttpServletResponse resp = (HttpServletResponse) response;
+        if (handleExcludeURL(req, resp))
+        {
+            chain.doFilter(request, response);
+            return;
+        }
+        XssHttpServletRequestWrapper xssRequest = new XssHttpServletRequestWrapper((HttpServletRequest) request);
+        chain.doFilter(xssRequest, response);
+    }
+
+    private boolean handleExcludeURL(HttpServletRequest request, HttpServletResponse response)
+    {
+        if (!enabled)
+        {
+            return true;
+        }
+        if (excludes == null || excludes.isEmpty())
+        {
+            return false;
+        }
+        String url = request.getServletPath();
+        for (String pattern : excludes)
+        {
+            Pattern p = Pattern.compile("^" + pattern);
+            Matcher m = p.matcher(url);
+            if (m.find())
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    @Override
+    public void destroy()
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java b/ruoyi/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java
new file mode 100644
index 0000000..1b90c88
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/common/xss/XssHttpServletRequestWrapper.java
@@ -0,0 +1,105 @@
+package com.ruoyi.common.xss;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import org.apache.commons.io.IOUtils;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.html.EscapeUtil;
+
+/**
+ * XSS杩囨护澶勭悊
+ * 
+ * @author ruoyi
+ */
+public class XssHttpServletRequestWrapper extends HttpServletRequestWrapper
+{
+    /**
+     * @param request
+     */
+    public XssHttpServletRequestWrapper(HttpServletRequest request)
+    {
+        super(request);
+    }
+
+    @Override
+    public String[] getParameterValues(String name)
+    {
+        String[] values = super.getParameterValues(name);
+        if (values != null)
+        {
+            int length = values.length;
+            String[] escapseValues = new String[length];
+            for (int i = 0; i < length; i++)
+            {
+                // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
+                escapseValues[i] = EscapeUtil.clean(values[i]).trim();
+            }
+            return escapseValues;
+        }
+        return super.getParameterValues(name);
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+        // 闈瀓son绫诲瀷锛岀洿鎺ヨ繑鍥�
+        if (!isJsonRequest())
+        {
+            return super.getInputStream();
+        }
+
+        // 涓虹┖锛岀洿鎺ヨ繑鍥�
+        String json = IOUtils.toString(super.getInputStream(), "utf-8");
+        if (StringUtils.isEmpty(json))
+        {
+            return super.getInputStream();
+        }
+
+        // xss杩囨护
+        json = EscapeUtil.clean(json).trim();
+        final ByteArrayInputStream bis = new ByteArrayInputStream(json.getBytes("utf-8"));
+        return new ServletInputStream()
+        {
+            @Override
+            public boolean isFinished()
+            {
+                return true;
+            }
+
+            @Override
+            public boolean isReady()
+            {
+                return true;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener)
+            {
+            }
+
+            @Override
+            public int read() throws IOException
+            {
+                return bis.read();
+            }
+        };
+    }
+
+    /**
+     * 鏄惁鏄疛son璇锋眰
+     * 
+     * @param request
+     */
+    public boolean isJsonRequest()
+    {
+        String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
+        return MediaType.APPLICATION_JSON_VALUE.equalsIgnoreCase(header)
+                || MediaType.APPLICATION_JSON_UTF8_VALUE.equalsIgnoreCase(header);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
new file mode 100644
index 0000000..634f0ed
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
@@ -0,0 +1,160 @@
+package com.ruoyi.framework.aspectj;
+
+import java.lang.reflect.Method;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.domain.BaseEntity;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.domain.SysUser;
+
+/**
+ * 鏁版嵁杩囨护澶勭悊
+ * 
+ * @author ruoyi
+ */
+@Aspect
+@Component
+public class DataScopeAspect
+{
+    /**
+     * 鍏ㄩ儴鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_ALL = "1";
+
+    /**
+     * 鑷畾鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_CUSTOM = "2";
+
+    /**
+     * 閮ㄩ棬鏁版嵁鏉冮檺
+     */
+    public static final String DATA_SCOPE_DEPT = "3";
+
+    /**
+     * 閮ㄩ棬鍙婁互涓嬫暟鎹潈闄�
+     */
+    public static final String DATA_SCOPE_DEPT_AND_CHILD = "4";
+
+    /**
+     * 浠呮湰浜烘暟鎹潈闄�
+     */
+    public static final String DATA_SCOPE_SELF = "5";
+
+    // 閰嶇疆缁囧叆鐐�
+    @Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.DataScope)")
+    public void dataScopePointCut()
+    {
+    }
+
+    @Before("dataScopePointCut()")
+    public void doBefore(JoinPoint point) throws Throwable
+    {
+        handleDataScope(point);
+    }
+
+    protected void handleDataScope(final JoinPoint joinPoint)
+    {
+        // 鑾峰緱娉ㄨВ
+        DataScope controllerDataScope = getAnnotationLog(joinPoint);
+        if (controllerDataScope == null)
+        {
+            return;
+        }
+        // 鑾峰彇褰撳墠鐨勭敤鎴�
+        LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+        SysUser currentUser = loginUser.getUser();
+        if (currentUser != null)
+        {
+            // 濡傛灉鏄秴绾х鐞嗗憳锛屽垯涓嶈繃婊ゆ暟鎹�
+            if (!currentUser.isAdmin())
+            {
+                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(),
+                        controllerDataScope.userAlias());
+            }
+        }
+    }
+
+    /**
+     * 鏁版嵁鑼冨洿杩囨护
+     * 
+     * @param joinPoint 鍒囩偣
+     * @param user 鐢ㄦ埛
+     * @param alias 鍒悕
+     */
+    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias)
+    {
+        StringBuilder sqlString = new StringBuilder();
+
+        for (SysRole role : user.getRoles())
+        {
+            String dataScope = role.getDataScope();
+            if (DATA_SCOPE_ALL.equals(dataScope))
+            {
+                sqlString = new StringBuilder();
+                break;
+            }
+            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id = {} ) ", deptAlias,
+                        role.getRoleId()));
+            }
+            else if (DATA_SCOPE_DEPT.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(" OR {}.dept_id = {} ", deptAlias, user.getDeptId()));
+            }
+            else if (DATA_SCOPE_DEPT_AND_CHILD.equals(dataScope))
+            {
+                sqlString.append(StringUtils.format(
+                        " OR {}.dept_id IN ( SELECT dept_id FROM sys_dept WHERE dept_id = {} or find_in_set( {} , ancestors ) )",
+                        deptAlias, user.getDeptId(), user.getDeptId()));
+            }
+            else if (DATA_SCOPE_SELF.equals(dataScope))
+            {
+                if (StringUtils.isNotBlank(userAlias))
+                {
+                    sqlString.append(StringUtils.format(" OR {}.user_id = {} ", userAlias, user.getUserId()));
+                }
+                else
+                {
+                    // 鏁版嵁鏉冮檺涓轰粎鏈汉涓旀病鏈塽serAlias鍒悕涓嶆煡璇换浣曟暟鎹�
+                    sqlString.append(" OR 1=0 ");
+                }
+            }
+        }
+
+        if (StringUtils.isNotBlank(sqlString.toString()))
+        {
+            BaseEntity baseEntity = (BaseEntity) joinPoint.getArgs()[0];
+            baseEntity.setDataScope(" AND (" + sqlString.substring(4) + ")");
+        }
+    }
+
+    /**
+     * 鏄惁瀛樺湪娉ㄨВ锛屽鏋滃瓨鍦ㄥ氨鑾峰彇
+     */
+    private DataScope getAnnotationLog(JoinPoint joinPoint)
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(DataScope.class);
+        }
+        return null;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
new file mode 100644
index 0000000..5bdff86
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -0,0 +1,76 @@
+package com.ruoyi.framework.aspectj;
+
+import java.lang.reflect.Method;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.DataSource;
+import com.ruoyi.framework.datasource.DynamicDataSourceContextHolder;
+
+/**
+ * 澶氭暟鎹簮澶勭悊
+ * 
+ * @author ruoyi
+ */
+@Aspect
+@Order(1)
+@Component
+public class DataSourceAspect
+{
+    protected Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.DataSource)"
+            + "|| @within(com.ruoyi.framework.aspectj.lang.annotation.DataSource)")
+    public void dsPointCut()
+    {
+
+    }
+
+    @Around("dsPointCut()")
+    public Object around(ProceedingJoinPoint point) throws Throwable
+    {
+        DataSource dataSource = getDataSource(point);
+
+        if (StringUtils.isNotNull(dataSource))
+        {
+            DynamicDataSourceContextHolder.setDataSourceType(dataSource.value().name());
+        }
+
+        try
+        {
+            return point.proceed();
+        }
+        finally
+        {
+            // 閿�姣佹暟鎹簮 鍦ㄦ墽琛屾柟娉曚箣鍚�
+            DynamicDataSourceContextHolder.clearDataSourceType();
+        }
+    }
+
+    /**
+     * 鑾峰彇闇�瑕佸垏鎹㈢殑鏁版嵁婧�
+     */
+    public DataSource getDataSource(ProceedingJoinPoint point)
+    {
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        Class<? extends Object> targetClass = point.getTarget().getClass();
+        DataSource targetDataSource = targetClass.getAnnotation(DataSource.class);
+        if (StringUtils.isNotNull(targetDataSource))
+        {
+            return targetDataSource;
+        }
+        else
+        {
+            Method method = signature.getMethod();
+            DataSource dataSource = method.getAnnotation(DataSource.class);
+            return dataSource;
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
new file mode 100644
index 0000000..8bb2074
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
@@ -0,0 +1,204 @@
+package com.ruoyi.framework.aspectj;
+
+import java.lang.reflect.Method;
+import java.util.Map;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.Signature;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import org.springframework.web.multipart.MultipartFile;
+import org.springframework.web.servlet.HandlerMapping;
+import com.alibaba.fastjson.JSON;
+import com.ruoyi.common.enums.HttpMethod;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessStatus;
+import com.ruoyi.framework.manager.AsyncManager;
+import com.ruoyi.framework.manager.factory.AsyncFactory;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍澶勭悊
+ * 
+ * @author ruoyi
+ */
+@Aspect
+@Component
+public class LogAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    // 閰嶇疆缁囧叆鐐�
+    @Pointcut("@annotation(com.ruoyi.framework.aspectj.lang.annotation.Log)")
+    public void logPointCut()
+    {
+    }
+
+    /**
+     * 澶勭悊瀹岃姹傚悗鎵ц
+     *
+     * @param joinPoint 鍒囩偣
+     */
+    @AfterReturning(pointcut = "logPointCut()", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Object jsonResult)
+    {
+        handleLog(joinPoint, null, jsonResult);
+    }
+
+    /**
+     * 鎷︽埅寮傚父鎿嶄綔
+     * 
+     * @param joinPoint 鍒囩偣
+     * @param e 寮傚父
+     */
+    @AfterThrowing(value = "logPointCut()", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Exception e)
+    {
+        handleLog(joinPoint, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, final Exception e, Object jsonResult)
+    {
+        try
+        {
+            // 鑾峰緱娉ㄨВ
+            Log controllerLog = getAnnotationLog(joinPoint);
+            if (controllerLog == null)
+            {
+                return;
+            }
+
+            // 鑾峰彇褰撳墠鐨勭敤鎴�
+            LoginUser loginUser = SpringUtils.getBean(TokenService.class).getLoginUser(ServletUtils.getRequest());
+
+            // *========鏁版嵁搴撴棩蹇�=========*//
+            SysOperLog operLog = new SysOperLog();
+            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+            // 璇锋眰鐨勫湴鍧�
+            String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
+            operLog.setOperIp(ip);
+            // 杩斿洖鍙傛暟
+            operLog.setJsonResult(JSON.toJSONString(jsonResult));
+
+            operLog.setOperUrl(ServletUtils.getRequest().getRequestURI());
+            if (loginUser != null)
+            {
+                operLog.setOperName(loginUser.getUsername());
+            }
+
+            if (e != null)
+            {
+                operLog.setStatus(BusinessStatus.FAIL.ordinal());
+                operLog.setErrorMsg(StringUtils.substring(e.getMessage(), 0, 2000));
+            }
+            // 璁剧疆鏂规硶鍚嶇О
+            String className = joinPoint.getTarget().getClass().getName();
+            String methodName = joinPoint.getSignature().getName();
+            operLog.setMethod(className + "." + methodName + "()");
+            // 璁剧疆璇锋眰鏂瑰紡
+            operLog.setRequestMethod(ServletUtils.getRequest().getMethod());
+            // 澶勭悊璁剧疆娉ㄨВ涓婄殑鍙傛暟
+            getControllerMethodDescription(joinPoint, controllerLog, operLog);
+            // 淇濆瓨鏁版嵁搴�
+            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
+        }
+        catch (Exception exp)
+        {
+            // 璁板綍鏈湴寮傚父鏃ュ織
+            log.error("==鍓嶇疆閫氱煡寮傚父==");
+            log.error("寮傚父淇℃伅:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+    }
+
+    /**
+     * 鑾峰彇娉ㄨВ涓鏂规硶鐨勬弿杩颁俊鎭� 鐢ㄤ簬Controller灞傛敞瑙�
+     * 
+     * @param log 鏃ュ織
+     * @param operLog 鎿嶄綔鏃ュ織
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog) throws Exception
+    {
+        // 璁剧疆action鍔ㄤ綔
+        operLog.setBusinessType(log.businessType().ordinal());
+        // 璁剧疆鏍囬
+        operLog.setTitle(log.title());
+        // 璁剧疆鎿嶄綔浜虹被鍒�
+        operLog.setOperatorType(log.operatorType().ordinal());
+        // 鏄惁闇�瑕佷繚瀛榬equest锛屽弬鏁板拰鍊�
+        if (log.isSaveRequestData())
+        {
+            // 鑾峰彇鍙傛暟鐨勪俊鎭紝浼犲叆鍒版暟鎹簱涓��
+            setRequestValue(joinPoint, operLog);
+        }
+    }
+
+    /**
+     * 鑾峰彇璇锋眰鐨勫弬鏁帮紝鏀惧埌log涓�
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織
+     * @throws Exception 寮傚父
+     */
+    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog) throws Exception
+    {
+        String requestMethod = operLog.getRequestMethod();
+        if (HttpMethod.PUT.name().equals(requestMethod) || HttpMethod.POST.name().equals(requestMethod))
+        {
+            String params = argsArrayToString(joinPoint.getArgs());
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+        }
+        else
+        {
+            Map<?, ?> paramsMap = (Map<?, ?>) ServletUtils.getRequest().getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
+            operLog.setOperParam(StringUtils.substring(paramsMap.toString(), 0, 2000));
+        }
+    }
+
+    /**
+     * 鏄惁瀛樺湪娉ㄨВ锛屽鏋滃瓨鍦ㄥ氨鑾峰彇
+     */
+    private Log getAnnotationLog(JoinPoint joinPoint) throws Exception
+    {
+        Signature signature = joinPoint.getSignature();
+        MethodSignature methodSignature = (MethodSignature) signature;
+        Method method = methodSignature.getMethod();
+
+        if (method != null)
+        {
+            return method.getAnnotation(Log.class);
+        }
+        return null;
+    }
+
+    /**
+     * 鍙傛暟鎷艰
+     */
+    private String argsArrayToString(Object[] paramsArray)
+    {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0)
+        {
+            for (int i = 0; i < paramsArray.length; i++)
+            {
+                if (!(paramsArray[i] instanceof MultipartFile))
+                {
+                    Object jsonObj = JSON.toJSON(paramsArray[i]);
+                    params += jsonObj.toString() + " ";
+                }
+            }
+        }
+        return params.trim();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataScope.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataScope.java
new file mode 100644
index 0000000..5e4cc9c
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataScope.java
@@ -0,0 +1,28 @@
+package com.ruoyi.framework.aspectj.lang.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鏁版嵁鏉冮檺杩囨护娉ㄨВ
+ * 
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope
+{
+    /**
+     * 閮ㄩ棬琛ㄧ殑鍒悕
+     */
+    public String deptAlias() default "";
+
+    /**
+     * 鐢ㄦ埛琛ㄧ殑鍒悕
+     */
+    public String userAlias() default "";
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataSource.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataSource.java
new file mode 100644
index 0000000..4df29ff
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/DataSource.java
@@ -0,0 +1,26 @@
+package com.ruoyi.framework.aspectj.lang.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.framework.aspectj.lang.enums.DataSourceType;
+
+/**
+ * 鑷畾涔夊鏁版嵁婧愬垏鎹㈡敞瑙�
+ * 
+ * @author ruoyi
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource
+{
+    /**
+     * 鍒囨崲鏁版嵁婧愬悕绉�
+     */
+    public DataSourceType value() default DataSourceType.MASTER;
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Log.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Log.java
new file mode 100644
index 0000000..548eace
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/annotation/Log.java
@@ -0,0 +1,41 @@
+package com.ruoyi.framework.aspectj.lang.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.aspectj.lang.enums.OperatorType;
+
+/**
+ * 鑷畾涔夋搷浣滄棩蹇楄褰曟敞瑙�
+ * 
+ * @author ruoyi
+ *
+ */
+@Target({ ElementType.PARAMETER, ElementType.METHOD })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log
+{
+    /**
+     * 妯″潡 
+     */
+    public String title() default "";
+
+    /**
+     * 鍔熻兘
+     */
+    public BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 鎿嶄綔浜虹被鍒�
+     */
+    public OperatorType operatorType() default OperatorType.MANAGE;
+
+    /**
+     * 鏄惁淇濆瓨璇锋眰鐨勫弬鏁�
+     */
+    public boolean isSaveRequestData() default true;
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessStatus.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessStatus.java
new file mode 100644
index 0000000..7e27f2e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessStatus.java
@@ -0,0 +1,20 @@
+package com.ruoyi.framework.aspectj.lang.enums;
+
+/**
+ * 鎿嶄綔鐘舵��
+ * 
+ * @author ruoyi
+ *
+ */
+public enum BusinessStatus
+{
+    /**
+     * 鎴愬姛
+     */
+    SUCCESS,
+
+    /**
+     * 澶辫触
+     */
+    FAIL,
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessType.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessType.java
new file mode 100644
index 0000000..d974a64
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/BusinessType.java
@@ -0,0 +1,59 @@
+package com.ruoyi.framework.aspectj.lang.enums;
+
+/**
+ * 涓氬姟鎿嶄綔绫诲瀷
+ * 
+ * @author ruoyi
+ */
+public enum BusinessType
+{
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鏂板
+     */
+    INSERT,
+
+    /**
+     * 淇敼
+     */
+    UPDATE,
+
+    /**
+     * 鍒犻櫎
+     */
+    DELETE,
+
+    /**
+     * 鎺堟潈
+     */
+    GRANT,
+
+    /**
+     * 瀵煎嚭
+     */
+    EXPORT,
+
+    /**
+     * 瀵煎叆
+     */
+    IMPORT,
+
+    /**
+     * 寮洪��
+     */
+    FORCE,
+
+    /**
+     * 鐢熸垚浠g爜
+     */
+    GENCODE,
+    
+    /**
+     * 娓呯┖鏁版嵁
+     */
+    CLEAN,
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DataSourceType.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DataSourceType.java
new file mode 100644
index 0000000..274dd34
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/DataSourceType.java
@@ -0,0 +1,19 @@
+package com.ruoyi.framework.aspectj.lang.enums;
+
+/**
+ * 鏁版嵁婧�
+ * 
+ * @author ruoyi
+ */
+public enum DataSourceType
+{
+    /**
+     * 涓诲簱
+     */
+    MASTER,
+
+    /**
+     * 浠庡簱
+     */
+    SLAVE
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/OperatorType.java b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/OperatorType.java
new file mode 100644
index 0000000..98685a6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/aspectj/lang/enums/OperatorType.java
@@ -0,0 +1,24 @@
+package com.ruoyi.framework.aspectj.lang.enums;
+
+/**
+ * 鎿嶄綔浜虹被鍒�
+ * 
+ * @author ruoyi
+ */
+public enum OperatorType
+{
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鍚庡彴鐢ㄦ埛
+     */
+    MANAGE,
+
+    /**
+     * 鎵嬫満绔敤鎴�
+     */
+    MOBILE
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
new file mode 100644
index 0000000..4dd3338
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
@@ -0,0 +1,20 @@
+package com.ruoyi.framework.config;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * 绋嬪簭娉ㄨВ閰嶇疆
+ *
+ * @author ruoyi
+ */
+@Configuration
+// 琛ㄧず閫氳繃aop妗嗘灦鏆撮湶璇ヤ唬鐞嗗璞�,AopContext鑳藉璁块棶
+@EnableAspectJAutoProxy(exposeProxy = true)
+// 鎸囧畾瑕佹壂鎻忕殑Mapper绫荤殑鍖呯殑璺緞
+@MapperScan("com.ruoyi.project.**.mapper")
+public class ApplicationConfig
+{
+
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/DruidConfig.java
new file mode 100644
index 0000000..26135c8
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/DruidConfig.java
@@ -0,0 +1,106 @@
+package com.ruoyi.framework.config;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.Filter;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.ServletRequest;
+import javax.servlet.ServletResponse;
+import javax.sql.DataSource;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
+import com.alibaba.druid.spring.boot.autoconfigure.properties.DruidStatProperties;
+import com.alibaba.druid.util.Utils;
+import com.ruoyi.framework.aspectj.lang.enums.DataSourceType;
+import com.ruoyi.framework.config.properties.DruidProperties;
+import com.ruoyi.framework.datasource.DynamicDataSource;
+
+/**
+ * druid 閰嶇疆澶氭暟鎹簮
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class DruidConfig
+{
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.master")
+    public DataSource masterDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
+
+    @Bean
+    @ConfigurationProperties("spring.datasource.druid.slave")
+    @ConditionalOnProperty(prefix = "spring.datasource.druid.slave", name = "enabled", havingValue = "true")
+    public DataSource slaveDataSource(DruidProperties druidProperties)
+    {
+        DruidDataSource dataSource = DruidDataSourceBuilder.create().build();
+        return druidProperties.dataSource(dataSource);
+    }
+
+    @Bean(name = "dynamicDataSource")
+    @Primary
+    public DynamicDataSource dataSource(DataSource masterDataSource, DataSource slaveDataSource)
+    {
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        targetDataSources.put(DataSourceType.SLAVE.name(), slaveDataSource);
+        return new DynamicDataSource(masterDataSource, targetDataSources);
+    }
+
+    /**
+     * 鍘婚櫎鐩戞帶椤甸潰搴曢儴鐨勫箍鍛�
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    @ConditionalOnProperty(name = "spring.datasource.druid.statViewServlet.enabled", havingValue = "true")
+    public FilterRegistrationBean removeDruidFilterRegistrationBean(DruidStatProperties properties)
+    {
+        // 鑾峰彇web鐩戞帶椤甸潰鐨勫弬鏁�
+        DruidStatProperties.StatViewServlet config = properties.getStatViewServlet();
+        // 鎻愬彇common.js鐨勯厤缃矾寰�
+        String pattern = config.getUrlPattern() != null ? config.getUrlPattern() : "/druid/*";
+        String commonJsPattern = pattern.replaceAll("\\*", "js/common.js");
+        final String filePath = "support/http/resources/js/common.js";
+        // 鍒涘缓filter杩涜杩囨护
+        Filter filter = new Filter()
+        {
+            @Override
+            public void init(javax.servlet.FilterConfig filterConfig) throws ServletException
+            {
+            }
+            @Override
+            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+                    throws IOException, ServletException
+            {
+                chain.doFilter(request, response);
+                // 閲嶇疆缂撳啿鍖猴紝鍝嶅簲澶翠笉浼氳閲嶇疆
+                response.resetBuffer();
+                // 鑾峰彇common.js
+                String text = Utils.readFromResource(filePath);
+                // 姝e垯鏇挎崲banner, 闄ゅ幓搴曢儴鐨勫箍鍛婁俊鎭�
+                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
+                text = text.replaceAll("powered.*?shrek.wang</a>", "");
+                response.getWriter().write(text);
+            }
+            @Override
+            public void destroy()
+            {
+            }
+        };
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        registrationBean.addUrlPatterns(commonJsPattern);
+        return registrationBean;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java b/ruoyi/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
new file mode 100644
index 0000000..b623cae
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
@@ -0,0 +1,69 @@
+package com.ruoyi.framework.config;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.serializer.SerializerFeature;
+import com.fasterxml.jackson.databind.JavaType;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.type.TypeFactory;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+import com.alibaba.fastjson.parser.ParserConfig;
+import org.springframework.util.Assert;
+import java.nio.charset.Charset;
+
+/**
+ * Redis浣跨敤FastJson搴忓垪鍖�
+ * 
+ * @author ruoyi
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
+{
+    @SuppressWarnings("unused")
+    private ObjectMapper objectMapper = new ObjectMapper();
+
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    private Class<T> clazz;
+
+    static
+    {
+        ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
+    }
+
+    public FastJson2JsonRedisSerializer(Class<T> clazz)
+    {
+        super();
+        this.clazz = clazz;
+    }
+
+    public byte[] serialize(T t) throws SerializationException
+    {
+        if (t == null)
+        {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, SerializerFeature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    public T deserialize(byte[] bytes) throws SerializationException
+    {
+        if (bytes == null || bytes.length <= 0)
+        {
+            return null;
+        }
+        String str = new String(bytes, DEFAULT_CHARSET);
+
+        return JSON.parseObject(str, clazz);
+    }
+
+    public void setObjectMapper(ObjectMapper objectMapper)
+    {
+        Assert.notNull(objectMapper, "'objectMapper' must not be null");
+        this.objectMapper = objectMapper;
+    }
+
+    protected JavaType getJavaType(Class<?> clazz)
+    {
+        return TypeFactory.defaultInstance().constructType(clazz);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/FilterConfig.java
new file mode 100644
index 0000000..92d010e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/FilterConfig.java
@@ -0,0 +1,46 @@
+package com.ruoyi.framework.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.DispatcherType;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.xss.XssFilter;
+
+/**
+ * Filter閰嶇疆
+ *
+ * @author ruoyi
+ */
+@Configuration
+public class FilterConfig
+{
+    @Value("${xss.enabled}")
+    private String enabled;
+
+    @Value("${xss.excludes}")
+    private String excludes;
+
+    @Value("${xss.urlPatterns}")
+    private String urlPatterns;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    public FilterRegistrationBean xssFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setDispatcherTypes(DispatcherType.REQUEST);
+        registration.setFilter(new XssFilter());
+        registration.addUrlPatterns(StringUtils.split(urlPatterns, ","));
+        registration.setName("xssFilter");
+        registration.setOrder(Integer.MAX_VALUE);
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("excludes", excludes);
+        initParameters.put("enabled", enabled);
+        registration.setInitParameters(initParameters);
+        return registration;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
new file mode 100644
index 0000000..69868f0
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
@@ -0,0 +1,105 @@
+package com.ruoyi.framework.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import javax.sql.DataSource;
+import org.apache.ibatis.io.VFS;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.boot.autoconfigure.SpringBootVFS;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.env.Environment;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.core.type.classreading.CachingMetadataReaderFactory;
+import org.springframework.core.type.classreading.MetadataReader;
+import org.springframework.core.type.classreading.MetadataReaderFactory;
+import org.springframework.util.ClassUtils;
+
+/**
+ * Mybatis鏀寔*鍖归厤鎵弿鍖�
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class MyBatisConfig
+{
+    @Autowired
+    private Environment env;
+
+    static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";
+
+    public static String setTypeAliasesPackage(String typeAliasesPackage)
+    {
+        ResourcePatternResolver resolver = (ResourcePatternResolver) new PathMatchingResourcePatternResolver();
+        MetadataReaderFactory metadataReaderFactory = new CachingMetadataReaderFactory(resolver);
+        List<String> allResult = new ArrayList<String>();
+        try
+        {
+            for (String aliasesPackage : typeAliasesPackage.split(","))
+            {
+                List<String> result = new ArrayList<String>();
+                aliasesPackage = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX
+                        + ClassUtils.convertClassNameToResourcePath(aliasesPackage.trim()) + "/" + DEFAULT_RESOURCE_PATTERN;
+                Resource[] resources = resolver.getResources(aliasesPackage);
+                if (resources != null && resources.length > 0)
+                {
+                    MetadataReader metadataReader = null;
+                    for (Resource resource : resources)
+                    {
+                        if (resource.isReadable())
+                        {
+                            metadataReader = metadataReaderFactory.getMetadataReader(resource);
+                            try
+                            {
+                                result.add(Class.forName(metadataReader.getClassMetadata().getClassName()).getPackage().getName());
+                            }
+                            catch (ClassNotFoundException e)
+                            {
+                                e.printStackTrace();
+                            }
+                        }
+                    }
+                }
+                if (result.size() > 0)
+                {
+                    HashSet<String> hashResult = new HashSet<String>(result);
+                    allResult.addAll(hashResult);
+                }
+            }
+            if (allResult.size() > 0)
+            {
+                typeAliasesPackage = String.join(",", (String[]) allResult.toArray(new String[0]));
+            }
+            else
+            {
+                throw new RuntimeException("mybatis typeAliasesPackage 璺緞鎵弿閿欒,鍙傛暟typeAliasesPackage:" + typeAliasesPackage + "鏈壘鍒颁换浣曞寘");
+            }
+        }
+        catch (IOException e)
+        {
+            e.printStackTrace();
+        }
+        return typeAliasesPackage;
+    }
+
+    @Bean
+    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    {
+        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis.mapperLocations");
+        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
+        VFS.addImplClass(SpringBootVFS.class);
+
+        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        sessionFactory.setDataSource(dataSource);
+        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
+        sessionFactory.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(mapperLocations));
+        return sessionFactory.getObject();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/RedisConfig.java
new file mode 100644
index 0000000..6322686
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/RedisConfig.java
@@ -0,0 +1,43 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.cache.annotation.CachingConfigurerSupport;
+import org.springframework.cache.annotation.EnableCaching;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+
+/**
+ * redis閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Configuration
+@EnableCaching
+public class RedisConfig extends CachingConfigurerSupport
+{
+    @Bean
+    @SuppressWarnings(value = { "unchecked", "rawtypes" })
+    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory)
+    {
+        RedisTemplate<Object, Object> template = new RedisTemplate<>();
+        template.setConnectionFactory(connectionFactory);
+
+        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);
+
+        ObjectMapper mapper = new ObjectMapper();
+        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
+        serializer.setObjectMapper(mapper);
+
+        template.setValueSerializer(serializer);
+        // 浣跨敤StringRedisSerializer鏉ュ簭鍒楀寲鍜屽弽搴忓垪鍖杛edis鐨刱ey鍊�
+        template.setKeySerializer(new StringRedisSerializer());
+        template.afterPropertiesSet();
+        return template;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
new file mode 100644
index 0000000..b836c21
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -0,0 +1,26 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import com.ruoyi.common.constant.Constants;
+
+/**
+ * 閫氱敤閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class ResourcesConfig implements WebMvcConfigurer
+{
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry)
+    {
+        /** 鏈湴鏂囦欢涓婁紶璺緞 */
+        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**").addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
+
+        /** swagger閰嶇疆 */
+        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
+        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/RuoYiConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/RuoYiConfig.java
new file mode 100644
index 0000000..1f6e20a
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/RuoYiConfig.java
@@ -0,0 +1,116 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 璇诲彇椤圭洰鐩稿叧閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "ruoyi")
+public class RuoYiConfig
+{
+    /** 椤圭洰鍚嶇О */
+    private String name;
+
+    /** 鐗堟湰 */
+    private String version;
+
+    /** 鐗堟潈骞翠唤 */
+    private String copyrightYear;
+
+    /** 瀹炰緥婕旂ず寮�鍏� */
+    private boolean demoEnabled;
+
+    /** 涓婁紶璺緞 */
+    private static String profile;
+
+    /** 鑾峰彇鍦板潃寮�鍏� */
+    private static boolean addressEnabled;
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion(String version)
+    {
+        this.version = version;
+    }
+
+    public String getCopyrightYear()
+    {
+        return copyrightYear;
+    }
+
+    public void setCopyrightYear(String copyrightYear)
+    {
+        this.copyrightYear = copyrightYear;
+    }
+
+    public boolean isDemoEnabled()
+    {
+        return demoEnabled;
+    }
+
+    public void setDemoEnabled(boolean demoEnabled)
+    {
+        this.demoEnabled = demoEnabled;
+    }
+
+    public static String getProfile()
+    {
+        return profile;
+    }
+
+    public void setProfile(String profile)
+    {
+        RuoYiConfig.profile = profile;
+    }
+
+    public static boolean isAddressEnabled()
+    {
+        return addressEnabled;
+    }
+
+    public void setAddressEnabled(boolean addressEnabled)
+    {
+        RuoYiConfig.addressEnabled = addressEnabled;
+    }
+
+    /**
+     * 鑾峰彇澶村儚涓婁紶璺緞
+     */
+    public static String getAvatarPath()
+    {
+        return getProfile() + "/avatar";
+    }
+
+    /**
+     * 鑾峰彇涓嬭浇璺緞
+     */
+    public static String getDownloadPath()
+    {
+        return getProfile() + "/download/";
+    }
+
+    /**
+     * 鑾峰彇涓婁紶璺緞
+     */
+    public static String getUploadPath()
+    {
+        return getProfile() + "/upload";
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
new file mode 100644
index 0000000..45000b5
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -0,0 +1,133 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
+import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import com.ruoyi.framework.security.filter.JwtAuthenticationTokenFilter;
+import com.ruoyi.framework.security.handle.AuthenticationEntryPointImpl;
+import com.ruoyi.framework.security.handle.LogoutSuccessHandlerImpl;
+
+/**
+ * spring security閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
+public class SecurityConfig extends WebSecurityConfigurerAdapter
+{
+    /**
+     * 鑷畾涔夌敤鎴疯璇侀�昏緫
+     */
+    @Autowired
+    private UserDetailsService userDetailsService;
+    
+    /**
+     * 璁よ瘉澶辫触澶勭悊绫�
+     */
+    @Autowired
+    private AuthenticationEntryPointImpl unauthorizedHandler;
+
+    /**
+     * 閫�鍑哄鐞嗙被
+     */
+    @Autowired
+    private LogoutSuccessHandlerImpl logoutSuccessHandler;
+
+    /**
+     * token璁よ瘉杩囨护鍣�
+     */
+    @Autowired
+    private JwtAuthenticationTokenFilter authenticationTokenFilter;
+    
+    /**
+     * 瑙e喅 鏃犳硶鐩存帴娉ㄥ叆 AuthenticationManager
+     *
+     * @return
+     * @throws Exception
+     */
+    @Bean
+    @Override
+    public AuthenticationManager authenticationManagerBean() throws Exception
+    {
+        return super.authenticationManagerBean();
+    }
+
+    /**
+     * anyRequest          |   鍖归厤鎵�鏈夎姹傝矾寰�
+     * access              |   SpringEl琛ㄨ揪寮忕粨鏋滀负true鏃跺彲浠ヨ闂�
+     * anonymous           |   鍖垮悕鍙互璁块棶
+     * denyAll             |   鐢ㄦ埛涓嶈兘璁块棶
+     * fullyAuthenticated  |   鐢ㄦ埛瀹屽叏璁よ瘉鍙互璁块棶锛堥潪remember-me涓嬭嚜鍔ㄧ櫥褰曪級
+     * hasAnyAuthority     |   濡傛灉鏈夊弬鏁帮紝鍙傛暟琛ㄧず鏉冮檺锛屽垯鍏朵腑浠讳綍涓�涓潈闄愬彲浠ヨ闂�
+     * hasAnyRole          |   濡傛灉鏈夊弬鏁帮紝鍙傛暟琛ㄧず瑙掕壊锛屽垯鍏朵腑浠讳綍涓�涓鑹插彲浠ヨ闂�
+     * hasAuthority        |   濡傛灉鏈夊弬鏁帮紝鍙傛暟琛ㄧず鏉冮檺锛屽垯鍏舵潈闄愬彲浠ヨ闂�
+     * hasIpAddress        |   濡傛灉鏈夊弬鏁帮紝鍙傛暟琛ㄧずIP鍦板潃锛屽鏋滅敤鎴稩P鍜屽弬鏁板尮閰嶏紝鍒欏彲浠ヨ闂�
+     * hasRole             |   濡傛灉鏈夊弬鏁帮紝鍙傛暟琛ㄧず瑙掕壊锛屽垯鍏惰鑹插彲浠ヨ闂�
+     * permitAll           |   鐢ㄦ埛鍙互浠绘剰璁块棶
+     * rememberMe          |   鍏佽閫氳繃remember-me鐧诲綍鐨勭敤鎴疯闂�
+     * authenticated       |   鐢ㄦ埛鐧诲綍鍚庡彲璁块棶
+     */
+    @Override
+    protected void configure(HttpSecurity httpSecurity) throws Exception
+    {
+        httpSecurity
+                // CRSF绂佺敤锛屽洜涓轰笉浣跨敤session
+                .csrf().disable()
+                // 璁よ瘉澶辫触澶勭悊绫�
+                .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
+                // 鍩轰簬token锛屾墍浠ヤ笉闇�瑕乻ession
+                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
+                // 杩囨护璇锋眰
+                .authorizeRequests()
+                // 瀵逛簬鐧诲綍login 楠岃瘉鐮乧aptchaImage 鍏佽鍖垮悕璁块棶
+                .antMatchers("/login", "/captchaImage").anonymous()
+                .antMatchers(
+                        HttpMethod.GET,
+                        "/*.html",
+                        "/**/*.html",
+                        "/**/*.css",
+                        "/**/*.js"
+                ).permitAll()
+                .antMatchers("/profile/**").anonymous()
+                .antMatchers("/swagger-ui.html").anonymous()
+                .antMatchers("/swagger-resources/**").anonymous()
+                .antMatchers("/webjars/**").anonymous()
+                .antMatchers("/*/api-docs").anonymous()
+                .antMatchers("/druid/**").anonymous()
+                // 闄や笂闈㈠鐨勬墍鏈夎姹傚叏閮ㄩ渶瑕侀壌鏉冭璇�
+                .anyRequest().authenticated()
+                .and()
+                .headers().frameOptions().disable();
+        httpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);
+        // 娣诲姞JWT filter
+        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
+    }
+
+    
+    /**
+     * 寮烘暎鍒楀搱甯屽姞瀵嗗疄鐜�
+     */
+    @Bean
+    public BCryptPasswordEncoder bCryptPasswordEncoder()
+    {
+        return new BCryptPasswordEncoder();
+    }
+
+    /**
+     * 韬唤璁よ瘉鎺ュ彛
+     */
+    @Override
+    protected void configure(AuthenticationManagerBuilder auth) throws Exception
+    {
+        auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/ServerConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/ServerConfig.java
new file mode 100644
index 0000000..157e9f4
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/ServerConfig.java
@@ -0,0 +1,32 @@
+package com.ruoyi.framework.config;
+
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.ServletUtils;
+
+/**
+ * 鏈嶅姟鐩稿叧閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Component
+public class ServerConfig
+{
+    /**
+     * 鑾峰彇瀹屾暣鐨勮姹傝矾寰勶紝鍖呮嫭锛氬煙鍚嶏紝绔彛锛屼笂涓嬫枃璁块棶璺緞
+     * 
+     * @return 鏈嶅姟鍦板潃
+     */
+    public String getUrl()
+    {
+        HttpServletRequest request = ServletUtils.getRequest();
+        return getDomain(request);
+    }
+
+    public static String getDomain(HttpServletRequest request)
+    {
+        StringBuffer url = request.getRequestURL();
+        String contextPath = request.getServletContext().getContextPath();
+        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java
new file mode 100644
index 0000000..a2da4e8
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/SwaggerConfig.java
@@ -0,0 +1,66 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import io.swagger.annotations.ApiOperation;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Contact;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+/**
+ * Swagger2鐨勬帴鍙i厤缃�
+ * 
+ * @author ruoyi
+ */
+@Configuration
+@EnableSwagger2
+public class SwaggerConfig
+{
+    /** 绯荤粺鍩虹閰嶇疆 */
+    @Autowired
+    private RuoYiConfig ruoyiConfig;
+
+    /**
+     * 鍒涘缓API
+     */
+    @Bean
+    public Docket createRestApi()
+    {
+        return new Docket(DocumentationType.SWAGGER_2)
+                // 鐢ㄦ潵鍒涘缓璇PI鐨勫熀鏈俊鎭紝灞曠ず鍦ㄦ枃妗g殑椤甸潰涓紙鑷畾涔夊睍绀虹殑淇℃伅锛�
+                .apiInfo(apiInfo())
+                // 璁剧疆鍝簺鎺ュ彛鏆撮湶缁橲wagger灞曠ず
+                .select()
+                // 鎵弿鎵�鏈夋湁娉ㄨВ鐨刟pi锛岀敤杩欑鏂瑰紡鏇寸伒娲�
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 鎵弿鎸囧畾鍖呬腑鐨剆wagger娉ㄨВ
+                //.apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
+                // 鎵弿鎵�鏈� .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build();
+    }
+
+    /**
+     * 娣诲姞鎽樿淇℃伅
+     */
+    private ApiInfo apiInfo()
+    {
+        // 鐢ˋpiInfoBuilder杩涜瀹氬埗
+        return new ApiInfoBuilder()
+                // 璁剧疆鏍囬
+                .title("鏍囬锛氫綑蹇冪鐞嗙郴缁焈鎺ュ彛鏂囨。")
+                // 鎻忚堪
+                .description("鎻忚堪锛氱敤浜庣鐞嗛泦鍥㈡棗涓嬪叕鍙哥殑浜哄憳淇℃伅,鍏蜂綋鍖呮嫭XXX,XXX妯″潡...")
+                // 浣滆�呬俊鎭�
+                .contact(new Contact(ruoyiConfig.getName(), null, null))
+                // 鐗堟湰
+                .version("鐗堟湰鍙�:" + ruoyiConfig.getVersion())
+                .build();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/ruoyi/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..618a925
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
@@ -0,0 +1,62 @@
+package com.ruoyi.framework.config;
+
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+import org.apache.commons.lang3.concurrent.BasicThreadFactory;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import com.ruoyi.common.utils.Threads;
+
+/**
+ * 绾跨▼姹犻厤缃�
+ *
+ * @author ruoyi
+ **/
+@Configuration
+public class ThreadPoolConfig
+{
+    // 鏍稿績绾跨▼姹犲ぇ灏�
+    private int corePoolSize = 50;
+
+    // 鏈�澶у彲鍒涘缓鐨勭嚎绋嬫暟
+    private int maxPoolSize = 200;
+
+    // 闃熷垪鏈�澶ч暱搴�
+    private int queueCapacity = 1000;
+
+    // 绾跨▼姹犵淮鎶ょ嚎绋嬫墍鍏佽鐨勭┖闂叉椂闂�
+    private int keepAliveSeconds = 300;
+
+    @Bean(name = "threadPoolTaskExecutor")
+    public ThreadPoolTaskExecutor threadPoolTaskExecutor()
+    {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setMaxPoolSize(maxPoolSize);
+        executor.setCorePoolSize(corePoolSize);
+        executor.setQueueCapacity(queueCapacity);
+        executor.setKeepAliveSeconds(keepAliveSeconds);
+        // 绾跨▼姹犲鎷掔粷浠诲姟(鏃犵嚎绋嬪彲鐢�)鐨勫鐞嗙瓥鐣�
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
+        return executor;
+    }
+
+    /**
+     * 鎵ц鍛ㄦ湡鎬ф垨瀹氭椂浠诲姟
+     */
+    @Bean(name = "scheduledExecutorService")
+    protected ScheduledExecutorService scheduledExecutorService()
+    {
+        return new ScheduledThreadPoolExecutor(corePoolSize,
+                new BasicThreadFactory.Builder().namingPattern("schedule-pool-%d").daemon(true).build())
+        {
+            @Override
+            protected void afterExecute(Runnable r, Throwable t)
+            {
+                super.afterExecute(r, t);
+                Threads.printException(r, t);
+            }
+        };
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java b/ruoyi/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
new file mode 100644
index 0000000..ae6e02f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
@@ -0,0 +1,77 @@
+package com.ruoyi.framework.config.properties;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import com.alibaba.druid.pool.DruidDataSource;
+
+/**
+ * druid 閰嶇疆灞炴��
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class DruidProperties
+{
+    @Value("${spring.datasource.druid.initialSize}")
+    private int initialSize;
+
+    @Value("${spring.datasource.druid.minIdle}")
+    private int minIdle;
+
+    @Value("${spring.datasource.druid.maxActive}")
+    private int maxActive;
+
+    @Value("${spring.datasource.druid.maxWait}")
+    private int maxWait;
+
+    @Value("${spring.datasource.druid.timeBetweenEvictionRunsMillis}")
+    private int timeBetweenEvictionRunsMillis;
+
+    @Value("${spring.datasource.druid.minEvictableIdleTimeMillis}")
+    private int minEvictableIdleTimeMillis;
+
+    @Value("${spring.datasource.druid.maxEvictableIdleTimeMillis}")
+    private int maxEvictableIdleTimeMillis;
+
+    @Value("${spring.datasource.druid.validationQuery}")
+    private String validationQuery;
+
+    @Value("${spring.datasource.druid.testWhileIdle}")
+    private boolean testWhileIdle;
+
+    @Value("${spring.datasource.druid.testOnBorrow}")
+    private boolean testOnBorrow;
+
+    @Value("${spring.datasource.druid.testOnReturn}")
+    private boolean testOnReturn;
+
+    public DruidDataSource dataSource(DruidDataSource datasource)
+    {
+        /** 閰嶇疆鍒濆鍖栧ぇ灏忋�佹渶灏忋�佹渶澶� */
+        datasource.setInitialSize(initialSize);
+        datasource.setMaxActive(maxActive);
+        datasource.setMinIdle(minIdle);
+
+        /** 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂� */
+        datasource.setMaxWait(maxWait);
+
+        /** 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣 */
+        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+
+        /** 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忋�佹渶澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣 */
+        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
+
+        /**
+         * 鐢ㄦ潵妫�娴嬭繛鎺ユ槸鍚︽湁鏁堢殑sql锛岃姹傛槸涓�涓煡璇㈣鍙ワ紝甯哥敤select 'x'銆傚鏋渧alidationQuery涓簄ull锛宼estOnBorrow銆乼estOnReturn銆乼estWhileIdle閮戒笉浼氳捣浣滅敤銆�
+         */
+        datasource.setValidationQuery(validationQuery);
+        /** 寤鸿閰嶇疆涓簍rue锛屼笉褰卞搷鎬ц兘锛屽苟涓斾繚璇佸畨鍏ㄦ�с�傜敵璇疯繛鎺ョ殑鏃跺�欐娴嬶紝濡傛灉绌洪棽鏃堕棿澶т簬timeBetweenEvictionRunsMillis锛屾墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堛�� */
+        datasource.setTestWhileIdle(testWhileIdle);
+        /** 鐢宠杩炴帴鏃舵墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堬紝鍋氫簡杩欎釜閰嶇疆浼氶檷浣庢�ц兘銆� */
+        datasource.setTestOnBorrow(testOnBorrow);
+        /** 褰掕繕杩炴帴鏃舵墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堬紝鍋氫簡杩欎釜閰嶇疆浼氶檷浣庢�ц兘銆� */
+        datasource.setTestOnReturn(testOnReturn);
+        return datasource;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java b/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
new file mode 100644
index 0000000..014ae38
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
@@ -0,0 +1,26 @@
+package com.ruoyi.framework.datasource;
+
+import java.util.Map;
+import javax.sql.DataSource;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/**
+ * 鍔ㄦ�佹暟鎹簮
+ * 
+ * @author ruoyi
+ */
+public class DynamicDataSource extends AbstractRoutingDataSource
+{
+    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
+    {
+        super.setDefaultTargetDataSource(defaultTargetDataSource);
+        super.setTargetDataSources(targetDataSources);
+        super.afterPropertiesSet();
+    }
+
+    @Override
+    protected Object determineCurrentLookupKey()
+    {
+        return DynamicDataSourceContextHolder.getDataSourceType();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java b/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
new file mode 100644
index 0000000..20a0dda
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
@@ -0,0 +1,45 @@
+package com.ruoyi.framework.datasource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 鏁版嵁婧愬垏鎹㈠鐞�
+ * 
+ * @author ruoyi
+ */
+public class DynamicDataSourceContextHolder
+{
+    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
+
+    /**
+     * 浣跨敤ThreadLocal缁存姢鍙橀噺锛孴hreadLocal涓烘瘡涓娇鐢ㄨ鍙橀噺鐨勭嚎绋嬫彁渚涚嫭绔嬬殑鍙橀噺鍓湰锛�
+     *  鎵�浠ユ瘡涓�涓嚎绋嬮兘鍙互鐙珛鍦版敼鍙樿嚜宸辩殑鍓湰锛岃�屼笉浼氬奖鍝嶅叾瀹冪嚎绋嬫墍瀵瑰簲鐨勫壇鏈��
+     */
+    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
+
+    /**
+     * 璁剧疆鏁版嵁婧愮殑鍙橀噺
+     */
+    public static void setDataSourceType(String dsType)
+    {
+        log.info("鍒囨崲鍒皗}鏁版嵁婧�", dsType);
+        CONTEXT_HOLDER.set(dsType);
+    }
+
+    /**
+     * 鑾峰緱鏁版嵁婧愮殑鍙橀噺
+     */
+    public static String getDataSourceType()
+    {
+        return CONTEXT_HOLDER.get();
+    }
+
+    /**
+     * 娓呯┖鏁版嵁婧愬彉閲�
+     */
+    public static void clearDataSourceType()
+    {
+        CONTEXT_HOLDER.remove();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/manager/AsyncManager.java b/ruoyi/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
new file mode 100644
index 0000000..6ed6d5b
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
@@ -0,0 +1,55 @@
+package com.ruoyi.framework.manager;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import com.ruoyi.common.utils.Threads;
+import com.ruoyi.common.utils.spring.SpringUtils;
+
+/**
+ * 寮傛浠诲姟绠$悊鍣�
+ * 
+ * @author ruoyi
+ */
+public class AsyncManager
+{
+    /**
+     * 鎿嶄綔寤惰繜10姣
+     */
+    private final int OPERATE_DELAY_TIME = 10;
+
+    /**
+     * 寮傛鎿嶄綔浠诲姟璋冨害绾跨▼姹�
+     */
+    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
+
+    /**
+     * 鍗曚緥妯″紡
+     */
+    private AsyncManager(){}
+
+    private static AsyncManager me = new AsyncManager();
+
+    public static AsyncManager me()
+    {
+        return me;
+    }
+
+    /**
+     * 鎵ц浠诲姟
+     * 
+     * @param task 浠诲姟
+     */
+    public void execute(TimerTask task)
+    {
+        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 鍋滄浠诲姟绾跨▼姹�
+     */
+    public void shutdown()
+    {
+        Threads.shutdownAndAwaitTermination(executor);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java b/ruoyi/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
new file mode 100644
index 0000000..8d8fb5a
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
@@ -0,0 +1,39 @@
+package com.ruoyi.framework.manager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import javax.annotation.PreDestroy;
+
+/**
+ * 纭繚搴旂敤閫�鍑烘椂鑳藉叧闂悗鍙扮嚎绋�
+ *
+ * @author ruoyi
+ */
+@Component
+public class ShutdownManager
+{
+    private static final Logger logger = LoggerFactory.getLogger("sys-user");
+
+    @PreDestroy
+    public void destroy()
+    {
+        shutdownAsyncManager();
+    }
+
+    /**
+     * 鍋滄寮傛鎵ц浠诲姟
+     */
+    private void shutdownAsyncManager()
+    {
+        try
+        {
+            logger.info("====鍏抽棴鍚庡彴浠诲姟浠诲姟绾跨▼姹�====");
+            AsyncManager.me().shutdown();
+        }
+        catch (Exception e)
+        {
+            logger.error(e.getMessage(), e);
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java b/ruoyi/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
new file mode 100644
index 0000000..0be7a30
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
@@ -0,0 +1,101 @@
+package com.ruoyi.framework.manager.factory;
+
+import java.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.LogUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.ip.AddressUtils;
+import com.ruoyi.common.utils.ip.IpUtils;
+import com.ruoyi.common.utils.spring.SpringUtils;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+import com.ruoyi.project.monitor.service.ISysLogininforService;
+import com.ruoyi.project.monitor.service.ISysOperLogService;
+import eu.bitwalker.useragentutils.UserAgent;
+
+/**
+ * 寮傛宸ュ巶锛堜骇鐢熶换鍔$敤锛�
+ * 
+ * @author ruoyi
+ */
+public class AsyncFactory
+{
+    private static final Logger sys_user_logger = LoggerFactory.getLogger("sys-user");
+
+    /**
+     * 璁板綍鐧婚檰淇℃伅
+     * 
+     * @param username 鐢ㄦ埛鍚�
+     * @param status 鐘舵��
+     * @param message 娑堟伅
+     * @param args 鍒楄〃
+     * @return 浠诲姟task
+     */
+    public static TimerTask recordLogininfor(final String username, final String status, final String message,
+            final Object... args)
+    {
+        final UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        final String ip = IpUtils.getIpAddr(ServletUtils.getRequest());
+        return new TimerTask()
+        {
+            @Override
+            public void run()
+            {
+                String address = AddressUtils.getRealAddressByIP(ip);
+                StringBuilder s = new StringBuilder();
+                s.append(LogUtils.getBlock(ip));
+                s.append(address);
+                s.append(LogUtils.getBlock(username));
+                s.append(LogUtils.getBlock(status));
+                s.append(LogUtils.getBlock(message));
+                // 鎵撳嵃淇℃伅鍒版棩蹇�
+                sys_user_logger.info(s.toString(), args);
+                // 鑾峰彇瀹㈡埛绔搷浣滅郴缁�
+                String os = userAgent.getOperatingSystem().getName();
+                // 鑾峰彇瀹㈡埛绔祻瑙堝櫒
+                String browser = userAgent.getBrowser().getName();
+                // 灏佽瀵硅薄
+                SysLogininfor logininfor = new SysLogininfor();
+                logininfor.setUserName(username);
+                logininfor.setIpaddr(ip);
+                logininfor.setLoginLocation(address);
+                logininfor.setBrowser(browser);
+                logininfor.setOs(os);
+                logininfor.setMsg(message);
+                // 鏃ュ織鐘舵��
+                if (Constants.LOGIN_SUCCESS.equals(status) || Constants.LOGOUT.equals(status))
+                {
+                    logininfor.setStatus(Constants.SUCCESS);
+                }
+                else if (Constants.LOGIN_FAIL.equals(status))
+                {
+                    logininfor.setStatus(Constants.FAIL);
+                }
+                // 鎻掑叆鏁版嵁
+                SpringUtils.getBean(ISysLogininforService.class).insertLogininfor(logininfor);
+            }
+        };
+    }
+
+    /**
+     * 鎿嶄綔鏃ュ織璁板綍
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織淇℃伅
+     * @return 浠诲姟task
+     */
+    public static TimerTask recordOper(final SysOperLog operLog)
+    {
+        return new TimerTask()
+        {
+            @Override
+            public void run()
+            {
+                // 杩滅▼鏌ヨ鎿嶄綔鍦扮偣
+                operLog.setOperLocation(AddressUtils.getRealAddressByIP(operLog.getOperIp()));
+                SpringUtils.getBean(ISysOperLogService.class).insertOperlog(operLog);
+            }
+        };
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java b/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java
new file mode 100644
index 0000000..a290494
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/redis/RedisCache.java
@@ -0,0 +1,200 @@
+package com.ruoyi.framework.redis;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.TimeUnit;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.BoundSetOperations;
+import org.springframework.data.redis.core.HashOperations;
+import org.springframework.data.redis.core.ListOperations;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring redis 宸ュ叿绫�
+ * 
+ * @author ruoyi
+ **/
+@SuppressWarnings(value = { "unchecked", "rawtypes" })
+@Component
+public class RedisCache
+{
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public <T> ValueOperations<String, T> setCacheObject(String key, T value)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        operation.set(key, value);
+        return operation;
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     * @param timeout 鏃堕棿
+     * @param timeUnit 鏃堕棿棰楃矑搴�
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public <T> ValueOperations<String, T> setCacheObject(String key, T value, Integer timeout, TimeUnit timeUnit)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        operation.set(key, value, timeout, timeUnit);
+        return operation;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨勫熀鏈璞°��
+     *
+     * @param key 缂撳瓨閿��
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public <T> T getCacheObject(String key)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 鍒犻櫎鍗曚釜瀵硅薄
+     *
+     * @param key
+     */
+    public void deleteObject(String key)
+    {
+        redisTemplate.delete(key);
+    }
+
+    /**
+     * 鍒犻櫎闆嗗悎瀵硅薄
+     *
+     * @param collection
+     */
+    public void deleteObject(Collection collection)
+    {
+        redisTemplate.delete(collection);
+    }
+
+    /**
+     * 缂撳瓨List鏁版嵁
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @param dataList 寰呯紦瀛樼殑List鏁版嵁
+     * @return 缂撳瓨鐨勫璞�
+     */
+    public <T> ListOperations<String, T> setCacheList(String key, List<T> dataList)
+    {
+        ListOperations listOperation = redisTemplate.opsForList();
+        if (null != dataList)
+        {
+            int size = dataList.size();
+            for (int i = 0; i < size; i++)
+            {
+                listOperation.leftPush(key, dataList.get(i));
+            }
+        }
+        return listOperation;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @return 缂撳瓨閿�煎搴旂殑鏁版嵁
+     */
+    public <T> List<T> getCacheList(String key)
+    {
+        List<T> dataList = new ArrayList<T>();
+        ListOperations<String, T> listOperation = redisTemplate.opsForList();
+        Long size = listOperation.size(key);
+
+        for (int i = 0; i < size; i++)
+        {
+            dataList.add(listOperation.index(key, i));
+        }
+        return dataList;
+    }
+
+    /**
+     * 缂撳瓨Set
+     *
+     * @param key 缂撳瓨閿��
+     * @param dataSet 缂撳瓨鐨勬暟鎹�
+     * @return 缂撳瓨鏁版嵁鐨勫璞�
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(String key, Set<T> dataSet)
+    {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext())
+        {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨剆et
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(String key)
+    {
+        Set<T> dataSet = new HashSet<T>();
+        BoundSetOperations<String, T> operation = redisTemplate.boundSetOps(key);
+        Long size = operation.size();
+        for (int i = 0; i < size; i++)
+        {
+            dataSet.add(operation.pop());
+        }
+        return dataSet;
+    }
+
+    /**
+     * 缂撳瓨Map
+     *
+     * @param key
+     * @param dataMap
+     * @return
+     */
+    public <T> HashOperations<String, String, T> setCacheMap(String key, Map<String, T> dataMap)
+    {
+        HashOperations hashOperations = redisTemplate.opsForHash();
+        if (null != dataMap)
+        {
+            for (Map.Entry<String, T> entry : dataMap.entrySet())
+            {
+                hashOperations.put(key, entry.getKey(), entry.getValue());
+            }
+        }
+        return hashOperations;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨凪ap
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(String key)
+    {
+        Map<String, T> map = redisTemplate.opsForHash().entries(key);
+        return map;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java b/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java
new file mode 100644
index 0000000..46afd22
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/LoginUser.java
@@ -0,0 +1,168 @@
+package com.ruoyi.framework.security;
+
+import java.util.Collection;
+import java.util.Set;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.ruoyi.project.system.domain.SysUser;
+
+/**
+ * 鐧诲綍鐢ㄦ埛韬唤鏉冮檺
+ * 
+ * @author ruoyi
+ */
+public class LoginUser implements UserDetails
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 鐢ㄦ埛鍞竴鏍囪瘑
+     */
+    private String token;
+
+    /**
+     * 鐧婚檰鏃堕棿
+     */
+    private Long loginTime;
+
+    /**
+     * 杩囨湡鏃堕棿
+     */
+    private Long expireTime;
+
+    /**
+     * 鏉冮檺鍒楄〃
+     */
+    private Set<String> permissions;
+
+    /**
+     * 鐢ㄦ埛淇℃伅
+     */
+    private SysUser user;
+
+    public String getToken()
+    {
+        return token;
+    }
+
+    public void setToken(String token)
+    {
+        this.token = token;
+    }
+
+    public LoginUser()
+    {
+    }
+
+    public LoginUser(SysUser user, Set<String> permissions)
+    {
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    @JsonIgnore
+    @Override
+    public String getPassword()
+    {
+        return user.getPassword();
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return user.getUserName();
+    }
+
+    /**
+     * 璐︽埛鏄惁鏈繃鏈�,杩囨湡鏃犳硶楠岃瘉
+     */
+    @JsonIgnore
+    @Override
+    public boolean isAccountNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 鎸囧畾鐢ㄦ埛鏄惁瑙i攣,閿佸畾鐨勭敤鎴锋棤娉曡繘琛岃韩浠介獙璇�
+     * 
+     * @return
+     */
+    @JsonIgnore
+    @Override
+    public boolean isAccountNonLocked()
+    {
+        return true;
+    }
+
+    /**
+     * 鎸囩ず鏄惁宸茶繃鏈熺殑鐢ㄦ埛鐨勫嚟鎹�(瀵嗙爜),杩囨湡鐨勫嚟鎹槻姝㈣璇�
+     * 
+     * @return
+     */
+    @JsonIgnore
+    @Override
+    public boolean isCredentialsNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 鏄惁鍙敤 ,绂佺敤鐨勭敤鎴蜂笉鑳借韩浠介獙璇�
+     * 
+     * @return
+     */
+    @JsonIgnore
+    @Override
+    public boolean isEnabled()
+    {
+        return true;
+    }
+
+    public Long getLoginTime()
+    {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime)
+    {
+        this.loginTime = loginTime;
+    }
+
+    public Long getExpireTime()
+    {
+        return expireTime;
+    }
+
+    public void setExpireTime(Long expireTime)
+    {
+        this.expireTime = expireTime;
+    }
+
+    public Set<String> getPermissions()
+    {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions)
+    {
+        this.permissions = permissions;
+    }
+
+    public SysUser getUser()
+    {
+        return user;
+    }
+
+    public void setUser(SysUser user)
+    {
+        this.user = user;
+    }
+
+    @Override
+    public Collection<? extends GrantedAuthority> getAuthorities()
+    {
+        return null;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/ruoyi/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
new file mode 100644
index 0000000..ede50be
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
@@ -0,0 +1,44 @@
+package com.ruoyi.framework.security.filter;
+
+import java.io.IOException;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
+import org.springframework.stereotype.Component;
+import org.springframework.web.filter.OncePerRequestFilter;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+
+/**
+ * token杩囨护鍣� 楠岃瘉token鏈夋晥鎬�
+ * 
+ * @author ruoyi
+ */
+@Component
+public class JwtAuthenticationTokenFilter extends OncePerRequestFilter
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Override
+    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
+            throws ServletException, IOException
+    {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNull(SecurityUtils.getAuthentication()))
+        {
+            tokenService.verifyToken(loginUser);
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(loginUser, null, loginUser.getAuthorities());
+            authenticationToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
+            SecurityContextHolder.getContext().setAuthentication(authenticationToken);
+        }
+        chain.doFilter(request, response);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
new file mode 100644
index 0000000..995b1f3
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
@@ -0,0 +1,34 @@
+package com.ruoyi.framework.security.handle;
+
+import java.io.IOException;
+import java.io.Serializable;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.AuthenticationEntryPoint;
+import org.springframework.stereotype.Component;
+import com.alibaba.fastjson.JSON;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+/**
+ * 璁よ瘉澶辫触澶勭悊绫� 杩斿洖鏈巿鏉�
+ * 
+ * @author ruoyi
+ */
+@Component
+public class AuthenticationEntryPointImpl implements AuthenticationEntryPoint, Serializable
+{
+    private static final long serialVersionUID = -8970718410437077606L;
+
+    @Override
+    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException e)
+            throws IOException
+    {
+        int code = HttpStatus.UNAUTHORIZED;
+        String msg = StringUtils.format("璇锋眰璁块棶锛歿}锛岃璇佸け璐ワ紝鏃犳硶璁块棶绯荤粺璧勬簮", request.getRequestURI());
+        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(code, msg)));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
new file mode 100644
index 0000000..e8883a5
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
@@ -0,0 +1,51 @@
+package com.ruoyi.framework.security.handle;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
+import com.alibaba.fastjson.JSON;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.manager.AsyncManager;
+import com.ruoyi.framework.manager.factory.AsyncFactory;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+/**
+ * 鑷畾涔夐��鍑哄鐞嗙被 杩斿洖鎴愬姛
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class LogoutSuccessHandlerImpl implements LogoutSuccessHandler
+{
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 閫�鍑哄鐞�
+     * 
+     * @return
+     */
+    @Override
+    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication)
+            throws IOException, ServletException
+    {
+        LoginUser loginUser = tokenService.getLoginUser(request);
+        if (StringUtils.isNotNull(loginUser))
+        {
+            String userName = loginUser.getUsername();
+            // 璁板綍鐢ㄦ埛閫�鍑烘棩蹇�
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, "閫�鍑烘垚鍔�"));
+        }
+        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.error(HttpStatus.SUCCESS, "閫�鍑烘垚鍔�")));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/PermissionService.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/PermissionService.java
new file mode 100644
index 0000000..d467282
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/service/PermissionService.java
@@ -0,0 +1,169 @@
+package com.ruoyi.framework.security.service;
+
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.project.system.domain.SysRole;
+
+/**
+ * RuoYi棣栧垱 鑷畾涔夋潈闄愬疄鐜帮紝se鍙栬嚜SpringSecurity棣栧瓧姣�
+ * 
+ * @author ruoyi
+ */
+@Service("ss")
+public class PermissionService
+{
+    /** 鎵�鏈夋潈闄愭爣璇� */
+    private static final String ALL_PERMISSION = "*:*:*";
+
+    /** 绠$悊鍛樿鑹叉潈闄愭爣璇� */
+    private static final String SUPER_ADMIN = "admin";
+
+    private static final String ROLE_DELIMETER = ",";
+
+    private static final String PERMISSION_DELIMETER = ",";
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     * 
+     * @param permission 鏉冮檺瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     */
+    public boolean hasPermi(String permission)
+    {
+        if (StringUtils.isEmpty(permission))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        return hasPermissions(loginUser.getPermissions(), permission);
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁涓嶅叿澶囨煇鏉冮檺锛屼笌 hasPermi閫昏緫鐩稿弽
+     *
+     * @param permission 鏉冮檺瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁涓嶅叿澶囨煇鏉冮檺
+     */
+    public boolean lacksPermi(String permission)
+    {
+        return hasPermi(permission) != true;
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁鍏锋湁浠ヤ笅浠绘剰涓�涓潈闄�
+     *
+     * @param permissions 浠� PERMISSION_NAMES_DELIMETER 涓哄垎闅旂鐨勬潈闄愬垪琛�
+     * @return 鐢ㄦ埛鏄惁鍏锋湁浠ヤ笅浠绘剰涓�涓潈闄�
+     */
+    public boolean hasAnyPermi(String permissions)
+    {
+        if (StringUtils.isEmpty(permissions))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        Set<String> authorities = loginUser.getPermissions();
+        for (String permission : permissions.split(PERMISSION_DELIMETER))
+        {
+            if (permission != null && hasPermissions(authorities, permission))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 鍒ゆ柇鐢ㄦ埛鏄惁鎷ユ湁鏌愪釜瑙掕壊
+     * 
+     * @param role 瑙掕壊瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愯鑹�
+     */
+    public boolean hasRole(String role)
+    {
+        if (StringUtils.isEmpty(role))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (SysRole sysRole : loginUser.getUser().getRoles())
+        {
+            String roleKey = sysRole.getRoleKey();
+            if (SUPER_ADMIN.contains(roleKey) || roleKey.contains(StringUtils.trim(role)))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁涓嶅叿澶囨煇瑙掕壊锛屼笌 isRole閫昏緫鐩稿弽銆�
+     *
+     * @param role 瑙掕壊鍚嶇О
+     * @return 鐢ㄦ埛鏄惁涓嶅叿澶囨煇瑙掕壊
+     */
+    public boolean lacksRole(String role)
+    {
+        return hasRole(role) != true;
+    }
+
+    /**
+     * 楠岃瘉鐢ㄦ埛鏄惁鍏锋湁浠ヤ笅浠绘剰涓�涓鑹�
+     *
+     * @param roles 浠� ROLE_NAMES_DELIMETER 涓哄垎闅旂鐨勮鑹插垪琛�
+     * @return 鐢ㄦ埛鏄惁鍏锋湁浠ヤ笅浠绘剰涓�涓鑹�
+     */
+    public boolean hasAnyRoles(String roles)
+    {
+        if (StringUtils.isEmpty(roles))
+        {
+            return false;
+        }
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (String role : roles.split(ROLE_DELIMETER))
+        {
+            if (hasRole(role))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鍖呭惈鏉冮檺
+     * 
+     * @param permissions 鏉冮檺鍒楄〃
+     * @param permission 鏉冮檺瀛楃涓�
+     * @return 鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+     */
+    private boolean hasPermissions(Set<String> permissions, String permission)
+    {
+        return permissions.contains(ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysLoginService.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysLoginService.java
new file mode 100644
index 0000000..a5d97a2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysLoginService.java
@@ -0,0 +1,88 @@
+package com.ruoyi.framework.security.service;
+
+import javax.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.BadCredentialsException;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.user.CaptchaException;
+import com.ruoyi.common.exception.user.CaptchaExpireException;
+import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
+import com.ruoyi.common.utils.MessageUtils;
+import com.ruoyi.framework.manager.AsyncManager;
+import com.ruoyi.framework.manager.factory.AsyncFactory;
+import com.ruoyi.framework.redis.RedisCache;
+import com.ruoyi.framework.security.LoginUser;
+
+/**
+ * 鐧诲綍鏍¢獙鏂规硶
+ * 
+ * @author ruoyi
+ */
+@Component
+public class SysLoginService
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Resource
+    private AuthenticationManager authenticationManager;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 鐧诲綍楠岃瘉
+     * 
+     * @param username 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @param captcha 楠岃瘉鐮�
+     * @param uuid 鍞竴鏍囪瘑
+     * @return 缁撴灉
+     */
+    public String login(String username, String password, String code, String uuid)
+    {
+        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+        String captcha = redisCache.getCacheObject(verifyKey);
+        redisCache.deleteObject(verifyKey);
+        if (captcha == null)
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+            throw new CaptchaException();
+        }
+        // 鐢ㄦ埛楠岃瘉
+        Authentication authentication = null;
+        try
+        {
+            // 璇ユ柟娉曚細鍘昏皟鐢║serDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager
+                    .authenticate(new UsernamePasswordAuthenticationToken(username, password));
+        }
+        catch (Exception e)
+        {
+            if (e instanceof BadCredentialsException)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+                throw new UserPasswordNotMatchException();
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, e.getMessage()));
+                throw new CustomException(e.getMessage());
+            }
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        // 鐢熸垚token
+        return tokenService.createToken(loginUser);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysPermissionService.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysPermissionService.java
new file mode 100644
index 0000000..1bdb667
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/service/SysPermissionService.java
@@ -0,0 +1,66 @@
+package com.ruoyi.framework.security.service;
+
+import java.util.HashSet;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysMenuService;
+import com.ruoyi.project.system.service.ISysRoleService;
+
+/**
+ * 鐢ㄦ埛鏉冮檺澶勭悊
+ * 
+ * @author ruoyi
+ */
+@Component
+public class SysPermissionService
+{
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    /**
+     * 鑾峰彇瑙掕壊鏁版嵁鏉冮檺
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 瑙掕壊鏉冮檺淇℃伅
+     */
+    public Set<String> getRolePermission(SysUser user)
+    {
+        Set<String> roles = new HashSet<String>();
+        // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+        if (user.isAdmin())
+        {
+            roles.add("admin");
+        }
+        else
+        {
+            roles.addAll(roleService.selectRolePermissionByUserId(user.getUserId()));
+        }
+        return roles;
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟鏁版嵁鏉冮檺
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鑿滃崟鏉冮檺淇℃伅
+     */
+    public Set<String> getMenuPermission(SysUser user)
+    {
+        Set<String> roles = new HashSet<String>();
+        // 绠$悊鍛樻嫢鏈夋墍鏈夋潈闄�
+        if (user.isAdmin())
+        {
+            roles.add("*:*:*");
+        }
+        else
+        {
+            roles.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
+        }
+        return roles;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java
new file mode 100644
index 0000000..5eafd02
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/service/TokenService.java
@@ -0,0 +1,179 @@
+package com.ruoyi.framework.security.service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.IdUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.redis.RedisCache;
+import com.ruoyi.framework.security.LoginUser;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+/**
+ * token楠岃瘉澶勭悊
+ * 
+ * @author ruoyi
+ */
+@Component
+public class TokenService
+{
+    // 浠ょ墝鑷畾涔夋爣璇�
+    @Value("${token.header}")
+    private String header;
+
+    // 浠ょ墝绉橀挜
+    @Value("${token.secret}")
+    private String secret;
+
+    // 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+    @Value("${token.expireTime}")
+    private int expireTime;
+
+    protected static final long MILLIS_SECOND = 1000;
+
+    protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
+
+    private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 鑾峰彇鐢ㄦ埛韬唤淇℃伅
+     * 
+     * @return 鐢ㄦ埛淇℃伅
+     */
+    public LoginUser getLoginUser(HttpServletRequest request)
+    {
+        // 鑾峰彇璇锋眰鎼哄甫鐨勪护鐗�
+        String token = getToken(request);
+        if (StringUtils.isNotEmpty(token))
+        {
+            Claims claims = parseToken(token);
+            // 瑙f瀽瀵瑰簲鐨勬潈闄愪互鍙婄敤鎴蜂俊鎭�
+            String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
+            String userKey = getTokenKey(uuid);
+            LoginUser user = redisCache.getCacheObject(userKey);
+            return user;
+        }
+        return null;
+    }
+
+    /**
+     * 鍒涘缓浠ょ墝
+     * 
+     * @param loginUser 鐢ㄦ埛淇℃伅
+     * @return 浠ょ墝
+     */
+    public String createToken(LoginUser loginUser)
+    {
+        String token = IdUtils.fastUUID();
+        loginUser.setToken(token);
+        refreshToken(loginUser);
+
+        Map<String, Object> claims = new HashMap<>();
+        claims.put(Constants.LOGIN_USER_KEY, token);
+        return createToken(claims);
+    }
+
+    /**
+     * 楠岃瘉浠ょ墝鏈夋晥鏈燂紝鐩稿樊涓嶈冻20鍒嗛挓锛岃嚜鍔ㄥ埛鏂扮紦瀛�
+     * 
+     * @param token 浠ょ墝
+     * @return 浠ょ墝
+     */
+    public void verifyToken(LoginUser loginUser)
+    {
+        long expireTime = loginUser.getExpireTime();
+        long currentTime = System.currentTimeMillis();
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
+        {
+            String token = loginUser.getToken();
+            loginUser.setToken(token);
+            refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 鍒锋柊浠ょ墝鏈夋晥鏈�
+     * 
+     * @param token 浠ょ墝
+     * @return 浠ょ墝
+     */
+    public void refreshToken(LoginUser loginUser)
+    {
+        loginUser.setLoginTime(System.currentTimeMillis());
+        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+        // 鏍规嵁uuid灏唋oginUser缂撳瓨
+        String userKey = getTokenKey(loginUser.getToken());
+        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+    }
+
+    /**
+     * 浠庢暟鎹0鏄庣敓鎴愪护鐗�
+     *
+     * @param claims 鏁版嵁澹版槑
+     * @return 浠ょ墝
+     */
+    private String createToken(Map<String, Object> claims)
+    {
+        String token = Jwts.builder()
+                .setClaims(claims)
+                .signWith(SignatureAlgorithm.HS512, secret).compact();
+        return token;
+    }
+
+    /**
+     * 浠庝护鐗屼腑鑾峰彇鏁版嵁澹版槑
+     *
+     * @param token 浠ょ墝
+     * @return 鏁版嵁澹版槑
+     */
+    private Claims parseToken(String token)
+    {
+        return Jwts.parser()
+                .setSigningKey(secret)
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    /**
+     * 浠庝护鐗屼腑鑾峰彇鐢ㄦ埛鍚�
+     *
+     * @param token 浠ょ墝
+     * @return 鐢ㄦ埛鍚�
+     */
+    public String getUsernameFromToken(String token)
+    {
+        Claims claims = parseToken(token);
+        return claims.getSubject();
+    }
+
+    /**
+     * 鑾峰彇璇锋眰token
+     *
+     * @param request
+     * @return token
+     */
+    private String getToken(HttpServletRequest request)
+    {
+        String token = request.getHeader(header);
+        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
+        {
+            token = token.replace(Constants.TOKEN_PREFIX, "");
+        }
+        return token;
+    }
+
+    private String getTokenKey(String uuid)
+    {
+        return Constants.LOGIN_TOKEN_KEY + uuid;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/security/service/UserDetailsServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/framework/security/service/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..2a8c692
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/security/service/UserDetailsServiceImpl.java
@@ -0,0 +1,60 @@
+package com.ruoyi.framework.security.service;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.enums.UserStatus;
+import com.ruoyi.common.exception.BaseException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysUserService;
+
+/**
+ * 鐢ㄦ埛楠岃瘉澶勭悊
+ *
+ * @author ruoyi
+ */
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService
+{
+    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
+
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Override
+    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException
+    {
+        SysUser user = userService.selectUserByUserName(username);
+        if (StringUtils.isNull(user))
+        {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 涓嶅瓨鍦�.", username);
+            throw new UsernameNotFoundException("鐧诲綍鐢ㄦ埛锛�" + username + " 涓嶅瓨鍦�");
+        }
+        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
+        {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍒犻櫎.", username);
+            throw new BaseException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸茶鍒犻櫎");
+        }
+        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
+        {
+            log.info("鐧诲綍鐢ㄦ埛锛歿} 宸茶鍋滅敤.", username);
+            throw new BaseException("瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿锛�" + username + " 宸插仠鐢�");
+        }
+
+        return createLoginUser(user);
+    }
+
+    public UserDetails createLoginUser(SysUser user)
+    {
+        return new LoginUser(user, permissionService.getMenuPermission(user));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/controller/BaseController.java b/ruoyi/src/main/java/com/ruoyi/framework/web/controller/BaseController.java
new file mode 100644
index 0000000..ccc60a3
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/controller/BaseController.java
@@ -0,0 +1,85 @@
+package com.ruoyi.framework.web.controller;
+
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.common.utils.sql.SqlUtil;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.PageDomain;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.framework.web.page.TableSupport;
+
+/**
+ * web灞傞�氱敤鏁版嵁澶勭悊
+ * 
+ * @author ruoyi
+ */
+public class BaseController
+{
+    protected final Logger logger = LoggerFactory.getLogger(BaseController.class);
+
+    /**
+     * 灏嗗墠鍙颁紶閫掕繃鏉ョ殑鏃ユ湡鏍煎紡鐨勫瓧绗︿覆锛岃嚜鍔ㄨ浆鍖栦负Date绫诲瀷
+     */
+    @InitBinder
+    public void initBinder(WebDataBinder binder)
+    {
+        // Date 绫诲瀷杞崲
+        binder.registerCustomEditor(Date.class, new PropertyEditorSupport()
+        {
+            @Override
+            public void setAsText(String text)
+            {
+                setValue(DateUtils.parseDate(text));
+            }
+        });
+    }
+
+    /**
+     * 璁剧疆璇锋眰鍒嗛〉鏁版嵁
+     */
+    protected void startPage()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        if (StringUtils.isNotNull(pageNum) && StringUtils.isNotNull(pageSize))
+        {
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            PageHelper.startPage(pageNum, pageSize, orderBy);
+        }
+    }
+
+    /**
+     * 鍝嶅簲璇锋眰鍒嗛〉鏁版嵁
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected TableDataInfo getDataTable(List<?> list)
+    {
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setRows(list);
+        rspData.setTotal(new PageInfo(list).getTotal());
+        return rspData;
+    }
+
+    /**
+     * 鍝嶅簲杩斿洖缁撴灉
+     * 
+     * @param rows 褰卞搷琛屾暟
+     * @return 鎿嶄綔缁撴灉
+     */
+    protected AjaxResult toAjax(int rows)
+    {
+        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/AjaxResult.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/AjaxResult.java
new file mode 100644
index 0000000..5c551bd
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/AjaxResult.java
@@ -0,0 +1,148 @@
+package com.ruoyi.framework.web.domain;
+
+import java.util.HashMap;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 鎿嶄綔娑堟伅鎻愰啋
+ * 
+ * @author ruoyi
+ */
+public class AjaxResult extends HashMap<String, Object>
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鐘舵�佺爜 */
+    public static final String CODE_TAG = "code";
+
+    /** 杩斿洖鍐呭 */
+    public static final String MSG_TAG = "msg";
+
+    /** 鏁版嵁瀵硅薄 */
+    public static final String DATA_TAG = "data";
+
+    /**
+     * 鍒濆鍖栦竴涓柊鍒涘缓鐨� AjaxResult 瀵硅薄锛屼娇鍏惰〃绀轰竴涓┖娑堟伅銆�
+     */
+    public AjaxResult()
+    {
+    }
+
+    /**
+     * 鍒濆鍖栦竴涓柊鍒涘缓鐨� AjaxResult 瀵硅薄
+     * 
+     * @param code 鐘舵�佺爜
+     * @param msg 杩斿洖鍐呭
+     */
+    public AjaxResult(int code, String msg)
+    {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+    }
+
+    /**
+     * 鍒濆鍖栦竴涓柊鍒涘缓鐨� AjaxResult 瀵硅薄
+     * 
+     * @param code 鐘舵�佺爜
+     * @param msg 杩斿洖鍐呭
+     * @param data 鏁版嵁瀵硅薄
+     */
+    public AjaxResult(int code, String msg, Object data)
+    {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+        if (StringUtils.isNotNull(data))
+        {
+            super.put(DATA_TAG, data);
+        }
+    }
+
+    /**
+     * 杩斿洖鎴愬姛娑堟伅
+     * 
+     * @return 鎴愬姛娑堟伅
+     */
+    public static AjaxResult success()
+    {
+        return AjaxResult.success("鎿嶄綔鎴愬姛");
+    }
+
+    /**
+     * 杩斿洖鎴愬姛鏁版嵁
+     * 
+     * @return 鎴愬姛娑堟伅
+     */
+    public static AjaxResult success(Object data)
+    {
+        return AjaxResult.success("鎿嶄綔鎴愬姛", data);
+    }
+
+    /**
+     * 杩斿洖鎴愬姛娑堟伅
+     * 
+     * @param msg 杩斿洖鍐呭
+     * @return 鎴愬姛娑堟伅
+     */
+    public static AjaxResult success(String msg)
+    {
+        return AjaxResult.success(msg, null);
+    }
+
+    /**
+     * 杩斿洖鎴愬姛娑堟伅
+     * 
+     * @param msg 杩斿洖鍐呭
+     * @param data 鏁版嵁瀵硅薄
+     * @return 鎴愬姛娑堟伅
+     */
+    public static AjaxResult success(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.SUCCESS, msg, data);
+    }
+
+    /**
+     * 杩斿洖閿欒娑堟伅
+     * 
+     * @return
+     */
+    public static AjaxResult error()
+    {
+        return AjaxResult.error("鎿嶄綔澶辫触");
+    }
+
+    /**
+     * 杩斿洖閿欒娑堟伅
+     * 
+     * @param msg 杩斿洖鍐呭
+     * @return 璀﹀憡娑堟伅
+     */
+    public static AjaxResult error(String msg)
+    {
+        return AjaxResult.error(msg, null);
+    }
+
+    /**
+     * 杩斿洖閿欒娑堟伅
+     * 
+     * @param msg 杩斿洖鍐呭
+     * @param data 鏁版嵁瀵硅薄
+     * @return 璀﹀憡娑堟伅
+     */
+    public static AjaxResult error(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.ERROR, msg, data);
+    }
+
+    /**
+     * 杩斿洖閿欒娑堟伅
+     * 
+     * @param code 鐘舵�佺爜
+     * @param msg 杩斿洖鍐呭
+     * @return 璀﹀憡娑堟伅
+     */
+    public static AjaxResult error(int code, String msg)
+    {
+        return new AjaxResult(code, msg, null);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/BaseEntity.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/BaseEntity.java
new file mode 100644
index 0000000..7548bc9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/BaseEntity.java
@@ -0,0 +1,131 @@
+package com.ruoyi.framework.web.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import com.alibaba.fastjson.JSON;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+
+/**
+ * Entity鍩虹被
+ * 
+ * @author ruoyi
+ */
+public class BaseEntity implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鎼滅储鍊� */
+    private String searchValue;
+
+    /** 鍒涘缓鑰� */
+    private String createBy;
+
+    /** 鍒涘缓鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /** 鏇存柊鑰� */
+    private String updateBy;
+
+    /** 鏇存柊鏃堕棿 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /** 澶囨敞 */
+    private String remark;
+
+    /** 鏁版嵁鏉冮檺 */
+    private String dataScope;
+
+    /** 璇锋眰鍙傛暟 */
+    @JsonIgnore
+    private String params;
+
+    public String getSearchValue()
+    {
+        return searchValue;
+    }
+
+    public void setSearchValue(String searchValue)
+    {
+        this.searchValue = searchValue;
+    }
+
+    public String getCreateBy()
+    {
+        return createBy;
+    }
+
+    public void setCreateBy(String createBy)
+    {
+        this.createBy = createBy;
+    }
+
+    public Date getCreateTime()
+    {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime)
+    {
+        this.createTime = createTime;
+    }
+
+    public String getUpdateBy()
+    {
+        return updateBy;
+    }
+
+    public void setUpdateBy(String updateBy)
+    {
+        this.updateBy = updateBy;
+    }
+
+    public Date getUpdateTime()
+    {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime)
+    {
+        this.updateTime = updateTime;
+    }
+
+    public String getRemark()
+    {
+        return remark;
+    }
+
+    public void setRemark(String remark)
+    {
+        this.remark = remark;
+    }
+
+    public String getDataScope()
+    {
+        return dataScope;
+    }
+
+    public void setDataScope(String dataScope)
+    {
+        this.dataScope = dataScope;
+    }
+
+    @SuppressWarnings("unchecked")
+    public Map<String, Object> getParams()
+    {
+        if (params == null)
+        {
+            return new HashMap<>();
+        }
+        return JSON.parseObject(params, Map.class);
+    }
+
+    public void setParams(String params)
+    {
+        this.params = params;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/Server.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/Server.java
new file mode 100644
index 0000000..79e174b
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/Server.java
@@ -0,0 +1,241 @@
+package com.ruoyi.framework.web.domain;
+
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import com.ruoyi.common.utils.Arith;
+import com.ruoyi.common.utils.ip.IpUtils;
+import com.ruoyi.framework.web.domain.server.Cpu;
+import com.ruoyi.framework.web.domain.server.Jvm;
+import com.ruoyi.framework.web.domain.server.Mem;
+import com.ruoyi.framework.web.domain.server.Sys;
+import com.ruoyi.framework.web.domain.server.SysFile;
+import oshi.SystemInfo;
+import oshi.hardware.CentralProcessor;
+import oshi.hardware.CentralProcessor.TickType;
+import oshi.hardware.GlobalMemory;
+import oshi.hardware.HardwareAbstractionLayer;
+import oshi.software.os.FileSystem;
+import oshi.software.os.OSFileStore;
+import oshi.software.os.OperatingSystem;
+import oshi.util.Util;
+
+/**
+ * 鏈嶅姟鍣ㄧ浉鍏充俊鎭�
+ * 
+ * @author ruoyi
+ */
+public class Server
+{
+    
+    private static final int OSHI_WAIT_SECOND = 1000;
+    
+    /**
+     * CPU鐩稿叧淇℃伅
+     */
+    private Cpu cpu = new Cpu();
+
+    /**
+     * 鍏у瓨鐩稿叧淇℃伅
+     */
+    private Mem mem = new Mem();
+
+    /**
+     * JVM鐩稿叧淇℃伅
+     */
+    private Jvm jvm = new Jvm();
+
+    /**
+     * 鏈嶅姟鍣ㄧ浉鍏充俊鎭�
+     */
+    private Sys sys = new Sys();
+
+    /**
+     * 纾佺洏鐩稿叧淇℃伅
+     */
+    private List<SysFile> sysFiles = new LinkedList<SysFile>();
+
+    public Cpu getCpu()
+    {
+        return cpu;
+    }
+
+    public void setCpu(Cpu cpu)
+    {
+        this.cpu = cpu;
+    }
+
+    public Mem getMem()
+    {
+        return mem;
+    }
+
+    public void setMem(Mem mem)
+    {
+        this.mem = mem;
+    }
+
+    public Jvm getJvm()
+    {
+        return jvm;
+    }
+
+    public void setJvm(Jvm jvm)
+    {
+        this.jvm = jvm;
+    }
+
+    public Sys getSys()
+    {
+        return sys;
+    }
+
+    public void setSys(Sys sys)
+    {
+        this.sys = sys;
+    }
+
+    public List<SysFile> getSysFiles()
+    {
+        return sysFiles;
+    }
+
+    public void setSysFiles(List<SysFile> sysFiles)
+    {
+        this.sysFiles = sysFiles;
+    }
+
+    public void copyTo() throws Exception
+    {
+        SystemInfo si = new SystemInfo();
+        HardwareAbstractionLayer hal = si.getHardware();
+
+        setCpuInfo(hal.getProcessor());
+
+        setMemInfo(hal.getMemory());
+
+        setSysInfo();
+
+        setJvmInfo();
+
+        setSysFiles(si.getOperatingSystem());
+    }
+
+    /**
+     * 璁剧疆CPU淇℃伅
+     */
+    private void setCpuInfo(CentralProcessor processor)
+    {
+        // CPU淇℃伅
+        long[] prevTicks = processor.getSystemCpuLoadTicks();
+        Util.sleep(OSHI_WAIT_SECOND);
+        long[] ticks = processor.getSystemCpuLoadTicks();
+        long nice = ticks[TickType.NICE.getIndex()] - prevTicks[TickType.NICE.getIndex()];
+        long irq = ticks[TickType.IRQ.getIndex()] - prevTicks[TickType.IRQ.getIndex()];
+        long softirq = ticks[TickType.SOFTIRQ.getIndex()] - prevTicks[TickType.SOFTIRQ.getIndex()];
+        long steal = ticks[TickType.STEAL.getIndex()] - prevTicks[TickType.STEAL.getIndex()];
+        long cSys = ticks[TickType.SYSTEM.getIndex()] - prevTicks[TickType.SYSTEM.getIndex()];
+        long user = ticks[TickType.USER.getIndex()] - prevTicks[TickType.USER.getIndex()];
+        long iowait = ticks[TickType.IOWAIT.getIndex()] - prevTicks[TickType.IOWAIT.getIndex()];
+        long idle = ticks[TickType.IDLE.getIndex()] - prevTicks[TickType.IDLE.getIndex()];
+        long totalCpu = user + nice + cSys + idle + iowait + irq + softirq + steal;
+        cpu.setCpuNum(processor.getLogicalProcessorCount());
+        cpu.setTotal(totalCpu);
+        cpu.setSys(cSys);
+        cpu.setUsed(user);
+        cpu.setWait(iowait);
+        cpu.setFree(idle);
+    }
+
+    /**
+     * 璁剧疆鍐呭瓨淇℃伅
+     */
+    private void setMemInfo(GlobalMemory memory)
+    {
+        mem.setTotal(memory.getTotal());
+        mem.setUsed(memory.getTotal() - memory.getAvailable());
+        mem.setFree(memory.getAvailable());
+    }
+
+    /**
+     * 璁剧疆鏈嶅姟鍣ㄤ俊鎭�
+     */
+    private void setSysInfo()
+    {
+        Properties props = System.getProperties();
+        sys.setComputerName(IpUtils.getHostName());
+        sys.setComputerIp(IpUtils.getHostIp());
+        sys.setOsName(props.getProperty("os.name"));
+        sys.setOsArch(props.getProperty("os.arch"));
+        sys.setUserDir(props.getProperty("user.dir"));
+    }
+
+    /**
+     * 璁剧疆Java铏氭嫙鏈�
+     */
+    private void setJvmInfo() throws UnknownHostException
+    {
+        Properties props = System.getProperties();
+        jvm.setTotal(Runtime.getRuntime().totalMemory());
+        jvm.setMax(Runtime.getRuntime().maxMemory());
+        jvm.setFree(Runtime.getRuntime().freeMemory());
+        jvm.setVersion(props.getProperty("java.version"));
+        jvm.setHome(props.getProperty("java.home"));
+    }
+
+    /**
+     * 璁剧疆纾佺洏淇℃伅
+     */
+    private void setSysFiles(OperatingSystem os)
+    {
+        FileSystem fileSystem = os.getFileSystem();
+        OSFileStore[] fsArray = fileSystem.getFileStores();
+        for (OSFileStore fs : fsArray)
+        {
+            long free = fs.getUsableSpace();
+            long total = fs.getTotalSpace();
+            long used = total - free;
+            SysFile sysFile = new SysFile();
+            sysFile.setDirName(fs.getMount());
+            sysFile.setSysTypeName(fs.getType());
+            sysFile.setTypeName(fs.getName());
+            sysFile.setTotal(convertFileSize(total));
+            sysFile.setFree(convertFileSize(free));
+            sysFile.setUsed(convertFileSize(used));
+            sysFile.setUsage(Arith.mul(Arith.div(used, total, 4), 100));
+            sysFiles.add(sysFile);
+        }
+    }
+
+    /**
+     * 瀛楄妭杞崲
+     * 
+     * @param size 瀛楄妭澶у皬
+     * @return 杞崲鍚庡��
+     */
+    public String convertFileSize(long size)
+    {
+        long kb = 1024;
+        long mb = kb * 1024;
+        long gb = mb * 1024;
+        if (size >= gb)
+        {
+            return String.format("%.1f GB", (float) size / gb);
+        }
+        else if (size >= mb)
+        {
+            float f = (float) size / mb;
+            return String.format(f > 100 ? "%.0f MB" : "%.1f MB", f);
+        }
+        else if (size >= kb)
+        {
+            float f = (float) size / kb;
+            return String.format(f > 100 ? "%.0f KB" : "%.1f KB", f);
+        }
+        else
+        {
+            return String.format("%d B", size);
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeSelect.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeSelect.java
new file mode 100644
index 0000000..2ace4e9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/TreeSelect.java
@@ -0,0 +1,77 @@
+package com.ruoyi.framework.web.domain;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.domain.SysMenu;
+
+/**
+ * Treeselect鏍戠粨鏋勫疄浣撶被
+ * 
+ * @author ruoyi
+ */
+public class TreeSelect implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鑺傜偣ID */
+    private Long id;
+
+    /** 鑺傜偣鍚嶇О */
+    private String label;
+
+    /** 瀛愯妭鐐� */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<TreeSelect> children;
+
+    public TreeSelect()
+    {
+
+    }
+
+    public TreeSelect(SysDept dept)
+    {
+        this.id = dept.getDeptId();
+        this.label = dept.getDeptName();
+        this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public TreeSelect(SysMenu menu)
+    {
+        this.id = menu.getMenuId();
+        this.label = menu.getMenuName();
+        this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public Long getId()
+    {
+        return id;
+    }
+
+    public void setId(Long id)
+    {
+        this.id = id;
+    }
+
+    public String getLabel()
+    {
+        return label;
+    }
+
+    public void setLabel(String label)
+    {
+        this.label = label;
+    }
+
+    public List<TreeSelect> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<TreeSelect> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
new file mode 100644
index 0000000..cf7b46e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
@@ -0,0 +1,101 @@
+package com.ruoyi.framework.web.domain.server;
+
+import com.ruoyi.common.utils.Arith;
+
+/**
+ * CPU鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Cpu
+{
+    /**
+     * 鏍稿績鏁�
+     */
+    private int cpuNum;
+
+    /**
+     * CPU鎬荤殑浣跨敤鐜�
+     */
+    private double total;
+
+    /**
+     * CPU绯荤粺浣跨敤鐜�
+     */
+    private double sys;
+
+    /**
+     * CPU鐢ㄦ埛浣跨敤鐜�
+     */
+    private double used;
+
+    /**
+     * CPU褰撳墠绛夊緟鐜�
+     */
+    private double wait;
+
+    /**
+     * CPU褰撳墠绌洪棽鐜�
+     */
+    private double free;
+
+    public int getCpuNum()
+    {
+        return cpuNum;
+    }
+
+    public void setCpuNum(int cpuNum)
+    {
+        this.cpuNum = cpuNum;
+    }
+
+    public double getTotal()
+    {
+        return Arith.round(Arith.mul(total, 100), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getSys()
+    {
+        return Arith.round(Arith.mul(sys / total, 100), 2);
+    }
+
+    public void setSys(double sys)
+    {
+        this.sys = sys;
+    }
+
+    public double getUsed()
+    {
+        return Arith.round(Arith.mul(used / total, 100), 2);
+    }
+
+    public void setUsed(double used)
+    {
+        this.used = used;
+    }
+
+    public double getWait()
+    {
+        return Arith.round(Arith.mul(wait / total, 100), 2);
+    }
+
+    public void setWait(double wait)
+    {
+        this.wait = wait;
+    }
+
+    public double getFree()
+    {
+        return Arith.round(Arith.mul(free / total, 100), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
new file mode 100644
index 0000000..f29d2cb
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
@@ -0,0 +1,122 @@
+package com.ruoyi.framework.web.domain.server;
+
+import java.lang.management.ManagementFactory;
+import com.ruoyi.common.utils.Arith;
+import com.ruoyi.common.utils.DateUtils;
+
+/**
+ * JVM鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Jvm
+{
+    /**
+     * 褰撳墠JVM鍗犵敤鐨勫唴瀛樻�绘暟(M)
+     */
+    private double total;
+
+    /**
+     * JVM鏈�澶у彲鐢ㄥ唴瀛樻�绘暟(M)
+     */
+    private double max;
+
+    /**
+     * JVM绌洪棽鍐呭瓨(M)
+     */
+    private double free;
+
+    /**
+     * JDK鐗堟湰
+     */
+    private String version;
+
+    /**
+     * JDK璺緞
+     */
+    private String home;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getMax()
+    {
+        return Arith.div(max, (1024 * 1024), 2);
+    }
+
+    public void setMax(double max)
+    {
+        this.max = max;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(total - free, (1024 * 1024), 2);
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(total - free, total, 4), 100);
+    }
+
+    /**
+     * 鑾峰彇JDK鍚嶇О
+     */
+    public String getName()
+    {
+        return ManagementFactory.getRuntimeMXBean().getVmName();
+    }
+
+    public String getVersion()
+    {
+        return version;
+    }
+
+    public void setVersion(String version)
+    {
+        this.version = version;
+    }
+
+    public String getHome()
+    {
+        return home;
+    }
+
+    public void setHome(String home)
+    {
+        this.home = home;
+    }
+
+    /**
+     * JDK鍚姩鏃堕棿
+     */
+    public String getStartTime()
+    {
+        return DateUtils.parseDateToStr(DateUtils.YYYY_MM_DD_HH_MM_SS, DateUtils.getServerStartDate());
+    }
+
+    /**
+     * JDK杩愯鏃堕棿
+     */
+    public String getRunTime()
+    {
+        return DateUtils.getDatePoor(DateUtils.getNowDate(), DateUtils.getServerStartDate());
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
new file mode 100644
index 0000000..ac71504
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
@@ -0,0 +1,61 @@
+package com.ruoyi.framework.web.domain.server;
+
+import com.ruoyi.common.utils.Arith;
+
+/**
+ * 鍏у瓨鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Mem
+{
+    /**
+     * 鍐呭瓨鎬婚噺
+     */
+    private double total;
+
+    /**
+     * 宸茬敤鍐呭瓨
+     */
+    private double used;
+
+    /**
+     * 鍓╀綑鍐呭瓨
+     */
+    private double free;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setTotal(long total)
+    {
+        this.total = total;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(used, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setUsed(long used)
+    {
+        this.used = used;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setFree(long free)
+    {
+        this.free = free;
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(used, total, 4), 100);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
new file mode 100644
index 0000000..a5f65e4
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
@@ -0,0 +1,84 @@
+package com.ruoyi.framework.web.domain.server;
+
+/**
+ * 绯荤粺鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Sys
+{
+    /**
+     * 鏈嶅姟鍣ㄥ悕绉�
+     */
+    private String computerName;
+
+    /**
+     * 鏈嶅姟鍣↖p
+     */
+    private String computerIp;
+
+    /**
+     * 椤圭洰璺緞
+     */
+    private String userDir;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String osName;
+
+    /**
+     * 绯荤粺鏋舵瀯
+     */
+    private String osArch;
+
+    public String getComputerName()
+    {
+        return computerName;
+    }
+
+    public void setComputerName(String computerName)
+    {
+        this.computerName = computerName;
+    }
+
+    public String getComputerIp()
+    {
+        return computerIp;
+    }
+
+    public void setComputerIp(String computerIp)
+    {
+        this.computerIp = computerIp;
+    }
+
+    public String getUserDir()
+    {
+        return userDir;
+    }
+
+    public void setUserDir(String userDir)
+    {
+        this.userDir = userDir;
+    }
+
+    public String getOsName()
+    {
+        return osName;
+    }
+
+    public void setOsName(String osName)
+    {
+        this.osName = osName;
+    }
+
+    public String getOsArch()
+    {
+        return osArch;
+    }
+
+    public void setOsArch(String osArch)
+    {
+        this.osArch = osArch;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
new file mode 100644
index 0000000..47ecf3f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
@@ -0,0 +1,114 @@
+package com.ruoyi.framework.web.domain.server;
+
+/**
+ * 绯荤粺鏂囦欢鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class SysFile
+{
+    /**
+     * 鐩樼璺緞
+     */
+    private String dirName;
+
+    /**
+     * 鐩樼绫诲瀷
+     */
+    private String sysTypeName;
+
+    /**
+     * 鏂囦欢绫诲瀷
+     */
+    private String typeName;
+
+    /**
+     * 鎬诲ぇ灏�
+     */
+    private String total;
+
+    /**
+     * 鍓╀綑澶у皬
+     */
+    private String free;
+
+    /**
+     * 宸茬粡浣跨敤閲�
+     */
+    private String used;
+
+    /**
+     * 璧勬簮鐨勪娇鐢ㄧ巼
+     */
+    private double usage;
+
+    public String getDirName()
+    {
+        return dirName;
+    }
+
+    public void setDirName(String dirName)
+    {
+        this.dirName = dirName;
+    }
+
+    public String getSysTypeName()
+    {
+        return sysTypeName;
+    }
+
+    public void setSysTypeName(String sysTypeName)
+    {
+        this.sysTypeName = sysTypeName;
+    }
+
+    public String getTypeName()
+    {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName)
+    {
+        this.typeName = typeName;
+    }
+
+    public String getTotal()
+    {
+        return total;
+    }
+
+    public void setTotal(String total)
+    {
+        this.total = total;
+    }
+
+    public String getFree()
+    {
+        return free;
+    }
+
+    public void setFree(String free)
+    {
+        this.free = free;
+    }
+
+    public String getUsed()
+    {
+        return used;
+    }
+
+    public void setUsed(String used)
+    {
+        this.used = used;
+    }
+
+    public double getUsage()
+    {
+        return usage;
+    }
+
+    public void setUsage(double usage)
+    {
+        this.usage = usage;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..d5e4289
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
@@ -0,0 +1,93 @@
+package com.ruoyi.framework.web.exception;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.security.authentication.AccountExpiredException;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.servlet.NoHandlerFoundException;
+import com.ruoyi.common.constant.HttpStatus;
+import com.ruoyi.common.exception.BaseException;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.exception.DemoModeException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+/**
+ * 鍏ㄥ眬寮傚父澶勭悊鍣�
+ * 
+ * @author ruoyi
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler
+{
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    /**
+     * 鍩虹寮傚父
+     */
+    @ExceptionHandler(BaseException.class)
+    public AjaxResult baseException(BaseException e)
+    {
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 涓氬姟寮傚父
+     */
+    @ExceptionHandler(CustomException.class)
+    public AjaxResult businessException(CustomException e)
+    {
+        if (StringUtils.isNull(e.getCode()))
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+        return AjaxResult.error(e.getCode(), e.getMessage());
+    }
+
+    @ExceptionHandler(NoHandlerFoundException.class)
+    public AjaxResult handlerNoFoundException(Exception e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(HttpStatus.NOT_FOUND, "璺緞涓嶅瓨鍦紝璇锋鏌ヨ矾寰勬槸鍚︽纭�");
+    }
+
+    @ExceptionHandler(AccessDeniedException.class)
+    public AjaxResult handleAuthorizationException(AccessDeniedException e)
+    {
+        log.error(e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "娌℃湁鏉冮檺锛岃鑱旂郴绠$悊鍛樻巿鏉�");
+    }
+
+    @ExceptionHandler(AccountExpiredException.class)
+    public AjaxResult handleAccountExpiredException(AccountExpiredException e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    @ExceptionHandler(UsernameNotFoundException.class)
+    public AjaxResult handleUsernameNotFoundException(UsernameNotFoundException e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    @ExceptionHandler(Exception.class)
+    public AjaxResult handleException(Exception e)
+    {
+        log.error(e.getMessage(), e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 婕旂ず妯″紡寮傚父
+     */
+    @ExceptionHandler(DemoModeException.class)
+    public AjaxResult demoModeException(DemoModeException e)
+    {
+        return AjaxResult.error("婕旂ず妯″紡锛屼笉鍏佽鎿嶄綔");
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/page/PageDomain.java b/ruoyi/src/main/java/com/ruoyi/framework/web/page/PageDomain.java
new file mode 100644
index 0000000..7e50472
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/page/PageDomain.java
@@ -0,0 +1,69 @@
+package com.ruoyi.framework.web.page;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 鍒嗛〉鏁版嵁
+ * 
+ * @author ruoyi
+ */
+public class PageDomain
+{
+    /** 褰撳墠璁板綍璧峰绱㈠紩 */
+    private Integer pageNum;
+    /** 姣忛〉鏄剧ず璁板綍鏁� */
+    private Integer pageSize;
+    /** 鎺掑簭鍒� */
+    private String orderByColumn;
+    /** 鎺掑簭鐨勬柟鍚� "desc" 鎴栬�� "asc". */
+    private String isAsc;
+
+    public String getOrderBy()
+    {
+        if (StringUtils.isEmpty(orderByColumn))
+        {
+            return "";
+        }
+        return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
+    }
+
+    public Integer getPageNum()
+    {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum)
+    {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getPageSize()
+    {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize)
+    {
+        this.pageSize = pageSize;
+    }
+
+    public String getOrderByColumn()
+    {
+        return orderByColumn;
+    }
+
+    public void setOrderByColumn(String orderByColumn)
+    {
+        this.orderByColumn = orderByColumn;
+    }
+
+    public String getIsAsc()
+    {
+        return isAsc;
+    }
+
+    public void setIsAsc(String isAsc)
+    {
+        this.isAsc = isAsc;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableDataInfo.java b/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableDataInfo.java
new file mode 100644
index 0000000..3a184c6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableDataInfo.java
@@ -0,0 +1,85 @@
+package com.ruoyi.framework.web.page;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 琛ㄦ牸鍒嗛〉鏁版嵁瀵硅薄
+ * 
+ * @author ruoyi
+ */
+public class TableDataInfo implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鎬昏褰曟暟 */
+    private long total;
+
+    /** 鍒楄〃鏁版嵁 */
+    private List<?> rows;
+
+    /** 娑堟伅鐘舵�佺爜 */
+    private int code;
+
+    /** 娑堟伅鍐呭 */
+    private int msg;
+
+    /**
+     * 琛ㄦ牸鏁版嵁瀵硅薄
+     */
+    public TableDataInfo()
+    {
+    }
+
+    /**
+     * 鍒嗛〉
+     * 
+     * @param list 鍒楄〃鏁版嵁
+     * @param total 鎬昏褰曟暟
+     */
+    public TableDataInfo(List<?> list, int total)
+    {
+        this.rows = list;
+        this.total = total;
+    }
+
+    public long getTotal()
+    {
+        return total;
+    }
+
+    public void setTotal(long total)
+    {
+        this.total = total;
+    }
+
+    public List<?> getRows()
+    {
+        return rows;
+    }
+
+    public void setRows(List<?> rows)
+    {
+        this.rows = rows;
+    }
+
+    public int getCode()
+    {
+        return code;
+    }
+
+    public void setCode(int code)
+    {
+        this.code = code;
+    }
+
+    public int getMsg()
+    {
+        return msg;
+    }
+
+    public void setMsg(int msg)
+    {
+        this.msg = msg;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableSupport.java b/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableSupport.java
new file mode 100644
index 0000000..fa6a9ee
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/framework/web/page/TableSupport.java
@@ -0,0 +1,49 @@
+package com.ruoyi.framework.web.page;
+
+import com.ruoyi.common.utils.ServletUtils;
+
+/**
+ * 琛ㄦ牸鏁版嵁澶勭悊
+ * 
+ * @author ruoyi
+ */
+public class TableSupport
+{
+    /**
+     * 褰撳墠璁板綍璧峰绱㈠紩
+     */
+    public static final String PAGE_NUM = "pageNum";
+
+    /**
+     * 姣忛〉鏄剧ず璁板綍鏁�
+     */
+    public static final String PAGE_SIZE = "pageSize";
+
+    /**
+     * 鎺掑簭鍒�
+     */
+    public static final String ORDER_BY_COLUMN = "orderByColumn";
+
+    /**
+     * 鎺掑簭鐨勬柟鍚� "desc" 鎴栬�� "asc".
+     */
+    public static final String IS_ASC = "isAsc";
+
+    /**
+     * 灏佽鍒嗛〉瀵硅薄
+     */
+    public static PageDomain getPageDomain()
+    {
+        PageDomain pageDomain = new PageDomain();
+        pageDomain.setPageNum(ServletUtils.getParameterToInt(PAGE_NUM));
+        pageDomain.setPageSize(ServletUtils.getParameterToInt(PAGE_SIZE));
+        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
+        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
+        return pageDomain;
+    }
+
+    public static PageDomain buildPageRequest()
+    {
+        return getPageDomain();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/common/CaptchaController.java b/ruoyi/src/main/java/com/ruoyi/project/common/CaptchaController.java
new file mode 100644
index 0000000..9a3af20
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/common/CaptchaController.java
@@ -0,0 +1,62 @@
+package com.ruoyi.project.common;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.IdUtils;
+import com.ruoyi.common.utils.VerifyCodeUtils;
+import com.ruoyi.common.utils.sign.Base64;
+import com.ruoyi.framework.redis.RedisCache;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+/**
+ * 楠岃瘉鐮佹搷浣滃鐞�
+ * 
+ * @author ruoyi
+ */
+@RestController
+public class CaptchaController
+{
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 鐢熸垚楠岃瘉鐮�
+     */
+    @GetMapping("/captchaImage")
+    public AjaxResult getCode(HttpServletResponse response) throws IOException
+    {
+        // 鐢熸垚闅忔満瀛椾覆
+        String verifyCode = VerifyCodeUtils.generateVerifyCode(4);
+        // 鍞竴鏍囪瘑
+        String uuid = IdUtils.simpleUUID();
+        String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
+
+        redisCache.setCacheObject(verifyKey, verifyCode, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+        // 鐢熸垚鍥剧墖
+        int w = 111, h = 36;
+        ByteArrayOutputStream stream = new ByteArrayOutputStream();
+        VerifyCodeUtils.outputImage(w, h, stream, verifyCode);
+        try
+        {
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("uuid", uuid);
+            ajax.put("img", Base64.encode(stream.toByteArray()));
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+            return AjaxResult.error(e.getMessage());
+        }
+        finally
+        {
+            stream.close();
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java b/ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java
new file mode 100644
index 0000000..3362e00
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/common/CommonController.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.common;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.framework.config.RuoYiConfig;
+import com.ruoyi.framework.config.ServerConfig;
+import com.ruoyi.framework.web.domain.AjaxResult;
+
+/**
+ * 閫氱敤璇锋眰澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+public class CommonController
+{
+    @Autowired
+    private ServerConfig serverConfig;
+
+    /**
+     * 閫氱敤涓婁紶璇锋眰
+     */
+    @PostMapping("/common/upload")
+    public AjaxResult uploadFile(MultipartFile file) throws Exception
+    {
+        try
+        {
+            // 涓婁紶鏂囦欢璺緞
+            String filePath = RuoYiConfig.getUploadPath();
+            // 涓婁紶骞惰繑鍥炴柊鏂囦欢鍚嶇О
+            String fileName = FileUploadUtils.upload(filePath, file);
+            String url = serverConfig.getUrl() + fileName;
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("fileName", fileName);
+            ajax.put("url", url);
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
new file mode 100644
index 0000000..a692226
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/ServerController.java
@@ -0,0 +1,28 @@
+package com.ruoyi.project.monitor.controller;
+
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.domain.Server;
+
+/**
+ * 鏈嶅姟鍣ㄧ洃鎺�
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController extends BaseController
+{
+    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Server server = new Server();
+        server.copyTo();
+        return AjaxResult.success(server);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
new file mode 100644
index 0000000..2915b84
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysLogininforController.java
@@ -0,0 +1,34 @@
+package com.ruoyi.project.monitor.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+import com.ruoyi.project.monitor.service.ISysLogininforService;
+
+/**
+ * 绯荤粺璁块棶璁板綍
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController
+{
+    @Autowired
+    private ISysLogininforService logininforService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor)
+    {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return getDataTable(list);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
new file mode 100644
index 0000000..5d316ab
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/controller/SysOperlogController.java
@@ -0,0 +1,34 @@
+package com.ruoyi.project.monitor.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+import com.ruoyi.project.monitor.service.ISysOperLogService;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController
+{
+    @Autowired
+    private ISysOperLogService operLogService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog)
+    {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        return getDataTable(list);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java
new file mode 100644
index 0000000..ea0c40f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysLogininfor.java
@@ -0,0 +1,131 @@
+package com.ruoyi.project.monitor.domain;
+
+import java.util.Date;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 绯荤粺璁块棶璁板綍琛� sys_logininfor
+ * 
+ * @author ruoyi
+ */
+public class SysLogininfor extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    private Long infoId;
+
+    /** 鐢ㄦ埛璐﹀彿 */
+    private String userName;
+
+    /** 鐧诲綍鐘舵�� 0鎴愬姛 1澶辫触 */
+    private String status;
+
+    /** 鐧诲綍IP鍦板潃 */
+    private String ipaddr;
+
+    /** 鐧诲綍鍦扮偣 */
+    private String loginLocation;
+
+    /** 娴忚鍣ㄧ被鍨� */
+    private String browser;
+
+    /** 鎿嶄綔绯荤粺 */
+    private String os;
+
+    /** 鎻愮ず娑堟伅 */
+    private String msg;
+
+    /** 璁块棶鏃堕棿 */
+    private Date loginTime;
+
+    public Long getInfoId()
+    {
+        return infoId;
+    }
+
+    public void setInfoId(Long infoId)
+    {
+        this.infoId = infoId;
+    }
+
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getIpaddr()
+    {
+        return ipaddr;
+    }
+
+    public void setIpaddr(String ipaddr)
+    {
+        this.ipaddr = ipaddr;
+    }
+
+    public String getLoginLocation()
+    {
+        return loginLocation;
+    }
+
+    public void setLoginLocation(String loginLocation)
+    {
+        this.loginLocation = loginLocation;
+    }
+
+    public String getBrowser()
+    {
+        return browser;
+    }
+
+    public void setBrowser(String browser)
+    {
+        this.browser = browser;
+    }
+
+    public String getOs()
+    {
+        return os;
+    }
+
+    public void setOs(String os)
+    {
+        this.os = os;
+    }
+
+    public String getMsg()
+    {
+        return msg;
+    }
+
+    public void setMsg(String msg)
+    {
+        this.msg = msg;
+    }
+
+    public Date getLoginTime()
+    {
+        return loginTime;
+    }
+
+    public void setLoginTime(Date loginTime)
+    {
+        this.loginTime = loginTime;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java
new file mode 100644
index 0000000..a111aca
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/domain/SysOperLog.java
@@ -0,0 +1,235 @@
+package com.ruoyi.project.monitor.domain;
+
+import java.util.Date;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 鎿嶄綔鏃ュ織璁板綍琛� oper_log
+ * 
+ * @author ruoyi
+ */
+public class SysOperLog extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鏃ュ織涓婚敭 */
+    private Long operId;
+
+    /** 鎿嶄綔妯″潡 */
+    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;
+
+    public Long getOperId()
+    {
+        return operId;
+    }
+
+    public void setOperId(Long operId)
+    {
+        this.operId = operId;
+    }
+
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setTitle(String title)
+    {
+        this.title = title;
+    }
+
+    public Integer getBusinessType()
+    {
+        return businessType;
+    }
+
+    public void setBusinessType(Integer businessType)
+    {
+        this.businessType = businessType;
+    }
+
+    public Integer[] getBusinessTypes()
+    {
+        return businessTypes;
+    }
+
+    public void setBusinessTypes(Integer[] businessTypes)
+    {
+        this.businessTypes = businessTypes;
+    }
+
+    public String getMethod()
+    {
+        return method;
+    }
+
+    public void setMethod(String method)
+    {
+        this.method = method;
+    }
+
+    public String getRequestMethod()
+    {
+        return requestMethod;
+    }
+
+    public void setRequestMethod(String requestMethod)
+    {
+        this.requestMethod = requestMethod;
+    }
+
+    public Integer getOperatorType()
+    {
+        return operatorType;
+    }
+
+    public void setOperatorType(Integer operatorType)
+    {
+        this.operatorType = operatorType;
+    }
+
+    public String getOperName()
+    {
+        return operName;
+    }
+
+    public void setOperName(String operName)
+    {
+        this.operName = operName;
+    }
+
+    public String getDeptName()
+    {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName)
+    {
+        this.deptName = deptName;
+    }
+
+    public String getOperUrl()
+    {
+        return operUrl;
+    }
+
+    public void setOperUrl(String operUrl)
+    {
+        this.operUrl = operUrl;
+    }
+
+    public String getOperIp()
+    {
+        return operIp;
+    }
+
+    public void setOperIp(String operIp)
+    {
+        this.operIp = operIp;
+    }
+
+    public String getOperLocation()
+    {
+        return operLocation;
+    }
+
+    public void setOperLocation(String operLocation)
+    {
+        this.operLocation = operLocation;
+    }
+
+    public String getOperParam()
+    {
+        return operParam;
+    }
+
+    public void setOperParam(String operParam)
+    {
+        this.operParam = operParam;
+    }
+
+    public String getJsonResult()
+    {
+        return jsonResult;
+    }
+
+    public void setJsonResult(String jsonResult)
+    {
+        this.jsonResult = jsonResult;
+    }
+
+    public Integer getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(Integer status)
+    {
+        this.status = status;
+    }
+
+    public String getErrorMsg()
+    {
+        return errorMsg;
+    }
+
+    public void setErrorMsg(String errorMsg)
+    {
+        this.errorMsg = errorMsg;
+    }
+
+    public Date getOperTime()
+    {
+        return operTime;
+    }
+
+    public void setOperTime(Date operTime)
+    {
+        this.operTime = operTime;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java
new file mode 100644
index 0000000..43cd82e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysLogininforMapper.java
@@ -0,0 +1,42 @@
+package com.ruoyi.project.monitor.mapper;
+
+import java.util.List;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysLogininforMapper
+{
+    /**
+     * 鏂板绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     */
+    public void insertLogininfor(SysLogininfor logininfor);
+
+    /**
+     * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     * @return 鐧诲綍璁板綍闆嗗悎
+     */
+    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return 缁撴灉
+     */
+    public int deleteLogininforByIds(String[] ids);
+
+    /**
+     * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @return 缁撴灉
+     */
+    public int cleanLogininfor();
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java
new file mode 100644
index 0000000..2f7c2da
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/mapper/SysOperLogMapper.java
@@ -0,0 +1,48 @@
+package com.ruoyi.project.monitor.mapper;
+
+import java.util.List;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysOperLogMapper
+{
+    /**
+     * 鏂板鎿嶄綔鏃ュ織
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    public void insertOperlog(SysOperLog operLog);
+
+    /**
+     * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     * @return 鎿嶄綔鏃ュ織闆嗗悎
+     */
+    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return 缁撴灉
+     */
+    public int deleteOperLogByIds(String[] ids);
+
+    /**
+     * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+     * 
+     * @param operId 鎿嶄綔ID
+     * @return 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    public SysOperLog selectOperLogById(Long operId);
+
+    /**
+     * 娓呯┖鎿嶄綔鏃ュ織
+     */
+    public void cleanOperLog();
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java
new file mode 100644
index 0000000..c00bff7
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysLogininforService.java
@@ -0,0 +1,40 @@
+package com.ruoyi.project.monitor.service;
+
+import java.util.List;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysLogininforService
+{
+    /**
+     * 鏂板绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     */
+    public void insertLogininfor(SysLogininfor logininfor);
+
+    /**
+     * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     * @return 鐧诲綍璁板綍闆嗗悎
+     */
+    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return
+     */
+    public int deleteLogininforByIds(String ids);
+
+    /**
+     * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+     */
+    public void cleanLogininfor();
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java
new file mode 100644
index 0000000..d99eaf0
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/ISysOperLogService.java
@@ -0,0 +1,48 @@
+package com.ruoyi.project.monitor.service;
+
+import java.util.List;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysOperLogService
+{
+    /**
+     * 鏂板鎿嶄綔鏃ュ織
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    public void insertOperlog(SysOperLog operLog);
+
+    /**
+     * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     * @return 鎿嶄綔鏃ュ織闆嗗悎
+     */
+    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return 缁撴灉
+     */
+    public int deleteOperLogByIds(String ids);
+
+    /**
+     * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+     * 
+     * @param operId 鎿嶄綔ID
+     * @return 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    public SysOperLog selectOperLogById(Long operId);
+
+    /**
+     * 娓呯┖鎿嶄綔鏃ュ織
+     */
+    public void cleanOperLog();
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java
new file mode 100644
index 0000000..6de6159
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysLogininforServiceImpl.java
@@ -0,0 +1,66 @@
+package com.ruoyi.project.monitor.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.project.monitor.domain.SysLogininfor;
+import com.ruoyi.project.monitor.mapper.SysLogininforMapper;
+import com.ruoyi.project.monitor.service.ISysLogininforService;
+
+/**
+ * 绯荤粺璁块棶鏃ュ織鎯呭喌淇℃伅 鏈嶅姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysLogininforServiceImpl implements ISysLogininforService
+{
+
+    @Autowired
+    private SysLogininforMapper logininforMapper;
+
+    /**
+     * 鏂板绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     */
+    @Override
+    public void insertLogininfor(SysLogininfor logininfor)
+    {
+        logininforMapper.insertLogininfor(logininfor);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鐧诲綍鏃ュ織闆嗗悎
+     * 
+     * @param logininfor 璁块棶鏃ュ織瀵硅薄
+     * @return 鐧诲綍璁板綍闆嗗悎
+     */
+    @Override
+    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor)
+    {
+        return logininforMapper.selectLogininforList(logininfor);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鐧诲綍鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return
+     */
+    @Override
+    public int deleteLogininforByIds(String ids)
+    {
+        return logininforMapper.deleteLogininforByIds(Convert.toStrArray(ids));
+    }
+
+    /**
+     * 娓呯┖绯荤粺鐧诲綍鏃ュ織
+     */
+    @Override
+    public void cleanLogininfor()
+    {
+        logininforMapper.cleanLogininfor();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java
new file mode 100644
index 0000000..fdf9684
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/monitor/service/impl/SysOperLogServiceImpl.java
@@ -0,0 +1,77 @@
+package com.ruoyi.project.monitor.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.project.monitor.domain.SysOperLog;
+import com.ruoyi.project.monitor.mapper.SysOperLogMapper;
+import com.ruoyi.project.monitor.service.ISysOperLogService;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysOperLogServiceImpl implements ISysOperLogService
+{
+    @Autowired
+    private SysOperLogMapper operLogMapper;
+
+    /**
+     * 鏂板鎿嶄綔鏃ュ織
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    @Override
+    public void insertOperlog(SysOperLog operLog)
+    {
+        operLogMapper.insertOperlog(operLog);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鎿嶄綔鏃ュ織闆嗗悎
+     * 
+     * @param operLog 鎿嶄綔鏃ュ織瀵硅薄
+     * @return 鎿嶄綔鏃ュ織闆嗗悎
+     */
+    @Override
+    public List<SysOperLog> selectOperLogList(SysOperLog operLog)
+    {
+        return operLogMapper.selectOperLogList(operLog);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎绯荤粺鎿嶄綔鏃ュ織
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁
+     * @return
+     */
+    @Override
+    public int deleteOperLogByIds(String ids)
+    {
+        return operLogMapper.deleteOperLogByIds(Convert.toStrArray(ids));
+    }
+
+    /**
+     * 鏌ヨ鎿嶄綔鏃ュ織璇︾粏
+     * 
+     * @param operId 鎿嶄綔ID
+     * @return 鎿嶄綔鏃ュ織瀵硅薄
+     */
+    @Override
+    public SysOperLog selectOperLogById(Long operId)
+    {
+        return operLogMapper.selectOperLogById(operId);
+    }
+
+    /**
+     * 娓呯┖鎿嶄綔鏃ュ織
+     */
+    @Override
+    public void cleanOperLog()
+    {
+        operLogMapper.cleanOperLog();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
new file mode 100644
index 0000000..13b9d7c
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysConfigController.java
@@ -0,0 +1,110 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysConfig;
+import com.ruoyi.project.system.service.ISysConfigService;
+
+/**
+ * 鍙傛暟閰嶇疆 淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController
+{
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 鑾峰彇鍙傛暟閰嶇疆鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysConfig config)
+    {
+        startPage();
+        List<SysConfig> list = configService.selectConfigList(config);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long configId)
+    {
+        return AjaxResult.success(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/configKey/{configKey}")
+    public AjaxResult getConfigKey(@PathVariable String configKey)
+    {
+        return AjaxResult.success(configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:add')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysConfig config)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
+        {
+            return AjaxResult.error("鏂板鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        config.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(configService.insertConfig(config));
+    }
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:edit')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysConfig config)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config)))
+        {
+            return AjaxResult.error("淇敼鍙傛暟'" + config.getConfigName() + "'澶辫触锛屽弬鏁伴敭鍚嶅凡瀛樺湪");
+        }
+        config.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(configService.updateConfig(config));
+    }
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "鍙傛暟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configId}")
+    public AjaxResult remove(@PathVariable Long configId)
+    {
+        return toAjax(configService.deleteConfigById(configId));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
new file mode 100644
index 0000000..00700b1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDeptController.java
@@ -0,0 +1,133 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.service.ISysDeptService;
+
+/**
+ * 閮ㄩ棬淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dept")
+public class SysDeptController extends BaseController
+{
+    @Autowired
+    private ISysDeptService deptService;
+
+    /**
+     * 鑾峰彇閮ㄩ棬鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysDept dept)
+    {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return AjaxResult.success(deptService.buildDeptTree(depts));
+    }
+
+    /**
+     * 鏍规嵁閮ㄩ棬缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable Long deptId)
+    {
+        return AjaxResult.success(deptService.selectDeptById(deptId));
+    }
+
+    /**
+     * 鑾峰彇閮ㄩ棬涓嬫媺鏍戝垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysDept dept)
+    {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return AjaxResult.success(deptService.buildDeptTreeSelect(depts));
+    }
+
+    /**
+     * 鍔犺浇瀵瑰簲瑙掕壊閮ㄩ棬鍒楄〃鏍�
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping(value = "/roleDeptTreeselect/{roleId}")
+    @ResponseBody
+    public AjaxResult roleDeptTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(deptService.selectDeptListByRoleId(roleId));
+    }
+
+    /**
+     * 鏂板閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:add')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysDept dept)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
+        {
+            return AjaxResult.error("鏂板閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        }
+        dept.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(deptService.insertDept(dept));
+    }
+
+    /**
+     * 淇敼閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysDept dept)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept)))
+        {
+            return AjaxResult.error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛岄儴闂ㄥ悕绉板凡瀛樺湪");
+        }
+        else if (dept.getParentId().equals(dept.getDeptId()))
+        {
+            return AjaxResult.error("淇敼閮ㄩ棬'" + dept.getDeptName() + "'澶辫触锛屼笂绾ч儴闂ㄤ笉鑳芥槸鑷繁");
+        }
+        dept.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(deptService.updateDept(dept));
+    }
+
+    /**
+     * 鍒犻櫎閮ㄩ棬
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:remove')")
+    @Log(title = "閮ㄩ棬绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{deptId}")
+    public AjaxResult remove(@PathVariable Long deptId)
+    {
+        if (deptService.hasChildByDeptId(deptId))
+        {
+            return AjaxResult.error("瀛樺湪涓嬬骇閮ㄩ棬,涓嶅厑璁稿垹闄�");
+        }
+        if (deptService.checkDeptExistUser(deptId))
+        {
+            return AjaxResult.error("閮ㄩ棬瀛樺湪鐢ㄦ埛,涓嶅厑璁稿垹闄�");
+        }
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
new file mode 100644
index 0000000..488eeb5
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictDataController.java
@@ -0,0 +1,100 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDictData;
+import com.ruoyi.project.system.service.ISysDictDataService;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController
+{
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(SysDictData dictData)
+    {
+        startPage();
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictCode}")
+    public AjaxResult getInfo(@PathVariable Long dictCode)
+    {
+        return AjaxResult.success(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/dictType/{dictType}")
+    public AjaxResult dictType(@PathVariable String dictType)
+    {
+        return AjaxResult.success(dictDataService.selectDictDataByType(dictType));
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysDictData dict)
+    {
+        dict.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(dictDataService.insertDictData(dict));
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "瀛楀吀鏁版嵁", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysDictData dict)
+    {
+        dict.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(dictDataService.updateDictData(dict));
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCode}")
+    public AjaxResult remove(@PathVariable Long dictCode)
+    {
+        return toAjax(dictDataService.deleteDictDataById(dictCode));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
new file mode 100644
index 0000000..e98abde
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysDictTypeController.java
@@ -0,0 +1,99 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysDictType;
+import com.ruoyi.project.system.service.ISysDictTypeService;
+
+/**
+ * 鏁版嵁瀛楀吀淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController
+{
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(SysDictType dictType)
+    {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictId}")
+    public AjaxResult getInfo(@PathVariable Long dictId)
+    {
+        return AjaxResult.success(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysDictType dict)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
+        {
+            return AjaxResult.error("鏂板瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dict.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(dictTypeService.insertDictType(dict));
+    }
+
+    /**
+     * 淇敼瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysDictType dict)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict)))
+        {
+            return AjaxResult.error("淇敼瀛楀吀'" + dict.getDictName() + "'澶辫触锛屽瓧鍏哥被鍨嬪凡瀛樺湪");
+        }
+        dict.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(dictTypeService.updateDictType(dict));
+    }
+
+    /**
+     * 鍒犻櫎瀛楀吀绫诲瀷
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "瀛楀吀绫诲瀷", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictId}")
+    public AjaxResult remove(@PathVariable Long dictId)
+    {
+        return toAjax(dictTypeService.deleteDictTypeById(dictId));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
new file mode 100644
index 0000000..d7bf923
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysLoginController.java
@@ -0,0 +1,94 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.Constants;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.SysLoginService;
+import com.ruoyi.framework.security.service.SysPermissionService;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysMenuService;
+
+/**
+ * 鐧诲綍楠岃瘉
+ * 
+ * @author ruoyi
+ */
+@RestController
+public class SysLoginController
+{
+    @Autowired
+    private SysLoginService loginService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 鐧诲綍鏂规硶
+     * 
+     * @param username 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @param captcha 楠岃瘉鐮�
+     * @param uuid 鍞竴鏍囪瘑
+     * @return 缁撴灉
+     */
+    @PostMapping("/login")
+    public AjaxResult login(String username, String password, String code, String uuid)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 鐢熸垚浠ょ墝
+        String token = loginService.login(username, password, code, uuid);
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 鑾峰彇鐢ㄦ埛淇℃伅
+     * 
+     * @return 鐢ㄦ埛淇℃伅
+     */
+    @GetMapping("getInfo")
+    public AjaxResult getInfo()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        SysUser user = loginUser.getUser();
+        // 瑙掕壊闆嗗悎
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 鏉冮檺闆嗗悎
+        Set<String> permissions = permissionService.getMenuPermission(user);
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("user", user);
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        return ajax;
+    }
+
+    /**
+     * 鑾峰彇璺敱淇℃伅
+     * 
+     * @return 璺敱淇℃伅
+     */
+    @GetMapping("getRouters")
+    public AjaxResult getRouters()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        // 鐢ㄦ埛淇℃伅
+        SysUser user = loginUser.getUser();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(user.getUserId());
+        return AjaxResult.success(menuService.buildMenus(menus));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
new file mode 100644
index 0000000..d47ff4d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysMenuController.java
@@ -0,0 +1,130 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.service.ISysMenuService;
+
+/**
+ * 鑿滃崟淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/menu")
+public class SysMenuController extends BaseController
+{
+    @Autowired
+    private ISysMenuService menuService;
+
+    /**
+     * 鑾峰彇鑿滃崟鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysMenu menu)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(menu);
+        return AjaxResult.success(menuService.buildMenuTree(menus));
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable Long menuId)
+    {
+        return AjaxResult.success(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 鑾峰彇鑿滃崟涓嬫媺鏍戝垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysMenu dept)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(dept);
+        return AjaxResult.success(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 鍔犺浇瀵瑰簲瑙掕壊鑿滃崟鍒楄〃鏍�
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+    @ResponseBody
+    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        return AjaxResult.success(menuService.selectMenuListByRoleId(roleId));
+    }
+
+    /**
+     * 鏂板鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:add')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody @Validated SysMenu menu)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
+        {
+            return AjaxResult.error("鏂板鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        }
+        menu.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 淇敼鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysMenu menu)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu)))
+        {
+            return AjaxResult.error("淇敼鑿滃崟'" + menu.getMenuName() + "'澶辫触锛岃彍鍗曞悕绉板凡瀛樺湪");
+        }
+        menu.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(menuService.updateMenu(menu));
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:remove')")
+    @Log(title = "鑿滃崟绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{menuId}")
+    public AjaxResult remove(@PathVariable("menuId") Long menuId)
+    {
+        if (menuService.hasChildByMenuId(menuId))
+        {
+            return AjaxResult.error("瀛樺湪瀛愯彍鍗�,涓嶅厑璁稿垹闄�");
+        }
+        if (menuService.checkMenuExistRole(menuId))
+        {
+            return AjaxResult.error("鑿滃崟宸插垎閰�,涓嶅厑璁稿垹闄�");
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
new file mode 100644
index 0000000..8bd3985
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysNoticeController.java
@@ -0,0 +1,91 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysNotice;
+import com.ruoyi.project.system.service.ISysNoticeService;
+
+/**
+ * 鍏憡 淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/notice")
+public class SysNoticeController extends BaseController
+{
+    @Autowired
+    private ISysNoticeService noticeService;
+
+    /**
+     * 鑾峰彇閫氱煡鍏憡鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysNotice notice)
+    {
+        startPage();
+        List<SysNotice> list = noticeService.selectNoticeList(notice);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏍规嵁閫氱煡鍏憡缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:query')")
+    @GetMapping(value = "/{noticeId}")
+    public AjaxResult getInfo(@PathVariable Long noticeId)
+    {
+        return AjaxResult.success(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 鏂板閫氱煡鍏憡
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:add')")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysNotice notice)
+    {
+        notice.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(noticeService.insertNotice(notice));
+    }
+
+    /**
+     * 淇敼閫氱煡鍏憡
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:edit')")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysNotice notice)
+    {
+        notice.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(noticeService.updateNotice(notice));
+    }
+
+    /**
+     * 鍒犻櫎閫氱煡鍏憡
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:remove')")
+    @Log(title = "閫氱煡鍏憡", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{noticeId}")
+    public AjaxResult remove(@PathVariable Long noticeId)
+    {
+        return toAjax(noticeService.deleteNoticeById(noticeId));
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
new file mode 100644
index 0000000..77c3b55
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysPostController.java
@@ -0,0 +1,118 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysPost;
+import com.ruoyi.project.system.service.ISysPostService;
+
+/**
+ * 宀椾綅淇℃伅鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/post")
+public class SysPostController extends BaseController
+{
+    @Autowired
+    private ISysPostService postService;
+
+    /**
+     * 鑾峰彇宀椾綅鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysPost post)
+    {
+        startPage();
+        List<SysPost> list = postService.selectPostList(post);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏍规嵁宀椾綅缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable Long postId)
+    {
+        return AjaxResult.success(postService.selectPostById(postId));
+    }
+
+    /**
+     * 鏂板宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:add')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysPost post)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
+        {
+            return AjaxResult.error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
+        {
+            return AjaxResult.error("鏂板宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        }
+        post.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 淇敼宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:edit')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysPost post)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post)))
+        {
+            return AjaxResult.error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶅悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post)))
+        {
+            return AjaxResult.error("淇敼宀椾綅'" + post.getPostName() + "'澶辫触锛屽矖浣嶇紪鐮佸凡瀛樺湪");
+        }
+        post.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:remove')")
+    @Log(title = "宀椾綅绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postId}")
+    public AjaxResult remove(@PathVariable Long postId)
+    {
+        return toAjax(postService.deletePostById(postId));
+    }
+
+    /**
+     * 鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysPost> posts = postService.selectPostAll();
+        return AjaxResult.success(posts);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
new file mode 100644
index 0000000..fd8eee2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysProfileController.java
@@ -0,0 +1,106 @@
+package com.ruoyi.project.system.controller;
+
+import java.io.IOException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RequestParam;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.ServletUtils;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.config.RuoYiConfig;
+import com.ruoyi.framework.security.LoginUser;
+import com.ruoyi.framework.security.service.TokenService;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysUserService;
+
+/**
+ * 涓汉淇℃伅 涓氬姟澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 涓汉淇℃伅
+     */
+    @GetMapping
+    public AjaxResult profile()
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        SysUser user = loginUser.getUser();
+        AjaxResult ajax = AjaxResult.success(user);
+        ajax.put("roleGroup", userService.selectUserRoleGroup(loginUser.getUsername()));
+        ajax.put("postGroup", userService.selectUserPostGroup(loginUser.getUsername()));
+        return ajax;
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛
+     */
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult updateProfile(@RequestBody SysUser user)
+    {
+        return toAjax(userService.updateUserProfile(user));
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     */
+    @Log(title = "涓汉淇℃伅", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public AjaxResult updatePwd(String oldPassword, String newPassword)
+    {
+        LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+        String userName = loginUser.getUsername();
+        String password = loginUser.getPassword();
+        if (!SecurityUtils.matchesPassword(oldPassword, password))
+        {
+            return AjaxResult.error("淇敼瀵嗙爜澶辫触锛屾棫瀵嗙爜閿欒");
+        }
+        if (SecurityUtils.matchesPassword(newPassword, password))
+        {
+            return AjaxResult.error("鏂板瘑鐮佷笉鑳戒笌鏃у瘑鐮佺浉鍚�");
+        }
+        return toAjax(userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)));
+    }
+
+    /**
+     * 澶村儚涓婁紶
+     */
+    @Log(title = "鐢ㄦ埛澶村儚", businessType = BusinessType.UPDATE)
+    @PostMapping("/avatar")
+    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws IOException
+    {
+        if (!file.isEmpty())
+        {
+            LoginUser loginUser = tokenService.getLoginUser(ServletUtils.getRequest());
+            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file);
+            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
+            {
+                AjaxResult ajax = AjaxResult.success();
+                ajax.put("imgUrl", avatar);
+                return ajax;
+            }
+        }
+        return AjaxResult.error("涓婁紶鍥剧墖寮傚父锛岃鑱旂郴绠$悊鍛�");
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
new file mode 100644
index 0000000..9eae5b4
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysRoleController.java
@@ -0,0 +1,143 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.service.ISysRoleService;
+
+/**
+ * 瑙掕壊淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController
+{
+    @Autowired
+    private ISysRoleService roleService;
+
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysRole role)
+    {
+        startPage();
+        List<SysRole> list = roleService.selectRoleList(role);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable Long roleId)
+    {
+        return AjaxResult.success(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 鏂板瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:add')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysRole role)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+        {
+            return AjaxResult.error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+        {
+            return AjaxResult.error("鏂板瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+        role.setCreateBy(SecurityUtils.getUsername());
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+        {
+            return AjaxResult.error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹插悕绉板凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+        {
+            return AjaxResult.error("淇敼瑙掕壊'" + role.getRoleName() + "'澶辫触锛岃鑹叉潈闄愬凡瀛樺湪");
+        }
+        role.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(roleService.updateRole(role));
+    }
+
+    /**
+     * 淇敼淇濆瓨鏁版嵁鏉冮檺
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/dataScope")
+    public AjaxResult dataScope(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        return toAjax(roleService.authDataScope(role));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        role.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(roleService.updateRoleStatus(role));
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:remove')")
+    @Log(title = "瑙掕壊绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleId}")
+    public AjaxResult remove(@PathVariable Long roleId)
+    {
+        roleService.checkRoleAllowed(new SysRole(roleId));
+        return toAjax(roleService.deleteRoleById(roleId));
+    }
+
+    /**
+     * 鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        return AjaxResult.success(roleService.selectRoleAll());
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
new file mode 100644
index 0000000..cd8cd89
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/controller/SysUserController.java
@@ -0,0 +1,153 @@
+package com.ruoyi.project.system.controller;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.Log;
+import com.ruoyi.framework.aspectj.lang.enums.BusinessType;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import com.ruoyi.framework.web.page.TableDataInfo;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.service.ISysPostService;
+import com.ruoyi.project.system.service.ISysRoleService;
+import com.ruoyi.project.system.service.ISysUserService;
+
+/**
+ * 鐢ㄦ埛淇℃伅
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysPostService postService;
+
+    /**
+     * 鑾峰彇鐢ㄦ埛鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectUserList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛缂栧彿鑾峰彇璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping(value = "/{userId}")
+    public AjaxResult getInfo(@PathVariable Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success(userService.selectUserById(userId));
+        ajax.put("postIds", postService.selectPostListByUserId(userId));
+        ajax.put("roleIds", roleService.selectRoleListByUserId(userId));
+        return ajax;
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:add')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysUser user)
+    {
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user.getUserName())))
+        {
+            return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岀櫥褰曡处鍙峰凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
+        {
+            return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
+        {
+            return AjaxResult.error("鏂板鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        user.setCreateBy(SecurityUtils.getUsername());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        return toAjax(userService.insertUser(user));
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user)))
+        {
+            return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛屾墜鏈哄彿鐮佸凡瀛樺湪");
+        }
+        else if (UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user)))
+        {
+            return AjaxResult.error("淇敼鐢ㄦ埛'" + user.getUserName() + "'澶辫触锛岄偖绠辫处鍙峰凡瀛樺湪");
+        }
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 鍒犻櫎鐢ㄦ埛
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:remove')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userId}")
+    public AjaxResult remove(@PathVariable Long userId)
+    {
+        userService.checkUserAllowed(new SysUser(userId));
+        return toAjax(userService.deleteUserById(userId));
+    }
+
+    /**
+     * 閲嶇疆瀵嗙爜
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public AjaxResult resetPwd(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.resetPwd(user));
+    }
+
+    /**
+     * 鐘舵�佷慨鏀�
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "鐢ㄦ埛绠$悊", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        user.setUpdateBy(SecurityUtils.getUsername());
+        return toAjax(userService.updateUserStatus(user));
+    }
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java
new file mode 100644
index 0000000..9b4352a
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysConfig.java
@@ -0,0 +1,86 @@
+package com.ruoyi.project.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 鍙傛暟閰嶇疆琛� sys_config
+ * 
+ * @author ruoyi
+ */
+public class SysConfig extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鍙傛暟涓婚敭 */
+    private Long configId;
+
+    /** 鍙傛暟鍚嶇О */
+    private String configName;
+
+    /** 鍙傛暟閿悕 */
+    private String configKey;
+
+    /** 鍙傛暟閿�� */
+    private String configValue;
+
+    /** 绯荤粺鍐呯疆锛圷鏄� N鍚︼級 */
+    private String configType;
+
+    public Long getConfigId()
+    {
+        return configId;
+    }
+
+    public void setConfigId(Long configId)
+    {
+        this.configId = configId;
+    }
+
+    @NotBlank(message = "鍙傛暟鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "鍙傛暟鍚嶇О涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getConfigName()
+    {
+        return configName;
+    }
+
+    public void setConfigName(String configName)
+    {
+        this.configName = configName;
+    }
+
+    @NotBlank(message = "鍙傛暟閿悕闀垮害涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "鍙傛暟閿悕闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getConfigKey()
+    {
+        return configKey;
+    }
+
+    public void setConfigKey(String configKey)
+    {
+        this.configKey = configKey;
+    }
+
+    @NotBlank(message = "鍙傛暟閿�间笉鑳戒负绌�")
+    @Size(min = 0, max = 500, message = "鍙傛暟閿�奸暱搴︿笉鑳借秴杩�500涓瓧绗�")
+    public String getConfigValue()
+    {
+        return configValue;
+    }
+
+    public void setConfigValue(String configValue)
+    {
+        this.configValue = configValue;
+    }
+
+    public String getConfigType()
+    {
+        return configType;
+    }
+
+    public void setConfigType(String configType)
+    {
+        this.configType = configType;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java
new file mode 100644
index 0000000..8541660
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDept.java
@@ -0,0 +1,171 @@
+package com.ruoyi.project.system.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 閮ㄩ棬琛� sys_dept
+ * 
+ * @author ruoyi
+ */
+public class SysDept extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 閮ㄩ棬ID */
+    private Long deptId;
+
+    /** 鐖堕儴闂↖D */
+    private Long parentId;
+
+    /** 绁栫骇鍒楄〃 */
+    private String ancestors;
+
+    /** 閮ㄩ棬鍚嶇О */
+    private String deptName;
+
+    /** 鏄剧ず椤哄簭 */
+    private String orderNum;
+
+    /** 璐熻矗浜� */
+    private String leader;
+
+    /** 鑱旂郴鐢佃瘽 */
+    private String phone;
+
+    /** 閭 */
+    private String email;
+
+    /** 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤 */
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鐖堕儴闂ㄥ悕绉� */
+    private String parentName;
+
+    /** 瀛愰儴闂� */
+    private List<SysDept> children = new ArrayList<SysDept>();
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getParentId()
+    {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId)
+    {
+        this.parentId = parentId;
+    }
+
+    public String getAncestors()
+    {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors)
+    {
+        this.ancestors = ancestors;
+    }
+
+    public String getDeptName()
+    {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName)
+    {
+        this.deptName = deptName;
+    }
+
+    public String getOrderNum()
+    {
+        return orderNum;
+    }
+
+    public void setOrderNum(String orderNum)
+    {
+        this.orderNum = orderNum;
+    }
+
+    public String getLeader()
+    {
+        return leader;
+    }
+
+    public void setLeader(String leader)
+    {
+        this.leader = leader;
+    }
+
+    public String getPhone()
+    {
+        return phone;
+    }
+
+    public void setPhone(String phone)
+    {
+        this.phone = phone;
+    }
+
+    public String getEmail()
+    {
+        return email;
+    }
+
+    public void setEmail(String email)
+    {
+        this.email = email;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getParentName()
+    {
+        return parentName;
+    }
+
+    public void setParentName(String parentName)
+    {
+        this.parentName = parentName;
+    }
+
+    public List<SysDept> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<SysDept> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java
new file mode 100644
index 0000000..4c7efc6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictData.java
@@ -0,0 +1,145 @@
+package com.ruoyi.project.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 瀛楀吀鏁版嵁琛� sys_dict_data
+ * 
+ * @author ruoyi
+ */
+public class SysDictData extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 瀛楀吀缂栫爜 */
+    private Long dictCode;
+
+    /** 瀛楀吀鎺掑簭 */
+    private Long dictSort;
+
+    /** 瀛楀吀鏍囩 */
+    private String dictLabel;
+
+    /** 瀛楀吀閿�� */
+    private String dictValue;
+
+    /** 瀛楀吀绫诲瀷 */
+    private String dictType;
+
+    /** 鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛� */
+    private String cssClass;
+
+    /** 琛ㄦ牸瀛楀吀鏍峰紡 */
+    private String listClass;
+
+    /** 鏄惁榛樿锛圷鏄� N鍚︼級 */
+    private String isDefault;
+
+    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    public Long getDictCode()
+    {
+        return dictCode;
+    }
+
+    public void setDictCode(Long dictCode)
+    {
+        this.dictCode = dictCode;
+    }
+
+    public Long getDictSort()
+    {
+        return dictSort;
+    }
+
+    public void setDictSort(Long dictSort)
+    {
+        this.dictSort = dictSort;
+    }
+
+    @NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictLabel()
+    {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel)
+    {
+        this.dictLabel = dictLabel;
+    }
+
+    @NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
+    @Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩�100涓瓧绗�")
+    public String getDictValue()
+    {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue)
+    {
+        this.dictValue = dictValue;
+    }
+
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    @Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩�100涓瓧绗�")
+    public String getCssClass()
+    {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass)
+    {
+        this.cssClass = cssClass;
+    }
+
+    public String getListClass()
+    {
+        return listClass;
+    }
+
+    public void setListClass(String listClass)
+    {
+        this.listClass = listClass;
+    }
+
+    public boolean getDefault()
+    {
+        return UserConstants.YES.equals(this.isDefault) ? true : false;
+    }
+
+    public String getIsDefault()
+    {
+        return isDefault;
+    }
+
+    public void setIsDefault(String isDefault)
+    {
+        this.isDefault = isDefault;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java
new file mode 100644
index 0000000..8d3021e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysDictType.java
@@ -0,0 +1,71 @@
+package com.ruoyi.project.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 瀛楀吀绫诲瀷琛� sys_dict_type
+ * 
+ * @author ruoyi
+ */
+public class SysDictType extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 瀛楀吀涓婚敭 */
+    private Long dictId;
+
+    /** 瀛楀吀鍚嶇О */
+    private String dictName;
+
+    /** 瀛楀吀绫诲瀷 */
+    private String dictType;
+
+    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    public Long getDictId()
+    {
+        return dictId;
+    }
+
+    public void setDictId(Long dictId)
+    {
+        this.dictId = dictId;
+    }
+
+    @NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictName()
+    {
+        return dictName;
+    }
+
+    public void setDictName(String dictName)
+    {
+        this.dictName = dictName;
+    }
+
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java
new file mode 100644
index 0000000..73303d2
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysMenu.java
@@ -0,0 +1,184 @@
+package com.ruoyi.project.system.domain;
+
+import java.util.List;
+import com.ruoyi.framework.web.domain.BaseEntity;
+import java.util.ArrayList;
+
+/**
+ * 鑿滃崟鏉冮檺琛� sys_menu
+ * 
+ * @author ruoyi
+ */
+public class SysMenu extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鑿滃崟ID */
+    private Long menuId;
+
+    /** 鑿滃崟鍚嶇О */
+    private String menuName;
+
+    /** 鐖惰彍鍗曞悕绉� */
+    private String parentName;
+
+    /** 鐖惰彍鍗旾D */
+    private Long parentId;
+
+    /** 鏄剧ず椤哄簭 */
+    private String orderNum;
+
+    /** 璺敱鍦板潃 */
+    private String path;
+
+    /** 缁勪欢璺緞 */
+    private String component;
+
+    /** 鏄惁涓哄閾撅紙0鏄� 1鍚︼級 */
+    private String isFrame;
+
+    /** 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛� */
+    private String menuType;
+
+    /** 鑿滃崟鐘舵��:0鏄剧ず,1闅愯棌 */
+    private String visible;
+
+    /** 鏉冮檺瀛楃涓� */
+    private String perms;
+
+    /** 鑿滃崟鍥炬爣 */
+    private String icon;
+
+    /** 瀛愯彍鍗� */
+    private List<SysMenu> children = new ArrayList<SysMenu>();
+
+    public Long getMenuId()
+    {
+        return menuId;
+    }
+
+    public void setMenuId(Long menuId)
+    {
+        this.menuId = menuId;
+    }
+
+    public String getMenuName()
+    {
+        return menuName;
+    }
+
+    public void setMenuName(String menuName)
+    {
+        this.menuName = menuName;
+    }
+
+    public String getParentName()
+    {
+        return parentName;
+    }
+
+    public void setParentName(String parentName)
+    {
+        this.parentName = parentName;
+    }
+
+    public Long getParentId()
+    {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId)
+    {
+        this.parentId = parentId;
+    }
+
+    public String getOrderNum()
+    {
+        return orderNum;
+    }
+
+    public void setOrderNum(String orderNum)
+    {
+        this.orderNum = orderNum;
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+
+    public String getComponent()
+    {
+        return component;
+    }
+
+    public void setComponent(String component)
+    {
+        this.component = component;
+    }
+
+    public String getIsFrame()
+    {
+        return isFrame;
+    }
+
+    public void setIsFrame(String isFrame)
+    {
+        this.isFrame = isFrame;
+    }
+
+    public String getMenuType()
+    {
+        return menuType;
+    }
+
+    public void setMenuType(String menuType)
+    {
+        this.menuType = menuType;
+    }
+
+    public String getVisible()
+    {
+        return visible;
+    }
+
+    public void setVisible(String visible)
+    {
+        this.visible = visible;
+    }
+
+    public String getPerms()
+    {
+        return perms;
+    }
+
+    public void setPerms(String perms)
+    {
+        this.perms = perms;
+    }
+
+    public String getIcon()
+    {
+        return icon;
+    }
+
+    public void setIcon(String icon)
+    {
+        this.icon = icon;
+    }
+
+    public List<SysMenu> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<SysMenu> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
new file mode 100644
index 0000000..dbf5248
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysNotice.java
@@ -0,0 +1,78 @@
+package com.ruoyi.project.system.domain;
+
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 閫氱煡鍏憡琛� sys_notice
+ * 
+ * @author ruoyi
+ */
+public class SysNotice extends BaseEntity
+{
+    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;
+
+    public Long getNoticeId()
+    {
+        return noticeId;
+    }
+
+    public void setNoticeId(Long noticeId)
+    {
+        this.noticeId = noticeId;
+    }
+
+    public void setNoticeTitle(String noticeTitle)
+    {
+        this.noticeTitle = noticeTitle;
+    }
+
+    public String getNoticeTitle()
+    {
+        return noticeTitle;
+    }
+
+    public void setNoticeType(String noticeType)
+    {
+        this.noticeType = noticeType;
+    }
+
+    public String getNoticeType()
+    {
+        return noticeType;
+    }
+
+    public void setNoticeContent(String noticeContent)
+    {
+        this.noticeContent = noticeContent;
+    }
+
+    public String getNoticeContent()
+    {
+        return noticeContent;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java
new file mode 100644
index 0000000..0b1a937
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysPost.java
@@ -0,0 +1,98 @@
+package com.ruoyi.project.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 宀椾綅琛� sys_post
+ * 
+ * @author ruoyi
+ */
+public class SysPost extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 宀椾綅搴忓彿 */
+    private Long postId;
+
+    /** 宀椾綅缂栫爜 */
+    private String postCode;
+
+    /** 宀椾綅鍚嶇О */
+    private String postName;
+
+    /** 宀椾綅鎺掑簭 */
+    private String postSort;
+
+    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    /** 鐢ㄦ埛鏄惁瀛樺湪姝ゅ矖浣嶆爣璇� 榛樿涓嶅瓨鍦� */
+    private boolean flag = false;
+
+    public Long getPostId()
+    {
+        return postId;
+    }
+
+    public void setPostId(Long postId)
+    {
+        this.postId = postId;
+    }
+
+    @NotBlank(message = "宀椾綅缂栫爜涓嶈兘涓虹┖")
+    @Size(min = 0, max = 64, message = "宀椾綅缂栫爜闀垮害涓嶈兘瓒呰繃64涓瓧绗�")
+    public String getPostCode()
+    {
+        return postCode;
+    }
+
+    public void setPostCode(String postCode)
+    {
+        this.postCode = postCode;
+    }
+
+    @NotBlank(message = "宀椾綅鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 50, message = "宀椾綅鍚嶇О闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+    public String getPostName()
+    {
+        return postName;
+    }
+
+    public void setPostName(String postName)
+    {
+        this.postName = postName;
+    }
+
+    @NotBlank(message = "鏄剧ず椤哄簭涓嶈兘涓虹┖")
+    public String getPostSort()
+    {
+        return postSort;
+    }
+
+    public void setPostSort(String postSort)
+    {
+        this.postSort = postSort;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public boolean isFlag()
+    {
+        return flag;
+    }
+
+    public void setFlag(boolean flag)
+    {
+        this.flag = flag;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java
new file mode 100644
index 0000000..27bed48
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRole.java
@@ -0,0 +1,163 @@
+package com.ruoyi.project.system.domain;
+
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 瑙掕壊琛� sys_role
+ * 
+ * @author ruoyi
+ */
+public class SysRole extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 瑙掕壊ID */
+    private Long roleId;
+
+    /** 瑙掕壊鍚嶇О */
+    private String roleName;
+
+    /** 瑙掕壊鏉冮檺 */
+    private String roleKey;
+
+    /** 瑙掕壊鎺掑簭 */
+    private String roleSort;
+
+    /** 鏁版嵁鑼冨洿 */
+    private String dataScope;
+
+    /** 瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鐢ㄦ埛鏄惁瀛樺湪姝よ鑹叉爣璇� 榛樿涓嶅瓨鍦� */
+    private boolean flag = false;
+
+    /** 鑿滃崟缁� */
+    private Long[] menuIds;
+
+    /** 閮ㄩ棬缁勶紙鏁版嵁鏉冮檺锛� */
+    private Long[] deptIds;
+
+    public SysRole()
+    {
+
+    }
+
+    public SysRole(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    public Long getRoleId()
+    {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    public boolean isAdmin()
+    {
+        return isAdmin(this.roleId);
+    }
+
+    public static boolean isAdmin(Long roleId)
+    {
+        return roleId != null && 1L == roleId;
+    }
+
+    public String getRoleName()
+    {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName)
+    {
+        this.roleName = roleName;
+    }
+
+    public String getRoleKey()
+    {
+        return roleKey;
+    }
+
+    public void setRoleKey(String roleKey)
+    {
+        this.roleKey = roleKey;
+    }
+
+    public String getRoleSort()
+    {
+        return roleSort;
+    }
+
+    public void setRoleSort(String roleSort)
+    {
+        this.roleSort = roleSort;
+    }
+
+    public String getDataScope()
+    {
+        return dataScope;
+    }
+
+    public void setDataScope(String dataScope)
+    {
+        this.dataScope = dataScope;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public boolean isFlag()
+    {
+        return flag;
+    }
+
+    public void setFlag(boolean flag)
+    {
+        this.flag = flag;
+    }
+
+    public Long[] getMenuIds()
+    {
+        return menuIds;
+    }
+
+    public void setMenuIds(Long[] menuIds)
+    {
+        this.menuIds = menuIds;
+    }
+
+    public Long[] getDeptIds()
+    {
+        return deptIds;
+    }
+
+    public void setDeptIds(Long[] deptIds)
+    {
+        this.deptIds = deptIds;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleDept.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleDept.java
new file mode 100644
index 0000000..f3dbd03
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleDept.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 瑙掕壊鍜岄儴闂ㄥ叧鑱� sys_role_dept
+ * 
+ * @author ruoyi
+ */
+public class SysRoleDept
+{
+    /** 瑙掕壊ID */
+    private Long roleId;
+    
+    /** 閮ㄩ棬ID */
+    private Long deptId;
+
+    public Long getRoleId()
+    {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("roleId", getRoleId())
+            .append("deptId", getDeptId())
+            .toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleMenu.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleMenu.java
new file mode 100644
index 0000000..5445229
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysRoleMenu.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 瑙掕壊鍜岃彍鍗曞叧鑱� sys_role_menu
+ * 
+ * @author ruoyi
+ */
+public class SysRoleMenu
+{
+    /** 瑙掕壊ID */
+    private Long roleId;
+    
+    /** 鑿滃崟ID */
+    private Long menuId;
+
+    public Long getRoleId()
+    {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    public Long getMenuId()
+    {
+        return menuId;
+    }
+
+    public void setMenuId(Long menuId)
+    {
+        this.menuId = menuId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("roleId", getRoleId())
+            .append("menuId", getMenuId())
+            .toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java
new file mode 100644
index 0000000..f6549bb
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUser.java
@@ -0,0 +1,270 @@
+package com.ruoyi.project.system.domain;
+
+import java.util.Date;
+import java.util.List;
+import com.ruoyi.framework.web.domain.BaseEntity;
+
+/**
+ * 鐢ㄦ埛瀵硅薄 sys_user
+ * 
+ * @author ruoyi
+ */
+public class SysUser extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鐢ㄦ埛ID */
+    private Long userId;
+
+    /** 閮ㄩ棬ID */
+    private Long deptId;
+
+    /** 鐢ㄦ埛璐﹀彿 */
+    private String userName;
+
+    /** 鐢ㄦ埛鏄电О */
+    private String nickName;
+
+    /** 鐢ㄦ埛閭 */
+    private String email;
+
+    /** 鎵嬫満鍙风爜 */
+    private String phonenumber;
+
+    /** 鐢ㄦ埛鎬у埆 */
+    private String sex;
+
+    /** 鐢ㄦ埛澶村儚 */
+    private String avatar;
+
+    /** 瀵嗙爜 */
+    private String password;
+
+    /** 鐩愬姞瀵� */
+    private String salt;
+
+    /** 甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鏈�鍚庣櫥闄咺P */
+    private String loginIp;
+
+    /** 鏈�鍚庣櫥闄嗘椂闂� */
+    private Date loginDate;
+
+    /** 閮ㄩ棬瀵硅薄 */
+    private SysDept dept;
+
+    /** 瑙掕壊瀵硅薄 */
+    private List<SysRole> roles;
+
+    /** 瑙掕壊缁� */
+    private Long[] roleIds;
+
+    /** 宀椾綅缁� */
+    private Long[] postIds;
+
+    public SysUser()
+    {
+
+    }
+
+    public SysUser(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public boolean isAdmin()
+    {
+        return isAdmin(this.userId);
+    }
+
+    public static boolean isAdmin(Long userId)
+    {
+        return userId != null && 1L == userId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public String getNickName()
+    {
+        return nickName;
+    }
+
+    public void setNickName(String nickName)
+    {
+        this.nickName = nickName;
+    }
+
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    public String getEmail()
+    {
+        return email;
+    }
+
+    public void setEmail(String email)
+    {
+        this.email = email;
+    }
+
+    public String getPhonenumber()
+    {
+        return phonenumber;
+    }
+
+    public void setPhonenumber(String phonenumber)
+    {
+        this.phonenumber = phonenumber;
+    }
+
+    public String getSex()
+    {
+        return sex;
+    }
+
+    public void setSex(String sex)
+    {
+        this.sex = sex;
+    }
+
+    public String getAvatar()
+    {
+        return avatar;
+    }
+
+    public void setAvatar(String avatar)
+    {
+        this.avatar = avatar;
+    }
+
+    public String getPassword()
+    {
+        return password;
+    }
+
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+
+    public String getSalt()
+    {
+        return salt;
+    }
+
+    public void setSalt(String salt)
+    {
+        this.salt = salt;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getLoginIp()
+    {
+        return loginIp;
+    }
+
+    public void setLoginIp(String loginIp)
+    {
+        this.loginIp = loginIp;
+    }
+
+    public Date getLoginDate()
+    {
+        return loginDate;
+    }
+
+    public void setLoginDate(Date loginDate)
+    {
+        this.loginDate = loginDate;
+    }
+
+    public SysDept getDept()
+    {
+        return dept;
+    }
+
+    public void setDept(SysDept dept)
+    {
+        this.dept = dept;
+    }
+
+    public List<SysRole> getRoles()
+    {
+        return roles;
+    }
+
+    public void setRoles(List<SysRole> roles)
+    {
+        this.roles = roles;
+    }
+
+    public Long[] getRoleIds()
+    {
+        return roleIds;
+    }
+
+    public void setRoleIds(Long[] roleIds)
+    {
+        this.roleIds = roleIds;
+    }
+
+    public Long[] getPostIds()
+    {
+        return postIds;
+    }
+
+    public void setPostIds(Long[] postIds)
+    {
+        this.postIds = postIds;
+    }
+
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserPost.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserPost.java
new file mode 100644
index 0000000..1ac4bfc
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserPost.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 鐢ㄦ埛鍜屽矖浣嶅叧鑱� sys_user_post
+ * 
+ * @author ruoyi
+ */
+public class SysUserPost
+{
+    /** 鐢ㄦ埛ID */
+    private Long userId;
+    
+    /** 宀椾綅ID */
+    private Long postId;
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getPostId()
+    {
+        return postId;
+    }
+
+    public void setPostId(Long postId)
+    {
+        this.postId = postId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("userId", getUserId())
+            .append("postId", getPostId())
+            .toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserRole.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserRole.java
new file mode 100644
index 0000000..e951bf3
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/SysUserRole.java
@@ -0,0 +1,46 @@
+package com.ruoyi.project.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 鐢ㄦ埛鍜岃鑹插叧鑱� sys_user_role
+ * 
+ * @author ruoyi
+ */
+public class SysUserRole
+{
+    /** 鐢ㄦ埛ID */
+    private Long userId;
+    
+    /** 瑙掕壊ID */
+    private Long roleId;
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getRoleId()
+    {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId)
+    {
+        this.roleId = roleId;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("userId", getUserId())
+            .append("roleId", getRoleId())
+            .toString();
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/MetaVo.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/MetaVo.java
new file mode 100644
index 0000000..118d2fa
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/MetaVo.java
@@ -0,0 +1,49 @@
+package com.ruoyi.project.system.domain.vo;
+
+/**
+ * 璺敱鏄剧ず淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class MetaVo
+{
+    /**
+     * 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+     */
+    private String title;
+
+    /**
+     * 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/icons/svg
+     */
+    private String icon;
+
+    public MetaVo()
+    {
+    }
+
+    public MetaVo(String title, String icon)
+    {
+        this.title = title;
+        this.icon = icon;
+    }
+
+    public String getTitle()
+    {
+        return title;
+    }
+
+    public void setTitle(String title)
+    {
+        this.title = title;
+    }
+
+    public String getIcon()
+    {
+        return icon;
+    }
+
+    public void setIcon(String icon)
+    {
+        this.icon = icon;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java b/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java
new file mode 100644
index 0000000..2177a7e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/domain/vo/RouterVo.java
@@ -0,0 +1,133 @@
+package com.ruoyi.project.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.List;
+
+/**
+ * 璺敱閰嶇疆淇℃伅
+ * 
+ * @author ruoyi
+ */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RouterVo
+{
+    /**
+     * 璺敱鍚嶅瓧
+     */
+    private String name;
+
+    /**
+     * 璺敱鍦板潃
+     */
+    private String path;
+
+    /**
+     * 鏄惁闅愯棌璺敱锛屽綋璁剧疆 true 鐨勬椂鍊欒璺敱涓嶄細鍐嶄晶杈规爮鍑虹幇
+     */
+    private String hidden;
+
+    /**
+     * 閲嶅畾鍚戝湴鍧�锛屽綋璁剧疆 noRedirect 鐨勬椂鍊欒璺敱鍦ㄩ潰鍖呭睉瀵艰埅涓笉鍙鐐瑰嚮
+     */
+    private String redirect;
+
+    /**
+     * 缁勪欢鍦板潃
+     */
+    private String component;
+
+    /**
+     * 褰撲綘涓�涓矾鐢变笅闈㈢殑 children 澹版槑鐨勮矾鐢卞ぇ浜�1涓椂锛岃嚜鍔ㄤ細鍙樻垚宓屽鐨勬ā寮�--濡傜粍浠堕〉闈�
+     */
+    private Boolean alwaysShow;
+
+    /**
+     * 鍏朵粬鍏冪礌
+     */
+    private MetaVo meta;
+
+    /**
+     * 瀛愯矾鐢�
+     */
+    private List<RouterVo> children;
+
+    public String getName()
+    {
+        return name;
+    }
+
+    public void setName(String name)
+    {
+        this.name = name;
+    }
+
+    public String getPath()
+    {
+        return path;
+    }
+
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+
+    public String getHidden()
+    {
+        return hidden;
+    }
+
+    public void setHidden(String hidden)
+    {
+        this.hidden = hidden;
+    }
+
+    public String getRedirect()
+    {
+        return redirect;
+    }
+
+    public void setRedirect(String redirect)
+    {
+        this.redirect = redirect;
+    }
+
+    public String getComponent()
+    {
+        return component;
+    }
+
+    public void setComponent(String component)
+    {
+        this.component = component;
+    }
+
+    public Boolean getAlwaysShow()
+    {
+        return alwaysShow;
+    }
+
+    public void setAlwaysShow(Boolean alwaysShow)
+    {
+        this.alwaysShow = alwaysShow;
+    }
+
+    public MetaVo getMeta()
+    {
+        return meta;
+    }
+
+    public void setMeta(MetaVo meta)
+    {
+        this.meta = meta;
+    }
+
+    public List<RouterVo> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<RouterVo> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..02d9270
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysConfigMapper.java
@@ -0,0 +1,60 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysConfig;
+
+/**
+ * 鍙傛暟閰嶇疆 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysConfigMapper
+{
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    public SysConfig selectConfig(SysConfig config);
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆闆嗗悎
+     */
+    public List<SysConfig> selectConfigList(SysConfig config);
+
+    /**
+     * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configKey 鍙傛暟閿悕
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    public SysConfig checkConfigKeyUnique(String configKey);
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertConfig(SysConfig config);
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateConfig(SysConfig config);
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆
+     * 
+     * @param configId 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteConfigById(Long configId);
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..7dac0cb
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDeptMapper.java
@@ -0,0 +1,109 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.ruoyi.project.system.domain.SysDept;
+
+/**
+ * 閮ㄩ棬绠$悊 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysDeptMapper
+{
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    public List<SysDept> selectDeptList(SysDept dept);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    public List<Integer> selectDeptListByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬淇℃伅
+     */
+    public SysDept selectDeptById(Long deptId);
+
+    /**
+     * 鏍规嵁ID鏌ヨ鎵�鏈夊瓙閮ㄩ棬
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬鍒楄〃
+     */
+    public List<SysDept> selectChildrenDeptById(Long deptId);
+
+    /**
+     * 鏄惁瀛樺湪瀛愯妭鐐�
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public int hasChildByDeptId(Long deptId);
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public int checkDeptExistUser(Long deptId);
+
+    /**
+     * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+     * 
+     * @param deptName 閮ㄩ棬鍚嶇О
+     * @param parentId 鐖堕儴闂↖D
+     * @return 缁撴灉
+     */
+    public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
+
+    /**
+     * 鏂板閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDept(SysDept dept);
+
+    /**
+     * 淇敼閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDept(SysDept dept);
+
+    /**
+     * 淇敼鎵�鍦ㄩ儴闂ㄧ殑鐖剁骇閮ㄩ棬鐘舵��
+     * 
+     * @param dept 閮ㄩ棬
+     */
+    public void updateDeptStatus(SysDept dept);
+
+    /**
+     * 淇敼瀛愬厓绱犲叧绯�
+     * 
+     * @param depts 瀛愬厓绱�
+     * @return 缁撴灉
+     */
+    public int updateDeptChildren(@Param("depts") List<SysDept> depts);
+
+    /**
+     * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public int deleteDeptById(Long deptId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..eaa25da
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictDataMapper.java
@@ -0,0 +1,87 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.ruoyi.project.system.domain.SysDictData;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysDictDataMapper
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysDictData> selectDictDataList(SysDictData dictData);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysDictData> selectDictDataByType(String dictType);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀閿��
+     * @return 瀛楀吀鏍囩
+     */
+    public String selectDictLabel(@Param("dictType") String dictType, @Param("dictValue") String dictValue);
+
+    /**
+     * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 瀛楀吀鏁版嵁
+     */
+    public SysDictData selectDictDataById(Long dictCode);
+
+    /**
+     * 鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁
+     */
+    public int countDictDataByType(String dictType);
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteDictDataById(Long dictCode);
+
+    /**
+     * 鏂板瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDictData(SysDictData dictData);
+
+    /**
+     * 淇敼瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDictData(SysDictData dictData);
+
+    /**
+     * 鍚屾淇敼瀛楀吀绫诲瀷
+     * 
+     * @param oldDictType 鏃у瓧鍏哥被鍨�
+     * @param newDictType 鏂版棫瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    public int updateDictDataType(@Param("oldDictType") String oldDictType, @Param("newDictType") String newDictType);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..16ceb69
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysDictTypeMapper.java
@@ -0,0 +1,77 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Mapper;
+import com.ruoyi.project.system.domain.SysDictType;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+@Mapper
+public interface SysDictTypeMapper
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    public List<SysDictType> selectDictTypeList(SysDictType dictType);
+
+    /**
+     * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+     * 
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    public List<SysDictType> selectDictTypeAll();
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+     * 
+     * @param dictId 瀛楀吀绫诲瀷ID
+     * @return 瀛楀吀绫诲瀷
+     */
+    public SysDictType selectDictTypeById(Long dictId);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀绫诲瀷
+     */
+    public SysDictType selectDictTypeByType(String dictType);
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀淇℃伅
+     * 
+     * @param dictId 瀛楀吀ID
+     * @return 缁撴灉
+     */
+    public int deleteDictTypeById(Long dictId);
+
+    /**
+     * 鏂板瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDictType(SysDictType dictType);
+
+    /**
+     * 淇敼瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDictType(SysDictType dictType);
+
+    /**
+     * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    public SysDictType checkDictTypeUnique(String dictType);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..d52a087
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysMenuMapper.java
@@ -0,0 +1,108 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.ruoyi.project.system.domain.SysMenu;
+
+/**
+ * 鑿滃崟琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysMenuMapper
+{
+    /**
+     * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 鑿滃崟鍒楄〃
+     */
+    public List<SysMenu> selectMenuList(SysMenu menu);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鎵�鏈夋潈闄�
+     * 
+     * @return 鏉冮檺鍒楄〃
+     */
+    public List<String> selectMenuPerms();
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    public List<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     * 
+     * @return 鑿滃崟鍒楄〃
+     */
+    public List<SysMenu> selectMenuTreeAll();
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     * 
+     * @param username 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    public List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    public List<Integer> selectMenuListByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    public SysMenu selectMenuById(Long menuId);
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    public int hasChildByMenuId(Long menuId);
+
+    /**
+     * 鏂板鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertMenu(SysMenu menu);
+
+    /**
+     * 淇敼鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateMenu(SysMenu menu);
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    public int deleteMenuById(Long menuId);
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     * 
+     * @param menuName 鑿滃崟鍚嶇О
+     * @param parentId 鐖惰彍鍗旾D
+     * @return 缁撴灉
+     */
+    public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java
new file mode 100644
index 0000000..ed6bcc0
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysNoticeMapper.java
@@ -0,0 +1,52 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysNotice;
+
+/**
+ * 閫氱煡鍏憡琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysNoticeMapper
+{
+    /**
+     * 鏌ヨ鍏憡淇℃伅
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 鍏憡淇℃伅
+     */
+    public SysNotice selectNoticeById(Long noticeId);
+
+    /**
+     * 鏌ヨ鍏憡鍒楄〃
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 鍏憡闆嗗悎
+     */
+    public List<SysNotice> selectNoticeList(SysNotice notice);
+
+    /**
+     * 鏂板鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertNotice(SysNotice notice);
+
+    /**
+     * 淇敼鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateNotice(SysNotice notice);
+
+    /**
+     * 鎵归噺鍒犻櫎鍏憡
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 缁撴灉
+     */
+    public int deleteNoticeById(Long noticeId);
+}
\ No newline at end of file
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java
new file mode 100644
index 0000000..4c0d41e
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysPostMapper.java
@@ -0,0 +1,91 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysPost;
+
+/**
+ * 宀椾綅淇℃伅 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysPostMapper
+{
+    /**
+     * 鏌ヨ宀椾綅鏁版嵁闆嗗悎
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 宀椾綅鏁版嵁闆嗗悎
+     */
+    public List<SysPost> selectPostList(SysPost post);
+
+    /**
+     * 鏌ヨ鎵�鏈夊矖浣�
+     * 
+     * @return 宀椾綅鍒楄〃
+     */
+    public List<SysPost> selectPostAll();
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    public SysPost selectPostById(Long postId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑宀椾綅ID鍒楄〃
+     */
+    public List<Integer> selectPostListByUserId(Long userId);
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 缁撴灉
+     */
+    public List<SysPost> selectPostsByUserName(String userName);
+
+    /**
+     * 鍒犻櫎宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    public int deletePostById(Long postId);
+
+    /**
+     * 淇敼宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int updatePost(SysPost post);
+
+    /**
+     * 鏂板宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertPost(SysPost post);
+
+    /**
+     * 鏍¢獙宀椾綅鍚嶇О
+     * 
+     * @param postName 宀椾綅鍚嶇О
+     * @return 缁撴灉
+     */
+    public SysPost checkPostNameUnique(String postName);
+
+    /**
+     * 鏍¢獙宀椾綅缂栫爜
+     * 
+     * @param postCode 宀椾綅缂栫爜
+     * @return 缁撴灉
+     */
+    public SysPost checkPostCodeUnique(String postCode);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleDeptMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleDeptMapper.java
new file mode 100644
index 0000000..fd4d6bd
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleDeptMapper.java
@@ -0,0 +1,44 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysRoleDept;
+
+/**
+ * 瑙掕壊涓庨儴闂ㄥ叧鑱旇〃 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysRoleDeptMapper
+{
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊鍜岄儴闂ㄥ叧鑱�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int deleteRoleDeptByRoleId(Long roleId);
+
+    /**
+     * 鎵归噺鍒犻櫎瑙掕壊閮ㄩ棬鍏宠仈淇℃伅
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteRoleDept(Long[] ids);
+
+    /**
+     * 鏌ヨ閮ㄩ棬浣跨敤鏁伴噺
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public int selectCountRoleDeptByDeptId(Long deptId);
+
+    /**
+     * 鎵归噺鏂板瑙掕壊閮ㄩ棬淇℃伅
+     * 
+     * @param roleDeptList 瑙掕壊閮ㄩ棬鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchRoleDept(List<SysRoleDept> roleDeptList);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..2f8cbd0
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMapper.java
@@ -0,0 +1,100 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysRole;
+
+/**
+ * 瑙掕壊琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysRoleMapper
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysRole> selectRoleList(SysRole role);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 瑙掕壊鍒楄〃
+     */
+    public List<SysRole> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 鏌ヨ鎵�鏈夎鑹�
+     * 
+     * @return 瑙掕壊鍒楄〃
+     */
+    public List<SysRole> selectRoleAll();
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑瑙掕壊ID鍒楄〃
+     */
+    public List<Integer> selectRoleListByUserId(Long userId);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    public SysRole selectRoleById(Long roleId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 瑙掕壊鍒楄〃
+     */
+    public List<SysRole> selectRolesByUserName(String userName);
+
+    /**
+     * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+     * 
+     * @param roleName 瑙掕壊鍚嶇О
+     * @return 瑙掕壊淇℃伅
+     */
+    public SysRole checkRoleNameUnique(String roleName);
+
+    /**
+     * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+     * 
+     * @param roleKey 瑙掕壊鏉冮檺
+     * @return 瑙掕壊淇℃伅
+     */
+    public SysRole checkRoleKeyUnique(String roleKey);
+
+    /**
+     * 淇敼瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateRole(SysRole role);
+
+    /**
+     * 鏂板瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertRole(SysRole role);
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int deleteRoleById(Long roleId);
+
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMenuMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..8d2e376
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysRoleMenuMapper.java
@@ -0,0 +1,36 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysRoleMenu;
+
+/**
+ * 瑙掕壊涓庤彍鍗曞叧鑱旇〃 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysRoleMenuMapper
+{
+    /**
+     * 鏌ヨ鑿滃崟浣跨敤鏁伴噺
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    public int checkMenuExistRole(Long menuId);
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊鍜岃彍鍗曞叧鑱�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int deleteRoleMenuByRoleId(Long roleId);
+
+    /**
+     * 鎵归噺鏂板瑙掕壊鑿滃崟淇℃伅
+     * 
+     * @param roleMenuList 瑙掕壊鑿滃崟鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..a93cb6f
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserMapper.java
@@ -0,0 +1,105 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+
+import org.apache.ibatis.annotations.Param;
+
+import com.ruoyi.project.system.domain.SysUser;
+
+/**
+ * 鐢ㄦ埛琛� 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysUserMapper
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     * 
+     * @param sysUser 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    public List<SysUser> selectUserList(SysUser sysUser);
+
+    /**
+     * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    public SysUser selectUserByUserName(String userName);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    public SysUser selectUserById(Long userId);
+
+    /**
+     * 鏂板鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertUser(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateUser(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛澶村儚
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @param avatar 澶村儚鍦板潃
+     * @return 缁撴灉
+     */
+    public int updateUserAvatar(@Param("userName") String userName, @Param("avatar") String avatar);
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @return 缁撴灉
+     */
+    public int resetUserPwd(@Param("userName") String userName, @Param("password") String password);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public int deleteUserById(Long userId);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     * 
+     * @param userName 鐢ㄦ埛鍚嶇О
+     * @return 缁撴灉
+     */
+    public int checkUserNameUnique(String userName);
+
+    /**
+     * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+     *
+     * @param phonenumber 鎵嬫満鍙风爜
+     * @return 缁撴灉
+     */
+    public SysUser checkPhoneUnique(String phonenumber);
+
+    /**
+     * 鏍¢獙email鏄惁鍞竴
+     *
+     * @param email 鐢ㄦ埛閭
+     * @return 缁撴灉
+     */
+    public SysUser checkEmailUnique(String email);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserPostMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserPostMapper.java
new file mode 100644
index 0000000..d67f403
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserPostMapper.java
@@ -0,0 +1,44 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysUserPost;
+
+/**
+ * 鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysUserPostMapper
+{
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛鍜屽矖浣嶅叧鑱�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public int deleteUserPostByUserId(Long userId);
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅浣跨敤鏁伴噺
+     * 
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    public int countUserPostById(Long postId);
+
+    /**
+     * 鎵归噺鍒犻櫎鐢ㄦ埛鍜屽矖浣嶅叧鑱�
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteUserPost(Long[] ids);
+
+    /**
+     * 鎵归噺鏂板鐢ㄦ埛宀椾綅淇℃伅
+     * 
+     * @param userPostList 鐢ㄦ埛瑙掕壊鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchUserPost(List<SysUserPost> userPostList);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserRoleMapper.java b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..614538d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/mapper/SysUserRoleMapper.java
@@ -0,0 +1,62 @@
+package com.ruoyi.project.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.ruoyi.project.system.domain.SysUserRole;
+
+/**
+ * 鐢ㄦ埛涓庤鑹插叧鑱旇〃 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysUserRoleMapper
+{
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleByUserId(Long userId);
+
+    /**
+     * 鎵归噺鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱�
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRole(Long[] ids);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int countUserRoleByRoleId(Long roleId);
+
+    /**
+     * 鎵归噺鏂板鐢ㄦ埛瑙掕壊淇℃伅
+     * 
+     * @param userRoleList 鐢ㄦ埛瑙掕壊鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchUserRole(List<SysUserRole> userRoleList);
+
+    /**
+     * 鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * 
+     * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleInfo(SysUserRole userRole);
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java
new file mode 100644
index 0000000..45353e9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysConfigService.java
@@ -0,0 +1,68 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysConfig;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysConfigService
+{
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configId 鍙傛暟閰嶇疆ID
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    public SysConfig selectConfigById(Long configId);
+
+    /**
+     * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configKey 鍙傛暟閿悕
+     * @return 鍙傛暟閿��
+     */
+    public Object selectConfigByKey(String configKey);
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆闆嗗悎
+     */
+    public List<SysConfig> selectConfigList(SysConfig config);
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertConfig(SysConfig config);
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateConfig(SysConfig config);
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configId 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteConfigById(Long configId);
+
+    /**
+     * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+     * 
+     * @param config 鍙傛暟淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkConfigKeyUnique(SysConfig config);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDeptService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDeptService.java
new file mode 100644
index 0000000..1d8a306
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDeptService.java
@@ -0,0 +1,101 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.framework.web.domain.TreeSelect;
+import com.ruoyi.project.system.domain.SysDept;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysDeptService
+{
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    public List<SysDept> selectDeptList(SysDept dept);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佹爲缁撴瀯
+     * 
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 鏍戠粨鏋勫垪琛�
+     */
+    public List<SysDept> buildDeptTree(List<SysDept> depts);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     * 
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    public List<Integer> selectDeptListByRoleId(Long roleId);
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬淇℃伅
+     */
+    public SysDept selectDeptById(Long deptId);
+
+    /**
+     * 鏄惁瀛樺湪閮ㄩ棬瀛愯妭鐐�
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public boolean hasChildByDeptId(Long deptId);
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    public boolean checkDeptExistUser(Long deptId);
+
+    /**
+     * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkDeptNameUnique(SysDept dept);
+
+    /**
+     * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDept(SysDept dept);
+
+    /**
+     * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDept(SysDept dept);
+
+    /**
+     * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    public int deleteDeptById(Long deptId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java
new file mode 100644
index 0000000..936bc44
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictDataService.java
@@ -0,0 +1,69 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysDictData;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysDictDataService
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysDictData> selectDictDataList(SysDictData dictData);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysDictData> selectDictDataByType(String dictType);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀閿��
+     * @return 瀛楀吀鏍囩
+     */
+    public String selectDictLabel(String dictType, String dictValue);
+
+    /**
+     * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 瀛楀吀鏁版嵁
+     */
+    public SysDictData selectDictDataById(Long dictCode);
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteDictDataById(Long dictCode);
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDictData(SysDictData dictData);
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDictData(SysDictData dictData);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java
new file mode 100644
index 0000000..1e3e7cf
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysDictTypeService.java
@@ -0,0 +1,75 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysDictType;
+
+/**
+ * 瀛楀吀 涓氬姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysDictTypeService
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    public List<SysDictType> selectDictTypeList(SysDictType dictType);
+
+    /**
+     * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+     * 
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    public List<SysDictType> selectDictTypeAll();
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+     * 
+     * @param dictId 瀛楀吀绫诲瀷ID
+     * @return 瀛楀吀绫诲瀷
+     */
+    public SysDictType selectDictTypeById(Long dictId);
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀绫诲瀷
+     */
+    public SysDictType selectDictTypeByType(String dictType);
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀淇℃伅
+     * 
+     * @param dictId 瀛楀吀ID
+     * @return 缁撴灉
+     */
+    public int deleteDictTypeById(Long dictId);
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDictType(SysDictType dictType);
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDictType(SysDictType dictType);
+
+    /**
+     * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    public String checkDictTypeUnique(SysDictType dictType);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysMenuService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysMenuService.java
new file mode 100644
index 0000000..8460554
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysMenuService.java
@@ -0,0 +1,127 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import java.util.Set;
+import com.ruoyi.framework.web.domain.TreeSelect;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.domain.vo.RouterVo;
+
+/**
+ * 鑿滃崟 涓氬姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysMenuService
+{
+    /**
+     * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 鑿滃崟鍒楄〃
+     */
+    public List<SysMenu> selectMenuList(SysMenu menu);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    public Set<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    public List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    public List<Integer> selectMenuListByRoleId(Long roleId);
+
+    /**
+     * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 璺敱鍒楄〃
+     */
+    public List<RouterVo> buildMenus(List<SysMenu> menus);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佹爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 鏍戠粨鏋勫垪琛�
+     */
+    public List<SysMenu> buildMenuTree(List<SysMenu> menus);
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus);
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    public SysMenu selectMenuById(Long menuId);
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    public boolean hasChildByMenuId(Long menuId);
+
+    /**
+     * 鏌ヨ鑿滃崟鏄惁瀛樺湪瑙掕壊
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    public boolean checkMenuExistRole(Long menuId);
+
+    /**
+     * 鏂板淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertMenu(SysMenu menu);
+
+    /**
+     * 淇敼淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateMenu(SysMenu menu);
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    public int deleteMenuById(Long menuId);
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkMenuNameUnique(SysMenu menu);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
new file mode 100644
index 0000000..77c6722
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysNoticeService.java
@@ -0,0 +1,52 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysNotice;
+
+/**
+ * 鍏憡 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysNoticeService
+{
+    /**
+     * 鏌ヨ鍏憡淇℃伅
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 鍏憡淇℃伅
+     */
+    public SysNotice selectNoticeById(Long noticeId);
+
+    /**
+     * 鏌ヨ鍏憡鍒楄〃
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 鍏憡闆嗗悎
+     */
+    public List<SysNotice> selectNoticeList(SysNotice notice);
+
+    /**
+     * 鏂板鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertNotice(SysNotice notice);
+
+    /**
+     * 淇敼鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateNotice(SysNotice notice);
+
+    /**
+     * 鍒犻櫎鍏憡淇℃伅
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 缁撴灉
+     */
+    public int deleteNoticeById(Long noticeId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java
new file mode 100644
index 0000000..f5770f6
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysPostService.java
@@ -0,0 +1,83 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysPost;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysPostService
+{
+    /**
+     * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 宀椾綅鍒楄〃
+     */
+    public List<SysPost> selectPostList(SysPost post);
+
+    /**
+     * 鏌ヨ鎵�鏈夊矖浣�
+     * 
+     * @return 宀椾綅鍒楄〃
+     */
+    public List<SysPost> selectPostAll();
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    public SysPost selectPostById(Long postId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑宀椾綅ID鍒楄〃
+     */
+    public List<Integer> selectPostListByUserId(Long userId);
+
+    /**
+     * 鏍¢獙宀椾綅鍚嶇О
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkPostNameUnique(SysPost post);
+
+    /**
+     * 鏍¢獙宀椾綅缂栫爜
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkPostCodeUnique(SysPost post);
+
+    /**
+     * 鍒犻櫎宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    public int deletePostById(Long postId);
+
+    /**
+     * 鏂板淇濆瓨宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertPost(SysPost post);
+
+    /**
+     * 淇敼淇濆瓨宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int updatePost(SysPost post);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java
new file mode 100644
index 0000000..1774f13
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysRoleService.java
@@ -0,0 +1,115 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import java.util.Set;
+import com.ruoyi.project.system.domain.SysRole;
+
+/**
+ * 瑙掕壊涓氬姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysRoleService
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    public List<SysRole> selectRoleList(SysRole role);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ瑙掕壊
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    public Set<String> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 鏌ヨ鎵�鏈夎鑹�
+     * 
+     * @return 瑙掕壊鍒楄〃
+     */
+    public List<SysRole> selectRoleAll();
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑瑙掕壊ID鍒楄〃
+     */
+    public List<Integer> selectRoleListByUserId(Long userId);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    public SysRole selectRoleById(Long roleId);
+
+    /**
+     * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkRoleNameUnique(SysRole role);
+
+    /**
+     * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkRoleKeyUnique(SysRole role);
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+     * 
+     * @param role 瑙掕壊淇℃伅
+     */
+    public void checkRoleAllowed(SysRole role);
+
+    /**
+     * 鏂板淇濆瓨瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertRole(SysRole role);
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateRole(SysRole role);
+
+    /**
+     * 淇敼瑙掕壊鐘舵��
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateRoleStatus(SysRole role);
+
+    /**
+     * 淇敼鏁版嵁鏉冮檺淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int authDataScope(SysRole role);
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int deleteRoleById(Long roleId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
new file mode 100644
index 0000000..2136cc9
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/ISysUserService.java
@@ -0,0 +1,149 @@
+package com.ruoyi.project.system.service;
+
+import java.util.List;
+import com.ruoyi.project.system.domain.SysUser;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞�
+ * 
+ * @author ruoyi
+ */
+public interface ISysUserService
+{
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    public List<SysUser> selectUserList(SysUser user);
+
+    /**
+     * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    public SysUser selectUserByUserName(String userName);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    public SysUser selectUserById(Long userId);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 缁撴灉
+     */
+    public String selectUserRoleGroup(String userName);
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 缁撴灉
+     */
+    public String selectUserPostGroup(String userName);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     * 
+     * @param userName 鐢ㄦ埛鍚嶇О
+     * @return 缁撴灉
+     */
+    public String checkUserNameUnique(String userName);
+
+    /**
+     * 鏍¢獙鎵嬫満鍙风爜鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkPhoneUnique(SysUser user);
+
+    /**
+     * 鏍¢獙email鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public String checkEmailUnique(SysUser user);
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     */
+    public void checkUserAllowed(SysUser user);
+
+    /**
+     * 鏂板鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertUser(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateUser(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛鐘舵��
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateUserStatus(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateUserProfile(SysUser user);
+
+    /**
+     * 淇敼鐢ㄦ埛澶村儚
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @param avatar 澶村儚鍦板潃
+     * @return 缁撴灉
+     */
+    public boolean updateUserAvatar(String userName, String avatar);
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    public int resetPwd(SysUser user);
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @return 缁撴灉
+     */
+    public int resetUserPwd(String userName, String password);
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public int deleteUserById(Long userId);
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..de62e8d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,117 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.project.system.domain.SysConfig;
+import com.ruoyi.project.system.mapper.SysConfigMapper;
+import com.ruoyi.project.system.service.ISysConfigService;
+
+/**
+ * 鍙傛暟閰嶇疆 鏈嶅姟灞傚疄鐜�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysConfigServiceImpl implements ISysConfigService
+{
+    @Autowired
+    private SysConfigMapper configMapper;
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configId 鍙傛暟閰嶇疆ID
+     * @return 鍙傛暟閰嶇疆淇℃伅
+     */
+    @Override
+    public SysConfig selectConfigById(Long configId)
+    {
+        SysConfig config = new SysConfig();
+        config.setConfigId(configId);
+        return configMapper.selectConfig(config);
+    }
+
+    /**
+     * 鏍规嵁閿悕鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configKey 鍙傛暟key
+     * @return 鍙傛暟閿��
+     */
+    @Override
+    public Object selectConfigByKey(String configKey)
+    {
+        SysConfig config = new SysConfig();
+        config.setConfigKey(configKey);
+        SysConfig retConfig = configMapper.selectConfig(config);
+        return StringUtils.isNotNull(retConfig) ? retConfig.getConfigValue() : "";
+    }
+
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆鍒楄〃
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 鍙傛暟閰嶇疆闆嗗悎
+     */
+    @Override
+    public List<SysConfig> selectConfigList(SysConfig config)
+    {
+        return configMapper.selectConfigList(config);
+    }
+
+    /**
+     * 鏂板鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertConfig(SysConfig config)
+    {
+        return configMapper.insertConfig(config);
+    }
+
+    /**
+     * 淇敼鍙傛暟閰嶇疆
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateConfig(SysConfig config)
+    {
+        return configMapper.updateConfig(config);
+    }
+
+    /**
+     * 鍒犻櫎鍙傛暟閰嶇疆淇℃伅
+     * 
+     * @param configId 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteConfigById(Long configId)
+    {
+        return configMapper.deleteConfigById(configId);
+    }
+
+    /**
+     * 鏍¢獙鍙傛暟閿悕鏄惁鍞竴
+     * 
+     * @param config 鍙傛暟閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkConfigKeyUnique(SysConfig config)
+    {
+        Long configId = StringUtils.isNull(config.getConfigId()) ? -1L : config.getConfigId();
+        SysConfig info = configMapper.checkConfigKeyUnique(config.getConfigKey());
+        if (StringUtils.isNotNull(info) && info.getConfigId().longValue() != configId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..f4e4dec
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDeptServiceImpl.java
@@ -0,0 +1,289 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.framework.web.domain.TreeSelect;
+import com.ruoyi.project.system.domain.SysDept;
+import com.ruoyi.project.system.mapper.SysDeptMapper;
+import com.ruoyi.project.system.service.ISysDeptService;
+
+/**
+ * 閮ㄩ棬绠$悊 鏈嶅姟瀹炵幇
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysDeptServiceImpl implements ISysDeptService
+{
+    @Autowired
+    private SysDeptMapper deptMapper;
+
+    /**
+     * 鏌ヨ閮ㄩ棬绠$悊鏁版嵁
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 閮ㄩ棬淇℃伅闆嗗悎
+     */
+    @Override
+    @DataScope(deptAlias = "d")
+    public List<SysDept> selectDeptList(SysDept dept)
+    {
+        return deptMapper.selectDeptList(dept);
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佹爲缁撴瀯
+     * 
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<SysDept> buildDeptTree(List<SysDept> depts)
+    {
+        List<SysDept> returnList = new ArrayList<SysDept>();
+        for (Iterator<SysDept> iterator = depts.iterator(); iterator.hasNext();)
+        {
+            SysDept t = (SysDept) iterator.next();
+            // 鏍规嵁浼犲叆鐨勬煇涓埗鑺傜偣ID,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (t.getParentId() == 0)
+            {
+                recursionFn(depts, t);
+                returnList.add(t);
+            }
+        }
+        if (returnList.isEmpty())
+        {
+            returnList = depts;
+        }
+        return returnList;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     * 
+     * @param depts 閮ㄩ棬鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<TreeSelect> buildDeptTreeSelect(List<SysDept> depts)
+    {
+        List<SysDept> deptTrees = buildDeptTree(depts);
+        return deptTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑閮ㄩ棬鍒楄〃
+     */
+    @Override
+    public List<Integer> selectDeptListByRoleId(Long roleId)
+    {
+        return deptMapper.selectDeptListByRoleId(roleId);
+    }
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID鏌ヨ淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 閮ㄩ棬淇℃伅
+     */
+    @Override
+    public SysDept selectDeptById(Long deptId)
+    {
+        return deptMapper.selectDeptById(deptId);
+    }
+
+    /**
+     * 鏄惁瀛樺湪瀛愯妭鐐�
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByDeptId(Long deptId)
+    {
+        int result = deptMapper.hasChildByDeptId(deptId);
+        return result > 0 ? true : false;
+    }
+
+    /**
+     * 鏌ヨ閮ㄩ棬鏄惁瀛樺湪鐢ㄦ埛
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉 true 瀛樺湪 false 涓嶅瓨鍦�
+     */
+    @Override
+    public boolean checkDeptExistUser(Long deptId)
+    {
+        int result = deptMapper.checkDeptExistUser(deptId);
+        return result > 0 ? true : false;
+    }
+
+    /**
+     * 鏍¢獙閮ㄩ棬鍚嶇О鏄惁鍞竴
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkDeptNameUnique(SysDept dept)
+    {
+        Long deptId = StringUtils.isNull(dept.getDeptId()) ? -1L : dept.getDeptId();
+        SysDept info = deptMapper.checkDeptNameUnique(dept.getDeptName(), dept.getParentId());
+        if (StringUtils.isNotNull(info) && info.getDeptId().longValue() != deptId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏂板淇濆瓨閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDept(SysDept dept)
+    {
+        SysDept info = deptMapper.selectDeptById(dept.getParentId());
+        // 濡傛灉鐖惰妭鐐逛笉涓烘甯哥姸鎬�,鍒欎笉鍏佽鏂板瀛愯妭鐐�
+        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
+        {
+            throw new CustomException("閮ㄩ棬鍋滅敤锛屼笉鍏佽鏂板");
+        }
+        dept.setAncestors(info.getAncestors() + "," + dept.getParentId());
+        return deptMapper.insertDept(dept);
+    }
+
+    /**
+     * 淇敼淇濆瓨閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDept(SysDept dept)
+    {
+        SysDept newParentDept = deptMapper.selectDeptById(dept.getParentId());
+        SysDept oldDept = deptMapper.selectDeptById(dept.getDeptId());
+        if (StringUtils.isNotNull(newParentDept) && StringUtils.isNotNull(oldDept))
+        {
+            String newAncestors = newParentDept.getAncestors() + "," + newParentDept.getDeptId();
+            String oldAncestors = oldDept.getAncestors();
+            dept.setAncestors(newAncestors);
+            updateDeptChildren(dept.getDeptId(), newAncestors, oldAncestors);
+        }
+        int result = deptMapper.updateDept(dept);
+        if (UserConstants.DEPT_NORMAL.equals(dept.getStatus()))
+        {
+            // 濡傛灉璇ラ儴闂ㄦ槸鍚敤鐘舵�侊紝鍒欏惎鐢ㄨ閮ㄩ棬鐨勬墍鏈変笂绾ч儴闂�
+            updateParentDeptStatus(dept);
+        }
+        return result;
+    }
+
+    /**
+     * 淇敼璇ラ儴闂ㄧ殑鐖剁骇閮ㄩ棬鐘舵��
+     * 
+     * @param dept 褰撳墠閮ㄩ棬
+     */
+    private void updateParentDeptStatus(SysDept dept)
+    {
+        String updateBy = dept.getUpdateBy();
+        dept = deptMapper.selectDeptById(dept.getDeptId());
+        dept.setUpdateBy(updateBy);
+        deptMapper.updateDeptStatus(dept);
+    }
+
+    /**
+     * 淇敼瀛愬厓绱犲叧绯�
+     * 
+     * @param deptId 琚慨鏀圭殑閮ㄩ棬ID
+     * @param newAncestors 鏂扮殑鐖禝D闆嗗悎
+     * @param oldAncestors 鏃х殑鐖禝D闆嗗悎
+     */
+    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
+    {
+        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
+        for (SysDept child : children)
+        {
+            child.setAncestors(child.getAncestors().replace(oldAncestors, newAncestors));
+        }
+        if (children.size() > 0)
+        {
+            deptMapper.updateDeptChildren(children);
+        }
+    }
+
+    /**
+     * 鍒犻櫎閮ㄩ棬绠$悊淇℃伅
+     * 
+     * @param deptId 閮ㄩ棬ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDeptById(Long deptId)
+    {
+        return deptMapper.deleteDeptById(deptId);
+    }
+
+    /**
+     * 閫掑綊鍒楄〃
+     */
+    private void recursionFn(List<SysDept> list, SysDept t)
+    {
+        // 寰楀埌瀛愯妭鐐瑰垪琛�
+        List<SysDept> childList = getChildList(list, t);
+        t.setChildren(childList);
+        for (SysDept tChild : childList)
+        {
+            if (hasChild(list, tChild))
+            {
+                // 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+                Iterator<SysDept> it = childList.iterator();
+                while (it.hasNext())
+                {
+                    SysDept n = (SysDept) it.next();
+                    recursionFn(list, n);
+                }
+            }
+        }
+    }
+
+    /**
+     * 寰楀埌瀛愯妭鐐瑰垪琛�
+     */
+    private List<SysDept> getChildList(List<SysDept> list, SysDept t)
+    {
+        List<SysDept> tlist = new ArrayList<SysDept>();
+        Iterator<SysDept> it = list.iterator();
+        while (it.hasNext())
+        {
+            SysDept n = (SysDept) it.next();
+            if (n.getParentId().longValue() == t.getDeptId().longValue())
+            {
+                tlist.add(n);
+            }
+        }
+        return tlist;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+     */
+    private boolean hasChild(List<SysDept> list, SysDept t)
+    {
+        return getChildList(list, t).size() > 0 ? true : false;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..d940743
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictDataServiceImpl.java
@@ -0,0 +1,105 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.project.system.domain.SysDictData;
+import com.ruoyi.project.system.mapper.SysDictDataMapper;
+import com.ruoyi.project.system.service.ISysDictDataService;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysDictDataServiceImpl implements ISysDictDataService
+{
+    @Autowired
+    private SysDictDataMapper dictDataMapper;
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictData> selectDictDataList(SysDictData dictData)
+    {
+        return dictDataMapper.selectDictDataList(dictData);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀鏁版嵁闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictData> selectDictDataByType(String dictType)
+    {
+        return dictDataMapper.selectDictDataByType(dictType);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鍜屽瓧鍏搁敭鍊兼煡璇㈠瓧鍏告暟鎹俊鎭�
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param dictValue 瀛楀吀閿��
+     * @return 瀛楀吀鏍囩
+     */
+    @Override
+    public String selectDictLabel(String dictType, String dictValue)
+    {
+        return dictDataMapper.selectDictLabel(dictType, dictValue);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀鏁版嵁ID鏌ヨ淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 瀛楀吀鏁版嵁
+     */
+    @Override
+    public SysDictData selectDictDataById(Long dictCode)
+    {
+        return dictDataMapper.selectDictDataById(dictCode);
+    }
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictCode 瀛楀吀鏁版嵁ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDictDataById(Long dictCode)
+    {
+        return dictDataMapper.deleteDictDataById(dictCode);
+    }
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDictData(SysDictData dictData)
+    {
+        return dictDataMapper.insertDictData(dictData);
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀鏁版嵁淇℃伅
+     * 
+     * @param dictData 瀛楀吀鏁版嵁淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDictData(SysDictData dictData)
+    {
+        return dictDataMapper.updateDictData(dictData);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..de784de
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysDictTypeServiceImpl.java
@@ -0,0 +1,130 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.project.system.domain.SysDictType;
+import com.ruoyi.project.system.mapper.SysDictDataMapper;
+import com.ruoyi.project.system.mapper.SysDictTypeMapper;
+import com.ruoyi.project.system.service.ISysDictTypeService;
+
+/**
+ * 瀛楀吀 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysDictTypeServiceImpl implements ISysDictTypeService
+{
+    @Autowired
+    private SysDictTypeMapper dictTypeMapper;
+
+    @Autowired
+    private SysDictDataMapper dictDataMapper;
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瀛楀吀绫诲瀷
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictType> selectDictTypeList(SysDictType dictType)
+    {
+        return dictTypeMapper.selectDictTypeList(dictType);
+    }
+
+    /**
+     * 鏍规嵁鎵�鏈夊瓧鍏哥被鍨�
+     * 
+     * @return 瀛楀吀绫诲瀷闆嗗悎淇℃伅
+     */
+    @Override
+    public List<SysDictType> selectDictTypeAll()
+    {
+        return dictTypeMapper.selectDictTypeAll();
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷ID鏌ヨ淇℃伅
+     * 
+     * @param dictId 瀛楀吀绫诲瀷ID
+     * @return 瀛楀吀绫诲瀷
+     */
+    @Override
+    public SysDictType selectDictTypeById(Long dictId)
+    {
+        return dictTypeMapper.selectDictTypeById(dictId);
+    }
+
+    /**
+     * 鏍规嵁瀛楀吀绫诲瀷鏌ヨ淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷
+     * @return 瀛楀吀绫诲瀷
+     */
+    public SysDictType selectDictTypeByType(String dictType)
+    {
+        return dictTypeMapper.selectDictTypeByType(dictType);
+    }
+
+    /**
+     * 閫氳繃瀛楀吀ID鍒犻櫎瀛楀吀淇℃伅
+     * 
+     * @param dictId 瀛楀吀ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDictTypeById(Long dictId)
+    {
+        return dictTypeMapper.deleteDictTypeById(dictId);
+    }
+
+    /**
+     * 鏂板淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDictType(SysDictType dictType)
+    {
+        return dictTypeMapper.insertDictType(dictType);
+    }
+
+    /**
+     * 淇敼淇濆瓨瀛楀吀绫诲瀷淇℃伅
+     * 
+     * @param dictType 瀛楀吀绫诲瀷淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int updateDictType(SysDictType dictType)
+    {
+        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dictType.getDictId());
+        dictDataMapper.updateDictDataType(oldDict.getDictType(), dictType.getDictType());
+        return dictTypeMapper.updateDictType(dictType);
+    }
+
+    /**
+     * 鏍¢獙瀛楀吀绫诲瀷绉版槸鍚﹀敮涓�
+     * 
+     * @param dict 瀛楀吀绫诲瀷
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkDictTypeUnique(SysDictType dict)
+    {
+        Long dictId = StringUtils.isNull(dict.getDictId()) ? -1L : dict.getDictId();
+        SysDictType dictType = dictTypeMapper.checkDictTypeUnique(dict.getDictType());
+        if (StringUtils.isNotNull(dictType) && dictType.getDictId().longValue() != dictId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..735faab
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysMenuServiceImpl.java
@@ -0,0 +1,359 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.domain.TreeSelect;
+import com.ruoyi.project.system.domain.SysMenu;
+import com.ruoyi.project.system.domain.vo.MetaVo;
+import com.ruoyi.project.system.domain.vo.RouterVo;
+import com.ruoyi.project.system.mapper.SysMenuMapper;
+import com.ruoyi.project.system.mapper.SysRoleMenuMapper;
+import com.ruoyi.project.system.service.ISysMenuService;
+
+/**
+ * 鑿滃崟 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysMenuServiceImpl implements ISysMenuService
+{
+    public static final String PREMISSION_STRING = "perms[\"{0}\"]";
+
+    @Autowired
+    private SysMenuMapper menuMapper;
+
+    @Autowired
+    private SysRoleMenuMapper roleMenuMapper;
+
+    /**
+     * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuList(SysMenu menu)
+    {
+        List<SysMenu> menuList = menuMapper.selectMenuList(menu);
+        return menuList;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectMenuPermsByUserId(Long userId)
+    {
+        List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
+        Set<String> permsSet = new HashSet<>();
+        for (String perm : perms)
+        {
+            if (StringUtils.isNotEmpty(perm))
+            {
+                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鍚嶇О鏌ヨ鑿滃崟
+     * 
+     * @param username 鐢ㄦ埛鍚嶇О
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuTreeByUserId(Long userId)
+    {
+        List<SysMenu> menus = null;
+        if (SecurityUtils.isAdmin(userId))
+        {
+            menus = menuMapper.selectMenuTreeAll();
+        }
+        else
+        {
+            menus = menuMapper.selectMenuTreeByUserId(userId);
+        }
+        return getChildPerms(menus, 0);
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    public List<Integer> selectMenuListByRoleId(Long roleId)
+    {
+        return menuMapper.selectMenuListByRoleId(roleId);
+    }
+
+    /**
+     * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 璺敱鍒楄〃
+     */
+    @Override
+    public List<RouterVo> buildMenus(List<SysMenu> menus)
+    {
+        List<RouterVo> routers = new LinkedList<RouterVo>();
+        for (SysMenu menu : menus)
+        {
+            RouterVo router = new RouterVo();
+            router.setName(menu.getMenuName());
+            router.setPath(getRouterPath(menu));
+            router.setComponent(StringUtils.isEmpty(menu.getComponent()) ? "Layout" : menu.getComponent());
+            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+            router.setName(menu.getMenuName());
+            List<SysMenu> cMenus = menu.getChildren();
+            if (!cMenus.isEmpty() && cMenus.size() > 0 && "M".equals(menu.getMenuType()))
+            {
+                router.setAlwaysShow(true);
+                router.setRedirect("noRedirect");
+                router.setChildren(buildMenus(cMenus));
+            }
+            routers.add(router);
+        }
+        return routers;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佹爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<SysMenu> buildMenuTree(List<SysMenu> menus)
+    {
+        List<SysMenu> returnList = new ArrayList<SysMenu>();
+        for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();)
+        {
+            SysMenu t = (SysMenu) iterator.next();
+            // 鏍规嵁浼犲叆鐨勬煇涓埗鑺傜偣ID,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (t.getParentId() == 0)
+            {
+                recursionFn(menus, t);
+                returnList.add(t);
+            }
+        }
+        if (returnList.isEmpty())
+        {
+            returnList = menus;
+        }
+        return returnList;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus)
+    {
+        List<SysMenu> menuTrees = buildMenuTree(menus);
+        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    @Override
+    public SysMenu selectMenuById(Long menuId)
+    {
+        return menuMapper.selectMenuById(menuId);
+    }
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByMenuId(Long menuId)
+    {
+        int result = menuMapper.hasChildByMenuId(menuId);
+        return result > 0 ? true : false;
+    }
+
+    /**
+     * 鏌ヨ鑿滃崟浣跨敤鏁伴噺
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkMenuExistRole(Long menuId)
+    {
+        int result = roleMenuMapper.checkMenuExistRole(menuId);
+        return result > 0 ? true : false;
+    }
+
+    /**
+     * 鏂板淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertMenu(SysMenu menu)
+    {
+        return menuMapper.insertMenu(menu);
+    }
+
+    /**
+     * 淇敼淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateMenu(SysMenu menu)
+    {
+        return menuMapper.updateMenu(menu);
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteMenuById(Long menuId)
+    {
+        return menuMapper.deleteMenuById(menuId);
+    }
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkMenuNameUnique(SysMenu menu)
+    {
+        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
+        SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());
+        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鑾峰彇璺敱鍦板潃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 璺敱鍦板潃
+     */
+    public String getRouterPath(SysMenu menu)
+    {
+        String routerPath = menu.getPath();
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰�
+        if (0 == menu.getParentId() && "1".equals(menu.getIsFrame()))
+        {
+            routerPath = "/" + menu.getPath();
+        }
+        return routerPath;
+    }
+
+    /**
+     * 鏍规嵁鐖惰妭鐐圭殑ID鑾峰彇鎵�鏈夊瓙鑺傜偣
+     * 
+     * @param list 鍒嗙被琛�
+     * @param parentId 浼犲叆鐨勭埗鑺傜偣ID
+     * @return String
+     */
+    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)
+    {
+        List<SysMenu> returnList = new ArrayList<SysMenu>();
+        for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
+        {
+            SysMenu t = (SysMenu) iterator.next();
+            // 涓�銆佹牴鎹紶鍏ョ殑鏌愪釜鐖惰妭鐐笽D,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (t.getParentId() == parentId)
+            {
+                recursionFn(list, t);
+                returnList.add(t);
+            }
+        }
+        return returnList;
+    }
+
+    /**
+     * 閫掑綊鍒楄〃
+     * 
+     * @param list
+     * @param t
+     */
+    private void recursionFn(List<SysMenu> list, SysMenu t)
+    {
+        // 寰楀埌瀛愯妭鐐瑰垪琛�
+        List<SysMenu> childList = getChildList(list, t);
+        t.setChildren(childList);
+        for (SysMenu tChild : childList)
+        {
+            if (hasChild(list, tChild))
+            {
+                // 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+                Iterator<SysMenu> it = childList.iterator();
+                while (it.hasNext())
+                {
+                    SysMenu n = (SysMenu) it.next();
+                    recursionFn(list, n);
+                }
+            }
+        }
+    }
+
+    /**
+     * 寰楀埌瀛愯妭鐐瑰垪琛�
+     */
+    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t)
+    {
+        List<SysMenu> tlist = new ArrayList<SysMenu>();
+        Iterator<SysMenu> it = list.iterator();
+        while (it.hasNext())
+        {
+            SysMenu n = (SysMenu) it.next();
+            if (n.getParentId().longValue() == t.getMenuId().longValue())
+            {
+                tlist.add(n);
+            }
+        }
+        return tlist;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+     */
+    private boolean hasChild(List<SysMenu> list, SysMenu t)
+    {
+        return getChildList(list, t).size() > 0 ? true : false;
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
new file mode 100644
index 0000000..800f4d1
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysNoticeServiceImpl.java
@@ -0,0 +1,80 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.project.system.domain.SysNotice;
+import com.ruoyi.project.system.mapper.SysNoticeMapper;
+import com.ruoyi.project.system.service.ISysNoticeService;
+
+/**
+ * 鍏憡 鏈嶅姟灞傚疄鐜�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysNoticeServiceImpl implements ISysNoticeService
+{
+    @Autowired
+    private SysNoticeMapper noticeMapper;
+
+    /**
+     * 鏌ヨ鍏憡淇℃伅
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 鍏憡淇℃伅
+     */
+    @Override
+    public SysNotice selectNoticeById(Long noticeId)
+    {
+        return noticeMapper.selectNoticeById(noticeId);
+    }
+
+    /**
+     * 鏌ヨ鍏憡鍒楄〃
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 鍏憡闆嗗悎
+     */
+    @Override
+    public List<SysNotice> selectNoticeList(SysNotice notice)
+    {
+        return noticeMapper.selectNoticeList(notice);
+    }
+
+    /**
+     * 鏂板鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertNotice(SysNotice notice)
+    {
+        return noticeMapper.insertNotice(notice);
+    }
+
+    /**
+     * 淇敼鍏憡
+     * 
+     * @param notice 鍏憡淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateNotice(SysNotice notice)
+    {
+        return noticeMapper.updateNotice(notice);
+    }
+
+    /**
+     * 鍒犻櫎鍏憡瀵硅薄
+     * 
+     * @param noticeId 鍏憡ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteNoticeById(Long noticeId)
+    {
+        return noticeMapper.deleteNoticeById(noticeId);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java
new file mode 100644
index 0000000..682d147
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysPostServiceImpl.java
@@ -0,0 +1,141 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.project.system.domain.SysPost;
+import com.ruoyi.project.system.mapper.SysPostMapper;
+import com.ruoyi.project.system.service.ISysPostService;
+
+/**
+ * 宀椾綅淇℃伅 鏈嶅姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysPostServiceImpl implements ISysPostService
+{
+    @Autowired
+    private SysPostMapper postMapper;
+
+    /**
+     * 鏌ヨ宀椾綅淇℃伅闆嗗悎
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 宀椾綅淇℃伅闆嗗悎
+     */
+    @Override
+    public List<SysPost> selectPostList(SysPost post)
+    {
+        return postMapper.selectPostList(post);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夊矖浣�
+     * 
+     * @return 宀椾綅鍒楄〃
+     */
+    @Override
+    public List<SysPost> selectPostAll()
+    {
+        return postMapper.selectPostAll();
+    }
+
+    /**
+     * 閫氳繃宀椾綅ID鏌ヨ宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    @Override
+    public SysPost selectPostById(Long postId)
+    {
+        return postMapper.selectPostById(postId);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇宀椾綅閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑宀椾綅ID鍒楄〃
+     */
+    public List<Integer> selectPostListByUserId(Long userId)
+    {
+        return postMapper.selectPostListByUserId(userId);
+    }
+
+
+    /**
+     * 鏍¢獙宀椾綅鍚嶇О鏄惁鍞竴
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkPostNameUnique(SysPost post)
+    {
+        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
+        SysPost info = postMapper.checkPostNameUnique(post.getPostName());
+        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙宀椾綅缂栫爜鏄惁鍞竴
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkPostCodeUnique(SysPost post)
+    {
+        Long postId = StringUtils.isNull(post.getPostId()) ? -1L : post.getPostId();
+        SysPost info = postMapper.checkPostCodeUnique(post.getPostCode());
+        if (StringUtils.isNotNull(info) && info.getPostId().longValue() != postId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鍒犻櫎宀椾綅淇℃伅
+     * 
+     * @param postId 宀椾綅ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deletePostById(Long postId)
+    {
+        return postMapper.deletePostById(postId);
+    }
+
+    /**
+     * 鏂板淇濆瓨宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertPost(SysPost post)
+    {
+        return postMapper.insertPost(post);
+    }
+
+    /**
+     * 淇敼淇濆瓨宀椾綅淇℃伅
+     * 
+     * @param post 宀椾綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updatePost(SysPost post)
+    {
+        return postMapper.updatePost(post);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..82c458d
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysRoleServiceImpl.java
@@ -0,0 +1,275 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.domain.SysRoleDept;
+import com.ruoyi.project.system.domain.SysRoleMenu;
+import com.ruoyi.project.system.mapper.SysRoleDeptMapper;
+import com.ruoyi.project.system.mapper.SysRoleMapper;
+import com.ruoyi.project.system.mapper.SysRoleMenuMapper;
+import com.ruoyi.project.system.service.ISysRoleService;
+
+/**
+ * 瑙掕壊 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysRoleServiceImpl implements ISysRoleService
+{
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    @Autowired
+    private SysRoleMenuMapper roleMenuMapper;
+
+    @Autowired
+    private SysRoleDeptMapper roleDeptMapper;
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ瑙掕壊鏁版嵁
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 瑙掕壊鏁版嵁闆嗗悎淇℃伅
+     */
+    @Override
+    @DataScope(deptAlias = "d")
+    public List<SysRole> selectRoleList(SysRole role)
+    {
+        return roleMapper.selectRoleList(role);
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectRolePermissionByUserId(Long userId)
+    {
+        List<SysRole> perms = roleMapper.selectRolePermissionByUserId(userId);
+        Set<String> permsSet = new HashSet<>();
+        for (SysRole perm : perms)
+        {
+            if (StringUtils.isNotNull(perm))
+            {
+                permsSet.addAll(Arrays.asList(perm.getRoleKey().trim().split(",")));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夎鑹�
+     * 
+     * @return 瑙掕壊鍒楄〃
+     */
+    public List<SysRole> selectRoleAll()
+    {
+        return roleMapper.selectRoleAll();
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鑾峰彇瑙掕壊閫夋嫨妗嗗垪琛�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 閫変腑瑙掕壊ID鍒楄〃
+     */
+    public List<Integer> selectRoleListByUserId(Long userId)
+    {
+        return roleMapper.selectRoleListByUserId(userId);
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 瑙掕壊瀵硅薄淇℃伅
+     */
+    public SysRole selectRoleById(Long roleId)
+    {
+        return roleMapper.selectRoleById(roleId);
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鍚嶇О鏄惁鍞竴
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkRoleNameUnique(SysRole role)
+    {
+        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
+        SysRole info = roleMapper.checkRoleNameUnique(role.getRoleName());
+        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鏉冮檺鏄惁鍞竴
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkRoleKeyUnique(SysRole role)
+    {
+        Long roleId = StringUtils.isNull(role.getRoleId()) ? -1L : role.getRoleId();
+        SysRole info = roleMapper.checkRoleKeyUnique(role.getRoleKey());
+        if (StringUtils.isNotNull(info) && info.getRoleId().longValue() != roleId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙瑙掕壊鏄惁鍏佽鎿嶄綔
+     * 
+     * @param role 瑙掕壊淇℃伅
+     */
+    public void checkRoleAllowed(SysRole role)
+    {
+        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())
+        {
+            throw new CustomException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳瑙掕壊");
+        }
+    }
+
+    /**
+     * 鏂板淇濆瓨瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int insertRole(SysRole role)
+    {
+        // 鏂板瑙掕壊淇℃伅
+        roleMapper.insertRole(role);
+        return insertRoleMenu(role);
+    }
+
+    /**
+     * 淇敼淇濆瓨瑙掕壊淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int updateRole(SysRole role)
+    {
+        // 淇敼瑙掕壊淇℃伅
+        roleMapper.updateRole(role);
+        // 鍒犻櫎瑙掕壊涓庤彍鍗曞叧鑱�
+        roleMenuMapper.deleteRoleMenuByRoleId(role.getRoleId());
+        return insertRoleMenu(role);
+    }
+
+    /**
+     * 淇敼瑙掕壊鐘舵��
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateRoleStatus(SysRole role)
+    {
+        return roleMapper.updateRole(role);
+    }
+
+    /**
+     * 淇敼鏁版嵁鏉冮檺淇℃伅
+     * 
+     * @param role 瑙掕壊淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int authDataScope(SysRole role)
+    {
+        // 淇敼瑙掕壊淇℃伅
+        roleMapper.updateRole(role);
+        // 鍒犻櫎瑙掕壊涓庨儴闂ㄥ叧鑱�
+        roleDeptMapper.deleteRoleDeptByRoleId(role.getRoleId());
+        // 鏂板瑙掕壊鍜岄儴闂ㄤ俊鎭紙鏁版嵁鏉冮檺锛�
+        return insertRoleDept(role);
+    }
+
+    /**
+     * 鏂板瑙掕壊鑿滃崟淇℃伅
+     * 
+     * @param role 瑙掕壊瀵硅薄
+     */
+    public int insertRoleMenu(SysRole 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.batchRoleMenu(list);
+        }
+        return rows;
+    }
+
+    /**
+     * 鏂板瑙掕壊閮ㄩ棬淇℃伅(鏁版嵁鏉冮檺)
+     *
+     * @param role 瑙掕壊瀵硅薄
+     */
+    public int insertRoleDept(SysRole 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.batchRoleDept(list);
+        }
+        return rows;
+    }
+
+    /**
+     * 閫氳繃瑙掕壊ID鍒犻櫎瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteRoleById(Long roleId)
+    {
+        return roleMapper.deleteRoleById(roleId);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..0a62aca
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/system/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,363 @@
+package com.ruoyi.project.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.ruoyi.common.constant.UserConstants;
+import com.ruoyi.common.exception.CustomException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.aspectj.lang.annotation.DataScope;
+import com.ruoyi.project.system.domain.SysPost;
+import com.ruoyi.project.system.domain.SysRole;
+import com.ruoyi.project.system.domain.SysUser;
+import com.ruoyi.project.system.domain.SysUserPost;
+import com.ruoyi.project.system.domain.SysUserRole;
+import com.ruoyi.project.system.mapper.SysPostMapper;
+import com.ruoyi.project.system.mapper.SysRoleMapper;
+import com.ruoyi.project.system.mapper.SysUserMapper;
+import com.ruoyi.project.system.mapper.SysUserPostMapper;
+import com.ruoyi.project.system.mapper.SysUserRoleMapper;
+import com.ruoyi.project.system.service.ISysUserService;
+
+/**
+ * 鐢ㄦ埛 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysUserServiceImpl implements ISysUserService
+{
+    @Autowired
+    private SysUserMapper userMapper;
+
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    @Autowired
+    private SysPostMapper postMapper;
+
+    @Autowired
+    private SysUserRoleMapper userRoleMapper;
+
+    @Autowired
+    private SysUserPostMapper userPostMapper;
+
+    /**
+     * 鏍规嵁鏉′欢鍒嗛〉鏌ヨ鐢ㄦ埛鍒楄〃
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 鐢ㄦ埛淇℃伅闆嗗悎淇℃伅
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<SysUser> selectUserList(SysUser user)
+    {
+        return userMapper.selectUserList(user);
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛鍚嶆煡璇㈢敤鎴�
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @Override
+    public SysUser selectUserByUserName(String userName)
+    {
+        return userMapper.selectUserByUserName(userName);
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鏌ヨ鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鐢ㄦ埛瀵硅薄淇℃伅
+     */
+    @Override
+    public SysUser selectUserById(Long userId)
+    {
+        return userMapper.selectUserById(userId);
+    }
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炶鑹茬粍
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 缁撴灉
+     */
+    @Override
+    public String selectUserRoleGroup(String userName)
+    {
+        List<SysRole> list = roleMapper.selectRolesByUserName(userName);
+        StringBuffer idsStr = new StringBuffer();
+        for (SysRole role : list)
+        {
+            idsStr.append(role.getRoleName()).append(",");
+        }
+        if (StringUtils.isNotEmpty(idsStr.toString()))
+        {
+            return idsStr.substring(0, idsStr.length() - 1);
+        }
+        return idsStr.toString();
+    }
+
+    /**
+     * 鏌ヨ鐢ㄦ埛鎵�灞炲矖浣嶇粍
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @return 缁撴灉
+     */
+    @Override
+    public String selectUserPostGroup(String userName)
+    {
+        List<SysPost> list = postMapper.selectPostsByUserName(userName);
+        StringBuffer idsStr = new StringBuffer();
+        for (SysPost post : list)
+        {
+            idsStr.append(post.getPostName()).append(",");
+        }
+        if (StringUtils.isNotEmpty(idsStr.toString()))
+        {
+            return idsStr.substring(0, idsStr.length() - 1);
+        }
+        return idsStr.toString();
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     * 
+     * @param userName 鐢ㄦ埛鍚嶇О
+     * @return 缁撴灉
+     */
+    @Override
+    public String checkUserNameUnique(String userName)
+    {
+        int count = userMapper.checkUserNameUnique(userName);
+        if (count > 0)
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鍚嶇О鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return
+     */
+    @Override
+    public String checkPhoneUnique(SysUser user)
+    {
+        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
+        SysUser info = userMapper.checkPhoneUnique(user.getPhonenumber());
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙email鏄惁鍞竴
+     *
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return
+     */
+    @Override
+    public String checkEmailUnique(SysUser user)
+    {
+        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
+        SysUser info = userMapper.checkEmailUnique(user.getEmail());
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鏍¢獙鐢ㄦ埛鏄惁鍏佽鎿嶄綔
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     */
+    public void checkUserAllowed(SysUser user)
+    {
+        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
+        {
+            throw new CustomException("涓嶅厑璁告搷浣滆秴绾х鐞嗗憳鐢ㄦ埛");
+        }
+    }
+
+    /**
+     * 鏂板淇濆瓨鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int insertUser(SysUser user)
+    {
+        // 鏂板鐢ㄦ埛淇℃伅
+        int rows = userMapper.insertUser(user);
+        // 鏂板鐢ㄦ埛宀椾綅鍏宠仈
+        insertUserPost(user);
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        insertUserRole(user);
+        return rows;
+    }
+
+    /**
+     * 淇敼淇濆瓨鐢ㄦ埛淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    @Transactional
+    public int updateUser(SysUser user)
+    {
+        Long userId = user.getUserId();
+        // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+        userRoleMapper.deleteUserRoleByUserId(userId);
+        // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+        insertUserRole(user);
+        // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶅叧鑱�
+        userPostMapper.deleteUserPostByUserId(userId);
+        // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+        insertUserPost(user);
+        return userMapper.updateUser(user);
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛鐘舵��
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateUserStatus(SysUser user)
+    {
+        return userMapper.updateUser(user);
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛鍩烘湰淇℃伅
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateUserProfile(SysUser user)
+    {
+        return userMapper.updateUser(user);
+    }
+
+    /**
+     * 淇敼鐢ㄦ埛澶村儚
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @param avatar 澶村儚鍦板潃
+     * @return 缁撴灉
+     */
+    public boolean updateUserAvatar(String userName, String avatar)
+    {
+        return userMapper.updateUserAvatar(userName, avatar) > 0;
+    }
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     * 
+     * @param user 鐢ㄦ埛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int resetPwd(SysUser user)
+    {
+        return userMapper.updateUser(user);
+    }
+
+    /**
+     * 閲嶇疆鐢ㄦ埛瀵嗙爜
+     * 
+     * @param userName 鐢ㄦ埛鍚�
+     * @param password 瀵嗙爜
+     * @return 缁撴灉
+     */
+    @Override
+    public int resetUserPwd(String userName, String password)
+    {
+        return userMapper.resetUserPwd(userName, password);
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛瑙掕壊淇℃伅
+     * 
+     * @param user 鐢ㄦ埛瀵硅薄
+     */
+    public void insertUserRole(SysUser user)
+    {
+        Long[] roles = user.getRoleIds();
+        if (StringUtils.isNotNull(roles))
+        {
+            // 鏂板鐢ㄦ埛涓庤鑹茬鐞�
+            List<SysUserRole> list = new ArrayList<SysUserRole>();
+            for (Long roleId : roles)
+            {
+                SysUserRole ur = new SysUserRole();
+                ur.setUserId(user.getUserId());
+                ur.setRoleId(roleId);
+                list.add(ur);
+            }
+            if (list.size() > 0)
+            {
+                userRoleMapper.batchUserRole(list);
+            }
+        }
+    }
+
+    /**
+     * 鏂板鐢ㄦ埛宀椾綅淇℃伅
+     * 
+     * @param user 鐢ㄦ埛瀵硅薄
+     */
+    public void insertUserPost(SysUser user)
+    {
+        Long[] posts = user.getPostIds();
+        if (StringUtils.isNotNull(posts))
+        {
+            // 鏂板鐢ㄦ埛涓庡矖浣嶇鐞�
+            List<SysUserPost> list = new ArrayList<SysUserPost>();
+            for (Long postId : posts)
+            {
+                SysUserPost up = new SysUserPost();
+                up.setUserId(user.getUserId());
+                up.setPostId(postId);
+                list.add(up);
+            }
+            if (list.size() > 0)
+            {
+                userPostMapper.batchUserPost(list);
+            }
+        }
+    }
+
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteUserById(Long userId)
+    {
+        // 鍒犻櫎鐢ㄦ埛涓庤鑹插叧鑱�
+        userRoleMapper.deleteUserRoleByUserId(userId);
+        // 鍒犻櫎鐢ㄦ埛涓庡矖浣嶈〃
+        userPostMapper.deleteUserPostByUserId(userId);
+        return userMapper.deleteUserById(userId);
+    }
+}
diff --git a/ruoyi/src/main/java/com/ruoyi/project/tool/swagger/TestController.java b/ruoyi/src/main/java/com/ruoyi/project/tool/swagger/TestController.java
new file mode 100644
index 0000000..17f4c31
--- /dev/null
+++ b/ruoyi/src/main/java/com/ruoyi/project/tool/swagger/TestController.java
@@ -0,0 +1,175 @@
+package com.ruoyi.project.tool.swagger;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import org.springframework.web.bind.annotation.DeleteMapping;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.PutMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.controller.BaseController;
+import com.ruoyi.framework.web.domain.AjaxResult;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * swagger 鐢ㄦ埛娴嬭瘯鏂规硶
+ * 
+ * @author ruoyi
+ */
+@Api("鐢ㄦ埛淇℃伅绠$悊")
+@RestController
+@RequestMapping("/test/user")
+public class TestController extends BaseController
+{
+    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
+    {
+        users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
+        users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
+    }
+
+    @ApiOperation("鑾峰彇鐢ㄦ埛鍒楄〃")
+    @GetMapping("/list")
+    public AjaxResult userList()
+    {
+        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
+        return AjaxResult.success(userList);
+    }
+
+    @ApiOperation("鑾峰彇鐢ㄦ埛璇︾粏")
+    @ApiImplicitParam(name = "userId", value = "鐢ㄦ埛ID", required = true, dataType = "int", paramType = "path")
+    @GetMapping("/{userId}")
+    public AjaxResult getUser(@PathVariable Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            return AjaxResult.success(users.get(userId));
+        }
+        else
+        {
+            return AjaxResult.error("鐢ㄦ埛涓嶅瓨鍦�");
+        }
+    }
+
+    @ApiOperation("鏂板鐢ㄦ埛")
+    @ApiImplicitParam(name = "userEntity", value = "鏂板鐢ㄦ埛淇℃伅", dataType = "UserEntity")
+    @PostMapping("/save")
+    public AjaxResult save(UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return AjaxResult.error("鐢ㄦ埛ID涓嶈兘涓虹┖");
+        }
+        return AjaxResult.success(users.put(user.getUserId(), user));
+    }
+
+    @ApiOperation("鏇存柊鐢ㄦ埛")
+    @ApiImplicitParam(name = "userEntity", value = "鏂板鐢ㄦ埛淇℃伅", dataType = "UserEntity")
+    @PutMapping("/update")
+    public AjaxResult update(UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return AjaxResult.error("鐢ㄦ埛ID涓嶈兘涓虹┖");
+        }
+        if (users.isEmpty() || !users.containsKey(user.getUserId()))
+        {
+            return AjaxResult.error("鐢ㄦ埛涓嶅瓨鍦�");
+        }
+        users.remove(user.getUserId());
+        return AjaxResult.success(users.put(user.getUserId(), user));
+    }
+
+    @ApiOperation("鍒犻櫎鐢ㄦ埛淇℃伅")
+    @ApiImplicitParam(name = "userId", value = "鐢ㄦ埛ID", required = true, dataType = "int", paramType = "path")
+    @DeleteMapping("/{userId}")
+    public AjaxResult delete(@PathVariable Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            users.remove(userId);
+            return AjaxResult.success();
+        }
+        else
+        {
+            return AjaxResult.error("鐢ㄦ埛涓嶅瓨鍦�");
+        }
+    }
+}
+
+@ApiModel("鐢ㄦ埛瀹炰綋")
+class UserEntity
+{
+    @ApiModelProperty("鐢ㄦ埛ID")
+    private Integer userId;
+
+    @ApiModelProperty("鐢ㄦ埛鍚嶇О")
+    private String username;
+
+    @ApiModelProperty("鐢ㄦ埛瀵嗙爜")
+    private String password;
+
+    @ApiModelProperty("鐢ㄦ埛鎵嬫満")
+    private String mobile;
+
+    public UserEntity()
+    {
+
+    }
+
+    public UserEntity(Integer userId, String username, String password, String mobile)
+    {
+        this.userId = userId;
+        this.username = username;
+        this.password = password;
+        this.mobile = mobile;
+    }
+
+    public Integer getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Integer userId)
+    {
+        this.userId = userId;
+    }
+
+    public String getUsername()
+    {
+        return username;
+    }
+
+    public void setUsername(String username)
+    {
+        this.username = username;
+    }
+
+    public String getPassword()
+    {
+        return password;
+    }
+
+    public void setPassword(String password)
+    {
+        this.password = password;
+    }
+
+    public String getMobile()
+    {
+        return mobile;
+    }
+
+    public void setMobile(String mobile)
+    {
+        this.mobile = mobile;
+    }
+}
diff --git a/ruoyi/src/main/resources/application-druid.yml b/ruoyi/src/main/resources/application-druid.yml
new file mode 100644
index 0000000..cdfb339
--- /dev/null
+++ b/ruoyi/src/main/resources/application-druid.yml
@@ -0,0 +1,57 @@
+# 鏁版嵁婧愰厤缃�
+spring:
+    datasource:
+        type: com.alibaba.druid.pool.DruidDataSource
+        driverClassName: com.mysql.cj.jdbc.Driver
+        druid:
+            # 涓诲簱鏁版嵁婧�
+            master:
+                url: jdbc:mysql://localhost:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+                username: root
+                password: password
+            # 浠庡簱鏁版嵁婧�
+            slave:
+                # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+                enabled: false
+                url: 
+                username: 
+                password: 
+            # 鍒濆杩炴帴鏁�
+            initialSize: 5
+            # 鏈�灏忚繛鎺ユ睜鏁伴噺
+            minIdle: 10
+            # 鏈�澶ц繛鎺ユ睜鏁伴噺
+            maxActive: 20
+            # 閰嶇疆鑾峰彇杩炴帴绛夊緟瓒呮椂鐨勬椂闂�
+            maxWait: 60000
+            # 閰嶇疆闂撮殧澶氫箙鎵嶈繘琛屼竴娆℃娴嬶紝妫�娴嬮渶瑕佸叧闂殑绌洪棽杩炴帴锛屽崟浣嶆槸姣
+            timeBetweenEvictionRunsMillis: 60000
+            # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�灏忕敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+            minEvictableIdleTimeMillis: 300000
+            # 閰嶇疆涓�涓繛鎺ュ湪姹犱腑鏈�澶х敓瀛樼殑鏃堕棿锛屽崟浣嶆槸姣
+            maxEvictableIdleTimeMillis: 900000
+            # 閰嶇疆妫�娴嬭繛鎺ユ槸鍚︽湁鏁�
+            validationQuery: SELECT 1 FROM DUAL
+            testWhileIdle: true
+            testOnBorrow: false
+            testOnReturn: false
+            webStatFilter: 
+                enabled: true
+            statViewServlet:
+                enabled: true
+                # 璁剧疆鐧藉悕鍗曪紝涓嶅~鍒欏厑璁告墍鏈夎闂�
+                allow:
+                url-pattern: /druid/*
+                # 鎺у埗鍙扮鐞嗙敤鎴峰悕鍜屽瘑鐮�
+                login-username: 
+                login-password: 
+            filter:
+                stat:
+                    enabled: true
+                    # 鎱QL璁板綍
+                    log-slow-sql: true
+                    slow-sql-millis: 1000
+                    merge-sql: true
+                wall:
+                    config:
+                        multi-statement-allow: true
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/application.yml b/ruoyi/src/main/resources/application.yml
new file mode 100644
index 0000000..4146e35
--- /dev/null
+++ b/ruoyi/src/main/resources/application.yml
@@ -0,0 +1,109 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi
+  # 鐗堟湰
+  version: 1.0.0
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2019
+  # 瀹炰緥婕旂ず寮�鍏�
+  demoEnabled: true
+  # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
+  profile: D:/ruoyi/uploadPath
+  # 鑾峰彇ip鍦板潃寮�鍏�
+  addressEnabled: true
+
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 8080
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  tomcat:
+    # tomcat鐨刄RI缂栫爜
+    uri-encoding: UTF-8
+    # tomcat鏈�澶х嚎绋嬫暟锛岄粯璁や负200
+    max-threads: 800
+    # Tomcat鍚姩鍒濆鍖栫殑绾跨▼鏁帮紝榛樿鍊�25
+    min-spare-threads: 30
+
+
+# 鏃ュ織閰嶇疆
+logging:
+  level:
+    com.ruoyi: debug
+    org.springframework: warn
+
+# Spring閰嶇疆
+spring:
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  profiles: 
+    active: druid
+  # 鏂囦欢涓婁紶
+  servlet:
+     multipart:
+       # 鍗曚釜鏂囦欢澶у皬
+       max-file-size:  10MB
+       # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+       max-request-size:  20MB
+  # 鏈嶅姟妯″潡
+  devtools:
+    restart:
+      # 鐑儴缃插紑鍏�
+      enabled: true
+  # redis 閰嶇疆
+  redis:
+    # 鍦板潃
+    host: localhost
+    # 绔彛锛岄粯璁や负6379
+    port: 6379
+    # 杩炴帴瓒呮椂鏃堕棿
+    timeout: 10s
+    lettuce:
+      pool:
+        # 杩炴帴姹犱腑鐨勬渶灏忕┖闂茶繛鎺�
+        min-idle: 0
+        # 杩炴帴姹犱腑鐨勬渶澶х┖闂茶繛鎺�
+        max-idle: 8
+        # 杩炴帴姹犵殑鏈�澶ф暟鎹簱杩炴帴鏁�
+        max-active: 8
+        # #杩炴帴姹犳渶澶ч樆濉炵瓑寰呮椂闂达紙浣跨敤璐熷�艰〃绀烘病鏈夐檺鍒讹級
+        max-wait: -1ms
+
+# token閰嶇疆
+token:
+    # 浠ょ墝鑷畾涔夋爣璇�
+    header: Authorization
+    # 浠ょ墝绉橀挜
+    secret: abcdefghijklmnopqrstuvwxyz
+    # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+    expireTime: 30
+  
+# MyBatis閰嶇疆
+mybatis:
+    # 鎼滅储鎸囧畾鍖呭埆鍚�
+    typeAliasesPackage: com.ruoyi.project.**.domain
+    # 閰嶇疆mapper鐨勬壂鎻忥紝鎵惧埌鎵�鏈夌殑mapper.xml鏄犲皠鏂囦欢
+    mapperLocations: classpath*:mybatis/**/*Mapper.xml
+    # 鍔犺浇鍏ㄥ眬鐨勯厤缃枃浠�
+    configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper鍒嗛〉鎻掍欢
+pagehelper: 
+  helperDialect: mysql
+  reasonable: true
+  supportMethodsArguments: true
+  params: count=countSql 
+
+# 闃叉XSS鏀诲嚮
+xss: 
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice/*
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/banner.txt b/ruoyi/src/main/resources/banner.txt
new file mode 100644
index 0000000..9466259
--- /dev/null
+++ b/ruoyi/src/main/resources/banner.txt
@@ -0,0 +1,24 @@
+Application Version: ${ruoyi.version}
+Spring Boot Version: ${spring-boot.version}
+////////////////////////////////////////////////////////////////////
+//                          _ooOoo_                               //
+//                         o8888888o                              //
+//                         88" . "88                              //
+//                         (| ^_^ |)                              //
+//                         O\  =  /O                              //
+//                      ____/`---'\____                           //
+//                    .'  \\|     |//  `.                         //
+//                   /  \\|||  :  |||//  \                        //
+//                  /  _||||| -:- |||||-  \                       //
+//                  |   | \\\  -  /// |   |                       //
+//                  | \_|  ''\---/''  |   |                       //
+//                  \  .-\__  `-`  ___/-. /                       //
+//                ___`. .'  /--.--\  `. . ___                     //
+//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
+//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
+//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
+//      ========`-.____`-.___\_____/___.-`____.-'========         //
+//                           `=---='                              //
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
+//             浣涚淇濅綉       姘镐笉瀹曟満      姘告棤BUG               //
+////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/i18n/messages.properties b/ruoyi/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..4baeb24
--- /dev/null
+++ b/ruoyi/src/main/resources/i18n/messages.properties
@@ -0,0 +1,36 @@
+#閿欒娑堟伅
+not.null=* 蹇呴』濉啓
+user.jcaptcha.error=楠岃瘉鐮侀敊璇�
+user.jcaptcha.expire=楠岃瘉鐮佸凡澶辨晥
+user.not.exists=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.password.not.match=鐢ㄦ埛涓嶅瓨鍦�/瀵嗙爜閿欒
+user.password.retry.limit.count=瀵嗙爜杈撳叆閿欒{0}娆�
+user.password.retry.limit.exceed=瀵嗙爜杈撳叆閿欒{0}娆★紝甯愭埛閿佸畾10鍒嗛挓
+user.password.delete=瀵逛笉璧凤紝鎮ㄧ殑璐﹀彿宸茶鍒犻櫎
+user.blocked=鐢ㄦ埛宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+role.blocked=瑙掕壊宸插皝绂侊紝璇疯仈绯荤鐞嗗憳
+user.logout.success=閫�鍑烘垚鍔�
+
+length.not.valid=闀垮害蹇呴』鍦▄min}鍒皗max}涓瓧绗︿箣闂�
+
+user.username.not.valid=* 2鍒�20涓眽瀛椼�佸瓧姣嶃�佹暟瀛楁垨涓嬪垝绾跨粍鎴愶紝涓斿繀椤讳互闈炴暟瀛楀紑澶�
+user.password.not.valid=* 5-50涓瓧绗�
+ 
+user.email.not.valid=閭鏍煎紡閿欒
+user.mobile.phone.number.not.valid=鎵嬫満鍙锋牸寮忛敊璇�
+user.login.success=鐧诲綍鎴愬姛
+user.notfound=璇烽噸鏂扮櫥褰�
+user.forcelogout=绠$悊鍛樺己鍒堕��鍑猴紝璇烽噸鏂扮櫥褰�
+user.unknown.error=鏈煡閿欒锛岃閲嶆柊鐧诲綍
+
+##鏂囦欢涓婁紶娑堟伅
+upload.exceed.maxSize=涓婁紶鐨勬枃浠跺ぇ灏忚秴鍑洪檺鍒剁殑鏂囦欢澶у皬锛�<br/>鍏佽鐨勬枃浠舵渶澶уぇ灏忔槸锛歿0}MB锛�
+upload.filename.exceed.length=涓婁紶鐨勬枃浠跺悕鏈�闀縶0}涓瓧绗�
+
+##鏉冮檺
+no.permission=鎮ㄦ病鏈夋暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.create.permission=鎮ㄦ病鏈夊垱寤烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.update.permission=鎮ㄦ病鏈変慨鏀规暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.delete.permission=鎮ㄦ病鏈夊垹闄ゆ暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.export.permission=鎮ㄦ病鏈夊鍑烘暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
+no.view.permission=鎮ㄦ病鏈夋煡鐪嬫暟鎹殑鏉冮檺锛岃鑱旂郴绠$悊鍛樻坊鍔犳潈闄� [{0}]
diff --git a/ruoyi/src/main/resources/logback.xml b/ruoyi/src/main/resources/logback.xml
new file mode 100644
index 0000000..d69a572
--- /dev/null
+++ b/ruoyi/src/main/resources/logback.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 鏃ュ織瀛樻斁璺緞 -->
+	<property name="log.path" value="/home/ruoyi/logs" />
+    <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 鎺у埗鍙拌緭鍑� -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+	
+	<!-- 绯荤粺鏃ュ織杈撳嚭 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-info.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>INFO</level>
+            <!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+	
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>ERROR</level>
+			<!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+	
+	<!-- 鐢ㄦ埛璁块棶鏃ュ織杈撳嚭  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鎸夊ぉ鍥炴粴 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+	
+	<!-- 绯荤粺妯″潡鏃ュ織绾у埆鎺у埗  -->
+	<logger name="com.ruoyi" level="info" />
+	<!-- Spring鏃ュ織绾у埆鎺у埗  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+	
+	<!--绯荤粺鎿嶄綔鏃ュ織-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+	
+	<!--绯荤粺鐢ㄦ埛鎿嶄綔鏃ュ織-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml b/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml
new file mode 100644
index 0000000..0301a3d
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/monitor/SysLogininforMapper.xml
@@ -0,0 +1,56 @@
+<?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="com.ruoyi.project.monitor.mapper.SysLogininforMapper">
+
+	<resultMap type="SysLogininfor" id="SysLogininforResult">
+		<id     property="infoId"        column="info_id"           />
+		<result property="userName"      column="user_name"         />
+		<result property="status"        column="status"            />
+		<result property="ipaddr"        column="ipaddr"            />
+		<result property="loginLocation" column="login_location"    />
+		<result property="browser"       column="browser"           />
+		<result property="os"            column="os"                />
+		<result property="msg"           column="msg"               />
+		<result property="loginTime"     column="login_time"        />
+	</resultMap>
+
+	<insert id="insertLogininfor" parameterType="SysLogininfor">
+		insert into sys_logininfor (user_name, status, ipaddr, login_location, browser, os, msg, login_time)
+		values (#{userName}, #{status}, #{ipaddr}, #{loginLocation}, #{browser}, #{os}, #{msg}, sysdate())
+	</insert>
+	
+	<select id="selectLogininforList" parameterType="SysLogininfor" resultMap="SysLogininforResult">
+		select info_id, user_name, ipaddr, login_location, browser, os, status, msg, login_time from sys_logininfor
+		<where>
+			<if test="ipaddr != null and ipaddr != ''">
+				AND ipaddr like concat('%', #{ipaddr}, '%')
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="userName != null and userName != ''">
+				AND user_name like concat('%', #{userName}, '%')
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+				and date_format(login_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+				and date_format(login_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+			</if>
+		</where>
+	</select>
+	
+	<delete id="deleteLogininforByIds" parameterType="String">
+ 		delete from sys_logininfor where info_id in
+ 		<foreach collection="array" item="infoId" open="(" separator="," close=")">
+ 			#{infoId}
+        </foreach> 
+ 	</delete>
+    
+    <update id="cleanLogininfor">
+        truncate table sys_logininfor
+    </update>
+    
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml b/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml
new file mode 100644
index 0000000..6517828
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/monitor/SysOperLogMapper.xml
@@ -0,0 +1,82 @@
+<?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="com.ruoyi.project.monitor.mapper.SysOperLogMapper">
+
+	<resultMap type="SysOperLog" id="SysOperLogResult">
+		<id     property="operId"         column="oper_id"        />
+		<result property="title"          column="title"          />
+		<result property="businessType"   column="business_type"  />
+		<result property="method"         column="method"         />
+		<result property="requestMethod"  column="request_method" />
+		<result property="operatorType"   column="operator_type"  />
+		<result property="operName"       column="oper_name"      />
+		<result property="deptName"       column="dept_name"      />
+		<result property="operUrl"        column="oper_url"       />
+		<result property="operIp"         column="oper_ip"        />
+		<result property="operLocation"   column="oper_location"  />
+		<result property="operParam"      column="oper_param"     />
+		<result property="jsonResult"     column="json_result"    />
+		<result property="status"         column="status"         />
+		<result property="errorMsg"       column="error_msg"      />
+		<result property="operTime"       column="oper_time"      />
+	</resultMap>
+
+	<sql id="selectOperLogVo">
+        select oper_id, title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time
+        from sys_oper_log
+    </sql>
+    
+	<insert id="insertOperlog" parameterType="SysOperLog">
+		insert into sys_oper_log(title, business_type, method, request_method, operator_type, oper_name, dept_name, oper_url, oper_ip, oper_location, oper_param, json_result, status, error_msg, oper_time)
+        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, sysdate())
+	</insert>
+	
+	<select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
+		<include refid="selectOperLogVo"/>
+		<where>
+			<if test="title != null and title != ''">
+				AND title like concat('%', #{title}, '%')
+			</if>
+			<if test="businessType != null">
+				AND business_type = #{businessType}
+			</if>
+			<if test="businessTypes != null and businessTypes.length > 0">
+			    AND business_type in
+			    <foreach collection="businessTypes" item="businessType" open="(" separator="," close=")">
+		 			#{businessType}
+		        </foreach> 
+			</if>
+			<if test="status != null">
+				AND status = #{status}
+			</if>
+			<if test="operName != null and operName != ''">
+				AND oper_name like concat('%', #{operName}, '%')
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+				and date_format(oper_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+				and date_format(oper_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+			</if>
+		</where>
+	</select>
+	
+	<delete id="deleteOperLogByIds" parameterType="String">
+ 		delete from sys_oper_log where oper_id in
+ 		<foreach collection="array" item="operId" open="(" separator="," close=")">
+ 			#{operId}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<select id="selectOperLogById" parameterType="Long" resultMap="SysOperLogResult">
+		<include refid="selectOperLogVo"/>
+		where oper_id = #{operId}
+	</select>
+	
+	<update id="cleanOperLog">
+        truncate table sys_oper_log
+    </update>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/mybatis-config.xml b/ruoyi/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..c7c36e3
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE configuration
+PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-config.dtd">
+<configuration>
+	
+	<settings>
+		<setting name="cacheEnabled"             value="true" />  <!-- 鍏ㄥ眬鏄犲皠鍣ㄥ惎鐢ㄧ紦瀛� -->
+		<setting name="useGeneratedKeys"         value="true" />  <!-- 鍏佽 JDBC 鏀寔鑷姩鐢熸垚涓婚敭 -->
+		<setting name="defaultExecutorType"      value="REUSE" /> <!-- 閰嶇疆榛樿鐨勬墽琛屽櫒 -->
+		<setting name="logImpl"                  value="SLF4J" /> <!-- 鎸囧畾 MyBatis 鎵�鐢ㄦ棩蹇楃殑鍏蜂綋瀹炵幇 -->
+		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/>  椹煎嘲寮忓懡鍚� -->
+	</settings>
+	
+</configuration>
diff --git a/ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml
new file mode 100644
index 0000000..2189371
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysConfigMapper.xml
@@ -0,0 +1,105 @@
+<?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="com.ruoyi.project.system.mapper.SysConfigMapper">
+    
+    <resultMap type="SysConfig" id="SysConfigResult">
+    	<id     property="configId"      column="config_id"      />
+        <result property="configName"    column="config_name"    />
+        <result property="configKey"     column="config_key"     />
+        <result property="configValue"   column="config_value"   />
+        <result property="configType"    column="config_type"    />
+        <result property="createBy"      column="create_by"      />
+        <result property="createTime"    column="create_time"    />
+        <result property="updateBy"      column="update_by"      />
+        <result property="updateTime"    column="update_time"    />
+    </resultMap>
+    
+    <sql id="selectConfigVo">
+        select config_id, config_name, config_key, config_value, config_type, create_by, create_time, update_by, update_time, remark 
+		from sys_config
+    </sql>
+    
+    <!-- 鏌ヨ鏉′欢 -->
+	<sql id="sqlwhereSearch">
+		<where>
+			<if test="configId !=null">
+				and config_id = #{configId}
+			</if>
+			<if test="configKey !=null and configKey != ''">
+				and config_key = #{configKey}
+			</if>
+		</where>
+	</sql>
+    
+    <select id="selectConfig" parameterType="SysConfig" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        <include refid="sqlwhereSearch"/>
+    </select>
+    
+    <select id="selectConfigList" parameterType="SysConfig" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        <where>
+			<if test="configName != null and configName != ''">
+				AND config_name like concat('%', #{configName}, '%')
+			</if>
+			<if test="configType != null and configType != ''">
+				AND config_type = #{configType}
+			</if>
+			<if test="configKey != null and configKey != ''">
+				AND config_key like concat('%', #{configKey}, '%')
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+				and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+				and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+			</if>
+		</where>
+    </select>
+    
+    <select id="checkConfigKeyUnique" parameterType="String" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        where config_key = #{configKey}
+    </select>
+    
+    <insert id="insertConfig" parameterType="SysConfig">
+        insert into sys_config (
+			<if test="configName != null and configName != '' ">config_name,</if>
+			<if test="configKey != null and configKey != '' ">config_key,</if>
+			<if test="configValue != null and configValue != '' ">config_value,</if>
+			<if test="configType != null and configType != '' ">config_type,</if>
+			<if test="createBy != null and createBy != ''">create_by,</if>
+			<if test="remark != null and remark != ''">remark,</if>
+ 			create_time
+        )values(
+			<if test="configName != null and configName != ''">#{configName},</if>
+			<if test="configKey != null and configKey != ''">#{configKey},</if>
+			<if test="configValue != null and configValue != ''">#{configValue},</if>
+			<if test="configType != null and configType != ''">#{configType},</if>
+			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			<if test="remark != null and remark != ''">#{remark},</if>
+ 			sysdate()
+		)
+    </insert>
+	 
+    <update id="updateConfig" parameterType="SysConfig">
+        update sys_config 
+        <set>
+            <if test="configName != null and configName != ''">config_name = #{configName},</if>
+            <if test="configKey != null and configKey != ''">config_key = #{configKey},</if>
+            <if test="configValue != null and configValue != ''">config_value = #{configValue},</if>
+            <if test="configType != null and configType != ''">config_type = #{configType},</if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+ 			update_time = sysdate()
+        </set>
+        where config_id = #{configId}
+    </update>
+	
+    <delete id="deleteConfigById" parameterType="Long">
+        delete from sys_config where config_id = #{configId}
+    </delete>
+    
+</mapper>
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysDeptMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysDeptMapper.xml
new file mode 100644
index 0000000..247bb69
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysDeptMapper.xml
@@ -0,0 +1,151 @@
+<?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="com.ruoyi.project.system.mapper.SysDeptMapper">
+
+	<resultMap type="SysDept" id="SysDeptResult">
+		<id     property="deptId"     column="dept_id"     />
+		<result property="parentId"   column="parent_id"   />
+		<result property="ancestors"  column="ancestors"   />
+		<result property="deptName"   column="dept_name"   />
+		<result property="orderNum"   column="order_num"   />
+		<result property="leader"     column="leader"      />
+		<result property="phone"      column="phone"       />
+		<result property="email"      column="email"       />
+		<result property="status"     column="status"      />
+		<result property="delFlag"    column="del_flag"    />
+		<result property="parentName" column="parent_name" />
+		<result property="createBy"   column="create_by"   />
+		<result property="createTime" column="create_time" />
+		<result property="updateBy"   column="update_by"   />
+		<result property="updateTime" column="update_time" />
+	</resultMap>
+	
+	<sql id="selectDeptVo">
+        select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status, d.del_flag, d.create_by, d.create_time 
+        from sys_dept d
+    </sql>
+    
+	<select id="selectDeptList" parameterType="SysDept" resultMap="SysDeptResult">
+        <include refid="selectDeptVo"/>
+        where d.del_flag = '0'
+        <if test="parentId != null and parentId != 0">
+			AND parent_id = #{parentId}
+		</if>
+		<if test="deptName != null and deptName != ''">
+			AND dept_name like concat('%', #{deptName}, '%')
+		</if>
+		<if test="status != null and status != ''">
+			AND status = #{status}
+		</if>
+		<!-- 鏁版嵁鑼冨洿杩囨护 -->
+		${dataScope}
+		order by d.parent_id, d.order_num
+    </select>
+    
+    <select id="selectDeptListByRoleId" parameterType="Long" resultType="Integer">
+		select d.dept_id, d.parent_id
+		from sys_dept d
+            left join sys_role_dept rd on d.dept_id = rd.dept_id
+        where rd.role_id = #{roleId}
+        	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})
+		order by d.parent_id, d.order_num
+	</select>
+    
+    <select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
+		<include refid="selectDeptVo"/>
+		where dept_id = #{deptId}
+	</select>
+    
+    <select id="checkDeptExistUser" parameterType="Long" resultType="int">
+		select count(1) from sys_user where dept_id = #{deptId} and del_flag = '0'
+	</select>
+	
+	<select id="hasChildByDeptId" parameterType="Long" resultType="int">
+		select count(1) from sys_dept
+		where del_flag = '0' and parent_id = #{deptId}
+	</select>
+	
+	<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
+		select * from sys_dept where find_in_set(#{deptId}, ancestors)
+	</select>
+	
+	<select id="checkDeptNameUnique" resultMap="SysDeptResult">
+	    <include refid="selectDeptVo"/>
+		where dept_name=#{deptName} and parent_id = #{parentId}
+	</select>
+    
+    <insert id="insertDept" parameterType="SysDept">
+ 		insert into sys_dept(
+ 			<if test="deptId != null and deptId != 0">dept_id,</if>
+ 			<if test="parentId != null and parentId != 0">parent_id,</if>
+ 			<if test="deptName != null and deptName != ''">dept_name,</if>
+ 			<if test="ancestors != null and ancestors != ''">ancestors,</if>
+ 			<if test="orderNum != null and orderNum != ''">order_num,</if>
+ 			<if test="leader != null and leader != ''">leader,</if>
+ 			<if test="phone != null and phone != ''">phone,</if>
+ 			<if test="email != null and email != ''">email,</if>
+ 			<if test="status != null">status,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 			<if test="deptId != null and deptId != 0">#{deptId},</if>
+ 			<if test="parentId != null and parentId != 0">#{parentId},</if>
+ 			<if test="deptName != null and deptName != ''">#{deptName},</if>
+ 			<if test="ancestors != null and ancestors != ''">#{ancestors},</if>
+ 			<if test="orderNum != null and orderNum != ''">#{orderNum},</if>
+ 			<if test="leader != null and leader != ''">#{leader},</if>
+ 			<if test="phone != null and phone != ''">#{phone},</if>
+ 			<if test="email != null and email != ''">#{email},</if>
+ 			<if test="status != null">#{status},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+	<update id="updateDept" parameterType="SysDept">
+ 		update sys_dept
+ 		<set>
+ 			<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
+ 			<if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
+ 			<if test="ancestors != null and ancestors != ''">ancestors = #{ancestors},</if>
+ 			<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if>
+ 			<if test="leader != null">leader = #{leader},</if>
+ 			<if test="phone != null">phone = #{phone},</if>
+ 			<if test="email != null">email = #{email},</if>
+ 			<if test="status != null and status != ''">status = #{status},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where dept_id = #{deptId}
+	</update>
+	
+	<update id="updateDeptChildren" parameterType="java.util.List">
+	    update sys_dept set ancestors =
+	    <foreach collection="depts" item="item" index="index"
+	        separator=" " open="case dept_id" close="end">
+	        when #{item.deptId} then #{item.ancestors}
+	    </foreach>
+	    where dept_id in
+	    <foreach collection="depts" item="item" index="index"
+	        separator="," open="(" close=")">
+	        #{item.deptId}
+	    </foreach>
+	</update>
+	 
+	 <update id="updateDeptStatus" parameterType="SysDept">
+ 	    update sys_dept
+ 	    <set>
+ 	        <if test="status != null and status != ''">status = #{status},</if>
+ 	        <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 	        update_time = sysdate()
+        </set>
+ 	    where dept_id in (${ancestors})
+	</update>
+	
+	<delete id="deleteDeptById" parameterType="Long">
+		update sys_dept set del_flag = '2' where dept_id = #{deptId}
+	</delete>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml
new file mode 100644
index 0000000..57e53c7
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysDictDataMapper.xml
@@ -0,0 +1,116 @@
+<?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="com.ruoyi.project.system.mapper.SysDictDataMapper">
+	
+	<resultMap type="SysDictData" id="SysDictDataResult">
+		<id     property="dictCode"   column="dict_code"   />
+		<result property="dictSort"   column="dict_sort"   />
+		<result property="dictLabel"  column="dict_label"  />
+		<result property="dictValue"  column="dict_value"  />
+		<result property="dictType"   column="dict_type"   />
+		<result property="cssClass"   column="css_class"   />
+		<result property="listClass"  column="list_class"  />
+		<result property="isDefault"  column="is_default"  />
+		<result property="status"     column="status"      />
+		<result property="createBy"   column="create_by"   />
+		<result property="createTime" column="create_time" />
+		<result property="updateBy"   column="update_by"   />
+		<result property="updateTime" column="update_time" />
+	</resultMap>
+	
+	<sql id="selectDictDataVo">
+        select dict_code, dict_sort, dict_label, dict_value, dict_type, css_class, list_class, is_default, status, create_by, create_time, remark 
+		from sys_dict_data
+    </sql>
+
+	<select id="selectDictDataList" parameterType="SysDictData" resultMap="SysDictDataResult">
+	    <include refid="selectDictDataVo"/>
+		<where>
+		    <if test="dictType != null and dictType != ''">
+				AND dict_type = #{dictType}
+			</if>
+			<if test="dictLabel != null and dictLabel != ''">
+				AND dict_label like concat('%', #{dictLabel}, '%')
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+		</where>
+	</select>
+	
+	<select id="selectDictDataByType" parameterType="SysDictData" resultMap="SysDictDataResult">
+		<include refid="selectDictDataVo"/>
+		where status = '0' and dict_type = #{dictType} order by dict_sort asc
+	</select>
+	
+	<select id="selectDictLabel" resultType="String">
+		select dict_label from sys_dict_data
+		where dict_type = #{dictType} and dict_value = #{dictValue}
+	</select>
+	
+	<select id="selectDictDataById" parameterType="Long" resultMap="SysDictDataResult">
+		<include refid="selectDictDataVo"/>
+		where dict_code = #{dictCode}
+	</select>
+	
+	<select id="countDictDataByType" resultType="Integer">
+	    select count(1) from sys_dict_data where dict_type=#{dictType}  
+	</select>
+	
+	<delete id="deleteDictDataById" parameterType="Long">
+ 		delete from sys_dict_data where dict_code = #{dictCode}
+ 	</delete>
+	
+	<update id="updateDictData" parameterType="SysDictData">
+ 		update sys_dict_data
+ 		<set>
+ 			<if test="dictSort != null and dictSort != ''">dict_sort = #{dictSort},</if>
+ 			<if test="dictLabel != null and dictLabel != ''">dict_label = #{dictLabel},</if>
+ 			<if test="dictValue != null and dictValue != ''">dict_value = #{dictValue},</if>
+ 			<if test="dictType != null and dictType != ''">dict_type = #{dictType},</if>
+ 			<if test="cssClass != null">css_class = #{cssClass},</if>
+ 			<if test="listClass != null">list_class = #{listClass},</if>
+ 			<if test="isDefault != null and isDefault != ''">is_default = #{isDefault},</if>
+ 			<if test="status != null">status = #{status},</if>
+ 			<if test="remark != null">remark = #{remark},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where dict_code = #{dictCode}
+	</update>
+	
+	<update id="updateDictDataType" parameterType="String">
+ 		update sys_dict_data set dict_type = #{newDictType} where dict_type = #{oldDictType}
+	</update>
+ 	
+ 	<insert id="insertDictData" parameterType="SysDictData">
+ 		insert into sys_dict_data(
+ 			<if test="dictSort != null and dictSort != ''">dict_sort,</if>
+ 			<if test="dictLabel != null and dictLabel != ''">dict_label,</if>
+ 			<if test="dictValue != null and dictValue != ''">dict_value,</if>
+ 			<if test="dictType != null and dictType != ''">dict_type,</if>
+ 			<if test="cssClass != null and cssClass != ''">css_class,</if>
+ 			<if test="listClass != null and listClass != ''">list_class,</if>
+ 			<if test="isDefault != null and isDefault != ''">is_default,</if>
+ 			<if test="status != null">status,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 		    <if test="dictSort != null and dictSort != ''">#{dictSort},</if>
+ 		    <if test="dictLabel != null and dictLabel != ''">#{dictLabel},</if>
+ 			<if test="dictValue != null and dictValue != ''">#{dictValue},</if>
+ 			<if test="dictType != null and dictType != ''">#{dictType},</if>
+ 			<if test="cssClass != null and cssClass != ''">#{cssClass},</if>
+ 			<if test="listClass != null and listClass != ''">#{listClass},</if>
+ 			<if test="isDefault != null and isDefault != ''">#{isDefault},</if>
+ 			<if test="status != null">#{status},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml
new file mode 100644
index 0000000..0a8b26c
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysDictTypeMapper.xml
@@ -0,0 +1,98 @@
+<?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="com.ruoyi.project.system.mapper.SysDictTypeMapper">
+
+	<resultMap type="SysDictType" id="SysDictTypeResult">
+		<id     property="dictId"     column="dict_id"     />
+		<result property="dictName"   column="dict_name"   />
+		<result property="dictType"   column="dict_type"   />
+		<result property="status"     column="status"      />
+		<result property="createBy"   column="create_by"   />
+		<result property="createTime" column="create_time" />
+		<result property="updateBy"   column="update_by"   />
+		<result property="updateTime" column="update_time" />
+	</resultMap>
+	
+	<sql id="selectDictTypeVo">
+        select dict_id, dict_name, dict_type, status, create_by, create_time, remark 
+		from sys_dict_type
+    </sql>
+
+	<select id="selectDictTypeList" parameterType="SysDictType" resultMap="SysDictTypeResult">
+	    <include refid="selectDictTypeVo"/>
+		<where>
+		    <if test="dictName != null and dictName != ''">
+				AND dict_name like concat('%', #{dictName}, '%')
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="dictType != null and dictType != ''">
+				AND dict_type like concat('%', #{dictType}, '%')
+			</if>
+			<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+				and date_format(create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+				and date_format(create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+			</if>
+	    </where>
+	</select>
+	
+	<select id="selectDictTypeAll" resultMap="SysDictTypeResult">
+		<include refid="selectDictTypeVo"/>
+	</select>
+	
+	<select id="selectDictTypeById" parameterType="Long" resultMap="SysDictTypeResult">
+		<include refid="selectDictTypeVo"/>
+		where dict_id = #{dictId}
+	</select>
+	
+	<select id="selectDictTypeByType" parameterType="String" resultMap="SysDictTypeResult">
+		<include refid="selectDictTypeVo"/>
+		where dict_type = #{dictType}
+	</select>
+	
+	<select id="checkDictTypeUnique" parameterType="String" resultMap="SysDictTypeResult">
+		<include refid="selectDictTypeVo"/>
+		where dict_type = #{dictType}
+	</select>
+	
+	<delete id="deleteDictTypeById" parameterType="Long">
+ 		delete from sys_dict_type where dict_id = #{dictId}
+ 	</delete>
+
+ 	<update id="updateDictType" parameterType="SysDictType">
+ 		update sys_dict_type
+ 		<set>
+ 			<if test="dictName != null and dictName != ''">dict_name = #{dictName},</if>
+ 			<if test="dictType != null and dictType != ''">dict_type = #{dictType},</if>
+ 			<if test="status != null">status = #{status},</if>
+ 			<if test="remark != null">remark = #{remark},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where dict_id = #{dictId}
+	</update>
+ 	
+ 	<insert id="insertDictType" parameterType="SysDictType">
+ 		insert into sys_dict_type(
+ 			<if test="dictName != null and dictName != ''">dict_name,</if>
+ 			<if test="dictType != null and dictType != ''">dict_type,</if>
+ 			<if test="status != null">status,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 			<if test="dictName != null and dictName != ''">#{dictName},</if>
+ 			<if test="dictType != null and dictType != ''">#{dictType},</if>
+ 			<if test="status != null">#{status},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysMenuMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysMenuMapper.xml
new file mode 100644
index 0000000..d233602
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysMenuMapper.xml
@@ -0,0 +1,158 @@
+<?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="com.ruoyi.project.system.mapper.SysMenuMapper">
+
+	<resultMap type="SysMenu" id="SysMenuResult">
+		<id     property="menuId"         column="menu_id"        />
+		<result property="menuName"       column="menu_name"      />
+		<result property="parentName"     column="parent_name"    />
+		<result property="parentId"       column="parent_id"      />
+		<result property="orderNum"       column="order_num"      />
+		<result property="path"           column="path"           />
+		<result property="component"      column="component"      />
+		<result property="isFrame"        column="is_frame"       />
+		<result property="menuType"       column="menu_type"      />
+		<result property="visible"        column="visible"        />
+		<result property="perms"          column="perms"          />
+		<result property="icon"           column="icon"           />
+		<result property="createBy"       column="create_by"      />
+		<result property="createTime"     column="create_time"    />
+		<result property="updateTime"     column="update_time"    />
+		<result property="updateBy"       column="update_by"      />
+		<result property="remark"         column="remark"         />
+	</resultMap>
+
+	<sql id="selectMenuVo">
+        select menu_id, menu_name, parent_id, order_num, path, component, is_frame, menu_type, visible, ifnull(perms,'') as perms, icon, create_time 
+		from sys_menu
+    </sql>
+    
+    <select id="selectMenuList" parameterType="SysMenu" resultMap="SysMenuResult">
+		<include refid="selectMenuVo"/>
+		<where>
+			<if test="menuName != null and menuName != ''">
+				AND menu_name like concat('%', #{menuName}, '%')
+			</if>
+			<if test="visible != null and visible != ''">
+				AND visible = #{visible}
+			</if>
+		</where>
+		order by parent_id, order_num
+	</select>
+	
+	<select id="selectMenuTreeAll" resultMap="SysMenuResult">
+		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, ifnull(m.perms,'') as perms, m.is_frame, m.menu_type, m.icon, m.order_num, m.create_time
+		from sys_menu m where m.menu_type in ('M', 'C') and m.visible = 0
+		order by m.parent_id, m.order_num
+	</select>
+    
+    <select id="selectMenuTreeByUserId" parameterType="Long" resultMap="SysMenuResult">
+		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.visible, ifnull(m.perms,'') as perms, m.is_frame, 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 ur on rm.role_id = ur.role_id
+			 left join sys_role ro on ur.role_id = ro.role_id
+			 left join sys_user u on ur.user_id = u.user_id
+		where u.user_id = #{userId} and m.menu_type in ('M', 'C') and m.visible = 0  AND ro.status = 0
+		order by m.parent_id, m.order_num
+	</select>
+	
+	<select id="selectMenuListByRoleId" parameterType="Long" resultType="Integer">
+		select m.menu_id, m.parent_id
+		from sys_menu m
+            left join sys_role_menu rm on m.menu_id = rm.menu_id
+        where rm.role_id = #{roleId}
+        	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})
+		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 ur on rm.role_id = ur.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 ur on rm.role_id = ur.role_id
+		where ur.user_id = #{userId}
+	</select>
+	
+	<select id="selectMenuById" parameterType="Long" resultMap="SysMenuResult">
+		<include refid="selectMenuVo"/>
+		where menu_id = #{menuId}
+	</select>
+	
+	<select id="hasChildByMenuId" resultType="Integer">
+	    select count(1) from sys_menu where parent_id = #{menuId}  
+	</select>
+	
+	<select id="checkMenuNameUnique" parameterType="SysMenu" resultMap="SysMenuResult">
+		<include refid="selectMenuVo"/>
+		where menu_name=#{menuName} and parent_id = #{parentId}
+	</select>
+	
+	<update id="updateMenu" parameterType="SysMenu">
+		update sys_menu
+		<set>
+			<if test="menuName != null and menuName != ''">menu_name = #{menuName},</if>
+			<if test="parentId != null and parentId != 0">parent_id = #{parentId},</if>
+			<if test="orderNum != null and orderNum != ''">order_num = #{orderNum},</if>
+			<if test="path != null and path != ''">path = #{path},</if>
+			<if test="component != null and component != ''">component = #{component},</if>
+			<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
+			<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
+			<if test="visible != null">visible = #{visible},</if>
+			<if test="perms !=null">perms = #{perms},</if>
+			<if test="icon !=null and icon != ''">icon = #{icon},</if>
+			<if test="remark != null and remark != ''">remark = #{remark},</if>
+			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+			update_time = sysdate()
+		</set>
+		where menu_id = #{menuId}
+	</update>
+
+	<insert id="insertMenu" parameterType="SysMenu">
+		insert into sys_menu(
+		<if test="menuId != null and menuId != 0">menu_id,</if>
+		<if test="parentId != null and parentId != 0">parent_id,</if>
+		<if test="menuName != null and menuName != ''">menu_name,</if>
+		<if test="orderNum != null and orderNum != ''">order_num,</if>
+		<if test="path != null and path != ''">path,</if>
+		<if test="component != null and component != ''">component,</if>
+		<if test="isFrame != null and isFrame != ''">is_frame,</if>
+		<if test="menuType != null and menuType != ''">menu_type,</if>
+		<if test="visible != null">visible,</if>
+		<if test="perms !=null and perms != ''">perms,</if>
+		<if test="icon != null and icon != ''">icon,</if>
+		<if test="remark != null and remark != ''">remark,</if>
+		<if test="createBy != null and createBy != ''">create_by,</if>
+		create_time
+		)values(
+		<if test="menuId != null and menuId != 0">#{menuId},</if>
+		<if test="parentId != null and parentId != 0">#{parentId},</if>
+		<if test="menuName != null and menuName != ''">#{menuName},</if>
+		<if test="orderNum != null and orderNum != ''">#{orderNum},</if>
+		<if test="path != null and path != ''">#{path},</if>
+		<if test="component != null and component != ''">#{component},</if>
+		<if test="isFrame != null and isFrame != ''">#{isFrame},</if>
+		<if test="menuType != null and menuType != ''">#{menuType},</if>
+		<if test="visible != null">#{visible},</if>
+		<if test="perms !=null and perms != ''">#{perms},</if>
+		<if test="icon != null and icon != ''">#{icon},</if>
+		<if test="remark != null and remark != ''">#{remark},</if>
+		<if test="createBy != null and createBy != ''">#{createBy},</if>
+		sysdate()
+		)
+	</insert>
+	
+	<delete id="deleteMenuById" parameterType="Long">
+	    delete from sys_menu where menu_id = #{menuId}
+	</delete>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml
new file mode 100644
index 0000000..952e92f
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysNoticeMapper.xml
@@ -0,0 +1,82 @@
+<?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="com.ruoyi.project.system.mapper.SysNoticeMapper">
+    
+    <resultMap type="SysNotice" id="SysNoticeResult">
+        <result property="noticeId"       column="notice_id"       />
+        <result property="noticeTitle"    column="notice_title"    />
+        <result property="noticeType"     column="notice_type"     />
+        <result property="noticeContent"  column="notice_content"  />
+        <result property="status"         column="status"          />
+        <result property="createBy"       column="create_by"       />
+        <result property="createTime"     column="create_time"     />
+        <result property="updateBy"       column="update_by"       />
+        <result property="updateTime"     column="update_time"     />
+        <result property="remark"         column="remark"          />
+    </resultMap>
+    
+    <sql id="selectNoticeVo">
+        select notice_id, notice_title, notice_type, notice_content, status, create_by, create_time, update_by, update_time, remark 
+		from sys_notice
+    </sql>
+    
+    <select id="selectNoticeById" parameterType="Long" resultMap="SysNoticeResult">
+        <include refid="selectNoticeVo"/>
+        where notice_id = #{noticeId}
+    </select>
+    
+    <select id="selectNoticeList" parameterType="SysNotice" resultMap="SysNoticeResult">
+        <include refid="selectNoticeVo"/>
+        <where>
+			<if test="noticeTitle != null and noticeTitle != ''">
+				AND notice_title like concat('%', #{noticeTitle}, '%')
+			</if>
+			<if test="noticeType != null and noticeType != ''">
+				AND notice_type = #{noticeType}
+			</if>
+			<if test="createBy != null and createBy != ''">
+				AND create_by like concat('%', #{createBy}, '%')
+			</if>
+		</where>
+    </select>
+    
+    <insert id="insertNotice" parameterType="SysNotice">
+        insert into sys_notice (
+			<if test="noticeTitle != null and noticeTitle != '' ">notice_title, </if>
+			<if test="noticeType != null and noticeType != '' ">notice_type, </if>
+			<if test="noticeContent != null and noticeContent != '' ">notice_content, </if>
+			<if test="status != null and status != '' ">status, </if>
+			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+			<if test="noticeTitle != null and noticeTitle != ''">#{noticeTitle}, </if>
+			<if test="noticeType != null and noticeType != ''">#{noticeType}, </if>
+			<if test="noticeContent != null and noticeContent != ''">#{noticeContent}, </if>
+			<if test="status != null and status != ''">#{status}, </if>
+			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+		)
+    </insert>
+	 
+    <update id="updateNotice" parameterType="SysNotice">
+        update sys_notice 
+        <set>
+            <if test="noticeTitle != null and noticeTitle != ''">notice_title = #{noticeTitle}, </if>
+            <if test="noticeType != null and noticeType != ''">notice_type = #{noticeType}, </if>
+            <if test="noticeContent != null">notice_content = #{noticeContent}, </if>
+            <if test="status != null and status != ''">status = #{status}, </if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+        </set>
+        where notice_id = #{noticeId}
+    </update>
+	
+    <delete id="deleteNoticeById" parameterType="Long">
+        delete from sys_notice where notice_id = #{noticeId}
+    </delete>
+    
+</mapper>
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml
new file mode 100644
index 0000000..232136c
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysPostMapper.xml
@@ -0,0 +1,115 @@
+<?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="com.ruoyi.project.system.mapper.SysPostMapper">
+
+	<resultMap type="SysPost" id="SysPostResult">
+		<id     property="postId"        column="post_id"       />
+		<result property="postCode"      column="post_code"     />
+		<result property="postName"      column="post_name"     />
+		<result property="postSort"      column="post_sort"     />
+		<result property="status"        column="status"        />
+		<result property="createBy"      column="create_by"     />
+		<result property="createTime"    column="create_time"   />
+		<result property="updateBy"      column="update_by"     />
+		<result property="updateTime"    column="update_time"   />
+		<result property="remark"        column="remark"        />
+	</resultMap>
+	
+	<sql id="selectPostVo">
+        select post_id, post_code, post_name, post_sort, status, create_by, create_time, remark 
+		from sys_post
+    </sql>
+	
+	<select id="selectPostList" parameterType="SysPost" resultMap="SysPostResult">
+	    <include refid="selectPostVo"/>
+		<where>
+			<if test="postCode != null and postCode != ''">
+				AND post_code like concat('%', #{postCode}, '%')
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="postName != null and postName != ''">
+				AND post_name like concat('%', #{postName}, '%')
+			</if>
+		</where>
+	</select>
+	
+	<select id="selectPostAll" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+	</select>
+	
+	<select id="selectPostById" parameterType="Long" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+		where post_id = #{postId}
+	</select>
+	
+	<select id="selectPostListByUserId" parameterType="Long" resultType="Integer">
+		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>
+	
+	<select id="checkPostNameUnique" parameterType="String" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+		 where post_name=#{postName}
+	</select>
+	
+	<select id="checkPostCodeUnique" parameterType="String" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+		 where post_code=#{postCode}
+	</select>
+	
+	<update id="updatePost" parameterType="SysPost">
+ 		update sys_post
+ 		<set>
+ 			<if test="postCode != null and postCode != ''">post_code = #{postCode},</if>
+ 			<if test="postName != null and postName != ''">post_name = #{postName},</if>
+ 			<if test="postSort != null and postSort != ''">post_sort = #{postSort},</if>
+ 			<if test="status != null and status != ''">status = #{status},</if>
+ 			<if test="remark != null">remark = #{remark},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where post_id = #{postId}
+	</update>
+ 	
+ 	<insert id="insertPost" parameterType="SysPost" useGeneratedKeys="true" keyProperty="postId">
+ 		insert into sys_post(
+ 			<if test="postId != null and postId != 0">post_id,</if>
+ 			<if test="postCode != null and postCode != ''">post_code,</if>
+ 			<if test="postName != null and postName != ''">post_name,</if>
+ 			<if test="postSort != null and postSort != ''">post_sort,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 			<if test="postId != null and postId != 0">#{postId},</if>
+ 			<if test="postCode != null and postCode != ''">#{postCode},</if>
+ 			<if test="postName != null and postName != ''">#{postName},</if>
+ 			<if test="postSort != null and postSort != ''">#{postSort},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+	<delete id="deletePostById" parameterType="Long">
+		delete from sys_post where post_id = #{postId}
+	</delete>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysRoleDeptMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysRoleDeptMapper.xml
new file mode 100644
index 0000000..acda245
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysRoleDeptMapper.xml
@@ -0,0 +1,34 @@
+<?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="com.ruoyi.project.system.mapper.SysRoleDeptMapper">
+
+	<resultMap type="SysRoleDept" id="SysRoleDeptResult">
+		<result property="roleId"     column="role_id"      />
+		<result property="deptId"     column="dept_id"      />
+	</resultMap>
+
+	<delete id="deleteRoleDeptByRoleId" parameterType="Long">
+		delete from sys_role_dept where role_id=#{roleId}
+	</delete>
+	
+	<select id="selectCountRoleDeptByDeptId" resultType="Integer">
+	    select count(1) from sys_role_dept where dept_id=#{deptId}
+	</select>
+	
+	<delete id="deleteRoleDept" parameterType="Long">
+ 		delete from sys_role_dept where role_id in
+ 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
+ 			#{roleId}
+        </foreach> 
+ 	</delete>
+	
+	<insert id="batchRoleDept">
+		insert into sys_role_dept(role_id, dept_id) values
+		<foreach item="item" index="index" collection="list" separator=",">
+			(#{item.roleId},#{item.deptId})
+		</foreach>
+	</insert>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml
new file mode 100644
index 0000000..4d62760
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysRoleMapper.xml
@@ -0,0 +1,137 @@
+<?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="com.ruoyi.project.system.mapper.SysRoleMapper">
+
+	<resultMap type="SysRole" id="SysRoleResult">
+		<id     property="roleId"       column="role_id"        />
+		<result property="roleName"     column="role_name"      />
+		<result property="roleKey"      column="role_key"       />
+		<result property="roleSort"     column="role_sort"      />
+		<result property="dataScope"    column="data_scope"     />
+		<result property="status"       column="status"         />
+		<result property="delFlag"      column="del_flag"       />
+		<result property="createBy"     column="create_by"      />
+		<result property="createTime"   column="create_time"    />
+		<result property="updateBy"     column="update_by"      />
+		<result property="updateTime"   column="update_time"    />
+		<result property="remark"       column="remark"         />
+	</resultMap>
+	
+	<sql id="selectRoleVo">
+	    select distinct r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope,
+            r.status, r.del_flag, r.create_time, r.remark 
+        from sys_role r
+	        left join sys_user_role ur on ur.role_id = r.role_id
+	        left join sys_user u on u.user_id = ur.user_id
+	        left join sys_dept d on u.dept_id = d.dept_id
+    </sql>
+    
+    <select id="selectRoleList" parameterType="SysRole" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		where r.del_flag = '0'
+		<if test="roleName != null and roleName != ''">
+			AND r.role_name like concat('%', #{roleName}, '%')
+		</if>
+		<if test="status != null and status != ''">
+			AND r.status = #{status}
+		</if>
+		<if test="roleKey != null and roleKey != ''">
+			AND r.role_key like concat('%', #{roleKey}, '%')
+		</if>
+		<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+			and date_format(r.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+		</if>
+		<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+			and date_format(r.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+		</if>
+		<!-- 鏁版嵁鑼冨洿杩囨护 -->
+		${dataScope}
+	</select>
+    
+	<select id="selectRolePermissionByUserId" parameterType="Long" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		WHERE r.del_flag = '0' and ur.user_id = #{userId}
+	</select>
+	
+	<select id="selectRoleAll" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+	</select>
+	
+	<select id="selectRoleListByUserId" parameterType="Long" resultType="Integer">
+		select r.role_id
+        from sys_role r
+	        left join sys_user_role ur on ur.role_id = r.role_id
+	        left join sys_user u on u.user_id = ur.user_id
+	    where u.user_id = #{userId}
+	</select>
+	
+	<select id="selectRoleById" parameterType="Long" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		where r.role_id = #{roleId}
+	</select>
+	
+	<select id="selectRolesByUserName" parameterType="String" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		WHERE r.del_flag = '0' and u.user_name = #{userName}
+	</select>
+	
+	<select id="checkRoleNameUnique" parameterType="String" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		 where r.role_name=#{roleName}
+	</select>
+	
+	<select id="checkRoleKeyUnique" parameterType="String" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		 where r.role_key=#{roleKey}
+	</select>
+	
+ 	<insert id="insertRole" parameterType="SysRole" useGeneratedKeys="true" keyProperty="roleId">
+ 		insert into sys_role(
+ 			<if test="roleId != null and roleId != 0">role_id,</if>
+ 			<if test="roleName != null and roleName != ''">role_name,</if>
+ 			<if test="roleKey != null and roleKey != ''">role_key,</if>
+ 			<if test="roleSort != null and roleSort != ''">role_sort,</if>
+ 			<if test="dataScope != null and dataScope != ''">data_scope,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			create_time
+ 		)values(
+ 			<if test="roleId != null and roleId != 0">#{roleId},</if>
+ 			<if test="roleName != null and roleName != ''">#{roleName},</if>
+ 			<if test="roleKey != null and roleKey != ''">#{roleKey},</if>
+ 			<if test="roleSort != null and roleSort != ''">#{roleSort},</if>
+ 			<if test="dataScope != null and dataScope != ''">#{dataScope},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+	<update id="updateRole" parameterType="SysRole">
+ 		update sys_role
+ 		<set>
+ 			<if test="roleName != null and roleName != ''">role_name = #{roleName},</if>
+ 			<if test="roleKey != null and roleKey != ''">role_key = #{roleKey},</if>
+ 			<if test="roleSort != null and roleSort != ''">role_sort = #{roleSort},</if>
+ 			<if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if>
+ 			<if test="status != null and status != ''">status = #{status},</if>
+ 			<if test="remark != null">remark = #{remark},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where role_id = #{roleId}
+	</update>
+	
+	<update id="updateRoleStatus" parameterType="SysRole">
+ 		update sys_user set status = #{status} where user_id = #{userId}
+	</update>
+	
+	<delete id="deleteRoleById" parameterType="Long">
+ 		delete from sys_role where role_id = #{roleId}
+ 	</delete>
+ 	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysRoleMenuMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysRoleMenuMapper.xml
new file mode 100644
index 0000000..b7c5b6b
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysRoleMenuMapper.xml
@@ -0,0 +1,27 @@
+<?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="com.ruoyi.project.system.mapper.SysRoleMenuMapper">
+
+	<resultMap type="SysRoleMenu" id="SysRoleMenuResult">
+		<result property="roleId"     column="role_id"      />
+		<result property="menuId"     column="menu_id"      />
+	</resultMap>
+	
+	<select id="checkMenuExistRole" resultType="Integer">
+	    select count(1) from sys_role_menu where menu_id = #{menuId}  
+	</select>
+
+	<delete id="deleteRoleMenuByRoleId" parameterType="Long">
+		delete from sys_role_menu where role_id=#{roleId}
+	</delete>
+	
+	<insert id="batchRoleMenu">
+		insert into sys_role_menu(role_id, menu_id) values
+		<foreach item="item" index="index" collection="list" separator=",">
+			(#{item.roleId},#{item.menuId})
+		</foreach>
+	</insert>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml
new file mode 100644
index 0000000..eaf27a0
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysUserMapper.xml
@@ -0,0 +1,174 @@
+<?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="com.ruoyi.project.system.mapper.SysUserMapper">
+
+	<resultMap type="SysUser" id="SysUserResult">
+		<id     property="userId"       column="user_id"      />
+		<result property="deptId"       column="dept_id"      />
+		<result property="userName"     column="user_name"    />
+		<result property="nickName"     column="nick_name"    />
+		<result property="email"        column="email"        />
+		<result property="phonenumber"  column="phonenumber"  />
+		<result property="sex"          column="sex"          />
+		<result property="avatar"       column="avatar"       />
+		<result property="password"     column="password"     />
+		<result property="status"       column="status"       />
+		<result property="delFlag"      column="del_flag"     />
+		<result property="loginIp"      column="login_ip"     />
+		<result property="loginDate"    column="login_date"   />
+		<result property="createBy"     column="create_by"    />
+		<result property="createTime"   column="create_time"  />
+		<result property="updateBy"     column="update_by"    />
+		<result property="updateTime"   column="update_time"  />
+		<result property="remark"       column="remark"       />
+		<association property="dept"    column="dept_id" javaType="SysDept" resultMap="deptResult" />
+		<collection  property="roles"   javaType="java.util.List"        resultMap="RoleResult" />
+	</resultMap>
+	
+	<resultMap id="deptResult" type="SysDept">
+		<id     property="deptId"   column="dept_id"     />
+		<result property="parentId" column="parent_id"   />
+		<result property="deptName" column="dept_name"   />
+		<result property="orderNum" column="order_num"   />
+		<result property="leader"   column="leader"      />
+		<result property="status"   column="dept_status" />
+	</resultMap>
+	
+	<resultMap id="RoleResult" type="SysRole">
+		<id     property="roleId"       column="role_id"        />
+		<result property="roleName"     column="role_name"      />
+		<result property="roleKey"      column="role_key"       />
+		<result property="roleSort"     column="role_sort"      />
+		<result property="dataScope"     column="data_scope"    />
+		<result property="status"       column="role_status"    />
+	</resultMap>
+	
+	<sql id="selectUserVo">
+        select u.user_id, u.dept_id, u.user_name, u.nick_name, 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.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 ur on u.user_id = ur.user_id
+		    left join sys_role r on r.role_id = ur.role_id
+    </sql>
+    
+    <select id="selectUserList" parameterType="SysUser" resultMap="SysUserResult">
+		<include refid="selectUserVo"/>
+		where u.del_flag = '0'
+		<if test="userName != null and userName != ''">
+			AND u.user_name like concat('%', #{userName}, '%')
+		</if>
+		<if test="status != null and status != ''">
+			AND u.status = #{status}
+		</if>
+		<if test="phonenumber != null and phonenumber != ''">
+			AND u.phonenumber like concat('%', #{phonenumber}, '%')
+		</if>
+		<if test="params.beginTime != null and params.beginTime != ''"><!-- 寮�濮嬫椂闂存绱� -->
+			AND date_format(u.create_time,'%y%m%d') &gt;= date_format(#{params.beginTime},'%y%m%d')
+		</if>
+		<if test="params.endTime != null and params.endTime != ''"><!-- 缁撴潫鏃堕棿妫�绱� -->
+			AND date_format(u.create_time,'%y%m%d') &lt;= date_format(#{params.endTime},'%y%m%d')
+		</if>
+		<if test="deptId != null and deptId != 0">
+			AND (u.dept_id = #{deptId} OR u.dept_id IN ( SELECT t.dept_id FROM sys_dept t WHERE FIND_IN_SET (#{deptId},ancestors) ))
+		</if>
+		<!-- 鏁版嵁鑼冨洿杩囨护 -->
+		${dataScope}
+	</select>
+	
+	<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
+	    <include refid="selectUserVo"/>
+		where u.user_name = #{userName}
+	</select>
+	
+	<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
+		<include refid="selectUserVo"/>
+		where u.user_id = #{userId}
+	</select>
+	
+	<select id="checkUserNameUnique" parameterType="String" resultType="int">
+		select count(1) from sys_user where user_name = #{userName}
+	</select>
+	
+	<select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
+		select user_id, phonenumber from sys_user where phonenumber = #{phonenumber}
+	</select>
+	
+	<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
+		select user_id, email from sys_user where email = #{email}
+	</select>
+	
+	<insert id="insertUser" parameterType="SysUser" useGeneratedKeys="true" keyProperty="userId">
+ 		insert into sys_user(
+ 			<if test="userId != null and userId != 0">user_id,</if>
+ 			<if test="deptId != null and deptId != 0">dept_id,</if>
+ 			<if test="userName != null and userName != ''">user_name,</if>
+ 			<if test="nickName != null and nickName != ''">nick_name,</if>
+ 			<if test="email != null and email != ''">email,</if>
+ 			<if test="avatar != null and avatar != ''">avatar,</if>
+ 			<if test="phonenumber != null and phonenumber != ''">phonenumber,</if>
+ 			<if test="sex != null and sex != ''">sex,</if>
+ 			<if test="password != null and password != ''">password,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+ 			<if test="remark != null and remark != ''">remark,</if>
+ 			create_time
+ 		)values(
+ 			<if test="userId != null and userId != ''">#{userId},</if>
+ 			<if test="deptId != null and deptId != ''">#{deptId},</if>
+ 			<if test="userName != null and userName != ''">#{userName},</if>
+ 			<if test="nickName != null and nickName != ''">#{nickName},</if>
+ 			<if test="email != null and email != ''">#{email},</if>
+ 			<if test="avatar != null and avatar != ''">#{avatar},</if>
+ 			<if test="phonenumber != null and phonenumber != ''">#{phonenumber},</if>
+ 			<if test="sex != null and sex != ''">#{sex},</if>
+ 			<if test="password != null and password != ''">#{password},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+ 			<if test="remark != null and remark != ''">#{remark},</if>
+ 			sysdate()
+ 		)
+	</insert>
+	
+	<update id="updateUser" parameterType="SysUser">
+ 		update sys_user
+ 		<set>
+ 			<if test="deptId != null and deptId != 0">dept_id = #{deptId},</if>
+ 			<if test="userName != null and userName != ''">user_name = #{userName},</if>
+ 			<if test="nickName != null and nickName != ''">nick_name = #{nickName},</if>
+ 			<if test="email != null and email != ''">email = #{email},</if>
+ 			<if test="phonenumber != null and phonenumber != ''">phonenumber = #{phonenumber},</if>
+ 			<if test="sex != null and sex != ''">sex = #{sex},</if>
+ 			<if test="avatar != null and avatar != ''">avatar = #{avatar},</if>
+ 			<if test="password != null and password != ''">password = #{password},</if>
+ 			<if test="status != null and status != ''">status = #{status},</if>
+ 			<if test="loginIp != null and loginIp != ''">login_ip = #{loginIp},</if>
+ 			<if test="loginDate != null">login_date = #{loginDate},</if>
+ 			<if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+ 			<if test="remark != null">remark = #{remark},</if>
+ 			update_time = sysdate()
+ 		</set>
+ 		where user_id = #{userId}
+	</update>
+	
+	<update id="updateUserStatus" parameterType="SysUser">
+ 		update sys_user set status = #{status} where user_id = #{userId}
+	</update>
+	
+	<update id="updateUserAvatar" parameterType="SysUser">
+ 		update sys_user set avatar = #{avatar} where user_name = #{userName}
+	</update>
+	
+	<update id="resetUserPwd" parameterType="SysUser">
+ 		update sys_user set password = #{password} where user_name = #{userName}
+	</update>
+	
+	<delete id="deleteUserById" parameterType="Long">
+ 		delete from sys_user where user_id = #{userId}
+ 	</delete>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysUserPostMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysUserPostMapper.xml
new file mode 100644
index 0000000..d634c8b
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysUserPostMapper.xml
@@ -0,0 +1,34 @@
+<?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="com.ruoyi.project.system.mapper.SysUserPostMapper">
+
+	<resultMap type="SysUserPost" id="SysUserPostResult">
+		<result property="userId"     column="user_id"      />
+		<result property="postId"     column="post_id"      />
+	</resultMap>
+
+	<delete id="deleteUserPostByUserId" parameterType="Long">
+		delete from sys_user_post where user_id=#{userId}
+	</delete>
+	
+	<select id="countUserPostById" resultType="Integer">
+	    select count(1) from sys_user_post where post_id=#{postId}  
+	</select>
+	
+	<delete id="deleteUserPost" parameterType="Long">
+ 		delete from sys_user_post where user_id in
+ 		<foreach collection="array" item="userId" open="(" separator="," close=")">
+ 			#{userId}
+        </foreach> 
+ 	</delete>
+	
+	<insert id="batchUserPost">
+		insert into sys_user_post(user_id, post_id) values
+		<foreach item="item" index="index" collection="list" separator=",">
+			(#{item.userId},#{item.postId})
+		</foreach>
+	</insert>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi/src/main/resources/mybatis/system/SysUserRoleMapper.xml b/ruoyi/src/main/resources/mybatis/system/SysUserRoleMapper.xml
new file mode 100644
index 0000000..3422b1c
--- /dev/null
+++ b/ruoyi/src/main/resources/mybatis/system/SysUserRoleMapper.xml
@@ -0,0 +1,44 @@
+<?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="com.ruoyi.project.system.mapper.SysUserRoleMapper">
+
+	<resultMap type="SysUserRole" id="SysUserRoleResult">
+		<result property="userId"     column="user_id"      />
+		<result property="roleId"     column="role_id"      />
+	</resultMap>
+
+	<delete id="deleteUserRoleByUserId" parameterType="Long">
+		delete from sys_user_role where user_id=#{userId}
+	</delete>
+	
+	<select id="countUserRoleByRoleId" resultType="Integer">
+	    select count(1) from sys_user_role where role_id=#{roleId}  
+	</select>
+	
+	<delete id="deleteUserRole" parameterType="Long">
+ 		delete from sys_user_role where user_id in
+ 		<foreach collection="array" item="userId" open="(" separator="," close=")">
+ 			#{userId}
+        </foreach> 
+ 	</delete>
+	
+	<insert id="batchUserRole">
+		insert into sys_user_role(user_id, role_id) values
+		<foreach item="item" index="index" collection="list" separator=",">
+			(#{item.userId},#{item.roleId})
+		</foreach>
+	</insert>
+	
+	<delete id="deleteUserRoleInfo" parameterType="SysUserRole">
+		delete from sys_user_role where user_id=#{userId} and role_id=#{roleId}
+	</delete>
+	
+	<delete id="deleteUserRoleInfos">
+	    delete from sys_user_role where role_id=#{roleId} and user_id in
+ 	    <foreach collection="userIds" item="userId" open="(" separator="," close=")">
+ 	        #{userId}
+            </foreach> 
+	</delete>
+</mapper> 
\ No newline at end of file

--
Gitblit v1.9.3