From e82aea57867f8b9a10f9041e1c264b13d8b1fcbb Mon Sep 17 00:00:00 2001
From: zzc <Zhengzhic18@163.com>
Date: Sat, 8 Feb 2025 17:31:51 +0800
Subject: [PATCH] =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .github/FUNDING.yml                           |    2 +-
 LICENSE                                       |    2 +-
 README.md                                     |   95 -
 {ruoyi-admin => acupuncture-admin}/pom.xml    |  190 +-
 .../acupuncture/AcupunctureApplication.java   |   60 +-
 .../acupuncture}/RuoYiServletInitializer.java |   36 +-
 .../controller/common/CaptchaController.java  |  188 +-
 .../controller/common/CommonController.java   |  326 +-
 .../controller/monitor/CacheController.java   |  242 +-
 .../controller/monitor/ServerController.java  |   54 +-
 .../monitor/SysLogininforController.java      |  164 +-
 .../monitor/SysOperlogController.java         |  138 +-
 .../monitor/SysUserOnlineController.java      |  166 +-
 .../system/SysConfigController.java           |  266 +-
 .../controller/system/SysDeptController.java  |  264 +-
 .../system/SysDictDataController.java         |  242 +-
 .../system/SysDictTypeController.java         |  262 +-
 .../controller/system/SysIndexController.java |   58 +-
 .../controller/system/SysLoginController.java |  194 +-
 .../controller/system/SysMenuController.java  |  282 +-
 .../system/SysNoticeController.java           |  182 +-
 .../controller/system/SysPostController.java  |  258 +-
 .../system/SysProfileController.java          |  280 +-
 .../system/SysRegisterController.java         |   76 +-
 .../controller/system/SysRoleController.java  |  524 +--
 .../controller/system/SysUserController.java  |  512 +--
 .../web/controller/tool/TestController.java   |  366 +-
 .../web/core/config/SwaggerConfig.java        |  250 +-
 .../META-INF/spring-devtools.properties       |    0
 .../src/main/resources/application-druid.yml  |  120 +-
 .../src/main/resources/application.yml        |  258 +-
 .../src/main/resources/banner.txt             |   46 +-
 .../main/resources/i18n/messages.properties   |   76 +-
 .../src/main/resources/logback.xml            |  184 +-
 .../main/resources/mybatis/mybatis-config.xml |   40 +-
 {ruoyi-common => acupuncture-common}/pom.xml  |  246 +-
 .../common/annotation/Anonymous.java          |   38 +-
 .../common/annotation/DataScope.java          |   66 +-
 .../common/annotation/DataSource.java         |   56 +-
 .../acupuncture}/common/annotation/Excel.java |  392 +-
 .../common/annotation/Excels.java             |   36 +-
 .../acupuncture}/common/annotation/Log.java   |  102 +-
 .../common/annotation/RateLimiter.java        |   80 +-
 .../common/annotation/RepeatSubmit.java       |   62 +-
 .../common/annotation/Sensitive.java          |    8 +-
 .../common/config/RuoYiConfig.java            |  244 +-
 .../serializer/SensitiveJsonSerializer.java   |   12 +-
 .../common/constant/CacheConstants.java       |   88 +-
 .../common/constant/Constants.java            |  346 +-
 .../common/constant/GenConstants.java         |  234 +-
 .../common/constant/HttpStatus.java           |  188 +-
 .../common/constant/ScheduleConstants.java    |  100 +-
 .../common/constant/UserConstants.java        |  162 +-
 .../core/controller/BaseController.java       |  404 +-
 .../common/core/domain/AjaxResult.java        |  432 +-
 .../common/core/domain/BaseEntity.java        |  236 +-
 .../acupuncture}/common/core/domain/R.java    |    6 +-
 .../common/core/domain/TreeEntity.java        |  158 +-
 .../common/core/domain/TreeSelect.java        |  186 +-
 .../common/core/domain/entity/SysDept.java    |  406 +-
 .../core/domain/entity/SysDictData.java       |  352 +-
 .../core/domain/entity/SysDictType.java       |  192 +-
 .../common/core/domain/entity/SysMenu.java    |  548 +--
 .../common/core/domain/entity/SysRole.java    |  482 +--
 .../common/core/domain/entity/SysUser.java    |  648 +--
 .../common/core/domain/model/LoginBody.java   |  138 +-
 .../common/core/domain/model/LoginUser.java   |  532 +--
 .../core/domain/model/RegisterBody.java       |   22 +-
 .../common/core/page/PageDomain.java          |    6 +-
 .../common/core/page/TableDataInfo.java       |  170 +-
 .../common/core/page/TableSupport.java        |  112 +-
 .../common/core/redis/RedisCache.java         |  536 +--
 .../common/core/text/CharsetKit.java          |  172 +-
 .../common/core/text/Convert.java             | 2020 ++++-----
 .../common/core/text/StrFormatter.java        |  184 +-
 .../common/enums/BusinessStatus.java          |   40 +-
 .../common/enums/BusinessType.java            |  118 +-
 .../common/enums/DataSourceType.java          |   38 +-
 .../common/enums/DesensitizedType.java        |    6 +-
 .../acupuncture}/common/enums/HttpMethod.java |   72 +-
 .../acupuncture}/common/enums/LimitType.java  |   40 +-
 .../common/enums/OperatorType.java            |   48 +-
 .../acupuncture}/common/enums/UserStatus.java |   60 +-
 .../common/exception/DemoModeException.java   |   30 +-
 .../common/exception/GlobalException.java     |  114 +-
 .../common/exception/ServiceException.java    |  146 +-
 .../common/exception/UtilException.java       |   52 +-
 .../common/exception/base/BaseException.java  |  194 +-
 .../common/exception/file/FileException.java  |   38 +-
 .../FileNameLengthLimitExceededException.java |   32 +-
 .../file/FileSizeLimitExceededException.java  |   32 +-
 .../exception/file/FileUploadException.java   |    4 +-
 .../file/InvalidExtensionException.java       |  160 +-
 .../common/exception/job/TaskException.java   |   66 +-
 .../exception/user/BlackListException.java    |    4 +-
 .../exception/user/CaptchaException.java      |   32 +-
 .../user/CaptchaExpireException.java          |   32 +-
 .../common/exception/user/UserException.java  |   36 +-
 .../user/UserNotExistsException.java          |    4 +-
 .../user/UserPasswordNotMatchException.java   |   32 +-
 ...UserPasswordRetryLimitExceedException.java |   32 +-
 .../filter/PropertyPreExcludeFilter.java      |   48 +-
 .../common/filter/RepeatableFilter.java       |  104 +-
 .../filter/RepeatedlyRequestWrapper.java      |  152 +-
 .../acupuncture}/common/filter/XssFilter.java |  148 +-
 .../filter/XssHttpServletRequestWrapper.java  |  220 +-
 .../com/acupuncture}/common/utils/Arith.java  |    4 +-
 .../acupuncture}/common/utils/DateUtils.java  |  382 +-
 .../common/utils/DesensitizedUtil.java        |    4 +-
 .../acupuncture}/common/utils/DictUtils.java  |  478 +--
 .../common/utils/ExceptionUtil.java           |   78 +-
 .../acupuncture}/common/utils/LogUtils.java   |   36 +-
 .../common/utils/MessageUtils.java            |   52 +-
 .../acupuncture}/common/utils/PageUtils.java  |   10 +-
 .../common/utils/SecurityUtils.java           |  356 +-
 .../common/utils/ServletUtils.java            |  436 +-
 .../common/utils/StringUtils.java             | 1366 +++---
 .../acupuncture}/common/utils/Threads.java    |  198 +-
 .../common/utils/bean/BeanUtils.java          |  220 +-
 .../common/utils/bean/BeanValidators.java     |   48 +-
 .../common/utils/file/FileTypeUtils.java      |  150 +-
 .../common/utils/file/FileUploadUtils.java    |  464 +-
 .../common/utils/file/FileUtils.java          |  582 +--
 .../common/utils/file/ImageUtils.java         |  196 +-
 .../common/utils/file/MimeTypeUtils.java      |  118 +-
 .../common/utils/html/EscapeUtil.java         |  334 +-
 .../common/utils/html/HTMLFilter.java         | 1138 ++---
 .../common/utils/http/HttpHelper.java         |  110 +-
 .../common/utils/http/HttpUtils.java          |  546 +--
 .../common/utils/ip/AddressUtils.java         |  112 +-
 .../acupuncture}/common/utils/ip/IpUtils.java |  762 ++--
 .../common/utils/poi/ExcelHandlerAdapter.java |   48 +-
 .../common/utils/poi/ExcelUtil.java           | 3800 ++++++++---------
 .../common/utils/reflect/ReflectUtils.java    |  820 ++--
 .../common/utils/sign/Base64.java             |  582 +--
 .../common/utils/sign/Md5Utils.java           |  134 +-
 .../common/utils/spring/SpringUtils.java      |  316 +-
 .../common/utils/sql/SqlUtil.java             |  140 +-
 .../common/utils/uuid/IdUtils.java            |   98 +-
 .../acupuncture}/common/utils/uuid/Seq.java   |  172 +-
 .../acupuncture}/common/utils/uuid/UUID.java  |  968 ++---
 .../java/com/acupuncture}/common/xss/Xss.java |   54 +-
 .../acupuncture}/common/xss/XssValidator.java |   76 +-
 .../pom.xml                                   |  126 +-
 .../framework/aspectj/DataScopeAspect.java    |  368 +-
 .../framework/aspectj/DataSourceAspect.java   |  144 +-
 .../framework/aspectj/LogAspect.java          |  508 +--
 .../framework/aspectj/RateLimiterAspect.java  |  178 +-
 .../framework/config/ApplicationConfig.java   |   60 +-
 .../framework/config/CaptchaConfig.java       |    6 +-
 .../framework/config/DruidConfig.java         |  252 +-
 .../config/FastJson2JsonRedisSerializer.java  |  104 +-
 .../framework/config/FilterConfig.java        |  116 +-
 .../framework/config/I18nConfig.java          |    6 +-
 .../framework/config/KaptchaTextCreator.java  |    4 +-
 .../framework/config/MyBatisConfig.java       |  262 +-
 .../framework/config/RedisConfig.java         |  138 +-
 .../framework/config/ResourcesConfig.java     |  144 +-
 .../framework/config/SecurityConfig.java      |  278 +-
 .../framework/config/ServerConfig.java        |   64 +-
 .../framework/config/ThreadPoolConfig.java    |  126 +-
 .../config/properties/DruidProperties.java    |  178 +-
 .../properties/PermitAllUrlProperties.java    |  146 +-
 .../datasource/DynamicDataSource.java         |   50 +-
 .../DynamicDataSourceContextHolder.java       |   90 +-
 .../interceptor/RepeatSubmitInterceptor.java  |  112 +-
 .../impl/SameUrlDataInterceptor.java          |  220 +-
 .../framework/manager/AsyncManager.java       |  110 +-
 .../framework/manager/ShutdownManager.java    |   78 +-
 .../manager/factory/AsyncFactory.java         |  204 +-
 .../context/AuthenticationContextHolder.java  |   56 +-
 .../context/PermissionContextHolder.java      |   54 +-
 .../filter/JwtAuthenticationTokenFilter.java  |   88 +-
 .../handle/AuthenticationEntryPointImpl.java  |   68 +-
 .../handle/LogoutSuccessHandlerImpl.java      |  106 +-
 .../framework/web/domain/Server.java          |  480 +--
 .../framework/web/domain/server/Cpu.java      |  202 +-
 .../framework/web/domain/server/Jvm.java      |  260 +-
 .../framework/web/domain/server/Mem.java      |  122 +-
 .../framework/web/domain/server/Sys.java      |  168 +-
 .../framework/web/domain/server/SysFile.java  |  228 +-
 .../web/exception/GlobalExceptionHandler.java |  290 +-
 .../web/service/PermissionService.java        |  318 +-
 .../web/service/SysLoginService.java          |  362 +-
 .../web/service/SysPasswordService.java       |  172 +-
 .../web/service/SysPermissionService.java     |  176 +-
 .../web/service/SysRegisterService.java       |  230 +-
 .../framework/web/service/TokenService.java   |  462 +-
 .../web/service/UserDetailsServiceImpl.java   |  132 +-
 .../pom.xml                                   |   78 +-
 .../generator/config/GenConfig.java           |  174 +-
 .../generator/controller/GenController.java   |  524 +--
 .../generator/domain/GenTable.java            |  768 ++--
 .../generator/domain/GenTableColumn.java      |  746 ++--
 .../mapper/GenTableColumnMapper.java          |  120 +-
 .../generator/mapper/GenTableMapper.java      |  182 +-
 .../service/GenTableColumnServiceImpl.java    |  136 +-
 .../service/GenTableServiceImpl.java          | 1060 ++---
 .../service/IGenTableColumnService.java       |   88 +-
 .../generator/service/IGenTableService.java   |  260 +-
 .../acupuncture}/generator/util/GenUtils.java |  514 +--
 .../generator/util/VelocityInitializer.java   |   68 +-
 .../generator/util/VelocityUtils.java         |  816 ++--
 .../src/main/resources/generator.yml          |   22 +-
 .../mapper/generator/GenTableColumnMapper.xml |  252 +-
 .../mapper/generator/GenTableMapper.xml       |  418 +-
 .../main/resources/vm/java/controller.java.vm |   12 +-
 .../src/main/resources/vm/java/domain.java.vm |  206 +-
 .../src/main/resources/vm/java/mapper.java.vm |    0
 .../main/resources/vm/java/service.java.vm    |  122 +-
 .../resources/vm/java/serviceImpl.java.vm     |  338 +-
 .../main/resources/vm/java/sub-domain.java.vm |  149 +-
 .../src/main/resources/vm/js/api.js.vm        |   88 +-
 .../src/main/resources/vm/sql/sql.vm          |   42 +-
 .../main/resources/vm/vue/index-tree.vue.vm   | 1010 ++---
 .../src/main/resources/vm/vue/index.vue.vm    | 1204 +++---
 .../resources/vm/vue/v3/index-tree.vue.vm     |    0
 .../src/main/resources/vm/vue/v3/index.vue.vm |    0
 .../src/main/resources/vm/xml/mapper.xml.vm   |  278 +-
 {ruoyi-quartz => acupuncture-quartz}/pom.xml  |   78 +-
 .../quartz/config/ScheduleConfig.java         |  114 +-
 .../quartz/controller/SysJobController.java   |  370 +-
 .../controller/SysJobLogController.java       |  184 +-
 .../acupuncture}/quartz/domain/SysJob.java    |  342 +-
 .../acupuncture}/quartz/domain/SysJobLog.java |  310 +-
 .../quartz/mapper/SysJobLogMapper.java        |  128 +-
 .../quartz/mapper/SysJobMapper.java           |  134 +-
 .../quartz/service/ISysJobLogService.java     |  112 +-
 .../quartz/service/ISysJobService.java        |  204 +-
 .../service/impl/SysJobLogServiceImpl.java    |  174 +-
 .../service/impl/SysJobServiceImpl.java       |  522 +--
 .../com/acupuncture}/quartz/task/RyTask.java  |   56 +-
 .../quartz/util/AbstractQuartzJob.java        |  214 +-
 .../acupuncture}/quartz/util/CronUtils.java   |  126 +-
 .../quartz/util/JobInvokeUtil.java            |  364 +-
 .../QuartzDisallowConcurrentExecution.java    |   42 +-
 .../quartz/util/QuartzJobExecution.java       |   38 +-
 .../quartz/util/ScheduleUtils.java            |  282 +-
 .../mapper/quartz/SysJobLogMapper.xml         |  186 +-
 .../resources/mapper/quartz/SysJobMapper.xml  |  220 +-
 {ruoyi-system => acupuncture-system}/pom.xml  |   54 +-
 .../acupuncture}/system/domain/SysCache.java  |  162 +-
 .../acupuncture}/system/domain/SysConfig.java |  222 +-
 .../system/domain/SysLogininfor.java          |  288 +-
 .../acupuncture}/system/domain/SysNotice.java |  204 +-
 .../system/domain/SysOperLog.java             |  538 +--
 .../acupuncture}/system/domain/SysPost.java   |  248 +-
 .../system/domain/SysRoleDept.java            |   92 +-
 .../system/domain/SysRoleMenu.java            |   92 +-
 .../system/domain/SysUserOnline.java          |  226 +-
 .../system/domain/SysUserPost.java            |   92 +-
 .../system/domain/SysUserRole.java            |   92 +-
 .../acupuncture}/system/domain/vo/MetaVo.java |  212 +-
 .../system/domain/vo/RouterVo.java            |  296 +-
 .../system/mapper/SysConfigMapper.java        |  152 +-
 .../system/mapper/SysDeptMapper.java          |  236 +-
 .../system/mapper/SysDictDataMapper.java      |  190 +-
 .../system/mapper/SysDictTypeMapper.java      |  166 +-
 .../system/mapper/SysLogininforMapper.java    |   84 +-
 .../system/mapper/SysMenuMapper.java          |  250 +-
 .../system/mapper/SysNoticeMapper.java        |  120 +-
 .../system/mapper/SysOperLogMapper.java       |   96 +-
 .../system/mapper/SysPostMapper.java          |  198 +-
 .../system/mapper/SysRoleDeptMapper.java      |   88 +-
 .../system/mapper/SysRoleMapper.java          |  214 +-
 .../system/mapper/SysRoleMenuMapper.java      |   88 +-
 .../system/mapper/SysUserMapper.java          |  254 +-
 .../system/mapper/SysUserPostMapper.java      |   88 +-
 .../system/mapper/SysUserRoleMapper.java      |  124 +-
 .../system/service/ISysConfigService.java     |  178 +-
 .../system/service/ISysDeptService.java       |  248 +-
 .../system/service/ISysDictDataService.java   |  120 +-
 .../system/service/ISysDictTypeService.java   |  196 +-
 .../system/service/ISysLogininforService.java |   80 +-
 .../system/service/ISysMenuService.java       |  288 +-
 .../system/service/ISysNoticeService.java     |  120 +-
 .../system/service/ISysOperLogService.java    |   96 +-
 .../system/service/ISysPostService.java       |  198 +-
 .../system/service/ISysRoleService.java       |  346 +-
 .../system/service/ISysUserOnlineService.java |   96 +-
 .../system/service/ISysUserService.java       |  412 +-
 .../service/impl/SysConfigServiceImpl.java    |  464 +-
 .../service/impl/SysDeptServiceImpl.java      |  676 +--
 .../service/impl/SysDictDataServiceImpl.java  |  222 +-
 .../service/impl/SysDictTypeServiceImpl.java  |  446 +-
 .../impl/SysLogininforServiceImpl.java        |  130 +-
 .../service/impl/SysMenuServiceImpl.java      |   32 +-
 .../service/impl/SysNoticeServiceImpl.java    |  184 +-
 .../service/impl/SysOperLogServiceImpl.java   |  152 +-
 .../service/impl/SysPostServiceImpl.java      |  356 +-
 .../service/impl/SysRoleServiceImpl.java      |  854 ++--
 .../impl/SysUserOnlineServiceImpl.java        |  192 +-
 .../service/impl/SysUserServiceImpl.java      | 1100 ++---
 .../mapper/system/SysConfigMapper.xml         |  232 +-
 .../resources/mapper/system/SysDeptMapper.xml |  316 +-
 .../mapper/system/SysDictDataMapper.xml       |  246 +-
 .../mapper/system/SysDictTypeMapper.xml       |  208 +-
 .../mapper/system/SysLogininforMapper.xml     |  112 +-
 .../resources/mapper/system/SysMenuMapper.xml |  410 +-
 .../mapper/system/SysNoticeMapper.xml         |  176 +-
 .../mapper/system/SysOperLogMapper.xml        |  172 +-
 .../resources/mapper/system/SysPostMapper.xml |  242 +-
 .../mapper/system/SysRoleDeptMapper.xml       |   66 +-
 .../resources/mapper/system/SysRoleMapper.xml |  302 +-
 .../mapper/system/SysRoleMenuMapper.xml       |   66 +-
 .../resources/mapper/system/SysUserMapper.xml |  440 +-
 .../mapper/system/SysUserPostMapper.xml       |   66 +-
 .../mapper/system/SysUserRoleMapper.xml       |   86 +-
 pom.xml                                       |   52 +-
 ruoyi-ui/README.md                            |   58 +-
 ruoyi-ui/package.json                         |  182 +-
 ruoyi-ui/src/api/system/user.js               |  272 +-
 ruoyi-ui/src/assets/styles/ruoyi.scss         |    2 +-
 ruoyi-ui/src/components/RuoYi/Doc/index.vue   |   42 +-
 ruoyi-ui/src/components/RuoYi/Git/index.vue   |   42 +-
 ruoyi-ui/src/directive/dialog/drag.js         |  128 +-
 ruoyi-ui/src/directive/dialog/dragHeight.js   |   68 +-
 ruoyi-ui/src/directive/dialog/dragWidth.js    |   60 +-
 ruoyi-ui/src/directive/module/clipboard.js    |    2 +-
 ruoyi-ui/src/directive/permission/hasPermi.js |   56 +-
 ruoyi-ui/src/directive/permission/hasRole.js  |   56 +-
 ruoyi-ui/src/layout/components/Navbar.vue     |  400 +-
 ruoyi-ui/src/main.js                          |  172 +-
 ruoyi-ui/src/plugins/download.js              |    2 +-
 ruoyi-ui/src/utils/dict/Dict.js               |  164 +-
 ruoyi-ui/src/utils/dict/DictMeta.js           |   76 +-
 ruoyi-ui/src/utils/dict/DictOptions.js        |  102 +-
 ruoyi-ui/src/utils/index.js                   |  780 ++--
 ruoyi-ui/src/utils/request.js                 |    2 +-
 ruoyi-ui/src/utils/ruoyi.js                   |    2 +-
 ruoyi-ui/src/views/index.vue                  | 2216 +++++-----
 ruoyi-ui/src/views/login.vue                  |  438 +-
 ruoyi-ui/src/views/monitor/job/index.vue      |    2 +-
 ruoyi-ui/src/views/register.vue               |  420 +-
 ruoyi-ui/src/views/tool/gen/genInfoForm.vue   |  624 +--
 ruoyi-ui/src/views/tool/gen/index.vue         |    2 +-
 ruoyi-ui/vue.config.js                        |  262 +-
 ry.sh                                         |    2 +-
 sql/ry_20240629.sql                           |    2 +-
 339 files changed, 39163 insertions(+), 39265 deletions(-)
 delete mode 100644 README.md
 rename {ruoyi-admin => acupuncture-admin}/pom.xml (84%)
 rename ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java => acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java (87%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/RuoYiServletInitializer.java (76%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/common/CaptchaController.java (83%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/common/CommonController.java (91%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/monitor/CacheController.java (92%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/monitor/ServerController.java (77%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/monitor/SysLogininforController.java (81%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/monitor/SysOperlogController.java (80%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/monitor/SysUserOnlineController.java (78%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysConfigController.java (87%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysDeptController.java (88%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysDictDataController.java (84%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysDictTypeController.java (87%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysIndexController.java (60%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysLoginController.java (76%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysMenuController.java (88%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysNoticeController.java (84%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysPostController.java (87%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysProfileController.java (84%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysRegisterController.java (67%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysRoleController.java (87%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/system/SysUserController.java (89%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/controller/tool/TestController.java (93%)
 rename {ruoyi-admin/src/main/java/com/ruoyi => acupuncture-admin/src/main/java/com/acupuncture}/web/core/config/SwaggerConfig.java (91%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/META-INF/spring-devtools.properties (100%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/application-druid.yml (95%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/application.yml (88%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/banner.txt (96%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/i18n/messages.properties (98%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/logback.xml (94%)
 rename {ruoyi-admin => acupuncture-admin}/src/main/resources/mybatis/mybatis-config.xml (97%)
 rename {ruoyi-common => acupuncture-common}/pom.xml (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/Anonymous.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/DataScope.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/DataSource.java (84%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/Excel.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/Excels.java (81%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/Log.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/RateLimiter.java (78%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/RepeatSubmit.java (88%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/annotation/Sensitive.java (73%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/config/RuoYiConfig.java (91%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/config/serializer/SensitiveJsonSerializer.java (86%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/CacheConstants.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/Constants.java (87%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/GenConstants.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/HttpStatus.java (91%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/ScheduleConstants.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/constant/UserConstants.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/controller/BaseController.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/AjaxResult.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/BaseEntity.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/R.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/TreeEntity.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/TreeSelect.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysDept.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysDictData.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysDictType.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysMenu.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysRole.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/entity/SysUser.java (91%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/model/LoginBody.java (87%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/model/LoginUser.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/domain/model/RegisterBody.java (53%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/page/PageDomain.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/page/TableDataInfo.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/page/TableSupport.java (86%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/redis/RedisCache.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/text/CharsetKit.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/text/Convert.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/core/text/StrFormatter.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/BusinessStatus.java (68%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/BusinessType.java (82%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/DataSourceType.java (67%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/DesensitizedType.java (91%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/HttpMethod.java (88%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/LimitType.java (71%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/OperatorType.java (73%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/enums/UserStatus.java (84%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/DemoModeException.java (73%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/GlobalException.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/ServiceException.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/UtilException.java (84%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/base/BaseException.java (87%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/file/FileException.java (65%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/file/FileNameLengthLimitExceededException.java (82%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/file/FileSizeLimitExceededException.java (81%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/file/FileUploadException.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/file/InvalidExtensionException.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/job/TaskException.java (86%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/BlackListException.java (76%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/CaptchaException.java (76%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/CaptchaExpireException.java (77%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/UserException.java (65%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/UserNotExistsException.java (77%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/UserPasswordNotMatchException.java (79%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/exception/user/UserPasswordRetryLimitExceedException.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/filter/PropertyPreExcludeFilter.java (85%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/filter/RepeatableFilter.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/filter/RepeatedlyRequestWrapper.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/filter/XssFilter.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/filter/XssHttpServletRequestWrapper.java (91%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/Arith.java (98%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/DateUtils.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/DesensitizedUtil.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/DictUtils.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/ExceptionUtil.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/LogUtils.java (78%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/MessageUtils.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/PageUtils.java (77%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/SecurityUtils.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/ServletUtils.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/StringUtils.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/Threads.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/bean/BeanUtils.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/bean/BeanValidators.java (88%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/file/FileTypeUtils.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/file/FileUploadUtils.java (90%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/file/FileUtils.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/file/ImageUtils.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/file/MimeTypeUtils.java (93%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/html/EscapeUtil.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/html/HTMLFilter.java (96%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/http/HttpHelper.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/http/HttpUtils.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/ip/AddressUtils.java (83%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/ip/IpUtils.java (95%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/poi/ExcelHandlerAdapter.java (86%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/poi/ExcelUtil.java (96%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/reflect/ReflectUtils.java (96%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/sign/Base64.java (96%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/sign/Md5Utils.java (92%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/spring/SpringUtils.java (94%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/sql/SqlUtil.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/uuid/IdUtils.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/uuid/Seq.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/utils/uuid/UUID.java (96%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/xss/Xss.java (89%)
 rename {ruoyi-common/src/main/java/com/ruoyi => acupuncture-common/src/main/java/com/acupuncture}/common/xss/XssValidator.java (88%)
 rename {ruoyi-framework => acupuncture-framework}/pom.xml (86%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/aspectj/DataScopeAspect.java (89%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/aspectj/DataSourceAspect.java (80%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/aspectj/LogAspect.java (90%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/aspectj/RateLimiterAspect.java (87%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/ApplicationConfig.java (87%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/CaptchaConfig.java (95%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/DruidConfig.java (92%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/FastJson2JsonRedisSerializer.java (90%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/FilterConfig.java (88%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/I18nConfig.java (91%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/KaptchaTextCreator.java (96%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/MyBatisConfig.java (95%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/RedisConfig.java (95%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/ResourcesConfig.java (89%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/SecurityConfig.java (92%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/ServerConfig.java (85%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/ThreadPoolConfig.java (92%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/properties/DruidProperties.java (95%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/config/properties/PermitAllUrlProperties.java (93%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/datasource/DynamicDataSource.java (88%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/datasource/DynamicDataSourceContextHolder.java (91%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/interceptor/RepeatSubmitInterceptor.java (86%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/interceptor/impl/SameUrlDataInterceptor.java (86%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/manager/AsyncManager.java (82%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/manager/ShutdownManager.java (88%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/manager/factory/AsyncFactory.java (82%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/security/context/AuthenticationContextHolder.java (84%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/security/context/PermissionContextHolder.java (84%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/security/filter/JwtAuthenticationTokenFilter.java (84%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/security/handle/AuthenticationEntryPointImpl.java (78%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/security/handle/LogoutSuccessHandlerImpl.java (72%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/Server.java (90%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/server/Cpu.java (87%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/server/Jvm.java (88%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/server/Mem.java (84%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/server/Sys.java (89%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/domain/server/SysFile.java (89%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/exception/GlobalExceptionHandler.java (90%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/PermissionService.java (87%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/SysLoginService.java (81%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/SysPasswordService.java (79%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/SysPermissionService.java (82%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/SysRegisterService.java (75%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/TokenService.java (89%)
 rename {ruoyi-framework/src/main/java/com/ruoyi => acupuncture-framework/src/main/java/com/acupuncture}/framework/web/service/UserDetailsServiceImpl.java (80%)
 rename {ruoyi-generator => acupuncture-generator}/pom.xml (79%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/config/GenConfig.java (93%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/controller/GenController.java (89%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/domain/GenTable.java (93%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/domain/GenTableColumn.java (93%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/mapper/GenTableColumnMapper.java (88%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/mapper/GenTableMapper.java (90%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/service/GenTableColumnServiceImpl.java (84%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/service/GenTableServiceImpl.java (93%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/service/IGenTableColumnService.java (85%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/service/IGenTableService.java (91%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/util/GenUtils.java (93%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/util/VelocityInitializer.java (85%)
 rename {ruoyi-generator/src/main/java/com/ruoyi => acupuncture-generator/src/main/java/com/acupuncture}/generator/util/VelocityUtils.java (95%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/generator.yml (86%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/mapper/generator/GenTableColumnMapper.xml (97%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/mapper/generator/GenTableMapper.xml (97%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/controller.java.vm (92%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/domain.java.vm (88%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/mapper.java.vm (100%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/service.java.vm (96%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/serviceImpl.java.vm (94%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/java/sub-domain.java.vm (88%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/js/api.js.vm (95%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/sql/sql.vm (99%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/vue/index-tree.vue.vm (97%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/vue/index.vue.vm (97%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/vue/v3/index-tree.vue.vm (100%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/vue/v3/index.vue.vm (100%)
 rename {ruoyi-generator => acupuncture-generator}/src/main/resources/vm/xml/mapper.xml.vm (98%)
 rename {ruoyi-quartz => acupuncture-quartz}/pom.xml (78%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/config/ScheduleConfig.java (90%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/controller/SysJobController.java (89%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/controller/SysJobLogController.java (83%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/domain/SysJob.java (89%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/domain/SysJobLog.java (91%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/mapper/SysJobLogMapper.java (89%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/mapper/SysJobMapper.java (88%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/service/ISysJobLogService.java (88%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/service/ISysJobService.java (89%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/service/impl/SysJobLogServiceImpl.java (85%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/service/impl/SysJobServiceImpl.java (91%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/task/RyTask.java (83%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/AbstractQuartzJob.java (83%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/CronUtils.java (93%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/JobInvokeUtil.java (93%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/QuartzDisallowConcurrentExecution.java (79%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/QuartzJobExecution.java (75%)
 rename {ruoyi-quartz/src/main/java/com/ruoyi => acupuncture-quartz/src/main/java/com/acupuncture}/quartz/util/ScheduleUtils.java (89%)
 rename {ruoyi-quartz => acupuncture-quartz}/src/main/resources/mapper/quartz/SysJobLogMapper.xml (96%)
 rename {ruoyi-quartz => acupuncture-quartz}/src/main/resources/mapper/quartz/SysJobMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/pom.xml (69%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysCache.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysConfig.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysLogininfor.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysNotice.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysOperLog.java (91%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysPost.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysRoleDept.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysRoleMenu.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysUserOnline.java (91%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysUserPost.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/SysUserRole.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/vo/MetaVo.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/domain/vo/RouterVo.java (92%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysConfigMapper.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysDeptMapper.java (92%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysDictDataMapper.java (91%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysDictTypeMapper.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysLogininforMapper.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysMenuMapper.java (92%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysNoticeMapper.java (87%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysOperLogMapper.java (86%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysPostMapper.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysRoleDeptMapper.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysRoleMapper.java (91%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysRoleMenuMapper.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysUserMapper.java (92%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysUserPostMapper.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/mapper/SysUserRoleMapper.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysConfigService.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysDeptService.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysDictDataService.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysDictTypeService.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysLogininforService.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysMenuService.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysNoticeService.java (87%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysOperLogService.java (86%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysPostService.java (90%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysRoleService.java (91%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysUserOnlineService.java (84%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/ISysUserService.java (93%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysConfigServiceImpl.java (87%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysDeptServiceImpl.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysDictDataServiceImpl.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysDictTypeServiceImpl.java (88%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysLogininforServiceImpl.java (82%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysMenuServiceImpl.java (94%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysNoticeServiceImpl.java (85%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysOperLogServiceImpl.java (84%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysPostServiceImpl.java (87%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysRoleServiceImpl.java (89%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysUserOnlineServiceImpl.java (87%)
 rename {ruoyi-system/src/main/java/com/ruoyi => acupuncture-system/src/main/java/com/acupuncture}/system/service/impl/SysUserServiceImpl.java (90%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysConfigMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysDeptMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysDictDataMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysDictTypeMapper.xml (95%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysLogininforMapper.xml (94%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysMenuMapper.xml (97%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysNoticeMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysOperLogMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysPostMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysRoleDeptMapper.xml (91%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysRoleMapper.xml (96%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysRoleMenuMapper.xml (91%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysUserMapper.xml (97%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysUserPostMapper.xml (91%)
 rename {ruoyi-system => acupuncture-system}/src/main/resources/mapper/system/SysUserRoleMapper.xml (93%)

diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
index fbcab775..c1bd5e0a 100644
--- a/.github/FUNDING.yml
+++ b/.github/FUNDING.yml
@@ -1 +1 @@
-custom: http://doc.ruoyi.vip/ruoyi-vue/other/donate.html
+custom: http://doc.acupuncture.vip/acupuncture-vue/other/donate.html
diff --git a/LICENSE b/LICENSE
index 8564f294..53d171cc 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2018 RuoYi
+Copyright (c) 2018 acupuncture
 
 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
diff --git a/README.md b/README.md
deleted file mode 100644
index 058fd43e..00000000
--- a/README.md
+++ /dev/null
@@ -1,95 +0,0 @@
-<p align="center">
-	<img alt="logo" src="https://oscimg.oschina.net/oscnet/up-d3d0a9303e11d522a06cd263f3079027715.png">
-</p>
-<h1 align="center" style="margin: 30px 0 30px; font-weight: bold;">RuoYi v3.8.9</h1>
-<h4 align="center">基于SpringBoot+Vue前后端分离的Java快速开发框架</h4>
-<p align="center">
-	<a href="https://gitee.com/y_project/RuoYi-Vue/stargazers"><img src="https://gitee.com/y_project/RuoYi-Vue/badge/star.svg?theme=dark"></a>
-	<a href="https://gitee.com/y_project/RuoYi-Vue"><img src="https://img.shields.io/badge/RuoYi-v3.8.9-brightgreen.svg"></a>
-	<a href="https://gitee.com/y_project/RuoYi-Vue/blob/master/LICENSE"><img src="https://img.shields.io/github/license/mashape/apistatus.svg"></a>
-</p>
-
-## 平台简介
-
-若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
-
-* 前端采用Vue、Element UI。
-* 后端采用Spring Boot、Spring Security、Redis & Jwt。
-* 权限认证使用Jwt,支持多终端认证系统。
-* 支持加载动态权限菜单,多方式轻松权限控制。
-* 高效率开发,使用代码生成器可以一键生成前后端代码。
-* 提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev))版本[RuoYi-Vue3](https://gitcode.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
-* 提供了单应用版本[RuoYi-Vue-fast](https://gitcode.com/yangzongzhuan/RuoYi-Vue-fast),Oracle版本[RuoYi-Vue-Oracle](https://gitcode.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
-* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi),微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
-* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)&nbsp;&nbsp;
-
-## 内置功能
-
-1.  用户管理:用户是系统操作者,该功能主要完成系统用户配置。
-2.  部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
-3.  岗位管理:配置系统用户所属担任职务。
-4.  菜单管理:配置系统菜单,操作权限,按钮权限标识等。
-5.  角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
-6.  字典管理:对系统中经常使用的一些较为固定的数据进行维护。
-7.  参数管理:对系统动态配置常用参数。
-8.  通知公告:系统通知公告信息发布维护。
-9.  操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
-10. 登录日志:系统登录日志记录查询包含登录异常。
-11. 在线用户:当前系统中活跃用户状态监控。
-12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
-13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
-14. 系统接口:根据业务代码自动生成相关的api接口文档。
-15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
-16. 缓存监控:对系统的缓存信息查询,命令统计等。
-17. 在线构建器:拖动表单元素生成相应的HTML代码。
-18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
-
-## 在线体验
-
-- admin/admin123  
-- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
-
-演示地址:http://vue.ruoyi.vip  
-文档地址:http://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/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
-    </tr>
-    <tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
-    </tr>
-	<tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></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/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
-    </tr>
-	<tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
-    </tr>
-    <tr>
-        <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
-        <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
-    </tr>
-</table>
-
-
-## 若依前后端分离交流群
-
-QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/已满-101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs) [![加入QQ群](https://img.shields.io/badge/已满-264312783-blue.svg)](https://jq.qq.com/?_wv=1027&k=EI9an8lJ) [![加入QQ群](https://img.shields.io/badge/已满-167385320-blue.svg)](https://jq.qq.com/?_wv=1027&k=SWCtLnMz) [![加入QQ群](https://img.shields.io/badge/已满-104748341-blue.svg)](https://jq.qq.com/?_wv=1027&k=96Dkdq0k) [![加入QQ群](https://img.shields.io/badge/已满-160110482-blue.svg)](https://jq.qq.com/?_wv=1027&k=0fsNiYZt) [![加入QQ群](https://img.shields.io/badge/已满-170801498-blue.svg)](https://jq.qq.com/?_wv=1027&k=7xw4xUG1) [![加入QQ群](https://img.shields.io/badge/已满-108482800-blue.svg)](https://jq.qq.com/?_wv=1027&k=eCx8eyoJ) [![加入QQ群](https://img.shields.io/badge/已满-101046199-blue.svg)](https://jq.qq.com/?_wv=1027&k=SpyH2875) [![加入QQ群](https://img.shields.io/badge/已满-136919097-blue.svg)](https://jq.qq.com/?_wv=1027&k=tKEt51dz) [![加入QQ群](https://img.shields.io/badge/已满-143961921-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=0vBbSb0ztbBgVtn3kJS-Q4HUNYwip89G&authKey=8irq5PhutrZmWIvsUsklBxhj57l%2F1nOZqjzigkXZVoZE451GG4JHPOqW7AW6cf0T&noverify=0&group_code=143961921) [![加入QQ群](https://img.shields.io/badge/已满-174951577-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=ZFAPAbp09S2ltvwrJzp7wGlbopsc0rwi&authKey=HB2cxpxP2yspk%2Bo3WKTBfktRCccVkU26cgi5B16u0KcAYrVu7sBaE7XSEqmMdFQp&noverify=0&group_code=174951577) [![加入QQ群](https://img.shields.io/badge/已满-161281055-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Fn2aF5IHpwsy8j6VlalNJK6qbwFLFHat&authKey=uyIT%2B97x2AXj3odyXpsSpVaPMC%2Bidw0LxG5MAtEqlrcBcWJUA%2FeS43rsF1Tg7IRJ&noverify=0&group_code=161281055) [![加入QQ群](https://img.shields.io/badge/已满-138988063-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=XIzkm_mV2xTsUtFxo63bmicYoDBA6Ifm&authKey=dDW%2F4qsmw3x9govoZY9w%2FoWAoC4wbHqGal%2BbqLzoS6VBarU8EBptIgPKN%2FviyC8j&noverify=0&group_code=138988063) [![加入QQ群](https://img.shields.io/badge/已满-151450850-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=DkugnCg68PevlycJSKSwjhFqfIgrWWwR&authKey=pR1Pa5lPIeGF%2FFtIk6d%2FGB5qFi0EdvyErtpQXULzo03zbhopBHLWcuqdpwY241R%2F&noverify=0&group_code=151450850) [![加入QQ群](https://img.shields.io/badge/已满-224622315-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=F58bgRa-Dp-rsQJThiJqIYv8t4-lWfXh&authKey=UmUs4CVG5OPA1whvsa4uSespOvyd8%2FAr9olEGaWAfdLmfKQk%2FVBp2YU3u2xXXt76&noverify=0&group_code=224622315) [![加入QQ群](https://img.shields.io/badge/已满-287842588-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=Nxb2EQ5qozWa218Wbs7zgBnjLSNk_tVT&authKey=obBKXj6SBKgrFTJZx0AqQnIYbNOvBB2kmgwWvGhzxR67RoRr84%2Bus5OadzMcdJl5&noverify=0&group_code=287842588) [![加入QQ群](https://img.shields.io/badge/187944233-blue.svg)](http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=numtK1M_I4eVd2Gvg8qtbuL8JgX42qNh&authKey=giV9XWMaFZTY%2FqPlmWbkB9g3fi0Ev5CwEtT9Tgei0oUlFFCQLDp4ozWRiVIzubIm&noverify=0&group_code=187944233) 点击按钮入群。
\ No newline at end of file
diff --git a/ruoyi-admin/pom.xml b/acupuncture-admin/pom.xml
similarity index 84%
rename from ruoyi-admin/pom.xml
rename to acupuncture-admin/pom.xml
index 34a40e84..5b7e7765 100644
--- a/ruoyi-admin/pom.xml
+++ b/acupuncture-admin/pom.xml
@@ -1,96 +1,96 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-    <packaging>jar</packaging>
-    <artifactId>ruoyi-admin</artifactId>
-
-    <description>
-        web服务入口
-    </description>
-
-    <dependencies>
-
-        <!-- spring-boot-devtools -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-devtools</artifactId>
-            <optional>true</optional> <!-- 表示依赖不会传递 -->
-        </dependency>
-
-        <!-- swagger3-->
-        <dependency>
-            <groupId>io.springfox</groupId>
-            <artifactId>springfox-boot-starter</artifactId>
-        </dependency>
-
-        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
-        <dependency>
-            <groupId>io.swagger</groupId>
-            <artifactId>swagger-models</artifactId>
-            <version>1.6.2</version>
-        </dependency>
-
-         <!-- Mysql驱动包 -->
-        <dependency>
-            <groupId>mysql</groupId>
-            <artifactId>mysql-connector-java</artifactId>
-        </dependency>
-
-        <!-- 核心模块-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-framework</artifactId>
-        </dependency>
-
-        <!-- 定时任务-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-quartz</artifactId>
-        </dependency>
-
-        <!-- 代码生成-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-generator</artifactId>
-        </dependency>
-
-    </dependencies>
-
-    <build>
-        <plugins>
-            <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
-                <version>2.5.15</version>
-                <configuration>
-                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
-                </configuration>
-                <executions>
-                    <execution>
-                        <goals>
-                            <goal>repackage</goal>
-                        </goals>
-                    </execution>
-                </executions>
-            </plugin>
-            <plugin>   
-                <groupId>org.apache.maven.plugins</groupId>   
-                <artifactId>maven-war-plugin</artifactId>   
-                <version>3.1.0</version>   
-                <configuration>
-                    <failOnMissingWebXml>false</failOnMissingWebXml>
-                    <warName>${project.artifactId}</warName>
-                </configuration>   
-           </plugin>   
-        </plugins>
-        <finalName>${project.artifactId}</finalName>
-    </build>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>acupuncture-admin</artifactId>
+
+    <description>
+        web服务入口
+    </description>
+
+    <dependencies>
+
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger3-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
+         <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-framework</artifactId>
+        </dependency>
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-quartz</artifactId>
+        </dependency>
+
+        <!-- 代码生成-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-generator</artifactId>
+        </dependency>
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.5.15</version>
+                <configuration>
+                    <fork>true</fork> <!-- 如果没有该配置,devtools不会生效 -->
+                </configuration>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <plugin>   
+                <groupId>org.apache.maven.plugins</groupId>   
+                <artifactId>maven-war-plugin</artifactId>   
+                <version>3.1.0</version>   
+                <configuration>
+                    <failOnMissingWebXml>false</failOnMissingWebXml>
+                    <warName>${project.artifactId}</warName>
+                </configuration>   
+           </plugin>   
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java
similarity index 87%
rename from ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
rename to acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java
index e3c56ee5..c08c3fb4 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/AcupunctureApplication.java
@@ -1,30 +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" +
-                " ''-'   `'-'    `-..-'              ");
-    }
-}
+package com.acupuncture;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 启动程序
+ * 
+ * @author acupuncture
+ */
+@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
+public class AcupunctureApplication
+{
+    public static void main(String[] args)
+    {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(AcupunctureApplication.class, args);
+        System.out.println("(♥◠‿◠)ノ゙  若依启动成功   ლ(´ڡ`ლ)゙  \n" +
+                " .-------.       ____     __        \n" +
+                " |  _ _   \\      \\   \\   /  /    \n" +
+                " | ( ' )  |       \\  _. /  '       \n" +
+                " |(_ o _) /        _( )_ .'         \n" +
+                " | (_,_).' __  ___(_ o _)'          \n" +
+                " |  |\\ \\  |  ||   |(_,_)'         \n" +
+                " |  | \\ `'   /|   `-'  /           \n" +
+                " |  |  \\    /  \\      /           \n" +
+                " ''-'   `'-'    `-..-'              ");
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/acupuncture-admin/src/main/java/com/acupuncture/RuoYiServletInitializer.java
similarity index 76%
rename from ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
rename to acupuncture-admin/src/main/java/com/acupuncture/RuoYiServletInitializer.java
index 9d82a237..64bc70df 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/RuoYiServletInitializer.java
@@ -1,18 +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);
-    }
-}
+package com.acupuncture;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web容器中进行部署
+ * 
+ * @author acupuncture
+ */
+public class RuoYiServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(AcupunctureApplication.class);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CaptchaController.java
similarity index 83%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CaptchaController.java
index e1a397e6..caf277f9 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CaptchaController.java
@@ -1,94 +1,94 @@
-package com.ruoyi.web.controller.common;
-
-import java.awt.image.BufferedImage;
-import java.io.IOException;
-import java.util.concurrent.TimeUnit;
-import javax.annotation.Resource;
-import javax.imageio.ImageIO;
-import javax.servlet.http.HttpServletResponse;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.FastByteArrayOutputStream;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.google.code.kaptcha.Producer;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.utils.sign.Base64;
-import com.ruoyi.common.utils.uuid.IdUtils;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 验证码操作处理
- * 
- * @author ruoyi
- */
-@RestController
-public class CaptchaController
-{
-    @Resource(name = "captchaProducer")
-    private Producer captchaProducer;
-
-    @Resource(name = "captchaProducerMath")
-    private Producer captchaProducerMath;
-
-    @Autowired
-    private RedisCache redisCache;
-    
-    @Autowired
-    private ISysConfigService configService;
-    /**
-     * 生成验证码
-     */
-    @GetMapping("/captchaImage")
-    public AjaxResult getCode(HttpServletResponse response) throws IOException
-    {
-        AjaxResult ajax = AjaxResult.success();
-        boolean captchaEnabled = configService.selectCaptchaEnabled();
-        ajax.put("captchaEnabled", captchaEnabled);
-        if (!captchaEnabled)
-        {
-            return ajax;
-        }
-
-        // 保存验证码信息
-        String uuid = IdUtils.simpleUUID();
-        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
-
-        String capStr = null, code = null;
-        BufferedImage image = null;
-
-        // 生成验证码
-        String captchaType = RuoYiConfig.getCaptchaType();
-        if ("math".equals(captchaType))
-        {
-            String capText = captchaProducerMath.createText();
-            capStr = capText.substring(0, capText.lastIndexOf("@"));
-            code = capText.substring(capText.lastIndexOf("@") + 1);
-            image = captchaProducerMath.createImage(capStr);
-        }
-        else if ("char".equals(captchaType))
-        {
-            capStr = code = captchaProducer.createText();
-            image = captchaProducer.createImage(capStr);
-        }
-
-        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
-        // 转换流信息写出
-        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
-        try
-        {
-            ImageIO.write(image, "jpg", os);
-        }
-        catch (IOException e)
-        {
-            return AjaxResult.error(e.getMessage());
-        }
-
-        ajax.put("uuid", uuid);
-        ajax.put("img", Base64.encode(os.toByteArray()));
-        return ajax;
-    }
-}
+package com.acupuncture.web.controller.common;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.FastByteArrayOutputStream;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.google.code.kaptcha.Producer;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.utils.sign.Base64;
+import com.acupuncture.common.utils.uuid.IdUtils;
+import com.acupuncture.system.service.ISysConfigService;
+
+/**
+ * 验证码操作处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+public class CaptchaController
+{
+    @Resource(name = "captchaProducer")
+    private Producer captchaProducer;
+
+    @Resource(name = "captchaProducerMath")
+    private Producer captchaProducerMath;
+
+    @Autowired
+    private RedisCache redisCache;
+    
+    @Autowired
+    private ISysConfigService configService;
+    /**
+     * 生成验证码
+     */
+    @GetMapping("/captchaImage")
+    public AjaxResult getCode(HttpServletResponse response) throws IOException
+    {
+        AjaxResult ajax = AjaxResult.success();
+        boolean captchaEnabled = configService.selectCaptchaEnabled();
+        ajax.put("captchaEnabled", captchaEnabled);
+        if (!captchaEnabled)
+        {
+            return ajax;
+        }
+
+        // 保存验证码信息
+        String uuid = IdUtils.simpleUUID();
+        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + uuid;
+
+        String capStr = null, code = null;
+        BufferedImage image = null;
+
+        // 生成验证码
+        String captchaType = RuoYiConfig.getCaptchaType();
+        if ("math".equals(captchaType))
+        {
+            String capText = captchaProducerMath.createText();
+            capStr = capText.substring(0, capText.lastIndexOf("@"));
+            code = capText.substring(capText.lastIndexOf("@") + 1);
+            image = captchaProducerMath.createImage(capStr);
+        }
+        else if ("char".equals(captchaType))
+        {
+            capStr = code = captchaProducer.createText();
+            image = captchaProducer.createImage(capStr);
+        }
+
+        redisCache.setCacheObject(verifyKey, code, Constants.CAPTCHA_EXPIRATION, TimeUnit.MINUTES);
+        // 转换流信息写出
+        FastByteArrayOutputStream os = new FastByteArrayOutputStream();
+        try
+        {
+            ImageIO.write(image, "jpg", os);
+        }
+        catch (IOException e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+
+        ajax.put("uuid", uuid);
+        ajax.put("img", Base64.encode(os.toByteArray()));
+        return ajax;
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CommonController.java
similarity index 91%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CommonController.java
index d51d61d0..aeffe438 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/common/CommonController.java
@@ -1,163 +1,163 @@
-package com.ruoyi.web.controller.common;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.http.MediaType;
-import org.springframework.web.bind.annotation.GetMapping;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.file.FileUploadUtils;
-import com.ruoyi.common.utils.file.FileUtils;
-import com.ruoyi.framework.config.ServerConfig;
-
-/**
- * 通用请求处理
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/common")
-public class CommonController
-{
-    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
-
-    @Autowired
-    private ServerConfig serverConfig;
-
-    private static final String FILE_DELIMETER = ",";
-
-    /**
-     * 通用下载请求
-     * 
-     * @param fileName 文件名称
-     * @param delete 是否删除
-     */
-    @GetMapping("/download")
-    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
-    {
-        try
-        {
-            if (!FileUtils.checkAllowDownload(fileName))
-            {
-                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
-            }
-            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
-            String filePath = RuoYiConfig.getDownloadPath() + fileName;
-
-            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
-            FileUtils.setAttachmentResponseHeader(response, realFileName);
-            FileUtils.writeBytes(filePath, response.getOutputStream());
-            if (delete)
-            {
-                FileUtils.deleteFile(filePath);
-            }
-        }
-        catch (Exception e)
-        {
-            log.error("下载文件失败", e);
-        }
-    }
-
-    /**
-     * 通用上传请求(单个)
-     */
-    @PostMapping("/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("url", url);
-            ajax.put("fileName", fileName);
-            ajax.put("newFileName", FileUtils.getName(fileName));
-            ajax.put("originalFilename", file.getOriginalFilename());
-            return ajax;
-        }
-        catch (Exception e)
-        {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-    /**
-     * 通用上传请求(多个)
-     */
-    @PostMapping("/uploads")
-    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
-    {
-        try
-        {
-            // 上传文件路径
-            String filePath = RuoYiConfig.getUploadPath();
-            List<String> urls = new ArrayList<String>();
-            List<String> fileNames = new ArrayList<String>();
-            List<String> newFileNames = new ArrayList<String>();
-            List<String> originalFilenames = new ArrayList<String>();
-            for (MultipartFile file : files)
-            {
-                // 上传并返回新文件名称
-                String fileName = FileUploadUtils.upload(filePath, file);
-                String url = serverConfig.getUrl() + fileName;
-                urls.add(url);
-                fileNames.add(fileName);
-                newFileNames.add(FileUtils.getName(fileName));
-                originalFilenames.add(file.getOriginalFilename());
-            }
-            AjaxResult ajax = AjaxResult.success();
-            ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
-            ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
-            ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
-            ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
-            return ajax;
-        }
-        catch (Exception e)
-        {
-            return AjaxResult.error(e.getMessage());
-        }
-    }
-
-    /**
-     * 本地资源通用下载
-     */
-    @GetMapping("/download/resource")
-    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
-            throws Exception
-    {
-        try
-        {
-            if (!FileUtils.checkAllowDownload(resource))
-            {
-                throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
-            }
-            // 本地资源路径
-            String localPath = RuoYiConfig.getProfile();
-            // 数据库资源地址
-            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
-            // 下载名称
-            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
-            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
-            FileUtils.setAttachmentResponseHeader(response, downloadName);
-            FileUtils.writeBytes(downloadPath, response.getOutputStream());
-        }
-        catch (Exception e)
-        {
-            log.error("下载文件失败", e);
-        }
-    }
-}
+package com.acupuncture.web.controller.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.MediaType;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.file.FileUploadUtils;
+import com.acupuncture.common.utils.file.FileUtils;
+import com.acupuncture.framework.config.ServerConfig;
+
+/**
+ * 通用请求处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/common")
+public class CommonController
+{
+    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+
+    @Autowired
+    private ServerConfig serverConfig;
+
+    private static final String FILE_DELIMETER = ",";
+
+    /**
+     * 通用下载请求
+     * 
+     * @param fileName 文件名称
+     * @param delete 是否删除
+     */
+    @GetMapping("/download")
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request)
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(fileName))
+            {
+                throw new Exception(StringUtils.format("文件名称({})非法,不允许下载。 ", fileName));
+            }
+            String realFileName = System.currentTimeMillis() + fileName.substring(fileName.indexOf("_") + 1);
+            String filePath = RuoYiConfig.getDownloadPath() + fileName;
+
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, realFileName);
+            FileUtils.writeBytes(filePath, response.getOutputStream());
+            if (delete)
+            {
+                FileUtils.deleteFile(filePath);
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+
+    /**
+     * 通用上传请求(单个)
+     */
+    @PostMapping("/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("url", url);
+            ajax.put("fileName", fileName);
+            ajax.put("newFileName", FileUtils.getName(fileName));
+            ajax.put("originalFilename", file.getOriginalFilename());
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 通用上传请求(多个)
+     */
+    @PostMapping("/uploads")
+    public AjaxResult uploadFiles(List<MultipartFile> files) throws Exception
+    {
+        try
+        {
+            // 上传文件路径
+            String filePath = RuoYiConfig.getUploadPath();
+            List<String> urls = new ArrayList<String>();
+            List<String> fileNames = new ArrayList<String>();
+            List<String> newFileNames = new ArrayList<String>();
+            List<String> originalFilenames = new ArrayList<String>();
+            for (MultipartFile file : files)
+            {
+                // 上传并返回新文件名称
+                String fileName = FileUploadUtils.upload(filePath, file);
+                String url = serverConfig.getUrl() + fileName;
+                urls.add(url);
+                fileNames.add(fileName);
+                newFileNames.add(FileUtils.getName(fileName));
+                originalFilenames.add(file.getOriginalFilename());
+            }
+            AjaxResult ajax = AjaxResult.success();
+            ajax.put("urls", StringUtils.join(urls, FILE_DELIMETER));
+            ajax.put("fileNames", StringUtils.join(fileNames, FILE_DELIMETER));
+            ajax.put("newFileNames", StringUtils.join(newFileNames, FILE_DELIMETER));
+            ajax.put("originalFilenames", StringUtils.join(originalFilenames, FILE_DELIMETER));
+            return ajax;
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 本地资源通用下载
+     */
+    @GetMapping("/download/resource")
+    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response)
+            throws Exception
+    {
+        try
+        {
+            if (!FileUtils.checkAllowDownload(resource))
+            {
+                throw new Exception(StringUtils.format("资源文件({})非法,不允许下载。 ", resource));
+            }
+            // 本地资源路径
+            String localPath = RuoYiConfig.getProfile();
+            // 数据库资源地址
+            String downloadPath = localPath + StringUtils.substringAfter(resource, Constants.RESOURCE_PREFIX);
+            // 下载名称
+            String downloadName = StringUtils.substringAfterLast(downloadPath, "/");
+            response.setContentType(MediaType.APPLICATION_OCTET_STREAM_VALUE);
+            FileUtils.setAttachmentResponseHeader(response, downloadName);
+            FileUtils.writeBytes(downloadPath, response.getOutputStream());
+        }
+        catch (Exception e)
+        {
+            log.error("下载文件失败", e);
+        }
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/CacheController.java
similarity index 92%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/CacheController.java
index 504c0fde..f06ac1b1 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/CacheController.java
@@ -1,121 +1,121 @@
-package com.ruoyi.web.controller.monitor;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Properties;
-import java.util.Set;
-import java.util.TreeSet;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisCallback;
-import org.springframework.data.redis.core.RedisTemplate;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysCache;
-
-/**
- * 缓存监控
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/cache")
-public class CacheController
-{
-    @Autowired
-    private RedisTemplate<String, String> redisTemplate;
-
-    private final static List<SysCache> caches = new ArrayList<SysCache>();
-    {
-        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
-        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
-        caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
-        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
-        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
-        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
-        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping()
-    public AjaxResult getInfo() throws Exception
-    {
-        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
-        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
-        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
-
-        Map<String, Object> result = new HashMap<>(3);
-        result.put("info", info);
-        result.put("dbSize", dbSize);
-
-        List<Map<String, String>> pieList = new ArrayList<>();
-        commandStats.stringPropertyNames().forEach(key -> {
-            Map<String, String> data = new HashMap<>(2);
-            String property = commandStats.getProperty(key);
-            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
-            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
-            pieList.add(data);
-        });
-        result.put("commandStats", pieList);
-        return AjaxResult.success(result);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getNames")
-    public AjaxResult cache()
-    {
-        return AjaxResult.success(caches);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getKeys/{cacheName}")
-    public AjaxResult getCacheKeys(@PathVariable String cacheName)
-    {
-        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
-        return AjaxResult.success(new TreeSet<>(cacheKeys));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @GetMapping("/getValue/{cacheName}/{cacheKey}")
-    public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
-    {
-        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
-        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
-        return AjaxResult.success(sysCache);
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheName/{cacheName}")
-    public AjaxResult clearCacheName(@PathVariable String cacheName)
-    {
-        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
-        redisTemplate.delete(cacheKeys);
-        return AjaxResult.success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheKey/{cacheKey}")
-    public AjaxResult clearCacheKey(@PathVariable String cacheKey)
-    {
-        redisTemplate.delete(cacheKey);
-        return AjaxResult.success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
-    @DeleteMapping("/clearCacheAll")
-    public AjaxResult clearCacheAll()
-    {
-        Collection<String> cacheKeys = redisTemplate.keys("*");
-        redisTemplate.delete(cacheKeys);
-        return AjaxResult.success();
-    }
-}
+package com.acupuncture.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.Set;
+import java.util.TreeSet;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisCallback;
+import org.springframework.data.redis.core.RedisTemplate;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.SysCache;
+
+/**
+ * 缓存监控
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController
+{
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    private final static List<SysCache> caches = new ArrayList<SysCache>();
+    {
+        caches.add(new SysCache(CacheConstants.LOGIN_TOKEN_KEY, "用户信息"));
+        caches.add(new SysCache(CacheConstants.SYS_CONFIG_KEY, "配置信息"));
+        caches.add(new SysCache(CacheConstants.SYS_DICT_KEY, "数据字典"));
+        caches.add(new SysCache(CacheConstants.CAPTCHA_CODE_KEY, "验证码"));
+        caches.add(new SysCache(CacheConstants.REPEAT_SUBMIT_KEY, "防重提交"));
+        caches.add(new SysCache(CacheConstants.RATE_LIMIT_KEY, "限流处理"));
+        caches.add(new SysCache(CacheConstants.PWD_ERR_CNT_KEY, "密码错误次数"));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception
+    {
+        Properties info = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info());
+        Properties commandStats = (Properties) redisTemplate.execute((RedisCallback<Object>) connection -> connection.info("commandstats"));
+        Object dbSize = redisTemplate.execute((RedisCallback<Object>) connection -> connection.dbSize());
+
+        Map<String, Object> result = new HashMap<>(3);
+        result.put("info", info);
+        result.put("dbSize", dbSize);
+
+        List<Map<String, String>> pieList = new ArrayList<>();
+        commandStats.stringPropertyNames().forEach(key -> {
+            Map<String, String> data = new HashMap<>(2);
+            String property = commandStats.getProperty(key);
+            data.put("name", StringUtils.removeStart(key, "cmdstat_"));
+            data.put("value", StringUtils.substringBetween(property, "calls=", ",usec"));
+            pieList.add(data);
+        });
+        result.put("commandStats", pieList);
+        return AjaxResult.success(result);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getNames")
+    public AjaxResult cache()
+    {
+        return AjaxResult.success(caches);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getKeys/{cacheName}")
+    public AjaxResult getCacheKeys(@PathVariable String cacheName)
+    {
+        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        return AjaxResult.success(new TreeSet<>(cacheKeys));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getValue/{cacheName}/{cacheKey}")
+    public AjaxResult getCacheValue(@PathVariable String cacheName, @PathVariable String cacheKey)
+    {
+        String cacheValue = redisTemplate.opsForValue().get(cacheKey);
+        SysCache sysCache = new SysCache(cacheName, cacheKey, cacheValue);
+        return AjaxResult.success(sysCache);
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheName/{cacheName}")
+    public AjaxResult clearCacheName(@PathVariable String cacheName)
+    {
+        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheKey/{cacheKey}")
+    public AjaxResult clearCacheKey(@PathVariable String cacheKey)
+    {
+        redisTemplate.delete(cacheKey);
+        return AjaxResult.success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @DeleteMapping("/clearCacheAll")
+    public AjaxResult clearCacheAll()
+    {
+        Collection<String> cacheKeys = redisTemplate.keys("*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/ServerController.java
similarity index 77%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/ServerController.java
index 082027be..547d4bea 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/ServerController.java
@@ -1,27 +1,27 @@
-package com.ruoyi.web.controller.monitor;
-
-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.common.core.domain.AjaxResult;
-import com.ruoyi.framework.web.domain.Server;
-
-/**
- * 服务器监控
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/server")
-public class ServerController
-{
-    @PreAuthorize("@ss.hasPermi('monitor:server:list')")
-    @GetMapping()
-    public AjaxResult getInfo() throws Exception
-    {
-        Server server = new Server();
-        server.copyTo();
-        return AjaxResult.success(server);
-    }
-}
+package com.acupuncture.web.controller.monitor;
+
+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.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.framework.web.domain.Server;
+
+/**
+ * 服务器监控
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController
+{
+    @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-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysLogininforController.java
similarity index 81%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysLogininforController.java
index f9f262e0..fc50159a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysLogininforController.java
@@ -1,82 +1,82 @@
-package com.ruoyi.web.controller.monitor;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.framework.web.service.SysPasswordService;
-import com.ruoyi.system.domain.SysLogininfor;
-import com.ruoyi.system.service.ISysLogininforService;
-
-/**
- * 系统访问记录
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/logininfor")
-public class SysLogininforController extends BaseController
-{
-    @Autowired
-    private ISysLogininforService logininforService;
-
-    @Autowired
-    private SysPasswordService passwordService;
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysLogininfor logininfor)
-    {
-        startPage();
-        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
-        return getDataTable(list);
-    }
-
-    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysLogininfor logininfor)
-    {
-        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
-        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
-        util.exportExcel(response, list, "登录日志");
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
-    @Log(title = "登录日志", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{infoIds}")
-    public AjaxResult remove(@PathVariable Long[] infoIds)
-    {
-        return toAjax(logininforService.deleteLogininforByIds(infoIds));
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
-    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        logininforService.cleanLogininfor();
-        return success();
-    }
-
-    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
-    @Log(title = "账户解锁", businessType = BusinessType.OTHER)
-    @GetMapping("/unlock/{userName}")
-    public AjaxResult unlock(@PathVariable("userName") String userName)
-    {
-        passwordService.clearLoginRecordCache(userName);
-        return success();
-    }
-}
+package com.acupuncture.web.controller.monitor;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.framework.web.service.SysPasswordService;
+import com.acupuncture.system.domain.SysLogininfor;
+import com.acupuncture.system.service.ISysLogininforService;
+
+/**
+ * 系统访问记录
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController
+{
+    @Autowired
+    private ISysLogininforService logininforService;
+
+    @Autowired
+    private SysPasswordService passwordService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor)
+    {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return getDataTable(list);
+    }
+
+    @Log(title = "登录日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysLogininfor logininfor)
+    {
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        ExcelUtil<SysLogininfor> util = new ExcelUtil<SysLogininfor>(SysLogininfor.class);
+        util.exportExcel(response, list, "登录日志");
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds)
+    {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        logininforService.cleanLogininfor();
+        return success();
+    }
+
+    @PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
+    @Log(title = "账户解锁", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public AjaxResult unlock(@PathVariable("userName") String userName)
+    {
+        passwordService.clearLoginRecordCache(userName);
+        return success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysOperlogController.java
similarity index 80%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysOperlogController.java
index 5378424a..64efaa67 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysOperlogController.java
@@ -1,69 +1,69 @@
-package com.ruoyi.web.controller.monitor;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.system.domain.SysOperLog;
-import com.ruoyi.system.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);
-    }
-
-    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysOperLog operLog)
-    {
-        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
-        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
-        util.exportExcel(response, list, "操作日志");
-    }
-
-    @Log(title = "操作日志", businessType = BusinessType.DELETE)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
-    @DeleteMapping("/{operIds}")
-    public AjaxResult remove(@PathVariable Long[] operIds)
-    {
-        return toAjax(operLogService.deleteOperLogByIds(operIds));
-    }
-
-    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
-    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        operLogService.cleanOperLog();
-        return success();
-    }
-}
+package com.acupuncture.web.controller.monitor;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.domain.SysOperLog;
+import com.acupuncture.system.service.ISysOperLogService;
+
+/**
+ * 操作日志记录
+ * 
+ * @author acupuncture
+ */
+@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);
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysOperLog operLog)
+    {
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        ExcelUtil<SysOperLog> util = new ExcelUtil<SysOperLog>(SysOperLog.class);
+        util.exportExcel(response, list, "操作日志");
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.DELETE)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds)
+    {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        operLogService.cleanOperLog();
+        return success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysUserOnlineController.java
similarity index 78%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysUserOnlineController.java
index 7c343e21..19261110 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/monitor/SysUserOnlineController.java
@@ -1,83 +1,83 @@
-package com.ruoyi.web.controller.monitor;
-
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysUserOnline;
-import com.ruoyi.system.service.ISysUserOnlineService;
-
-/**
- * 在线用户监控
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/online")
-public class SysUserOnlineController extends BaseController
-{
-    @Autowired
-    private ISysUserOnlineService userOnlineService;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(String ipaddr, String userName)
-    {
-        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
-        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
-        for (String key : keys)
-        {
-            LoginUser user = redisCache.getCacheObject(key);
-            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
-            }
-            else if (StringUtils.isNotEmpty(ipaddr))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
-            }
-            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
-            {
-                userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
-            }
-            else
-            {
-                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
-            }
-        }
-        Collections.reverse(userOnlineList);
-        userOnlineList.removeAll(Collections.singleton(null));
-        return getDataTable(userOnlineList);
-    }
-
-    /**
-     * 强退用户
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
-    @Log(title = "在线用户", businessType = BusinessType.FORCE)
-    @DeleteMapping("/{tokenId}")
-    public AjaxResult forceLogout(@PathVariable String tokenId)
-    {
-        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
-        return success();
-    }
-}
+package com.acupuncture.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.SysUserOnline;
+import com.acupuncture.system.service.ISysUserOnlineService;
+
+/**
+ * 在线用户监控
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController
+{
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @PreAuthorize("@ss.hasPermi('monitor:online:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(String ipaddr, String userName)
+    {
+        Collection<String> keys = redisCache.keys(CacheConstants.LOGIN_TOKEN_KEY + "*");
+        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
+        for (String key : keys)
+        {
+            LoginUser user = redisCache.getCacheObject(key);
+            if (StringUtils.isNotEmpty(ipaddr) && StringUtils.isNotEmpty(userName))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+            }
+            else if (StringUtils.isNotEmpty(ipaddr))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+            }
+            else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser()))
+            {
+                userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+            }
+            else
+            {
+                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        return getDataTable(userOnlineList);
+    }
+
+    /**
+     * 强退用户
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:online:forceLogout')")
+    @Log(title = "在线用户", businessType = BusinessType.FORCE)
+    @DeleteMapping("/{tokenId}")
+    public AjaxResult forceLogout(@PathVariable String tokenId)
+    {
+        redisCache.deleteObject(CacheConstants.LOGIN_TOKEN_KEY + tokenId);
+        return success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysConfigController.java
similarity index 87%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysConfigController.java
index 95bcaece..6911d7c6 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysConfigController.java
@@ -1,133 +1,133 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.system.domain.SysConfig;
-import com.ruoyi.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);
-    }
-
-    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:config:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysConfig config)
-    {
-        List<SysConfig> list = configService.selectConfigList(config);
-        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
-        util.exportExcel(response, list, "参数数据");
-    }
-
-    /**
-     * 根据参数编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:query')")
-    @GetMapping(value = "/{configId}")
-    public AjaxResult getInfo(@PathVariable Long configId)
-    {
-        return success(configService.selectConfigById(configId));
-    }
-
-    /**
-     * 根据参数键名查询参数值
-     */
-    @GetMapping(value = "/configKey/{configKey}")
-    public AjaxResult getConfigKey(@PathVariable String configKey)
-    {
-        return success(configService.selectConfigByKey(configKey));
-    }
-
-    /**
-     * 新增参数配置
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:add')")
-    @Log(title = "参数管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysConfig config)
-    {
-        if (!configService.checkConfigKeyUnique(config))
-        {
-            return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
-        }
-        config.setCreateBy(getUsername());
-        return toAjax(configService.insertConfig(config));
-    }
-
-    /**
-     * 修改参数配置
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:edit')")
-    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysConfig config)
-    {
-        if (!configService.checkConfigKeyUnique(config))
-        {
-            return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
-        }
-        config.setUpdateBy(getUsername());
-        return toAjax(configService.updateConfig(config));
-    }
-
-    /**
-     * 删除参数配置
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:remove')")
-    @Log(title = "参数管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{configIds}")
-    public AjaxResult remove(@PathVariable Long[] configIds)
-    {
-        configService.deleteConfigByIds(configIds);
-        return success();
-    }
-
-    /**
-     * 刷新参数缓存
-     */
-    @PreAuthorize("@ss.hasPermi('system:config:remove')")
-    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
-        configService.resetConfigCache();
-        return success();
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.domain.SysConfig;
+import com.acupuncture.system.service.ISysConfigService;
+
+/**
+ * 参数配置 信息操作处理
+ * 
+ * @author acupuncture
+ */
+@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);
+    }
+
+    @Log(title = "参数管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:config:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysConfig config)
+    {
+        List<SysConfig> list = configService.selectConfigList(config);
+        ExcelUtil<SysConfig> util = new ExcelUtil<SysConfig>(SysConfig.class);
+        util.exportExcel(response, list, "参数数据");
+    }
+
+    /**
+     * 根据参数编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long configId)
+    {
+        return success(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 根据参数键名查询参数值
+     */
+    @GetMapping(value = "/configKey/{configKey}")
+    public AjaxResult getConfigKey(@PathVariable String configKey)
+    {
+        return success(configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 新增参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:add')")
+    @Log(title = "参数管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysConfig config)
+    {
+        if (!configService.checkConfigKeyUnique(config))
+        {
+            return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setCreateBy(getUsername());
+        return toAjax(configService.insertConfig(config));
+    }
+
+    /**
+     * 修改参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:edit')")
+    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysConfig config)
+    {
+        if (!configService.checkConfigKeyUnique(config))
+        {
+            return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setUpdateBy(getUsername());
+        return toAjax(configService.updateConfig(config));
+    }
+
+    /**
+     * 删除参数配置
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "参数管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds)
+    {
+        configService.deleteConfigByIds(configIds);
+        return success();
+    }
+
+    /**
+     * 刷新参数缓存
+     */
+    @PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache()
+    {
+        configService.resetConfigCache();
+        return success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDeptController.java
similarity index 88%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDeptController.java
index 4d70b655..088e7970 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDeptController.java
@@ -1,132 +1,132 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import org.apache.commons.lang3.ArrayUtils;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysDept;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.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 success(depts);
-    }
-
-    /**
-     * 查询部门列表(排除节点)
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:list')")
-    @GetMapping("/list/exclude/{deptId}")
-    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
-    {
-        List<SysDept> depts = deptService.selectDeptList(new SysDept());
-        depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
-        return success(depts);
-    }
-
-    /**
-     * 根据部门编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:query')")
-    @GetMapping(value = "/{deptId}")
-    public AjaxResult getInfo(@PathVariable Long deptId)
-    {
-        deptService.checkDeptDataScope(deptId);
-        return success(deptService.selectDeptById(deptId));
-    }
-
-    /**
-     * 新增部门
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:add')")
-    @Log(title = "部门管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDept dept)
-    {
-        if (!deptService.checkDeptNameUnique(dept))
-        {
-            return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
-        }
-        dept.setCreateBy(getUsername());
-        return toAjax(deptService.insertDept(dept));
-    }
-
-    /**
-     * 修改部门
-     */
-    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
-    @Log(title = "部门管理", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDept dept)
-    {
-        Long deptId = dept.getDeptId();
-        deptService.checkDeptDataScope(deptId);
-        if (!deptService.checkDeptNameUnique(dept))
-        {
-            return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
-        }
-        else if (dept.getParentId().equals(deptId))
-        {
-            return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
-        }
-        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
-        {
-            return error("该部门包含未停用的子部门!");
-        }
-        dept.setUpdateBy(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 warn("存在下级部门,不允许删除");
-        }
-        if (deptService.checkDeptExistUser(deptId))
-        {
-            return warn("部门存在用户,不允许删除");
-        }
-        deptService.checkDeptDataScope(deptId);
-        return toAjax(deptService.deleteDeptById(deptId));
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import org.apache.commons.lang3.ArrayUtils;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysDept;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.service.ISysDeptService;
+
+/**
+ * 部门信息
+ * 
+ * @author acupuncture
+ */
+@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 success(depts);
+    }
+
+    /**
+     * 查询部门列表(排除节点)
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list/exclude/{deptId}")
+    public AjaxResult excludeChild(@PathVariable(value = "deptId", required = false) Long deptId)
+    {
+        List<SysDept> depts = deptService.selectDeptList(new SysDept());
+        depts.removeIf(d -> d.getDeptId().intValue() == deptId || ArrayUtils.contains(StringUtils.split(d.getAncestors(), ","), deptId + ""));
+        return success(depts);
+    }
+
+    /**
+     * 根据部门编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable Long deptId)
+    {
+        deptService.checkDeptDataScope(deptId);
+        return success(deptService.selectDeptById(deptId));
+    }
+
+    /**
+     * 新增部门
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:add')")
+    @Log(title = "部门管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDept dept)
+    {
+        if (!deptService.checkDeptNameUnique(dept))
+        {
+            return error("新增部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+        }
+        dept.setCreateBy(getUsername());
+        return toAjax(deptService.insertDept(dept));
+    }
+
+    /**
+     * 修改部门
+     */
+    @PreAuthorize("@ss.hasPermi('system:dept:edit')")
+    @Log(title = "部门管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDept dept)
+    {
+        Long deptId = dept.getDeptId();
+        deptService.checkDeptDataScope(deptId);
+        if (!deptService.checkDeptNameUnique(dept))
+        {
+            return error("修改部门'" + dept.getDeptName() + "'失败,部门名称已存在");
+        }
+        else if (dept.getParentId().equals(deptId))
+        {
+            return error("修改部门'" + dept.getDeptName() + "'失败,上级部门不能是自己");
+        }
+        else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0)
+        {
+            return error("该部门包含未停用的子部门!");
+        }
+        dept.setUpdateBy(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 warn("存在下级部门,不允许删除");
+        }
+        if (deptService.checkDeptExistUser(deptId))
+        {
+            return warn("部门存在用户,不允许删除");
+        }
+        deptService.checkDeptDataScope(deptId);
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictDataController.java
similarity index 84%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictDataController.java
index 1914b998..eda00c66 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictDataController.java
@@ -1,121 +1,121 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.system.service.ISysDictDataService;
-import com.ruoyi.system.service.ISysDictTypeService;
-
-/**
- * 数据字典信息
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/dict/data")
-public class SysDictDataController extends BaseController
-{
-    @Autowired
-    private ISysDictDataService dictDataService;
-
-    @Autowired
-    private ISysDictTypeService dictTypeService;
-
-    @PreAuthorize("@ss.hasPermi('system:dict:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysDictData dictData)
-    {
-        startPage();
-        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
-        return getDataTable(list);
-    }
-
-    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysDictData dictData)
-    {
-        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
-        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
-        util.exportExcel(response, list, "字典数据");
-    }
-
-    /**
-     * 查询字典数据详细
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:query')")
-    @GetMapping(value = "/{dictCode}")
-    public AjaxResult getInfo(@PathVariable Long dictCode)
-    {
-        return success(dictDataService.selectDictDataById(dictCode));
-    }
-
-    /**
-     * 根据字典类型查询字典数据信息
-     */
-    @GetMapping(value = "/type/{dictType}")
-    public AjaxResult dictType(@PathVariable String dictType)
-    {
-        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
-        if (StringUtils.isNull(data))
-        {
-            data = new ArrayList<SysDictData>();
-        }
-        return success(data);
-    }
-
-    /**
-     * 新增字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:add')")
-    @Log(title = "字典数据", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDictData dict)
-    {
-        dict.setCreateBy(getUsername());
-        return toAjax(dictDataService.insertDictData(dict));
-    }
-
-    /**
-     * 修改保存字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
-    @Log(title = "字典数据", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
-    {
-        dict.setUpdateBy(getUsername());
-        return toAjax(dictDataService.updateDictData(dict));
-    }
-
-    /**
-     * 删除字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "字典类型", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictCodes}")
-    public AjaxResult remove(@PathVariable Long[] dictCodes)
-    {
-        dictDataService.deleteDictDataByIds(dictCodes);
-        return success();
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.service.ISysDictDataService;
+import com.acupuncture.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController
+{
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictData dictData)
+    {
+        startPage();
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return getDataTable(list);
+    }
+
+    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictData dictData)
+    {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
+        util.exportExcel(response, list, "字典数据");
+    }
+
+    /**
+     * 查询字典数据详细
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictCode}")
+    public AjaxResult getInfo(@PathVariable Long dictCode)
+    {
+        return success(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 根据字典类型查询字典数据信息
+     */
+    @GetMapping(value = "/type/{dictType}")
+    public AjaxResult dictType(@PathVariable String dictType)
+    {
+        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
+        if (StringUtils.isNull(data))
+        {
+            data = new ArrayList<SysDictData>();
+        }
+        return success(data);
+    }
+
+    /**
+     * 新增字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典数据", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setCreateBy(getUsername());
+        return toAjax(dictDataService.insertDictData(dict));
+    }
+
+    /**
+     * 修改保存字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典数据", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictData dict)
+    {
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictDataService.updateDictData(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCodes}")
+    public AjaxResult remove(@PathVariable Long[] dictCodes)
+    {
+        dictDataService.deleteDictDataByIds(dictCodes);
+        return success();
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictTypeController.java
similarity index 87%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictTypeController.java
index 98088424..da0e74d3 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysDictTypeController.java
@@ -1,131 +1,131 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysDictType;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.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")
-    public TableDataInfo list(SysDictType dictType)
-    {
-        startPage();
-        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
-        return getDataTable(list);
-    }
-
-    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:dict:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysDictType dictType)
-    {
-        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
-        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
-        util.exportExcel(response, list, "字典类型");
-    }
-
-    /**
-     * 查询字典类型详细
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:query')")
-    @GetMapping(value = "/{dictId}")
-    public AjaxResult getInfo(@PathVariable Long dictId)
-    {
-        return success(dictTypeService.selectDictTypeById(dictId));
-    }
-
-    /**
-     * 新增字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:add')")
-    @Log(title = "字典类型", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysDictType dict)
-    {
-        if (!dictTypeService.checkDictTypeUnique(dict))
-        {
-            return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
-        }
-        dict.setCreateBy(getUsername());
-        return toAjax(dictTypeService.insertDictType(dict));
-    }
-
-    /**
-     * 修改字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
-    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
-    {
-        if (!dictTypeService.checkDictTypeUnique(dict))
-        {
-            return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
-        }
-        dict.setUpdateBy(getUsername());
-        return toAjax(dictTypeService.updateDictType(dict));
-    }
-
-    /**
-     * 删除字典类型
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "字典类型", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{dictIds}")
-    public AjaxResult remove(@PathVariable Long[] dictIds)
-    {
-        dictTypeService.deleteDictTypeByIds(dictIds);
-        return success();
-    }
-
-    /**
-     * 刷新字典缓存
-     */
-    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
-    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/refreshCache")
-    public AjaxResult refreshCache()
-    {
-        dictTypeService.resetDictCache();
-        return success();
-    }
-
-    /**
-     * 获取字典选择框列表
-     */
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
-        return success(dictTypes);
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysDictType;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.service.ISysDictTypeService;
+
+/**
+ * 数据字典信息
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController
+{
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictType dictType)
+    {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        return getDataTable(list);
+    }
+
+    @Log(title = "字典类型", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictType dictType)
+    {
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        ExcelUtil<SysDictType> util = new ExcelUtil<SysDictType>(SysDictType.class);
+        util.exportExcel(response, list, "字典类型");
+    }
+
+    /**
+     * 查询字典类型详细
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictId}")
+    public AjaxResult getInfo(@PathVariable Long dictId)
+    {
+        return success(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 新增字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典类型", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictType dict)
+    {
+        if (!dictTypeService.checkDictTypeUnique(dict))
+        {
+            return error("新增字典'" + dict.getDictName() + "'失败,字典类型已存在");
+        }
+        dict.setCreateBy(getUsername());
+        return toAjax(dictTypeService.insertDictType(dict));
+    }
+
+    /**
+     * 修改字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictType dict)
+    {
+        if (!dictTypeService.checkDictTypeUnique(dict))
+        {
+            return error("修改字典'" + dict.getDictName() + "'失败,字典类型已存在");
+        }
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictTypeService.updateDictType(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictIds}")
+    public AjaxResult remove(@PathVariable Long[] dictIds)
+    {
+        dictTypeService.deleteDictTypeByIds(dictIds);
+        return success();
+    }
+
+    /**
+     * 刷新字典缓存
+     */
+    @PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache()
+    {
+        dictTypeService.resetDictCache();
+        return success();
+    }
+
+    /**
+     * 获取字典选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
+        return success(dictTypes);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysIndexController.java
similarity index 60%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysIndexController.java
index 009219e0..d72855b1 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysIndexController.java
@@ -1,29 +1,29 @@
-package com.ruoyi.web.controller.system;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 首页
- *
- * @author ruoyi
- */
-@RestController
-public class SysIndexController
-{
-    /** 系统基础配置 */
-    @Autowired
-    private RuoYiConfig ruoyiConfig;
-
-    /**
-     * 访问首页,提示语
-     */
-    @RequestMapping("/")
-    public String index()
-    {
-        return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", ruoyiConfig.getName(), ruoyiConfig.getVersion());
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 首页
+ *
+ * @author acupuncture
+ */
+@RestController
+public class SysIndexController
+{
+    /** 系统基础配置 */
+    @Autowired
+    private RuoYiConfig RuoYiConfig;
+
+    /**
+     * 访问首页,提示语
+     */
+    @RequestMapping("/")
+    public String index()
+    {
+        return StringUtils.format("欢迎使用{}后台管理框架,当前版本:v{},请通过前端地址访问。", RuoYiConfig.getName(), RuoYiConfig.getVersion());
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysLoginController.java
similarity index 76%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysLoginController.java
index e575d287..deb79320 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysLoginController.java
@@ -1,97 +1,97 @@
-package com.ruoyi.web.controller.system;
-
-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.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginBody;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.web.service.SysLoginService;
-import com.ruoyi.framework.web.service.SysPermissionService;
-import com.ruoyi.framework.web.service.TokenService;
-import com.ruoyi.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 loginBody 登录信息
-     * @return 结果
-     */
-    @PostMapping("/login")
-    public AjaxResult login(@RequestBody LoginBody loginBody)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        // 生成令牌
-        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
-                loginBody.getUuid());
-        ajax.put(Constants.TOKEN, token);
-        return ajax;
-    }
-
-    /**
-     * 获取用户信息
-     * 
-     * @return 用户信息
-     */
-    @GetMapping("getInfo")
-    public AjaxResult getInfo()
-    {
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        SysUser user = loginUser.getUser();
-        // 角色集合
-        Set<String> roles = permissionService.getRolePermission(user);
-        // 权限集合
-        Set<String> permissions = permissionService.getMenuPermission(user);
-        if (!loginUser.getPermissions().equals(permissions))
-        {
-            loginUser.setPermissions(permissions);
-            tokenService.refreshToken(loginUser);
-        }
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("user", user);
-        ajax.put("roles", roles);
-        ajax.put("permissions", permissions);
-        return ajax;
-    }
-
-    /**
-     * 获取路由信息
-     * 
-     * @return 路由信息
-     */
-    @GetMapping("getRouters")
-    public AjaxResult getRouters()
-    {
-        Long userId = SecurityUtils.getUserId();
-        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
-        return AjaxResult.success(menuService.buildMenus(menus));
-    }
-}
+package com.acupuncture.web.controller.system;
+
+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.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginBody;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.framework.web.service.SysLoginService;
+import com.acupuncture.framework.web.service.SysPermissionService;
+import com.acupuncture.framework.web.service.TokenService;
+import com.acupuncture.system.service.ISysMenuService;
+
+/**
+ * 登录验证
+ * 
+ * @author acupuncture
+ */
+@RestController
+public class SysLoginController
+{
+    @Autowired
+    private SysLoginService loginService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 登录方法
+     * 
+     * @param loginBody 登录信息
+     * @return 结果
+     */
+    @PostMapping("/login")
+    public AjaxResult login(@RequestBody LoginBody loginBody)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        // 生成令牌
+        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(),
+                loginBody.getUuid());
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 获取用户信息
+     * 
+     * @return 用户信息
+     */
+    @GetMapping("getInfo")
+    public AjaxResult getInfo()
+    {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        SysUser user = loginUser.getUser();
+        // 角色集合
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 权限集合
+        Set<String> permissions = permissionService.getMenuPermission(user);
+        if (!loginUser.getPermissions().equals(permissions))
+        {
+            loginUser.setPermissions(permissions);
+            tokenService.refreshToken(loginUser);
+        }
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("user", user);
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        return ajax;
+    }
+
+    /**
+     * 获取路由信息
+     * 
+     * @return 路由信息
+     */
+    @GetMapping("getRouters")
+    public AjaxResult getRouters()
+    {
+        Long userId = SecurityUtils.getUserId();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId);
+        return AjaxResult.success(menuService.buildMenus(menus));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysMenuController.java
similarity index 88%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysMenuController.java
index eaaebd3e..bfc5c016 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysMenuController.java
@@ -1,142 +1,142 @@
-package com.ruoyi.web.controller.system;
-
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.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, getUserId());
-        return success(menus);
-    }
-
-    /**
-     * 根据菜单编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:query')")
-    @GetMapping(value = "/{menuId}")
-    public AjaxResult getInfo(@PathVariable Long menuId)
-    {
-        return success(menuService.selectMenuById(menuId));
-    }
-
-    /**
-     * 获取菜单下拉树列表
-     */
-    @GetMapping("/treeselect")
-    public AjaxResult treeselect(SysMenu menu)
-    {
-        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
-        return success(menuService.buildMenuTreeSelect(menus));
-    }
-
-    /**
-     * 加载对应角色菜单列表树
-     */
-    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
-    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
-    {
-        List<SysMenu> menus = menuService.selectMenuList(getUserId());
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
-        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
-        return ajax;
-    }
-
-    /**
-     * 新增菜单
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:add')")
-    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysMenu menu)
-    {
-        if (!menuService.checkMenuNameUnique(menu))
-        {
-            return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
-        }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
-        {
-            return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
-        }
-        menu.setCreateBy(getUsername());
-        return toAjax(menuService.insertMenu(menu));
-    }
-
-    /**
-     * 修改菜单
-     */
-    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
-    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
-    {
-        if (!menuService.checkMenuNameUnique(menu))
-        {
-            return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
-        }
-        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
-        {
-            return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
-        }
-        else if (menu.getMenuId().equals(menu.getParentId()))
-        {
-            return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
-        }
-        menu.setUpdateBy(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 warn("存在子菜单,不允许删除");
-        }
-        if (menuService.checkMenuExistRole(menuId))
-        {
-            return warn("菜单已分配,不允许删除");
-        }
-        return toAjax(menuService.deleteMenuById(menuId));
-    }
+package com.acupuncture.web.controller.system;
+
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.service.ISysMenuService;
+
+/**
+ * 菜单信息
+ * 
+ * @author acupuncture
+ */
+@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, getUserId());
+        return success(menus);
+    }
+
+    /**
+     * 根据菜单编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable Long menuId)
+    {
+        return success(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 获取菜单下拉树列表
+     */
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysMenu menu)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
+        return success(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 加载对应角色菜单列表树
+     */
+    @GetMapping(value = "/roleMenuTreeselect/{roleId}")
+    public AjaxResult roleMenuTreeselect(@PathVariable("roleId") Long roleId)
+    {
+        List<SysMenu> menus = menuService.selectMenuList(getUserId());
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
+        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
+        return ajax;
+    }
+
+    /**
+     * 新增菜单
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:add')")
+    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysMenu menu)
+    {
+        if (!menuService.checkMenuNameUnique(menu))
+        {
+            return error("新增菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+        {
+            return error("新增菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+        }
+        menu.setCreateBy(getUsername());
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 修改菜单
+     */
+    @PreAuthorize("@ss.hasPermi('system:menu:edit')")
+    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysMenu menu)
+    {
+        if (!menuService.checkMenuNameUnique(menu))
+        {
+            return error("修改菜单'" + menu.getMenuName() + "'失败,菜单名称已存在");
+        }
+        else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath()))
+        {
+            return error("修改菜单'" + menu.getMenuName() + "'失败,地址必须以http(s)://开头");
+        }
+        else if (menu.getMenuId().equals(menu.getParentId()))
+        {
+            return error("修改菜单'" + menu.getMenuName() + "'失败,上级菜单不能选择自己");
+        }
+        menu.setUpdateBy(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 warn("存在子菜单,不允许删除");
+        }
+        if (menuService.checkMenuExistRole(menuId))
+        {
+            return warn("菜单已分配,不允许删除");
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysNoticeController.java
similarity index 84%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysNoticeController.java
index 36c62b99..cf73c3ad 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysNoticeController.java
@@ -1,91 +1,91 @@
-package com.ruoyi.web.controller.system;
-
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.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 success(noticeService.selectNoticeById(noticeId));
-    }
-
-    /**
-     * 新增通知公告
-     */
-    @PreAuthorize("@ss.hasPermi('system:notice:add')")
-    @Log(title = "通知公告", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysNotice notice)
-    {
-        notice.setCreateBy(getUsername());
-        return toAjax(noticeService.insertNotice(notice));
-    }
-
-    /**
-     * 修改通知公告
-     */
-    @PreAuthorize("@ss.hasPermi('system:notice:edit')")
-    @Log(title = "通知公告", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysNotice notice)
-    {
-        notice.setUpdateBy(getUsername());
-        return toAjax(noticeService.updateNotice(notice));
-    }
-
-    /**
-     * 删除通知公告
-     */
-    @PreAuthorize("@ss.hasPermi('system:notice:remove')")
-    @Log(title = "通知公告", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{noticeIds}")
-    public AjaxResult remove(@PathVariable Long[] noticeIds)
-    {
-        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
-    }
-}
+package com.acupuncture.web.controller.system;
+
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.system.domain.SysNotice;
+import com.acupuncture.system.service.ISysNoticeService;
+
+/**
+ * 公告 信息操作处理
+ * 
+ * @author acupuncture
+ */
+@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 success(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 新增通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:add')")
+    @Log(title = "通知公告", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysNotice notice)
+    {
+        notice.setCreateBy(getUsername());
+        return toAjax(noticeService.insertNotice(notice));
+    }
+
+    /**
+     * 修改通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:edit')")
+    @Log(title = "通知公告", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysNotice notice)
+    {
+        notice.setUpdateBy(getUsername());
+        return toAjax(noticeService.updateNotice(notice));
+    }
+
+    /**
+     * 删除通知公告
+     */
+    @PreAuthorize("@ss.hasPermi('system:notice:remove')")
+    @Log(title = "通知公告", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{noticeIds}")
+    public AjaxResult remove(@PathVariable Long[] noticeIds)
+    {
+        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysPostController.java
similarity index 87%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysPostController.java
index a5b96c87..04d37137 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysPostController.java
@@ -1,129 +1,129 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.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);
-    }
-    
-    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:post:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysPost post)
-    {
-        List<SysPost> list = postService.selectPostList(post);
-        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
-        util.exportExcel(response, list, "岗位数据");
-    }
-
-    /**
-     * 根据岗位编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:query')")
-    @GetMapping(value = "/{postId}")
-    public AjaxResult getInfo(@PathVariable Long postId)
-    {
-        return success(postService.selectPostById(postId));
-    }
-
-    /**
-     * 新增岗位
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:add')")
-    @Log(title = "岗位管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysPost post)
-    {
-        if (!postService.checkPostNameUnique(post))
-        {
-            return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
-        }
-        else if (!postService.checkPostCodeUnique(post))
-        {
-            return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
-        }
-        post.setCreateBy(getUsername());
-        return toAjax(postService.insertPost(post));
-    }
-
-    /**
-     * 修改岗位
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:edit')")
-    @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysPost post)
-    {
-        if (!postService.checkPostNameUnique(post))
-        {
-            return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
-        }
-        else if (!postService.checkPostCodeUnique(post))
-        {
-            return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
-        }
-        post.setUpdateBy(getUsername());
-        return toAjax(postService.updatePost(post));
-    }
-
-    /**
-     * 删除岗位
-     */
-    @PreAuthorize("@ss.hasPermi('system:post:remove')")
-    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{postIds}")
-    public AjaxResult remove(@PathVariable Long[] postIds)
-    {
-        return toAjax(postService.deletePostByIds(postIds));
-    }
-
-    /**
-     * 获取岗位选择框列表
-     */
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        List<SysPost> posts = postService.selectPostAll();
-        return success(posts);
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.domain.SysPost;
+import com.acupuncture.system.service.ISysPostService;
+
+/**
+ * 岗位信息操作处理
+ * 
+ * @author acupuncture
+ */
+@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);
+    }
+    
+    @Log(title = "岗位管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:post:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysPost post)
+    {
+        List<SysPost> list = postService.selectPostList(post);
+        ExcelUtil<SysPost> util = new ExcelUtil<SysPost>(SysPost.class);
+        util.exportExcel(response, list, "岗位数据");
+    }
+
+    /**
+     * 根据岗位编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable Long postId)
+    {
+        return success(postService.selectPostById(postId));
+    }
+
+    /**
+     * 新增岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:add')")
+    @Log(title = "岗位管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysPost post)
+    {
+        if (!postService.checkPostNameUnique(post))
+        {
+            return error("新增岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+        }
+        else if (!postService.checkPostCodeUnique(post))
+        {
+            return error("新增岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+        }
+        post.setCreateBy(getUsername());
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 修改岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:edit')")
+    @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysPost post)
+    {
+        if (!postService.checkPostNameUnique(post))
+        {
+            return error("修改岗位'" + post.getPostName() + "'失败,岗位名称已存在");
+        }
+        else if (!postService.checkPostCodeUnique(post))
+        {
+            return error("修改岗位'" + post.getPostName() + "'失败,岗位编码已存在");
+        }
+        post.setUpdateBy(getUsername());
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 删除岗位
+     */
+    @PreAuthorize("@ss.hasPermi('system:post:remove')")
+    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds)
+    {
+        return toAjax(postService.deletePostByIds(postIds));
+    }
+
+    /**
+     * 获取岗位选择框列表
+     */
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        List<SysPost> posts = postService.selectPostAll();
+        return success(posts);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysProfileController.java
similarity index 84%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysProfileController.java
index 89e9bd33..cfc04fe9 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysProfileController.java
@@ -1,140 +1,140 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.Map;
-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.annotation.Log;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.file.FileUploadUtils;
-import com.ruoyi.common.utils.file.MimeTypeUtils;
-import com.ruoyi.framework.web.service.TokenService;
-import com.ruoyi.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 = getLoginUser();
-        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)
-    {
-        LoginUser loginUser = getLoginUser();
-        SysUser currentUser = loginUser.getUser();
-        currentUser.setNickName(user.getNickName());
-        currentUser.setEmail(user.getEmail());
-        currentUser.setPhonenumber(user.getPhonenumber());
-        currentUser.setSex(user.getSex());
-        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
-        {
-            return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
-        }
-        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
-        {
-            return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
-        }
-        if (userService.updateUserProfile(currentUser) > 0)
-        {
-            // 更新缓存用户信息
-            tokenService.setLoginUser(loginUser);
-            return success();
-        }
-        return error("修改个人信息异常,请联系管理员");
-    }
-
-    /**
-     * 重置密码
-     */
-    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
-    @PutMapping("/updatePwd")
-    public AjaxResult updatePwd(@RequestBody Map<String, String> params)
-    {
-        String oldPassword = params.get("oldPassword");
-        String newPassword = params.get("newPassword");
-        LoginUser loginUser = getLoginUser();
-        String userName = loginUser.getUsername();
-        String password = loginUser.getPassword();
-        if (!SecurityUtils.matchesPassword(oldPassword, password))
-        {
-            return error("修改密码失败,旧密码错误");
-        }
-        if (SecurityUtils.matchesPassword(newPassword, password))
-        {
-            return error("新密码不能与旧密码相同");
-        }
-        newPassword = SecurityUtils.encryptPassword(newPassword);
-        if (userService.resetUserPwd(userName, newPassword) > 0)
-        {
-            // 更新缓存用户密码
-            loginUser.getUser().setPassword(newPassword);
-            tokenService.setLoginUser(loginUser);
-            return success();
-        }
-        return error("修改密码异常,请联系管理员");
-    }
-
-    /**
-     * 头像上传
-     */
-    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
-    @PostMapping("/avatar")
-    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
-    {
-        if (!file.isEmpty())
-        {
-            LoginUser loginUser = getLoginUser();
-            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
-            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
-            {
-                AjaxResult ajax = AjaxResult.success();
-                ajax.put("imgUrl", avatar);
-                // 更新缓存用户头像
-                loginUser.getUser().setAvatar(avatar);
-                tokenService.setLoginUser(loginUser);
-                return ajax;
-            }
-        }
-        return error("上传图片异常,请联系管理员");
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.Map;
+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.acupuncture.common.annotation.Log;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.file.FileUploadUtils;
+import com.acupuncture.common.utils.file.MimeTypeUtils;
+import com.acupuncture.framework.web.service.TokenService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 个人信息 业务处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 个人信息
+     */
+    @GetMapping
+    public AjaxResult profile()
+    {
+        LoginUser loginUser = getLoginUser();
+        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)
+    {
+        LoginUser loginUser = getLoginUser();
+        SysUser currentUser = loginUser.getUser();
+        currentUser.setNickName(user.getNickName());
+        currentUser.setEmail(user.getEmail());
+        currentUser.setPhonenumber(user.getPhonenumber());
+        currentUser.setSex(user.getSex());
+        if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(currentUser))
+        {
+            return error("修改用户'" + loginUser.getUsername() + "'失败,手机号码已存在");
+        }
+        if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(currentUser))
+        {
+            return error("修改用户'" + loginUser.getUsername() + "'失败,邮箱账号已存在");
+        }
+        if (userService.updateUserProfile(currentUser) > 0)
+        {
+            // 更新缓存用户信息
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error("修改个人信息异常,请联系管理员");
+    }
+
+    /**
+     * 重置密码
+     */
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public AjaxResult updatePwd(@RequestBody Map<String, String> params)
+    {
+        String oldPassword = params.get("oldPassword");
+        String newPassword = params.get("newPassword");
+        LoginUser loginUser = getLoginUser();
+        String userName = loginUser.getUsername();
+        String password = loginUser.getPassword();
+        if (!SecurityUtils.matchesPassword(oldPassword, password))
+        {
+            return error("修改密码失败,旧密码错误");
+        }
+        if (SecurityUtils.matchesPassword(newPassword, password))
+        {
+            return error("新密码不能与旧密码相同");
+        }
+        newPassword = SecurityUtils.encryptPassword(newPassword);
+        if (userService.resetUserPwd(userName, newPassword) > 0)
+        {
+            // 更新缓存用户密码
+            loginUser.getUser().setPassword(newPassword);
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error("修改密码异常,请联系管理员");
+    }
+
+    /**
+     * 头像上传
+     */
+    @Log(title = "用户头像", businessType = BusinessType.UPDATE)
+    @PostMapping("/avatar")
+    public AjaxResult avatar(@RequestParam("avatarfile") MultipartFile file) throws Exception
+    {
+        if (!file.isEmpty())
+        {
+            LoginUser loginUser = getLoginUser();
+            String avatar = FileUploadUtils.upload(RuoYiConfig.getAvatarPath(), file, MimeTypeUtils.IMAGE_EXTENSION);
+            if (userService.updateUserAvatar(loginUser.getUsername(), avatar))
+            {
+                AjaxResult ajax = AjaxResult.success();
+                ajax.put("imgUrl", avatar);
+                // 更新缓存用户头像
+                loginUser.getUser().setAvatar(avatar);
+                tokenService.setLoginUser(loginUser);
+                return ajax;
+            }
+        }
+        return error("上传图片异常,请联系管理员");
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRegisterController.java
similarity index 67%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRegisterController.java
index f1552e03..32359ea5 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRegisterController.java
@@ -1,38 +1,38 @@
-package com.ruoyi.web.controller.system;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.web.bind.annotation.PostMapping;
-import org.springframework.web.bind.annotation.RequestBody;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.model.RegisterBody;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.web.service.SysRegisterService;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 注册验证
- * 
- * @author ruoyi
- */
-@RestController
-public class SysRegisterController extends BaseController
-{
-    @Autowired
-    private SysRegisterService registerService;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    @PostMapping("/register")
-    public AjaxResult register(@RequestBody RegisterBody user)
-    {
-        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
-        {
-            return error("当前系统没有开启注册功能!");
-        }
-        String msg = registerService.register(user);
-        return StringUtils.isEmpty(msg) ? success() : error(msg);
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.model.RegisterBody;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.web.service.SysRegisterService;
+import com.acupuncture.system.service.ISysConfigService;
+
+/**
+ * 注册验证
+ * 
+ * @author acupuncture
+ */
+@RestController
+public class SysRegisterController extends BaseController
+{
+    @Autowired
+    private SysRegisterService registerService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @PostMapping("/register")
+    public AjaxResult register(@RequestBody RegisterBody user)
+    {
+        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser"))))
+        {
+            return error("当前系统没有开启注册功能!");
+        }
+        String msg = registerService.register(user);
+        return StringUtils.isEmpty(msg) ? success() : error(msg);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRoleController.java
similarity index 87%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRoleController.java
index dfbf256b..55a8a88a 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysRoleController.java
@@ -1,262 +1,262 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysDept;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.framework.web.service.SysPermissionService;
-import com.ruoyi.framework.web.service.TokenService;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysRoleService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 角色信息
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/role")
-public class SysRoleController extends BaseController
-{
-    @Autowired
-    private ISysRoleService roleService;
-
-    @Autowired
-    private TokenService tokenService;
-
-    @Autowired
-    private SysPermissionService permissionService;
-
-    @Autowired
-    private ISysUserService userService;
-
-    @Autowired
-    private ISysDeptService deptService;
-
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysRole role)
-    {
-        startPage();
-        List<SysRole> list = roleService.selectRoleList(role);
-        return getDataTable(list);
-    }
-
-    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:role:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysRole role)
-    {
-        List<SysRole> list = roleService.selectRoleList(role);
-        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
-        util.exportExcel(response, list, "角色数据");
-    }
-
-    /**
-     * 根据角色编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping(value = "/{roleId}")
-    public AjaxResult getInfo(@PathVariable Long roleId)
-    {
-        roleService.checkRoleDataScope(roleId);
-        return success(roleService.selectRoleById(roleId));
-    }
-
-    /**
-     * 新增角色
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:add')")
-    @Log(title = "角色管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysRole role)
-    {
-        if (!roleService.checkRoleNameUnique(role))
-        {
-            return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
-        }
-        role.setCreateBy(getUsername());
-        return toAjax(roleService.insertRole(role));
-
-    }
-
-    /**
-     * 修改保存角色
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@Validated @RequestBody SysRole role)
-    {
-        roleService.checkRoleAllowed(role);
-        roleService.checkRoleDataScope(role.getRoleId());
-        if (!roleService.checkRoleNameUnique(role))
-        {
-            return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
-        }
-        else if (!roleService.checkRoleKeyUnique(role))
-        {
-            return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
-        }
-        role.setUpdateBy(getUsername());
-        
-        if (roleService.updateRole(role) > 0)
-        {
-            // 更新缓存用户权限
-            LoginUser loginUser = getLoginUser();
-            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
-            {
-                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
-                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
-                tokenService.setLoginUser(loginUser);
-            }
-            return success();
-        }
-        return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
-    }
-
-    /**
-     * 修改保存数据权限
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
-    @PutMapping("/dataScope")
-    public AjaxResult dataScope(@RequestBody SysRole role)
-    {
-        roleService.checkRoleAllowed(role);
-        roleService.checkRoleDataScope(role.getRoleId());
-        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);
-        roleService.checkRoleDataScope(role.getRoleId());
-        role.setUpdateBy(getUsername());
-        return toAjax(roleService.updateRoleStatus(role));
-    }
-
-    /**
-     * 删除角色
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:remove')")
-    @Log(title = "角色管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{roleIds}")
-    public AjaxResult remove(@PathVariable Long[] roleIds)
-    {
-        return toAjax(roleService.deleteRoleByIds(roleIds));
-    }
-
-    /**
-     * 获取角色选择框列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping("/optionselect")
-    public AjaxResult optionselect()
-    {
-        return success(roleService.selectRoleAll());
-    }
-
-    /**
-     * 查询已分配用户角色列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/authUser/allocatedList")
-    public TableDataInfo allocatedList(SysUser user)
-    {
-        startPage();
-        List<SysUser> list = userService.selectAllocatedList(user);
-        return getDataTable(list);
-    }
-
-    /**
-     * 查询未分配用户角色列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:list')")
-    @GetMapping("/authUser/unallocatedList")
-    public TableDataInfo unallocatedList(SysUser user)
-    {
-        startPage();
-        List<SysUser> list = userService.selectUnallocatedList(user);
-        return getDataTable(list);
-    }
-
-    /**
-     * 取消授权用户
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "角色管理", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/cancel")
-    public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
-    {
-        return toAjax(roleService.deleteAuthUser(userRole));
-    }
-
-    /**
-     * 批量取消授权用户
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "角色管理", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/cancelAll")
-    public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
-    {
-        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
-    }
-
-    /**
-     * 批量选择用户授权
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:edit')")
-    @Log(title = "角色管理", businessType = BusinessType.GRANT)
-    @PutMapping("/authUser/selectAll")
-    public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
-    {
-        roleService.checkRoleDataScope(roleId);
-        return toAjax(roleService.insertAuthUsers(roleId, userIds));
-    }
-
-    /**
-     * 获取对应角色部门树列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:role:query')")
-    @GetMapping(value = "/deptTree/{roleId}")
-    public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
-        ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
-        return ajax;
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysDept;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.framework.web.service.SysPermissionService;
+import com.acupuncture.framework.web.service.TokenService;
+import com.acupuncture.system.domain.SysUserRole;
+import com.acupuncture.system.service.ISysDeptService;
+import com.acupuncture.system.service.ISysRoleService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 角色信息
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController
+{
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysRole role)
+    {
+        startPage();
+        List<SysRole> list = roleService.selectRoleList(role);
+        return getDataTable(list);
+    }
+
+    @Log(title = "角色管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:role:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysRole role)
+    {
+        List<SysRole> list = roleService.selectRoleList(role);
+        ExcelUtil<SysRole> util = new ExcelUtil<SysRole>(SysRole.class);
+        util.exportExcel(response, list, "角色数据");
+    }
+
+    /**
+     * 根据角色编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable Long roleId)
+    {
+        roleService.checkRoleDataScope(roleId);
+        return success(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 新增角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:add')")
+    @Log(title = "角色管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysRole role)
+    {
+        if (!roleService.checkRoleNameUnique(role))
+        {
+            return error("新增角色'" + role.getRoleName() + "'失败,角色名称已存在");
+        }
+        else if (!roleService.checkRoleKeyUnique(role))
+        {
+            return error("新增角色'" + role.getRoleName() + "'失败,角色权限已存在");
+        }
+        role.setCreateBy(getUsername());
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 修改保存角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        if (!roleService.checkRoleNameUnique(role))
+        {
+            return error("修改角色'" + role.getRoleName() + "'失败,角色名称已存在");
+        }
+        else if (!roleService.checkRoleKeyUnique(role))
+        {
+            return error("修改角色'" + role.getRoleName() + "'失败,角色权限已存在");
+        }
+        role.setUpdateBy(getUsername());
+        
+        if (roleService.updateRole(role) > 0)
+        {
+            // 更新缓存用户权限
+            LoginUser loginUser = getLoginUser();
+            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin())
+            {
+                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
+                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
+                tokenService.setLoginUser(loginUser);
+            }
+            return success();
+        }
+        return error("修改角色'" + role.getRoleName() + "'失败,请联系管理员");
+    }
+
+    /**
+     * 修改保存数据权限
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/dataScope")
+    public AjaxResult dataScope(@RequestBody SysRole role)
+    {
+        roleService.checkRoleAllowed(role);
+        roleService.checkRoleDataScope(role.getRoleId());
+        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);
+        roleService.checkRoleDataScope(role.getRoleId());
+        role.setUpdateBy(getUsername());
+        return toAjax(roleService.updateRoleStatus(role));
+    }
+
+    /**
+     * 删除角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:remove')")
+    @Log(title = "角色管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds)
+    {
+        return toAjax(roleService.deleteRoleByIds(roleIds));
+    }
+
+    /**
+     * 获取角色选择框列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect()
+    {
+        return success(roleService.selectRoleAll());
+    }
+
+    /**
+     * 查询已分配用户角色列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/allocatedList")
+    public TableDataInfo allocatedList(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectAllocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询未分配用户角色列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/unallocatedList")
+    public TableDataInfo unallocatedList(SysUser user)
+    {
+        startPage();
+        List<SysUser> list = userService.selectUnallocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 取消授权用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancel")
+    public AjaxResult cancelAuthUser(@RequestBody SysUserRole userRole)
+    {
+        return toAjax(roleService.deleteAuthUser(userRole));
+    }
+
+    /**
+     * 批量取消授权用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/cancelAll")
+    public AjaxResult cancelAuthUserAll(Long roleId, Long[] userIds)
+    {
+        return toAjax(roleService.deleteAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 批量选择用户授权
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:edit')")
+    @Log(title = "角色管理", businessType = BusinessType.GRANT)
+    @PutMapping("/authUser/selectAll")
+    public AjaxResult selectAuthUserAll(Long roleId, Long[] userIds)
+    {
+        roleService.checkRoleDataScope(roleId);
+        return toAjax(roleService.insertAuthUsers(roleId, userIds));
+    }
+
+    /**
+     * 获取对应角色部门树列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/deptTree/{roleId}")
+    public AjaxResult deptTree(@PathVariable("roleId") Long roleId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", deptService.selectDeptListByRoleId(roleId));
+        ajax.put("depts", deptService.selectDeptTreeList(new SysDept()));
+        return ajax;
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysUserController.java
similarity index 89%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysUserController.java
index 11790f9b..6c78824c 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/system/SysUserController.java
@@ -1,256 +1,256 @@
-package com.ruoyi.web.controller.system;
-
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-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.RestController;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.entity.SysDept;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysPostService;
-import com.ruoyi.system.service.ISysRoleService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 用户信息
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/system/user")
-public class SysUserController extends BaseController
-{
-    @Autowired
-    private ISysUserService userService;
-
-    @Autowired
-    private ISysRoleService roleService;
-
-    @Autowired
-    private ISysDeptService deptService;
-
-    @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);
-    }
-
-    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
-    @PreAuthorize("@ss.hasPermi('system:user:export')")
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysUser user)
-    {
-        List<SysUser> list = userService.selectUserList(user);
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        util.exportExcel(response, list, "用户数据");
-    }
-
-    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
-    @PreAuthorize("@ss.hasPermi('system:user:import')")
-    @PostMapping("/importData")
-    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
-    {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        List<SysUser> userList = util.importExcel(file.getInputStream());
-        String operName = getUsername();
-        String message = userService.importUser(userList, updateSupport, operName);
-        return success(message);
-    }
-
-    @PostMapping("/importTemplate")
-    public void importTemplate(HttpServletResponse response)
-    {
-        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
-        util.importTemplateExcel(response, "用户数据");
-    }
-
-    /**
-     * 根据用户编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:query')")
-    @GetMapping(value = { "/", "/{userId}" })
-    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        if (StringUtils.isNotNull(userId))
-        {
-            userService.checkUserDataScope(userId);
-            SysUser sysUser = userService.selectUserById(userId);
-            ajax.put(AjaxResult.DATA_TAG, sysUser);
-            ajax.put("postIds", postService.selectPostListByUserId(userId));
-            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
-        }
-        List<SysRole> roles = roleService.selectRoleAll();
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
-        ajax.put("posts", postService.selectPostAll());
-        return ajax;
-    }
-
-    /**
-     * 新增用户
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:add')")
-    @Log(title = "用户管理", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@Validated @RequestBody SysUser user)
-    {
-        deptService.checkDeptDataScope(user.getDeptId());
-        roleService.checkRoleDataScope(user.getRoleIds());
-        if (!userService.checkUserNameUnique(user))
-        {
-            return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }
-        user.setCreateBy(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(@Validated @RequestBody SysUser user)
-    {
-        userService.checkUserAllowed(user);
-        userService.checkUserDataScope(user.getUserId());
-        deptService.checkDeptDataScope(user.getDeptId());
-        roleService.checkRoleDataScope(user.getRoleIds());
-        if (!userService.checkUserNameUnique(user))
-        {
-            return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
-        {
-            return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
-        }
-        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
-        {
-            return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
-        }
-        user.setUpdateBy(getUsername());
-        return toAjax(userService.updateUser(user));
-    }
-
-    /**
-     * 删除用户
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:remove')")
-    @Log(title = "用户管理", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{userIds}")
-    public AjaxResult remove(@PathVariable Long[] userIds)
-    {
-        if (ArrayUtils.contains(userIds, getUserId()))
-        {
-            return error("当前用户不能删除");
-        }
-        return toAjax(userService.deleteUserByIds(userIds));
-    }
-
-    /**
-     * 重置密码
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
-    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
-    @PutMapping("/resetPwd")
-    public AjaxResult resetPwd(@RequestBody SysUser user)
-    {
-        userService.checkUserAllowed(user);
-        userService.checkUserDataScope(user.getUserId());
-        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
-        user.setUpdateBy(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);
-        userService.checkUserDataScope(user.getUserId());
-        user.setUpdateBy(getUsername());
-        return toAjax(userService.updateUserStatus(user));
-    }
-
-    /**
-     * 根据用户编号获取授权角色
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:query')")
-    @GetMapping("/authRole/{userId}")
-    public AjaxResult authRole(@PathVariable("userId") Long userId)
-    {
-        AjaxResult ajax = AjaxResult.success();
-        SysUser user = userService.selectUserById(userId);
-        List<SysRole> roles = roleService.selectRolesByUserId(userId);
-        ajax.put("user", user);
-        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
-        return ajax;
-    }
-
-    /**
-     * 用户授权角色
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:edit')")
-    @Log(title = "用户管理", businessType = BusinessType.GRANT)
-    @PutMapping("/authRole")
-    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
-    {
-        userService.checkUserDataScope(userId);
-        roleService.checkRoleDataScope(roleIds);
-        userService.insertUserAuth(userId, roleIds);
-        return success();
-    }
-
-    /**
-     * 获取部门树列表
-     */
-    @PreAuthorize("@ss.hasPermi('system:user:list')")
-    @GetMapping("/deptTree")
-    public AjaxResult deptTree(SysDept dept)
-    {
-        return success(deptService.selectDeptTreeList(dept));
-    }
-}
+package com.acupuncture.web.controller.system;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+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.RestController;
+import org.springframework.web.multipart.MultipartFile;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.entity.SysDept;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.system.service.ISysDeptService;
+import com.acupuncture.system.service.ISysPostService;
+import com.acupuncture.system.service.ISysRoleService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 用户信息
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @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);
+    }
+
+    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysUser user)
+    {
+        List<SysUser> list = userService.selectUserList(user);
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.exportExcel(response, list, "用户数据");
+    }
+
+    @Log(title = "用户管理", businessType = BusinessType.IMPORT)
+    @PreAuthorize("@ss.hasPermi('system:user:import')")
+    @PostMapping("/importData")
+    public AjaxResult importData(MultipartFile file, boolean updateSupport) throws Exception
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        List<SysUser> userList = util.importExcel(file.getInputStream());
+        String operName = getUsername();
+        String message = userService.importUser(userList, updateSupport, operName);
+        return success(message);
+    }
+
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response)
+    {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.importTemplateExcel(response, "用户数据");
+    }
+
+    /**
+     * 根据用户编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping(value = { "/", "/{userId}" })
+    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        if (StringUtils.isNotNull(userId))
+        {
+            userService.checkUserDataScope(userId);
+            SysUser sysUser = userService.selectUserById(userId);
+            ajax.put(AjaxResult.DATA_TAG, sysUser);
+            ajax.put("postIds", postService.selectPostListByUserId(userId));
+            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
+        }
+        List<SysRole> roles = roleService.selectRoleAll();
+        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        ajax.put("posts", postService.selectPostAll());
+        return ajax;
+    }
+
+    /**
+     * 新增用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:add')")
+    @Log(title = "用户管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysUser user)
+    {
+        deptService.checkDeptDataScope(user.getDeptId());
+        roleService.checkRoleDataScope(user.getRoleIds());
+        if (!userService.checkUserNameUnique(user))
+        {
+            return error("新增用户'" + user.getUserName() + "'失败,登录账号已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+        {
+            return error("新增用户'" + user.getUserName() + "'失败,手机号码已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+        {
+            return error("新增用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+        }
+        user.setCreateBy(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(@Validated @RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        userService.checkUserDataScope(user.getUserId());
+        deptService.checkDeptDataScope(user.getDeptId());
+        roleService.checkRoleDataScope(user.getRoleIds());
+        if (!userService.checkUserNameUnique(user))
+        {
+            return error("修改用户'" + user.getUserName() + "'失败,登录账号已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getPhonenumber()) && !userService.checkPhoneUnique(user))
+        {
+            return error("修改用户'" + user.getUserName() + "'失败,手机号码已存在");
+        }
+        else if (StringUtils.isNotEmpty(user.getEmail()) && !userService.checkEmailUnique(user))
+        {
+            return error("修改用户'" + user.getUserName() + "'失败,邮箱账号已存在");
+        }
+        user.setUpdateBy(getUsername());
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 删除用户
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:remove')")
+    @Log(title = "用户管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{userIds}")
+    public AjaxResult remove(@PathVariable Long[] userIds)
+    {
+        if (ArrayUtils.contains(userIds, getUserId()))
+        {
+            return error("当前用户不能删除");
+        }
+        return toAjax(userService.deleteUserByIds(userIds));
+    }
+
+    /**
+     * 重置密码
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:resetPwd')")
+    @Log(title = "用户管理", businessType = BusinessType.UPDATE)
+    @PutMapping("/resetPwd")
+    public AjaxResult resetPwd(@RequestBody SysUser user)
+    {
+        userService.checkUserAllowed(user);
+        userService.checkUserDataScope(user.getUserId());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        user.setUpdateBy(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);
+        userService.checkUserDataScope(user.getUserId());
+        user.setUpdateBy(getUsername());
+        return toAjax(userService.updateUserStatus(user));
+    }
+
+    /**
+     * 根据用户编号获取授权角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping("/authRole/{userId}")
+    public AjaxResult authRole(@PathVariable("userId") Long userId)
+    {
+        AjaxResult ajax = AjaxResult.success();
+        SysUser user = userService.selectUserById(userId);
+        List<SysRole> roles = roleService.selectRolesByUserId(userId);
+        ajax.put("user", user);
+        ajax.put("roles", SysUser.isAdmin(userId) ? roles : roles.stream().filter(r -> !r.isAdmin()).collect(Collectors.toList()));
+        return ajax;
+    }
+
+    /**
+     * 用户授权角色
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.GRANT)
+    @PutMapping("/authRole")
+    public AjaxResult insertAuthRole(Long userId, Long[] roleIds)
+    {
+        userService.checkUserDataScope(userId);
+        roleService.checkRoleDataScope(roleIds);
+        userService.insertUserAuth(userId, roleIds);
+        return success();
+    }
+
+    /**
+     * 获取部门树列表
+     */
+    @PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/deptTree")
+    public AjaxResult deptTree(SysDept dept)
+    {
+        return success(deptService.selectDeptTreeList(dept));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/tool/TestController.java
similarity index 93%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/controller/tool/TestController.java
index c55f9749..1b85b5df 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/tool/TestController.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/controller/tool/TestController.java
@@ -1,183 +1,183 @@
-package com.ruoyi.web.controller.tool;
-
-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.RequestBody;
-import org.springframework.web.bind.annotation.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.R;
-import com.ruoyi.common.utils.StringUtils;
-import io.swagger.annotations.Api;
-import io.swagger.annotations.ApiImplicitParam;
-import io.swagger.annotations.ApiImplicitParams;
-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 R<List<UserEntity>> userList()
-    {
-        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
-        return R.ok(userList);
-    }
-
-    @ApiOperation("获取用户详细")
-    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
-    @GetMapping("/{userId}")
-    public R<UserEntity> getUser(@PathVariable Integer userId)
-    {
-        if (!users.isEmpty() && users.containsKey(userId))
-        {
-            return R.ok(users.get(userId));
-        }
-        else
-        {
-            return R.fail("用户不存在");
-        }
-    }
-
-    @ApiOperation("新增用户")
-    @ApiImplicitParams({
-        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
-        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
-        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
-        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
-    })
-    @PostMapping("/save")
-    public R<String> save(UserEntity user)
-    {
-        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
-        {
-            return R.fail("用户ID不能为空");
-        }
-        users.put(user.getUserId(), user);
-        return R.ok();
-    }
-
-    @ApiOperation("更新用户")
-    @PutMapping("/update")
-    public R<String> update(@RequestBody UserEntity user)
-    {
-        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
-        {
-            return R.fail("用户ID不能为空");
-        }
-        if (users.isEmpty() || !users.containsKey(user.getUserId()))
-        {
-            return R.fail("用户不存在");
-        }
-        users.remove(user.getUserId());
-        users.put(user.getUserId(), user);
-        return R.ok();
-    }
-
-    @ApiOperation("删除用户信息")
-    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
-    @DeleteMapping("/{userId}")
-    public R<String> delete(@PathVariable Integer userId)
-    {
-        if (!users.isEmpty() && users.containsKey(userId))
-        {
-            users.remove(userId);
-            return R.ok();
-        }
-        else
-        {
-            return R.fail("用户不存在");
-        }
-    }
-}
-
-@ApiModel(value = "UserEntity", description = "用户实体")
-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;
-    }
-}
+package com.acupuncture.web.controller.tool;
+
+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.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.R;
+import com.acupuncture.common.utils.StringUtils;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiImplicitParam;
+import io.swagger.annotations.ApiImplicitParams;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import io.swagger.annotations.ApiOperation;
+
+/**
+ * swagger 用户测试方法
+ * 
+ * @author acupuncture
+ */
+@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 R<List<UserEntity>> userList()
+    {
+        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
+        return R.ok(userList);
+    }
+
+    @ApiOperation("获取用户详细")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
+    @GetMapping("/{userId}")
+    public R<UserEntity> getUser(@PathVariable Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            return R.ok(users.get(userId));
+        }
+        else
+        {
+            return R.fail("用户不存在");
+        }
+    }
+
+    @ApiOperation("新增用户")
+    @ApiImplicitParams({
+        @ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class),
+        @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class),
+        @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class),
+        @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)
+    })
+    @PostMapping("/save")
+    public R<String> save(UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return R.fail("用户ID不能为空");
+        }
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+
+    @ApiOperation("更新用户")
+    @PutMapping("/update")
+    public R<String> update(@RequestBody UserEntity user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId()))
+        {
+            return R.fail("用户ID不能为空");
+        }
+        if (users.isEmpty() || !users.containsKey(user.getUserId()))
+        {
+            return R.fail("用户不存在");
+        }
+        users.remove(user.getUserId());
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+
+    @ApiOperation("删除用户信息")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
+    @DeleteMapping("/{userId}")
+    public R<String> delete(@PathVariable Integer userId)
+    {
+        if (!users.isEmpty() && users.containsKey(userId))
+        {
+            users.remove(userId);
+            return R.ok();
+        }
+        else
+        {
+            return R.fail("用户不存在");
+        }
+    }
+}
+
+@ApiModel(value = "UserEntity", description = "用户实体")
+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-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java b/acupuncture-admin/src/main/java/com/acupuncture/web/core/config/SwaggerConfig.java
similarity index 91%
rename from ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
rename to acupuncture-admin/src/main/java/com/acupuncture/web/core/config/SwaggerConfig.java
index 0b942450..448ce860 100644
--- a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
+++ b/acupuncture-admin/src/main/java/com/acupuncture/web/core/config/SwaggerConfig.java
@@ -1,125 +1,125 @@
-package com.ruoyi.web.core.config;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import com.ruoyi.common.config.RuoYiConfig;
-import io.swagger.annotations.ApiOperation;
-import io.swagger.models.auth.In;
-import springfox.documentation.builders.ApiInfoBuilder;
-import springfox.documentation.builders.PathSelectors;
-import springfox.documentation.builders.RequestHandlerSelectors;
-import springfox.documentation.service.ApiInfo;
-import springfox.documentation.service.ApiKey;
-import springfox.documentation.service.AuthorizationScope;
-import springfox.documentation.service.Contact;
-import springfox.documentation.service.SecurityReference;
-import springfox.documentation.service.SecurityScheme;
-import springfox.documentation.spi.DocumentationType;
-import springfox.documentation.spi.service.contexts.SecurityContext;
-import springfox.documentation.spring.web.plugins.Docket;
-
-/**
- * Swagger2的接口配置
- * 
- * @author ruoyi
- */
-@Configuration
-public class SwaggerConfig
-{
-    /** 系统基础配置 */
-    @Autowired
-    private RuoYiConfig ruoyiConfig;
-
-    /** 是否开启swagger */
-    @Value("${swagger.enabled}")
-    private boolean enabled;
-
-    /** 设置请求的统一前缀 */
-    @Value("${swagger.pathMapping}")
-    private String pathMapping;
-
-    /**
-     * 创建API
-     */
-    @Bean
-    public Docket createRestApi()
-    {
-        return new Docket(DocumentationType.OAS_30)
-                // 是否启用Swagger
-                .enable(enabled)
-                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
-                .apiInfo(apiInfo())
-                // 设置哪些接口暴露给Swagger展示
-                .select()
-                // 扫描所有有注解的api,用这种方式更灵活
-                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
-                // 扫描指定包中的swagger注解
-                // .apis(RequestHandlerSelectors.basePackage("com.ruoyi.project.tool.swagger"))
-                // 扫描所有 .apis(RequestHandlerSelectors.any())
-                .paths(PathSelectors.any())
-                .build()
-                /* 设置安全模式,swagger可以设置访问token */
-                .securitySchemes(securitySchemes())
-                .securityContexts(securityContexts())
-                .pathMapping(pathMapping);
-    }
-
-    /**
-     * 安全模式,这里指定token通过Authorization头请求头传递
-     */
-    private List<SecurityScheme> securitySchemes()
-    {
-        List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
-        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
-        return apiKeyList;
-    }
-
-    /**
-     * 安全上下文
-     */
-    private List<SecurityContext> securityContexts()
-    {
-        List<SecurityContext> securityContexts = new ArrayList<>();
-        securityContexts.add(
-                SecurityContext.builder()
-                        .securityReferences(defaultAuth())
-                        .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
-                        .build());
-        return securityContexts;
-    }
-
-    /**
-     * 默认的安全上引用
-     */
-    private List<SecurityReference> defaultAuth()
-    {
-        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
-        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
-        authorizationScopes[0] = authorizationScope;
-        List<SecurityReference> securityReferences = new ArrayList<>();
-        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
-        return securityReferences;
-    }
-
-    /**
-     * 添加摘要信息
-     */
-    private ApiInfo apiInfo()
-    {
-        // 用ApiInfoBuilder进行定制
-        return new ApiInfoBuilder()
-                // 设置标题
-                .title("标题:若依管理系统_接口文档")
-                // 描述
-                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
-                // 作者信息
-                .contact(new Contact(ruoyiConfig.getName(), null, null))
-                // 版本
-                .version("版本号:" + ruoyiConfig.getVersion())
-                .build();
-    }
-}
+package com.acupuncture.web.core.config;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.acupuncture.common.config.RuoYiConfig;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.models.auth.In;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.ApiKey;
+import springfox.documentation.service.AuthorizationScope;
+import springfox.documentation.service.Contact;
+import springfox.documentation.service.SecurityReference;
+import springfox.documentation.service.SecurityScheme;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+/**
+ * Swagger2的接口配置
+ * 
+ * @author acupuncture
+ */
+@Configuration
+public class SwaggerConfig
+{
+    /** 系统基础配置 */
+    @Autowired
+    private RuoYiConfig RuoYiConfig;
+
+    /** 是否开启swagger */
+    @Value("${swagger.enabled}")
+    private boolean enabled;
+
+    /** 设置请求的统一前缀 */
+    @Value("${swagger.pathMapping}")
+    private String pathMapping;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi()
+    {
+        return new Docket(DocumentationType.OAS_30)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                // .apis(RequestHandlerSelectors.basePackage("com.acupuncture.project.tool.swagger"))
+                // 扫描所有 .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts())
+                .pathMapping(pathMapping);
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<SecurityScheme> securitySchemes()
+    {
+        List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
+        return apiKeyList;
+    }
+
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts()
+    {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(
+                SecurityContext.builder()
+                        .securityReferences(defaultAuth())
+                        .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
+                        .build());
+        return securityContexts;
+    }
+
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth()
+    {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo()
+    {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title("标题:若依管理系统_接口文档")
+                // 描述
+                .description("描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...")
+                // 作者信息
+                .contact(new Contact(RuoYiConfig.getName(), null, null))
+                // 版本
+                .version("版本号:" + RuoYiConfig.getVersion())
+                .build();
+    }
+}
diff --git a/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties b/acupuncture-admin/src/main/resources/META-INF/spring-devtools.properties
similarity index 100%
rename from ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties
rename to acupuncture-admin/src/main/resources/META-INF/spring-devtools.properties
diff --git a/ruoyi-admin/src/main/resources/application-druid.yml b/acupuncture-admin/src/main/resources/application-druid.yml
similarity index 95%
rename from ruoyi-admin/src/main/resources/application-druid.yml
rename to acupuncture-admin/src/main/resources/application-druid.yml
index bcfad3ea..1ec88cde 100644
--- a/ruoyi-admin/src/main/resources/application-druid.yml
+++ b/acupuncture-admin/src/main/resources/application-druid.yml
@@ -1,61 +1,61 @@
-# 数据源配置
-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
-            # 配置连接超时时间
-            connectTimeout: 30000
-            # 配置网络超时时间
-            socketTimeout: 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: ruoyi
-                login-password: 123456
-            filter:
-                stat:
-                    enabled: true
-                    # 慢SQL记录
-                    log-slow-sql: true
-                    slow-sql-millis: 1000
-                    merge-sql: true
-                wall:
-                    config:
+# 数据源配置
+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
+            # 配置连接超时时间
+            connectTimeout: 30000
+            # 配置网络超时时间
+            socketTimeout: 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: acupuncture
+                login-password: 123456
+            filter:
+                stat:
+                    enabled: true
+                    # 慢SQL记录
+                    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-admin/src/main/resources/application.yml b/acupuncture-admin/src/main/resources/application.yml
similarity index 88%
rename from ruoyi-admin/src/main/resources/application.yml
rename to acupuncture-admin/src/main/resources/application.yml
index e70ea3e1..cbbdabe6 100644
--- a/ruoyi-admin/src/main/resources/application.yml
+++ b/acupuncture-admin/src/main/resources/application.yml
@@ -1,129 +1,129 @@
-# 项目相关配置
-ruoyi:
-  # 名称
-  name: RuoYi
-  # 版本
-  version: 3.8.9
-  # 版权年份
-  copyrightYear: 2025
-  # 文件路径 示例( Windows配置D:/ruoyi/uploadPath,Linux配置 /home/ruoyi/uploadPath)
-  profile: D:/ruoyi/uploadPath
-  # 获取ip地址开关
-  addressEnabled: false
-  # 验证码类型 math 数字计算 char 字符验证
-  captchaType: math
-
-# 开发环境配置
-server:
-  # 服务器的HTTP端口,默认为8080
-  port: 8080
-  servlet:
-    # 应用的访问路径
-    context-path: /
-  tomcat:
-    # tomcat的URI编码
-    uri-encoding: UTF-8
-    # 连接数满后的排队数,默认为100
-    accept-count: 1000
-    threads:
-      # tomcat最大线程数,默认为200
-      max: 800
-      # Tomcat启动初始化的线程数,默认值10
-      min-spare: 100
-
-# 日志配置
-logging:
-  level:
-    com.ruoyi: debug
-    org.springframework: warn
-
-# 用户配置
-user:
-  password:
-    # 密码最大错误次数
-    maxRetryCount: 5
-    # 密码锁定时间(默认10分钟)
-    lockTime: 10
-
-# 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
-    # 数据库索引
-    database: 0
-    # 密码
-    password:
-    # 连接超时时间
-    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.**.domain
-  # 配置mapper的扫描,找到所有的mapper.xml映射文件
-  mapperLocations: classpath*:mapper/**/*Mapper.xml
-  # 加载全局的配置文件
-  configLocation: classpath:mybatis/mybatis-config.xml
-
-# PageHelper分页插件
-pagehelper:
-  helperDialect: mysql
-  supportMethodsArguments: true
-  params: count=countSql
-
-# Swagger配置
-swagger:
-  # 是否开启swagger
-  enabled: true
-  # 请求前缀
-  pathMapping: /dev-api
-
-# 防止XSS攻击
-xss:
-  # 过滤开关
-  enabled: true
-  # 排除链接(多个用逗号分隔)
-  excludes: /system/notice
-  # 匹配链接
-  urlPatterns: /system/*,/monitor/*,/tool/*
+# 项目相关配置
+acupuncture:
+  # 名称
+  name: acupuncture
+  # 版本
+  version: 3.8.9
+  # 版权年份
+  copyrightYear: 2025
+  # 文件路径 示例( Windows配置D:/acupuncture/uploadPath,Linux配置 /home/acupuncture/uploadPath)
+  profile: D:/acupuncture/uploadPath
+  # 获取ip地址开关
+  addressEnabled: false
+  # 验证码类型 math 数字计算 char 字符验证
+  captchaType: math
+
+# 开发环境配置
+server:
+  # 服务器的HTTP端口,默认为8080
+  port: 8080
+  servlet:
+    # 应用的访问路径
+    context-path: /
+  tomcat:
+    # tomcat的URI编码
+    uri-encoding: UTF-8
+    # 连接数满后的排队数,默认为100
+    accept-count: 1000
+    threads:
+      # tomcat最大线程数,默认为200
+      max: 800
+      # Tomcat启动初始化的线程数,默认值10
+      min-spare: 100
+
+# 日志配置
+logging:
+  level:
+    com.acupuncture: debug
+    org.springframework: warn
+
+# 用户配置
+user:
+  password:
+    # 密码最大错误次数
+    maxRetryCount: 5
+    # 密码锁定时间(默认10分钟)
+    lockTime: 10
+
+# 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
+    # 数据库索引
+    database: 0
+    # 密码
+    password:
+    # 连接超时时间
+    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.acupuncture.**.domain
+  # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  mapperLocations: classpath*:mapper/**/*Mapper.xml
+  # 加载全局的配置文件
+  configLocation: classpath:mybatis/mybatis-config.xml
+
+# PageHelper分页插件
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Swagger配置
+swagger:
+  # 是否开启swagger
+  enabled: true
+  # 请求前缀
+  pathMapping: /dev-api
+
+# 防止XSS攻击
+xss:
+  # 过滤开关
+  enabled: true
+  # 排除链接(多个用逗号分隔)
+  excludes: /system/notice
+  # 匹配链接
+  urlPatterns: /system/*,/monitor/*,/tool/*
diff --git a/ruoyi-admin/src/main/resources/banner.txt b/acupuncture-admin/src/main/resources/banner.txt
similarity index 96%
rename from ruoyi-admin/src/main/resources/banner.txt
rename to acupuncture-admin/src/main/resources/banner.txt
index 94662592..a63c47b2 100644
--- a/ruoyi-admin/src/main/resources/banner.txt
+++ b/acupuncture-admin/src/main/resources/banner.txt
@@ -1,24 +1,24 @@
-Application Version: ${ruoyi.version}
-Spring Boot Version: ${spring-boot.version}
-////////////////////////////////////////////////////////////////////
-//                          _ooOoo_                               //
-//                         o8888888o                              //
-//                         88" . "88                              //
-//                         (| ^_^ |)                              //
-//                         O\  =  /O                              //
-//                      ____/`---'\____                           //
-//                    .'  \\|     |//  `.                         //
-//                   /  \\|||  :  |||//  \                        //
-//                  /  _||||| -:- |||||-  \                       //
-//                  |   | \\\  -  /// |   |                       //
-//                  | \_|  ''\---/''  |   |                       //
-//                  \  .-\__  `-`  ___/-. /                       //
-//                ___`. .'  /--.--\  `. . ___                     //
-//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
-//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
-//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
-//      ========`-.____`-.___\_____/___.-`____.-'========         //
-//                           `=---='                              //
-//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
-//             佛祖保佑       永不宕机      永无BUG               //
+Application Version: ${acupuncture.version}
+Spring Boot Version: ${spring-boot.version}
+////////////////////////////////////////////////////////////////////
+//                          _ooOoo_                               //
+//                         o8888888o                              //
+//                         88" . "88                              //
+//                         (| ^_^ |)                              //
+//                         O\  =  /O                              //
+//                      ____/`---'\____                           //
+//                    .'  \\|     |//  `.                         //
+//                   /  \\|||  :  |||//  \                        //
+//                  /  _||||| -:- |||||-  \                       //
+//                  |   | \\\  -  /// |   |                       //
+//                  | \_|  ''\---/''  |   |                       //
+//                  \  .-\__  `-`  ___/-. /                       //
+//                ___`. .'  /--.--\  `. . ___                     //
+//              ."" '<  `.___\_<|>_/___.'  >'"".                  //
+//            | | :  `- \`.;`\ _ /`;.`/ - ` : | |                 //
+//            \  \ `-.   \_ __\ /__ _/   .-` /  /                 //
+//      ========`-.____`-.___\_____/___.-`____.-'========         //
+//                           `=---='                              //
+//      ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^        //
+//             佛祖保佑       永不宕机      永无BUG               //
 ////////////////////////////////////////////////////////////////////
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/acupuncture-admin/src/main/resources/i18n/messages.properties
similarity index 98%
rename from ruoyi-admin/src/main/resources/i18n/messages.properties
rename to acupuncture-admin/src/main/resources/i18n/messages.properties
index c3956b27..93de0055 100644
--- a/ruoyi-admin/src/main/resources/i18n/messages.properties
+++ b/acupuncture-admin/src/main/resources/i18n/messages.properties
@@ -1,38 +1,38 @@
-#错误消息
-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}次,帐户锁定{1}分钟
-user.password.delete=对不起,您的账号已被删除
-user.blocked=用户已封禁,请联系管理员
-role.blocked=角色已封禁,请联系管理员
-login.blocked=很遗憾,访问IP已被列入系统黑名单
-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.register.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}]
+#错误消息
+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}次,帐户锁定{1}分钟
+user.password.delete=对不起,您的账号已被删除
+user.blocked=用户已封禁,请联系管理员
+role.blocked=角色已封禁,请联系管理员
+login.blocked=很遗憾,访问IP已被列入系统黑名单
+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.register.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-admin/src/main/resources/logback.xml b/acupuncture-admin/src/main/resources/logback.xml
similarity index 94%
rename from ruoyi-admin/src/main/resources/logback.xml
rename to acupuncture-admin/src/main/resources/logback.xml
index d69a5720..a6d484ac 100644
--- a/ruoyi-admin/src/main/resources/logback.xml
+++ b/acupuncture-admin/src/main/resources/logback.xml
@@ -1,93 +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>
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+	<property name="log.path" value="/home/acupuncture/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.acupuncture" 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-admin/src/main/resources/mybatis/mybatis-config.xml b/acupuncture-admin/src/main/resources/mybatis/mybatis-config.xml
similarity index 97%
rename from ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
rename to acupuncture-admin/src/main/resources/mybatis/mybatis-config.xml
index 4b8c4962..ac47c038 100644
--- a/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
+++ b/acupuncture-admin/src/main/resources/mybatis/mybatis-config.xml
@@ -1,20 +1,20 @@
-<?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"   />
-        <!-- 允许JDBC 支持自动生成主键 -->
-        <setting name="useGeneratedKeys"         value="true"   />
-        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
-        <setting name="defaultExecutorType"      value="SIMPLE" />
-		<!-- 指定 MyBatis 所用日志的具体实现 -->
-        <setting name="logImpl"                  value="SLF4J"  />
-        <!-- 使用驼峰命名法转换字段 -->
-		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
-	</settings>
-	
-</configuration>
+<?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"   />
+        <!-- 允许JDBC 支持自动生成主键 -->
+        <setting name="useGeneratedKeys"         value="true"   />
+        <!-- 配置默认的执行器.SIMPLE就是普通执行器;REUSE执行器会重用预处理语句(prepared statements);BATCH执行器将重用语句并执行批量更新 -->
+        <setting name="defaultExecutorType"      value="SIMPLE" />
+		<!-- 指定 MyBatis 所用日志的具体实现 -->
+        <setting name="logImpl"                  value="SLF4J"  />
+        <!-- 使用驼峰命名法转换字段 -->
+		<!-- <setting name="mapUnderscoreToCamelCase" value="true"/> -->
+	</settings>
+	
+</configuration>
diff --git a/ruoyi-common/pom.xml b/acupuncture-common/pom.xml
similarity index 93%
rename from ruoyi-common/pom.xml
rename to acupuncture-common/pom.xml
index b0dddd96..5c29bf7a 100644
--- a/ruoyi-common/pom.xml
+++ b/acupuncture-common/pom.xml
@@ -1,124 +1,124 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ruoyi-common</artifactId>
-
-    <description>
-        common通用工具
-    </description>
-
-    <dependencies>
-
-        <!-- Spring框架基本的核心工具 -->
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-context-support</artifactId>
-        </dependency>
-
-        <!-- SpringWeb模块 -->
-        <dependency>
-            <groupId>org.springframework</groupId>
-            <artifactId>spring-web</artifactId>
-        </dependency>
-
-        <!-- spring security 安全认证 -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-security</artifactId>
-        </dependency>
-
-        <!-- pagehelper 分页插件 -->
-        <dependency>
-            <groupId>com.github.pagehelper</groupId>
-            <artifactId>pagehelper-spring-boot-starter</artifactId>
-        </dependency>
-
-        <!-- 自定义验证注解 -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-validation</artifactId>
-        </dependency>
-
-        <!--常用工具类 -->
-        <dependency>
-            <groupId>org.apache.commons</groupId>
-            <artifactId>commons-lang3</artifactId>
-        </dependency>
-  
-        <!-- JSON工具类 -->
-        <dependency>
-            <groupId>com.fasterxml.jackson.core</groupId>
-            <artifactId>jackson-databind</artifactId>
-        </dependency>
-        
-        <!-- 阿里JSON解析器 -->
-        <dependency>
-            <groupId>com.alibaba.fastjson2</groupId>
-            <artifactId>fastjson2</artifactId>
-        </dependency>
-
-        <!-- io常用工具类 -->
-        <dependency>
-            <groupId>commons-io</groupId>
-            <artifactId>commons-io</artifactId>
-        </dependency>
-
-        <!-- excel工具 -->
-        <dependency>
-            <groupId>org.apache.poi</groupId>
-            <artifactId>poi-ooxml</artifactId>
-        </dependency>
-
-        <!-- yml解析器 -->
-        <dependency>
-            <groupId>org.yaml</groupId>
-            <artifactId>snakeyaml</artifactId>
-        </dependency>
-
-        <!-- Token生成与解析-->
-        <dependency>
-            <groupId>io.jsonwebtoken</groupId>
-            <artifactId>jjwt</artifactId>
-        </dependency>
-
-        <!-- Jaxb -->
-        <dependency>
-            <groupId>javax.xml.bind</groupId>
-            <artifactId>jaxb-api</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>
-
-        <!-- 解析客户端操作系统、浏览器等 -->
-        <dependency>
-            <groupId>eu.bitwalker</groupId>
-            <artifactId>UserAgentUtils</artifactId>
-        </dependency>
-
-        <!-- servlet包 -->
-        <dependency>
-            <groupId>javax.servlet</groupId>
-            <artifactId>javax.servlet-api</artifactId>
-        </dependency>
-
-    </dependencies>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>acupuncture-common</artifactId>
+
+    <description>
+        common通用工具
+    </description>
+
+    <dependencies>
+
+        <!-- Spring框架基本的核心工具 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context-support</artifactId>
+        </dependency>
+
+        <!-- SpringWeb模块 -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-web</artifactId>
+        </dependency>
+
+        <!-- spring security 安全认证 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-security</artifactId>
+        </dependency>
+
+        <!-- pagehelper 分页插件 -->
+        <dependency>
+            <groupId>com.github.pagehelper</groupId>
+            <artifactId>pagehelper-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 自定义验证注解 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+
+        <!--常用工具类 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+        </dependency>
+  
+        <!-- JSON工具类 -->
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+        </dependency>
+        
+        <!-- 阿里JSON解析器 -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+        </dependency>
+
+        <!-- io常用工具类 -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- excel工具 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <!-- yml解析器 -->
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+        </dependency>
+
+        <!-- Token生成与解析-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+        </dependency>
+
+        <!-- Jaxb -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</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>
+
+        <!-- 解析客户端操作系统、浏览器等 -->
+        <dependency>
+            <groupId>eu.bitwalker</groupId>
+            <artifactId>UserAgentUtils</artifactId>
+        </dependency>
+
+        <!-- servlet包 -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Anonymous.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/Anonymous.java
index 8b6966ec..cf72ce6b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Anonymous.java
@@ -1,19 +1,19 @@
-package com.ruoyi.common.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, ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface Anonymous
-{
-}
+package com.acupuncture.common.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 acupuncture
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous
+{
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataScope.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataScope.java
index cebe592c..2f770c4e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataScope.java
@@ -1,33 +1,33 @@
-package com.ruoyi.common.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 "";
-
-    /**
-     * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
-     */
-    public String permission() default "";
-}
+package com.acupuncture.common.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 acupuncture
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope
+{
+    /**
+     * 部门表的别名
+     */
+    public String deptAlias() default "";
+
+    /**
+     * 用户表的别名
+     */
+    public String userAlias() default "";
+
+    /**
+     * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
+     */
+    public String permission() default "";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataSource.java
similarity index 84%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataSource.java
index 6b41ee73..cb7c9ae5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/DataSource.java
@@ -1,28 +1,28 @@
-package com.ruoyi.common.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.common.enums.DataSourceType;
-
-/**
- * 自定义多数据源切换注解
- *
- * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
- *
- * @author ruoyi
- */
-@Target({ ElementType.METHOD, ElementType.TYPE })
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-@Inherited
-public @interface DataSource
-{
-    /**
-     * 切换数据源名称
-     */
-    public DataSourceType value() default DataSourceType.MASTER;
-}
+package com.acupuncture.common.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.acupuncture.common.enums.DataSourceType;
+
+/**
+ * 自定义多数据源切换注解
+ *
+ * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
+ *
+ * @author acupuncture
+ */
+@Target({ ElementType.METHOD, ElementType.TYPE })
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource
+{
+    /**
+     * 切换数据源名称
+     */
+    public DataSourceType value() default DataSourceType.MASTER;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excel.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excel.java
index cfb5f9c9..337b54b9 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excel.java
@@ -1,197 +1,197 @@
-package com.ruoyi.common.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-import java.math.BigDecimal;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import com.ruoyi.common.utils.poi.ExcelHandlerAdapter;
-
-/**
- * 自定义导出Excel数据注解
- * 
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(ElementType.FIELD)
-public @interface Excel
-{
-    /**
-     * 导出时在excel中排序
-     */
-    public int sort() default Integer.MAX_VALUE;
-
-    /**
-     * 导出到Excel中的名字.
-     */
-    public String name() default "";
-
-    /**
-     * 日期格式, 如: yyyy-MM-dd
-     */
-    public String dateFormat() default "";
-
-    /**
-     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
-     */
-    public String dictType() default "";
-
-    /**
-     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
-     */
-    public String readConverterExp() default "";
-
-    /**
-     * 分隔符,读取字符串组内容
-     */
-    public String separator() default ",";
-
-    /**
-     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
-     */
-    public int scale() default -1;
-
-    /**
-     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
-     */
-    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
-
-    /**
-     * 导出时在excel中每个列的高度
-     */
-    public double height() default 14;
-
-    /**
-     * 导出时在excel中每个列的宽度
-     */
-    public double width() default 16;
-
-    /**
-     * 文字后缀,如% 90 变成90%
-     */
-    public String suffix() default "";
-
-    /**
-     * 当值为空时,字段的默认值
-     */
-    public String defaultValue() default "";
-
-    /**
-     * 提示信息
-     */
-    public String prompt() default "";
-
-    /**
-     * 是否允许内容换行 
-     */
-    public boolean wrapText() default false;
-
-    /**
-     * 设置只能选择不能输入的列内容.
-     */
-    public String[] combo() default {};
-
-    /**
-     * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
-     */
-    public boolean comboReadDict() default false;
-
-    /**
-     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
-     */
-    public boolean needMerge() default false;
-
-    /**
-     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
-     */
-    public boolean isExport() default true;
-
-    /**
-     * 另一个类中的属性名称,支持多级获取,以小数点隔开
-     */
-    public String targetAttr() default "";
-
-    /**
-     * 是否自动统计数据,在最后追加一行统计数据总和
-     */
-    public boolean isStatistics() default false;
-
-    /**
-     * 导出类型(0数字 1字符串 2图片)
-     */
-    public ColumnType cellType() default ColumnType.STRING;
-
-    /**
-     * 导出列头背景颜色
-     */
-    public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
-
-    /**
-     * 导出列头字体颜色
-     */
-    public IndexedColors headerColor() default IndexedColors.WHITE;
-
-    /**
-     * 导出单元格背景颜色
-     */
-    public IndexedColors backgroundColor() default IndexedColors.WHITE;
-
-    /**
-     * 导出单元格字体颜色
-     */
-    public IndexedColors color() default IndexedColors.BLACK;
-
-    /**
-     * 导出字段对齐方式
-     */
-    public HorizontalAlignment align() default HorizontalAlignment.CENTER;
-
-    /**
-     * 自定义数据处理器
-     */
-    public Class<?> handler() default ExcelHandlerAdapter.class;
-
-    /**
-     * 自定义数据处理器参数
-     */
-    public String[] args() default {};
-
-    /**
-     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
-     */
-    Type type() default Type.ALL;
-
-    public enum Type
-    {
-        ALL(0), EXPORT(1), IMPORT(2);
-        private final int value;
-
-        Type(int value)
-        {
-            this.value = value;
-        }
-
-        public int value()
-        {
-            return this.value;
-        }
-    }
-
-    public enum ColumnType
-    {
-        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
-        private final int value;
-
-        ColumnType(int value)
-        {
-            this.value = value;
-        }
-
-        public int value()
-        {
-            return this.value;
-        }
-    }
+package com.acupuncture.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import com.acupuncture.common.utils.poi.ExcelHandlerAdapter;
+
+/**
+ * 自定义导出Excel数据注解
+ * 
+ * @author acupuncture
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+    /**
+     * 导出时在excel中排序
+     */
+    public int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 导出到Excel中的名字.
+     */
+    public String name() default "";
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    public String dateFormat() default "";
+
+    /**
+     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+     */
+    public String dictType() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    public String readConverterExp() default "";
+
+    /**
+     * 分隔符,读取字符串组内容
+     */
+    public String separator() default ",";
+
+    /**
+     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+     */
+    public int scale() default -1;
+
+    /**
+     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+     */
+    public int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+    /**
+     * 导出时在excel中每个列的高度
+     */
+    public double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽度
+     */
+    public double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    public String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    public String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    public String prompt() default "";
+
+    /**
+     * 是否允许内容换行 
+     */
+    public boolean wrapText() default false;
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    public String[] combo() default {};
+
+    /**
+     * 是否从字典读数据到combo,默认不读取,如读取需要设置dictType注解.
+     */
+    public boolean comboReadDict() default false;
+
+    /**
+     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+     */
+    public boolean needMerge() default false;
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    public boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    public String targetAttr() default "";
+
+    /**
+     * 是否自动统计数据,在最后追加一行统计数据总和
+     */
+    public boolean isStatistics() default false;
+
+    /**
+     * 导出类型(0数字 1字符串 2图片)
+     */
+    public ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出列头背景颜色
+     */
+    public IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+    /**
+     * 导出列头字体颜色
+     */
+    public IndexedColors headerColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格背景颜色
+     */
+    public IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格字体颜色
+     */
+    public IndexedColors color() default IndexedColors.BLACK;
+
+    /**
+     * 导出字段对齐方式
+     */
+    public HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+    /**
+     * 自定义数据处理器
+     */
+    public Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    public String[] args() default {};
+
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    public enum Type
+    {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
+
+    public enum ColumnType
+    {
+        NUMERIC(0), STRING(1), IMAGE(2), TEXT(3);
+        private final int value;
+
+        ColumnType(int value)
+        {
+            this.value = value;
+        }
+
+        public int value()
+        {
+            return this.value;
+        }
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excels.java
similarity index 81%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excels.java
index 58507230..188ec84e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Excels.java
@@ -1,18 +1,18 @@
-package com.ruoyi.common.annotation;
-
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * Excel注解集
- * 
- * @author ruoyi
- */
-@Target(ElementType.FIELD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface Excels
-{
-    public Excel[] value();
-}
+package com.acupuncture.common.annotation;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * Excel注解集
+ * 
+ * @author acupuncture
+ */
+@Target(ElementType.FIELD)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Excels
+{
+    public Excel[] value();
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Log.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/Log.java
index 5ae846a1..66ceefca 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Log.java
@@ -1,51 +1,51 @@
-package com.ruoyi.common.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.common.enums.BusinessType;
-import com.ruoyi.common.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;
-
-    /**
-     * 是否保存响应的参数
-     */
-    public boolean isSaveResponseData() default true;
-
-    /**
-     * 排除指定的请求参数
-     */
-    public String[] excludeParamNames() default {};
-}
+package com.acupuncture.common.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.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.enums.OperatorType;
+
+/**
+ * 自定义操作日志记录注解
+ * 
+ * @author acupuncture
+ *
+ */
+@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;
+
+    /**
+     * 是否保存响应的参数
+     */
+    public boolean isSaveResponseData() default true;
+
+    /**
+     * 排除指定的请求参数
+     */
+    public String[] excludeParamNames() default {};
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/RateLimiter.java
similarity index 78%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/RateLimiter.java
index 050ac2d1..12a2be8c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/RateLimiter.java
@@ -1,40 +1,40 @@
-package com.ruoyi.common.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.common.constant.CacheConstants;
-import com.ruoyi.common.enums.LimitType;
-
-/**
- * 限流注解
- * 
- * @author ruoyi
- */
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface RateLimiter
-{
-    /**
-     * 限流key
-     */
-    public String key() default CacheConstants.RATE_LIMIT_KEY;
-
-    /**
-     * 限流时间,单位秒
-     */
-    public int time() default 60;
-
-    /**
-     * 限流次数
-     */
-    public int count() default 100;
-
-    /**
-     * 限流类型
-     */
-    public LimitType limitType() default LimitType.DEFAULT;
-}
+package com.acupuncture.common.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.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.enums.LimitType;
+
+/**
+ * 限流注解
+ * 
+ * @author acupuncture
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter
+{
+    /**
+     * 限流key
+     */
+    public String key() default CacheConstants.RATE_LIMIT_KEY;
+
+    /**
+     * 限流时间,单位秒
+     */
+    public int time() default 60;
+
+    /**
+     * 限流次数
+     */
+    public int count() default 100;
+
+    /**
+     * 限流类型
+     */
+    public LimitType limitType() default LimitType.DEFAULT;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/RepeatSubmit.java
similarity index 88%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/RepeatSubmit.java
index 1e277435..44cb1fc2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/RepeatSubmit.java
@@ -1,31 +1,31 @@
-package com.ruoyi.common.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;
-
-/**
- * 自定义注解防止表单重复提交
- * 
- * @author ruoyi
- *
- */
-@Inherited
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-@Documented
-public @interface RepeatSubmit
-{
-    /**
-     * 间隔时间(ms),小于此时间视为重复提交
-     */
-    public int interval() default 5000;
-
-    /**
-     * 提示消息
-     */
-    public String message() default "不允许重复提交,请稍候再试";
-}
+package com.acupuncture.common.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;
+
+/**
+ * 自定义注解防止表单重复提交
+ * 
+ * @author acupuncture
+ *
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit
+{
+    /**
+     * 间隔时间(ms),小于此时间视为重复提交
+     */
+    public int interval() default 5000;
+
+    /**
+     * 提示消息
+     */
+    public String message() default "不允许重复提交,请稍候再试";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Sensitive.java
similarity index 73%
rename from ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/annotation/Sensitive.java
index c0621e9e..9fde9735 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/annotation/Sensitive.java
@@ -1,4 +1,4 @@
-package com.ruoyi.common.annotation;
+package com.acupuncture.common.annotation;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -6,13 +6,13 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import com.fasterxml.jackson.annotation.JacksonAnnotationsInside;
 import com.fasterxml.jackson.databind.annotation.JsonSerialize;
-import com.ruoyi.common.config.serializer.SensitiveJsonSerializer;
-import com.ruoyi.common.enums.DesensitizedType;
+import com.acupuncture.common.config.serializer.SensitiveJsonSerializer;
+import com.acupuncture.common.enums.DesensitizedType;
 
 /**
  * 数据脱敏注解
  *
- * @author ruoyi
+ * @author acupuncture
  */
 @Retention(RetentionPolicy.RUNTIME)
 @Target(ElementType.FIELD)
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/acupuncture-common/src/main/java/com/acupuncture/common/config/RuoYiConfig.java
similarity index 91%
rename from ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/config/RuoYiConfig.java
index eac3da15..9509d51d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/config/RuoYiConfig.java
@@ -1,122 +1,122 @@
-package com.ruoyi.common.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 static String profile;
-
-    /** 获取地址开关 */
-    private static boolean addressEnabled;
-
-    /** 验证码类型 */
-    private static String captchaType;
-
-    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 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 getCaptchaType() {
-        return captchaType;
-    }
-
-    public void setCaptchaType(String captchaType) {
-        RuoYiConfig.captchaType = captchaType;
-    }
-
-    /**
-     * 获取导入上传路径
-     */
-    public static String getImportPath()
-    {
-        return getProfile() + "/import";
-    }
-
-    /**
-     * 获取头像上传路径
-     */
-    public static String getAvatarPath()
-    {
-        return getProfile() + "/avatar";
-    }
-
-    /**
-     * 获取下载路径
-     */
-    public static String getDownloadPath()
-    {
-        return getProfile() + "/download/";
-    }
-
-    /**
-     * 获取上传路径
-     */
-    public static String getUploadPath()
-    {
-        return getProfile() + "/upload";
-    }
-}
+package com.acupuncture.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取项目相关配置
+ * 
+ * @author acupuncture
+ */
+@Component
+@ConfigurationProperties(prefix = "acupuncture")
+public class RuoYiConfig
+{
+    /** 项目名称 */
+    private String name;
+
+    /** 版本 */
+    private String version;
+
+    /** 版权年份 */
+    private String copyrightYear;
+
+    /** 上传路径 */
+    private static String profile;
+
+    /** 获取地址开关 */
+    private static boolean addressEnabled;
+
+    /** 验证码类型 */
+    private static String captchaType;
+
+    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 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 getCaptchaType() {
+        return captchaType;
+    }
+
+    public void setCaptchaType(String captchaType) {
+        RuoYiConfig.captchaType = captchaType;
+    }
+
+    /**
+     * 获取导入上传路径
+     */
+    public static String getImportPath()
+    {
+        return getProfile() + "/import";
+    }
+
+    /**
+     * 获取头像上传路径
+     */
+    public static String getAvatarPath()
+    {
+        return getProfile() + "/avatar";
+    }
+
+    /**
+     * 获取下载路径
+     */
+    public static String getDownloadPath()
+    {
+        return getProfile() + "/download/";
+    }
+
+    /**
+     * 获取上传路径
+     */
+    public static String getUploadPath()
+    {
+        return getProfile() + "/upload";
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java b/acupuncture-common/src/main/java/com/acupuncture/common/config/serializer/SensitiveJsonSerializer.java
similarity index 86%
rename from ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/config/serializer/SensitiveJsonSerializer.java
index e819a1d7..8bd09754 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/config/serializer/SensitiveJsonSerializer.java
@@ -1,4 +1,4 @@
-package com.ruoyi.common.config.serializer;
+package com.acupuncture.common.config.serializer;
 
 import java.io.IOException;
 import java.util.Objects;
@@ -8,15 +8,15 @@ import com.fasterxml.jackson.databind.JsonMappingException;
 import com.fasterxml.jackson.databind.JsonSerializer;
 import com.fasterxml.jackson.databind.SerializerProvider;
 import com.fasterxml.jackson.databind.ser.ContextualSerializer;
-import com.ruoyi.common.annotation.Sensitive;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.enums.DesensitizedType;
-import com.ruoyi.common.utils.SecurityUtils;
+import com.acupuncture.common.annotation.Sensitive;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.enums.DesensitizedType;
+import com.acupuncture.common.utils.SecurityUtils;
 
 /**
  * 数据脱敏序列化过滤
  *
- * @author ruoyi
+ * @author acupuncture
  */
 public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/CacheConstants.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/CacheConstants.java
index c89692c2..42172c46 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/CacheConstants.java
@@ -1,44 +1,44 @@
-package com.ruoyi.common.constant;
-
-/**
- * 缓存的key 常量
- * 
- * @author ruoyi
- */
-public class CacheConstants
-{
-    /**
-     * 登录用户 redis key
-     */
-    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
-
-    /**
-     * 验证码 redis key
-     */
-    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
-
-    /**
-     * 参数管理 cache key
-     */
-    public static final String SYS_CONFIG_KEY = "sys_config:";
-
-    /**
-     * 字典管理 cache key
-     */
-    public static final String SYS_DICT_KEY = "sys_dict:";
-
-    /**
-     * 防重提交 redis key
-     */
-    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
-
-    /**
-     * 限流 redis key
-     */
-    public static final String RATE_LIMIT_KEY = "rate_limit:";
-
-    /**
-     * 登录账户密码错误次数 redis key
-     */
-    public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
-}
+package com.acupuncture.common.constant;
+
+/**
+ * 缓存的key 常量
+ * 
+ * @author acupuncture
+ */
+public class CacheConstants
+{
+    /**
+     * 登录用户 redis key
+     */
+    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 验证码 redis key
+     */
+    public static final String CAPTCHA_CODE_KEY = "captcha_codes:";
+
+    /**
+     * 参数管理 cache key
+     */
+    public static final String SYS_CONFIG_KEY = "sys_config:";
+
+    /**
+     * 字典管理 cache key
+     */
+    public static final String SYS_DICT_KEY = "sys_dict:";
+
+    /**
+     * 防重提交 redis key
+     */
+    public static final String REPEAT_SUBMIT_KEY = "repeat_submit:";
+
+    /**
+     * 限流 redis key
+     */
+    public static final String RATE_LIMIT_KEY = "rate_limit:";
+
+    /**
+     * 登录账户密码错误次数 redis key
+     */
+    public static final String PWD_ERR_CNT_KEY = "pwd_err_cnt:";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/Constants.java
similarity index 87%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/Constants.java
index a94c3fa3..f966c790 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/Constants.java
@@ -1,173 +1,173 @@
-package com.ruoyi.common.constant;
-
-import java.util.Locale;
-import io.jsonwebtoken.Claims;
-
-/**
- * 通用常量信息
- * 
- * @author ruoyi
- */
-public class Constants
-{
-    /**
-     * UTF-8 字符集
-     */
-    public static final String UTF8 = "UTF-8";
-
-    /**
-     * GBK 字符集
-     */
-    public static final String GBK = "GBK";
-
-    /**
-     * 系统语言
-     */
-    public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
-
-    /**
-     * www主域
-     */
-    public static final String WWW = "www.";
-
-    /**
-     * http请求
-     */
-    public static final String HTTP = "http://";
-
-    /**
-     * https请求
-     */
-    public static final String HTTPS = "https://";
-
-    /**
-     * 通用成功标识
-     */
-    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 REGISTER = "Register";
-
-    /**
-     * 登录失败
-     */
-    public static final String LOGIN_FAIL = "Error";
-
-    /**
-     * 所有权限标识
-     */
-    public static final String ALL_PERMISSION = "*:*:*";
-
-    /**
-     * 管理员角色权限标识
-     */
-    public static final String SUPER_ADMIN = "admin";
-
-    /**
-     * 角色权限分隔符
-     */
-    public static final String ROLE_DELIMETER = ",";
-
-    /**
-     * 权限标识分隔符
-     */
-    public static final String PERMISSION_DELIMETER = ",";
-
-    /**
-     * 验证码有效期(分钟)
-     */
-    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";
-
-    /**
-     * RMI 远程方法调用
-     */
-    public static final String LOOKUP_RMI = "rmi:";
-
-    /**
-     * LDAP 远程方法调用
-     */
-    public static final String LOOKUP_LDAP = "ldap:";
-
-    /**
-     * LDAPS 远程方法调用
-     */
-    public static final String LOOKUP_LDAPS = "ldaps:";
-
-    /**
-     * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
-     */
-    public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.ruoyi" };
-
-    /**
-     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
-     */
-    public static final String[] JOB_WHITELIST_STR = { "com.ruoyi.quartz.task" };
-
-    /**
-     * 定时任务违规的字符
-     */
-    public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
-            "org.springframework", "org.apache", "com.ruoyi.common.utils.file", "com.ruoyi.common.config", "com.ruoyi.generator" };
-}
+package com.acupuncture.common.constant;
+
+import java.util.Locale;
+import io.jsonwebtoken.Claims;
+
+/**
+ * 通用常量信息
+ * 
+ * @author acupuncture
+ */
+public class Constants
+{
+    /**
+     * UTF-8 字符集
+     */
+    public static final String UTF8 = "UTF-8";
+
+    /**
+     * GBK 字符集
+     */
+    public static final String GBK = "GBK";
+
+    /**
+     * 系统语言
+     */
+    public static final Locale DEFAULT_LOCALE = Locale.SIMPLIFIED_CHINESE;
+
+    /**
+     * www主域
+     */
+    public static final String WWW = "www.";
+
+    /**
+     * http请求
+     */
+    public static final String HTTP = "http://";
+
+    /**
+     * https请求
+     */
+    public static final String HTTPS = "https://";
+
+    /**
+     * 通用成功标识
+     */
+    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 REGISTER = "Register";
+
+    /**
+     * 登录失败
+     */
+    public static final String LOGIN_FAIL = "Error";
+
+    /**
+     * 所有权限标识
+     */
+    public static final String ALL_PERMISSION = "*:*:*";
+
+    /**
+     * 管理员角色权限标识
+     */
+    public static final String SUPER_ADMIN = "admin";
+
+    /**
+     * 角色权限分隔符
+     */
+    public static final String ROLE_DELIMETER = ",";
+
+    /**
+     * 权限标识分隔符
+     */
+    public static final String PERMISSION_DELIMETER = ",";
+
+    /**
+     * 验证码有效期(分钟)
+     */
+    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";
+
+    /**
+     * RMI 远程方法调用
+     */
+    public static final String LOOKUP_RMI = "rmi:";
+
+    /**
+     * LDAP 远程方法调用
+     */
+    public static final String LOOKUP_LDAP = "ldap:";
+
+    /**
+     * LDAPS 远程方法调用
+     */
+    public static final String LOOKUP_LDAPS = "ldaps:";
+
+    /**
+     * 自动识别json对象白名单配置(仅允许解析的包名,范围越小越安全)
+     */
+    public static final String[] JSON_WHITELIST_STR = { "org.springframework", "com.acupuncture" };
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = { "com.acupuncture.quartz.task" };
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = { "java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml",
+            "org.springframework", "org.apache", "com.acupuncture.common.utils.file", "com.acupuncture.common.config", "com.acupuncture.generator" };
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/GenConstants.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/GenConstants.java
index e7382b3f..722e8617 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/GenConstants.java
@@ -1,117 +1,117 @@
-package com.ruoyi.common.constant;
-
-/**
- * 代码生成通用常量
- * 
- * @author ruoyi
- */
-public class GenConstants
-{
-    /** 单表(增删改查) */
-    public static final String TPL_CRUD = "crud";
-
-    /** 树表(增删改查) */
-    public static final String TPL_TREE = "tree";
-
-    /** 主子表(增删改查) */
-    public static final String TPL_SUB = "sub";
-
-    /** 树编码字段 */
-    public static final String TREE_CODE = "treeCode";
-
-    /** 树父编码字段 */
-    public static final String TREE_PARENT_CODE = "treeParentCode";
-
-    /** 树名称字段 */
-    public static final String TREE_NAME = "treeName";
-
-    /** 上级菜单ID字段 */
-    public static final String PARENT_MENU_ID = "parentMenuId";
-
-    /** 上级菜单名称字段 */
-    public static final String PARENT_MENU_NAME = "parentMenuName";
-
-    /** 数据库字符串类型 */
-    public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
-
-    /** 数据库文本类型 */
-    public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
-
-    /** 数据库时间类型 */
-    public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
-
-    /** 数据库数字类型 */
-    public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
-            "bit", "bigint", "float", "double", "decimal" };
-
-    /** 页面不需要编辑字段 */
-    public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
-
-    /** 页面不需要显示的列表字段 */
-    public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
-            "update_time" };
-
-    /** 页面不需要查询字段 */
-    public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
-            "update_time", "remark" };
-
-    /** Entity基类字段 */
-    public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
-
-    /** Tree基类字段 */
-    public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
-
-    /** 文本框 */
-    public static final String HTML_INPUT = "input";
-
-    /** 文本域 */
-    public static final String HTML_TEXTAREA = "textarea";
-
-    /** 下拉框 */
-    public static final String HTML_SELECT = "select";
-
-    /** 单选框 */
-    public static final String HTML_RADIO = "radio";
-
-    /** 复选框 */
-    public static final String HTML_CHECKBOX = "checkbox";
-
-    /** 日期控件 */
-    public static final String HTML_DATETIME = "datetime";
-
-    /** 图片上传控件 */
-    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
-
-    /** 文件上传控件 */
-    public static final String HTML_FILE_UPLOAD = "fileUpload";
-
-    /** 富文本控件 */
-    public static final String HTML_EDITOR = "editor";
-
-    /** 字符串类型 */
-    public static final String TYPE_STRING = "String";
-
-    /** 整型 */
-    public static final String TYPE_INTEGER = "Integer";
-
-    /** 长整型 */
-    public static final String TYPE_LONG = "Long";
-
-    /** 浮点型 */
-    public static final String TYPE_DOUBLE = "Double";
-
-    /** 高精度计算类型 */
-    public static final String TYPE_BIGDECIMAL = "BigDecimal";
-
-    /** 时间类型 */
-    public static final String TYPE_DATE = "Date";
-
-    /** 模糊查询 */
-    public static final String QUERY_LIKE = "LIKE";
-
-    /** 相等查询 */
-    public static final String QUERY_EQ = "EQ";
-
-    /** 需要 */
-    public static final String REQUIRE = "1";
-}
+package com.acupuncture.common.constant;
+
+/**
+ * 代码生成通用常量
+ * 
+ * @author acupuncture
+ */
+public class GenConstants
+{
+    /** 单表(增删改查) */
+    public static final String TPL_CRUD = "crud";
+
+    /** 树表(增删改查) */
+    public static final String TPL_TREE = "tree";
+
+    /** 主子表(增删改查) */
+    public static final String TPL_SUB = "sub";
+
+    /** 树编码字段 */
+    public static final String TREE_CODE = "treeCode";
+
+    /** 树父编码字段 */
+    public static final String TREE_PARENT_CODE = "treeParentCode";
+
+    /** 树名称字段 */
+    public static final String TREE_NAME = "treeName";
+
+    /** 上级菜单ID字段 */
+    public static final String PARENT_MENU_ID = "parentMenuId";
+
+    /** 上级菜单名称字段 */
+    public static final String PARENT_MENU_NAME = "parentMenuName";
+
+    /** 数据库字符串类型 */
+    public static final String[] COLUMNTYPE_STR = { "char", "varchar", "nvarchar", "varchar2" };
+
+    /** 数据库文本类型 */
+    public static final String[] COLUMNTYPE_TEXT = { "tinytext", "text", "mediumtext", "longtext" };
+
+    /** 数据库时间类型 */
+    public static final String[] COLUMNTYPE_TIME = { "datetime", "time", "date", "timestamp" };
+
+    /** 数据库数字类型 */
+    public static final String[] COLUMNTYPE_NUMBER = { "tinyint", "smallint", "mediumint", "int", "number", "integer",
+            "bit", "bigint", "float", "double", "decimal" };
+
+    /** 页面不需要编辑字段 */
+    public static final String[] COLUMNNAME_NOT_EDIT = { "id", "create_by", "create_time", "del_flag" };
+
+    /** 页面不需要显示的列表字段 */
+    public static final String[] COLUMNNAME_NOT_LIST = { "id", "create_by", "create_time", "del_flag", "update_by",
+            "update_time" };
+
+    /** 页面不需要查询字段 */
+    public static final String[] COLUMNNAME_NOT_QUERY = { "id", "create_by", "create_time", "del_flag", "update_by",
+            "update_time", "remark" };
+
+    /** Entity基类字段 */
+    public static final String[] BASE_ENTITY = { "createBy", "createTime", "updateBy", "updateTime", "remark" };
+
+    /** Tree基类字段 */
+    public static final String[] TREE_ENTITY = { "parentName", "parentId", "orderNum", "ancestors", "children" };
+
+    /** 文本框 */
+    public static final String HTML_INPUT = "input";
+
+    /** 文本域 */
+    public static final String HTML_TEXTAREA = "textarea";
+
+    /** 下拉框 */
+    public static final String HTML_SELECT = "select";
+
+    /** 单选框 */
+    public static final String HTML_RADIO = "radio";
+
+    /** 复选框 */
+    public static final String HTML_CHECKBOX = "checkbox";
+
+    /** 日期控件 */
+    public static final String HTML_DATETIME = "datetime";
+
+    /** 图片上传控件 */
+    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+    /** 文件上传控件 */
+    public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+    /** 富文本控件 */
+    public static final String HTML_EDITOR = "editor";
+
+    /** 字符串类型 */
+    public static final String TYPE_STRING = "String";
+
+    /** 整型 */
+    public static final String TYPE_INTEGER = "Integer";
+
+    /** 长整型 */
+    public static final String TYPE_LONG = "Long";
+
+    /** 浮点型 */
+    public static final String TYPE_DOUBLE = "Double";
+
+    /** 高精度计算类型 */
+    public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+    /** 时间类型 */
+    public static final String TYPE_DATE = "Date";
+
+    /** 模糊查询 */
+    public static final String QUERY_LIKE = "LIKE";
+
+    /** 相等查询 */
+    public static final String QUERY_EQ = "EQ";
+
+    /** 需要 */
+    public static final String REQUIRE = "1";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/HttpStatus.java
similarity index 91%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/HttpStatus.java
index db839c50..040a64b2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/HttpStatus.java
@@ -1,94 +1,94 @@
-package com.ruoyi.common.constant;
-
-/**
- * 返回状态码
- * 
- * @author ruoyi
- */
-public class 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;
-
-    /**
-     * 系统警告消息
-     */
-    public static final int WARN = 601;
-}
+package com.acupuncture.common.constant;
+
+/**
+ * 返回状态码
+ * 
+ * @author acupuncture
+ */
+public class 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;
+
+    /**
+     * 系统警告消息
+     */
+    public static final int WARN = 601;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/ScheduleConstants.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/ScheduleConstants.java
index 8318b8f5..c2b28675 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/ScheduleConstants.java
@@ -1,50 +1,50 @@
-package com.ruoyi.common.constant;
-
-/**
- * 任务调度通用常量
- * 
- * @author ruoyi
- */
-public class ScheduleConstants
-{
-    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
-
-    /** 执行目标key */
-    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
-
-    /** 默认 */
-    public static final String MISFIRE_DEFAULT = "0";
-
-    /** 立即触发执行 */
-    public static final String MISFIRE_IGNORE_MISFIRES = "1";
-
-    /** 触发一次执行 */
-    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
-
-    /** 不触发立即执行 */
-    public static final String MISFIRE_DO_NOTHING = "3";
-
-    public enum Status
-    {
-        /**
-         * 正常
-         */
-        NORMAL("0"),
-        /**
-         * 暂停
-         */
-        PAUSE("1");
-
-        private String value;
-
-        private Status(String value)
-        {
-            this.value = value;
-        }
-
-        public String getValue()
-        {
-            return value;
-        }
-    }
-}
+package com.acupuncture.common.constant;
+
+/**
+ * 任务调度通用常量
+ * 
+ * @author acupuncture
+ */
+public class ScheduleConstants
+{
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /** 执行目标key */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /** 默认 */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /** 立即触发执行 */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /** 触发一次执行 */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /** 不触发立即执行 */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status
+    {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private String value;
+
+        private Status(String value)
+        {
+            this.value = value;
+        }
+
+        public String getValue()
+        {
+            return value;
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java b/acupuncture-common/src/main/java/com/acupuncture/common/constant/UserConstants.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/constant/UserConstants.java
index f2b5ab58..3a2ea2cd 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/constant/UserConstants.java
@@ -1,81 +1,81 @@
-package com.ruoyi.common.constant;
-
-/**
- * 用户常量信息
- * 
- * @author ruoyi
- */
-public class UserConstants
-{
-    /**
-     * 平台内系统用户的唯一标志
-     */
-    public static final String SYS_USER = "SYS_USER";
-
-    /** 正常状态 */
-    public static final String NORMAL = "0";
-
-    /** 异常状态 */
-    public static final String EXCEPTION = "1";
-
-    /** 用户封禁状态 */
-    public static final String USER_DISABLE = "1";
-
-    /** 角色正常状态 */
-    public static final String ROLE_NORMAL = "0";
-
-    /** 角色封禁状态 */
-    public static final String ROLE_DISABLE = "1";
-
-    /** 部门正常状态 */
-    public static final String DEPT_NORMAL = "0";
-
-    /** 部门停用状态 */
-    public static final String DEPT_DISABLE = "1";
-
-    /** 字典正常状态 */
-    public static final String DICT_NORMAL = "0";
-
-    /** 是否为系统默认(是) */
-    public static final String YES = "Y";
-
-    /** 是否菜单外链(是) */
-    public static final String YES_FRAME = "0";
-
-    /** 是否菜单外链(否) */
-    public static final String NO_FRAME = "1";
-
-    /** 菜单类型(目录) */
-    public static final String TYPE_DIR = "M";
-
-    /** 菜单类型(菜单) */
-    public static final String TYPE_MENU = "C";
-
-    /** 菜单类型(按钮) */
-    public static final String TYPE_BUTTON = "F";
-
-    /** Layout组件标识 */
-    public final static String LAYOUT = "Layout";
-    
-    /** ParentView组件标识 */
-    public final static String PARENT_VIEW = "ParentView";
-
-    /** InnerLink组件标识 */
-    public final static String INNER_LINK = "InnerLink";
-
-    /** 校验是否唯一的返回标识 */
-    public final static boolean UNIQUE = true;
-    public final static boolean NOT_UNIQUE = false;
-
-    /**
-     * 用户名长度限制
-     */
-    public static final int USERNAME_MIN_LENGTH = 2;
-    public static final int USERNAME_MAX_LENGTH = 20;
-
-    /**
-     * 密码长度限制
-     */
-    public static final int PASSWORD_MIN_LENGTH = 5;
-    public static final int PASSWORD_MAX_LENGTH = 20;
-}
+package com.acupuncture.common.constant;
+
+/**
+ * 用户常量信息
+ * 
+ * @author acupuncture
+ */
+public class UserConstants
+{
+    /**
+     * 平台内系统用户的唯一标志
+     */
+    public static final String SYS_USER = "SYS_USER";
+
+    /** 正常状态 */
+    public static final String NORMAL = "0";
+
+    /** 异常状态 */
+    public static final String EXCEPTION = "1";
+
+    /** 用户封禁状态 */
+    public static final String USER_DISABLE = "1";
+
+    /** 角色正常状态 */
+    public static final String ROLE_NORMAL = "0";
+
+    /** 角色封禁状态 */
+    public static final String ROLE_DISABLE = "1";
+
+    /** 部门正常状态 */
+    public static final String DEPT_NORMAL = "0";
+
+    /** 部门停用状态 */
+    public static final String DEPT_DISABLE = "1";
+
+    /** 字典正常状态 */
+    public static final String DICT_NORMAL = "0";
+
+    /** 是否为系统默认(是) */
+    public static final String YES = "Y";
+
+    /** 是否菜单外链(是) */
+    public static final String YES_FRAME = "0";
+
+    /** 是否菜单外链(否) */
+    public static final String NO_FRAME = "1";
+
+    /** 菜单类型(目录) */
+    public static final String TYPE_DIR = "M";
+
+    /** 菜单类型(菜单) */
+    public static final String TYPE_MENU = "C";
+
+    /** 菜单类型(按钮) */
+    public static final String TYPE_BUTTON = "F";
+
+    /** Layout组件标识 */
+    public final static String LAYOUT = "Layout";
+    
+    /** ParentView组件标识 */
+    public final static String PARENT_VIEW = "ParentView";
+
+    /** InnerLink组件标识 */
+    public final static String INNER_LINK = "InnerLink";
+
+    /** 校验是否唯一的返回标识 */
+    public final static boolean UNIQUE = true;
+    public final static boolean NOT_UNIQUE = false;
+
+    /**
+     * 用户名长度限制
+     */
+    public static final int USERNAME_MIN_LENGTH = 2;
+    public static final int USERNAME_MAX_LENGTH = 20;
+
+    /**
+     * 密码长度限制
+     */
+    public static final int PASSWORD_MIN_LENGTH = 5;
+    public static final int PASSWORD_MAX_LENGTH = 20;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/controller/BaseController.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/controller/BaseController.java
index c131bc47..0d910f8b 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/controller/BaseController.java
@@ -1,202 +1,202 @@
-package com.ruoyi.common.core.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.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.page.PageDomain;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.core.page.TableSupport;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.PageUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.sql.SqlUtil;
-
-/**
- * web层通用数据处理
- * 
- * @author ruoyi
- */
-public class BaseController
-{
-    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
-
-    /**
-     * 将前台传递过来的日期格式的字符串,自动转化为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()
-    {
-        PageUtils.startPage();
-    }
-
-    /**
-     * 设置请求排序数据
-     */
-    protected void startOrderBy()
-    {
-        PageDomain pageDomain = TableSupport.buildPageRequest();
-        if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
-        {
-            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
-            PageHelper.orderBy(orderBy);
-        }
-    }
-
-    /**
-     * 清理分页的线程变量
-     */
-    protected void clearPage()
-    {
-        PageUtils.clearPage();
-    }
-
-    /**
-     * 响应请求分页数据
-     */
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    protected TableDataInfo getDataTable(List<?> list)
-    {
-        TableDataInfo rspData = new TableDataInfo();
-        rspData.setCode(HttpStatus.SUCCESS);
-        rspData.setMsg("查询成功");
-        rspData.setRows(list);
-        rspData.setTotal(new PageInfo(list).getTotal());
-        return rspData;
-    }
-
-    /**
-     * 返回成功
-     */
-    public AjaxResult success()
-    {
-        return AjaxResult.success();
-    }
-
-    /**
-     * 返回失败消息
-     */
-    public AjaxResult error()
-    {
-        return AjaxResult.error();
-    }
-
-    /**
-     * 返回成功消息
-     */
-    public AjaxResult success(String message)
-    {
-        return AjaxResult.success(message);
-    }
-    
-    /**
-     * 返回成功消息
-     */
-    public AjaxResult success(Object data)
-    {
-        return AjaxResult.success(data);
-    }
-
-    /**
-     * 返回失败消息
-     */
-    public AjaxResult error(String message)
-    {
-        return AjaxResult.error(message);
-    }
-
-    /**
-     * 返回警告消息
-     */
-    public AjaxResult warn(String message)
-    {
-        return AjaxResult.warn(message);
-    }
-
-    /**
-     * 响应返回结果
-     * 
-     * @param rows 影响行数
-     * @return 操作结果
-     */
-    protected AjaxResult toAjax(int rows)
-    {
-        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
-    }
-
-    /**
-     * 响应返回结果
-     * 
-     * @param result 结果
-     * @return 操作结果
-     */
-    protected AjaxResult toAjax(boolean result)
-    {
-        return result ? success() : error();
-    }
-
-    /**
-     * 页面跳转
-     */
-    public String redirect(String url)
-    {
-        return StringUtils.format("redirect:{}", url);
-    }
-
-    /**
-     * 获取用户缓存信息
-     */
-    public LoginUser getLoginUser()
-    {
-        return SecurityUtils.getLoginUser();
-    }
-
-    /**
-     * 获取登录用户id
-     */
-    public Long getUserId()
-    {
-        return getLoginUser().getUserId();
-    }
-
-    /**
-     * 获取登录部门id
-     */
-    public Long getDeptId()
-    {
-        return getLoginUser().getDeptId();
-    }
-
-    /**
-     * 获取登录用户名
-     */
-    public String getUsername()
-    {
-        return getLoginUser().getUsername();
-    }
-}
+package com.acupuncture.common.core.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.acupuncture.common.constant.HttpStatus;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.page.PageDomain;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.core.page.TableSupport;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.PageUtils;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.sql.SqlUtil;
+
+/**
+ * web层通用数据处理
+ * 
+ * @author acupuncture
+ */
+public class BaseController
+{
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 将前台传递过来的日期格式的字符串,自动转化为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()
+    {
+        PageUtils.startPage();
+    }
+
+    /**
+     * 设置请求排序数据
+     */
+    protected void startOrderBy()
+    {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        if (StringUtils.isNotEmpty(pageDomain.getOrderBy()))
+        {
+            String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+            PageHelper.orderBy(orderBy);
+        }
+    }
+
+    /**
+     * 清理分页的线程变量
+     */
+    protected void clearPage()
+    {
+        PageUtils.clearPage();
+    }
+
+    /**
+     * 响应请求分页数据
+     */
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    protected TableDataInfo getDataTable(List<?> list)
+    {
+        TableDataInfo rspData = new TableDataInfo();
+        rspData.setCode(HttpStatus.SUCCESS);
+        rspData.setMsg("查询成功");
+        rspData.setRows(list);
+        rspData.setTotal(new PageInfo(list).getTotal());
+        return rspData;
+    }
+
+    /**
+     * 返回成功
+     */
+    public AjaxResult success()
+    {
+        return AjaxResult.success();
+    }
+
+    /**
+     * 返回失败消息
+     */
+    public AjaxResult error()
+    {
+        return AjaxResult.error();
+    }
+
+    /**
+     * 返回成功消息
+     */
+    public AjaxResult success(String message)
+    {
+        return AjaxResult.success(message);
+    }
+    
+    /**
+     * 返回成功消息
+     */
+    public AjaxResult success(Object data)
+    {
+        return AjaxResult.success(data);
+    }
+
+    /**
+     * 返回失败消息
+     */
+    public AjaxResult error(String message)
+    {
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 返回警告消息
+     */
+    public AjaxResult warn(String message)
+    {
+        return AjaxResult.warn(message);
+    }
+
+    /**
+     * 响应返回结果
+     * 
+     * @param rows 影响行数
+     * @return 操作结果
+     */
+    protected AjaxResult toAjax(int rows)
+    {
+        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+    }
+
+    /**
+     * 响应返回结果
+     * 
+     * @param result 结果
+     * @return 操作结果
+     */
+    protected AjaxResult toAjax(boolean result)
+    {
+        return result ? success() : error();
+    }
+
+    /**
+     * 页面跳转
+     */
+    public String redirect(String url)
+    {
+        return StringUtils.format("redirect:{}", url);
+    }
+
+    /**
+     * 获取用户缓存信息
+     */
+    public LoginUser getLoginUser()
+    {
+        return SecurityUtils.getLoginUser();
+    }
+
+    /**
+     * 获取登录用户id
+     */
+    public Long getUserId()
+    {
+        return getLoginUser().getUserId();
+    }
+
+    /**
+     * 获取登录部门id
+     */
+    public Long getDeptId()
+    {
+        return getLoginUser().getDeptId();
+    }
+
+    /**
+     * 获取登录用户名
+     */
+    public String getUsername()
+    {
+        return getLoginUser().getUsername();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/AjaxResult.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/AjaxResult.java
index 42dcbcde..8ec2d956 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/AjaxResult.java
@@ -1,216 +1,216 @@
-package com.ruoyi.common.core.domain;
-
-import java.util.HashMap;
-import java.util.Objects;
-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);
-    }
-
-    /**
-     * 返回警告消息
-     *
-     * @param msg 返回内容
-     * @return 警告消息
-     */
-    public static AjaxResult warn(String msg)
-    {
-        return AjaxResult.warn(msg, null);
-    }
-
-    /**
-     * 返回警告消息
-     *
-     * @param msg 返回内容
-     * @param data 数据对象
-     * @return 警告消息
-     */
-    public static AjaxResult warn(String msg, Object data)
-    {
-        return new AjaxResult(HttpStatus.WARN, 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);
-    }
-
-    /**
-     * 是否为成功消息
-     *
-     * @return 结果
-     */
-    public boolean isSuccess()
-    {
-        return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
-    }
-
-    /**
-     * 是否为警告消息
-     *
-     * @return 结果
-     */
-    public boolean isWarn()
-    {
-        return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
-    }
-
-    /**
-     * 是否为错误消息
-     *
-     * @return 结果
-     */
-    public boolean isError()
-    {
-        return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
-    }
-
-    /**
-     * 方便链式调用
-     *
-     * @param key 键
-     * @param value 值
-     * @return 数据对象
-     */
-    @Override
-    public AjaxResult put(String key, Object value)
-    {
-        super.put(key, value);
-        return this;
-    }
-}
+package com.acupuncture.common.core.domain;
+
+import java.util.HashMap;
+import java.util.Objects;
+import com.acupuncture.common.constant.HttpStatus;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 操作消息提醒
+ * 
+ * @author acupuncture
+ */
+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);
+    }
+
+    /**
+     * 返回警告消息
+     *
+     * @param msg 返回内容
+     * @return 警告消息
+     */
+    public static AjaxResult warn(String msg)
+    {
+        return AjaxResult.warn(msg, null);
+    }
+
+    /**
+     * 返回警告消息
+     *
+     * @param msg 返回内容
+     * @param data 数据对象
+     * @return 警告消息
+     */
+    public static AjaxResult warn(String msg, Object data)
+    {
+        return new AjaxResult(HttpStatus.WARN, 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);
+    }
+
+    /**
+     * 是否为成功消息
+     *
+     * @return 结果
+     */
+    public boolean isSuccess()
+    {
+        return Objects.equals(HttpStatus.SUCCESS, this.get(CODE_TAG));
+    }
+
+    /**
+     * 是否为警告消息
+     *
+     * @return 结果
+     */
+    public boolean isWarn()
+    {
+        return Objects.equals(HttpStatus.WARN, this.get(CODE_TAG));
+    }
+
+    /**
+     * 是否为错误消息
+     *
+     * @return 结果
+     */
+    public boolean isError()
+    {
+        return Objects.equals(HttpStatus.ERROR, this.get(CODE_TAG));
+    }
+
+    /**
+     * 方便链式调用
+     *
+     * @param key 键
+     * @param value 值
+     * @return 数据对象
+     */
+    @Override
+    public AjaxResult put(String key, Object value)
+    {
+        super.put(key, value);
+        return this;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/BaseEntity.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/BaseEntity.java
index 67269ff6..18ffab20 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/BaseEntity.java
@@ -1,118 +1,118 @@
-package com.ruoyi.common.core.domain;
-
-import java.io.Serializable;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.Map;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.fasterxml.jackson.annotation.JsonIgnore;
-import com.fasterxml.jackson.annotation.JsonInclude;
-
-/**
- * Entity基类
- * 
- * @author ruoyi
- */
-public class BaseEntity implements Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 搜索值 */
-    @JsonIgnore
-    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;
-
-    /** 请求参数 */
-    @JsonInclude(JsonInclude.Include.NON_EMPTY)
-    private Map<String, Object> 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 Map<String, Object> getParams()
-    {
-        if (params == null)
-        {
-            params = new HashMap<>();
-        }
-        return params;
-    }
-
-    public void setParams(Map<String, Object> params)
-    {
-        this.params = params;
-    }
-}
+package com.acupuncture.common.core.domain;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+/**
+ * Entity基类
+ * 
+ * @author acupuncture
+ */
+public class BaseEntity implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 搜索值 */
+    @JsonIgnore
+    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;
+
+    /** 请求参数 */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private Map<String, Object> 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 Map<String, Object> getParams()
+    {
+        if (params == null)
+        {
+            params = new HashMap<>();
+        }
+        return params;
+    }
+
+    public void setParams(Map<String, Object> params)
+    {
+        this.params = params;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/R.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/R.java
index ef15802b..e59394d2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/R.java
@@ -1,12 +1,12 @@
-package com.ruoyi.common.core.domain;
+package com.acupuncture.common.core.domain;
 
 import java.io.Serializable;
-import com.ruoyi.common.constant.HttpStatus;
+import com.acupuncture.common.constant.HttpStatus;
 
 /**
  * 响应信息主体
  *
- * @author ruoyi
+ * @author acupuncture
  */
 public class R<T> implements Serializable
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeEntity.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeEntity.java
index 171f04c9..38c6e562 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeEntity.java
@@ -1,79 +1,79 @@
-package com.ruoyi.common.core.domain;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Tree基类
- * 
- * @author ruoyi
- */
-public class TreeEntity extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 父菜单名称 */
-    private String parentName;
-
-    /** 父菜单ID */
-    private Long parentId;
-
-    /** 显示顺序 */
-    private Integer orderNum;
-
-    /** 祖级列表 */
-    private String ancestors;
-
-    /** 子部门 */
-    private List<?> children = new ArrayList<>();
-
-    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 Integer getOrderNum()
-    {
-        return orderNum;
-    }
-
-    public void setOrderNum(Integer orderNum)
-    {
-        this.orderNum = orderNum;
-    }
-
-    public String getAncestors()
-    {
-        return ancestors;
-    }
-
-    public void setAncestors(String ancestors)
-    {
-        this.ancestors = ancestors;
-    }
-
-    public List<?> getChildren()
-    {
-        return children;
-    }
-
-    public void setChildren(List<?> children)
-    {
-        this.children = children;
-    }
-}
+package com.acupuncture.common.core.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ * 
+ * @author acupuncture
+ */
+public class TreeEntity extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 父菜单名称 */
+    private String parentName;
+
+    /** 父菜单ID */
+    private Long parentId;
+
+    /** 显示顺序 */
+    private Integer orderNum;
+
+    /** 祖级列表 */
+    private String ancestors;
+
+    /** 子部门 */
+    private List<?> children = new ArrayList<>();
+
+    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 Integer getOrderNum()
+    {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum)
+    {
+        this.orderNum = orderNum;
+    }
+
+    public String getAncestors()
+    {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors)
+    {
+        this.ancestors = ancestors;
+    }
+
+    public List<?> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<?> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeSelect.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeSelect.java
index a762704c..b9de7ad2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/TreeSelect.java
@@ -1,93 +1,93 @@
-package com.ruoyi.common.core.domain;
-
-import java.io.Serializable;
-import java.util.List;
-import java.util.stream.Collectors;
-import com.fasterxml.jackson.annotation.JsonInclude;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysDept;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * Treeselect树结构实体类
- * 
- * @author ruoyi
- */
-public class TreeSelect implements Serializable
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 节点ID */
-    private Long id;
-
-    /** 节点名称 */
-    private String label;
-
-    /** 节点禁用 */
-    private boolean disabled = false;
-
-    /** 子节点 */
-    @JsonInclude(JsonInclude.Include.NON_EMPTY)
-    private List<TreeSelect> children;
-
-    public TreeSelect()
-    {
-
-    }
-
-    public TreeSelect(SysDept dept)
-    {
-        this.id = dept.getDeptId();
-        this.label = dept.getDeptName();
-        this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
-        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 boolean isDisabled()
-    {
-        return disabled;
-    }
-
-    public void setDisabled(boolean disabled)
-    {
-        this.disabled = disabled;
-    }
-
-    public List<TreeSelect> getChildren()
-    {
-        return children;
-    }
-
-    public void setChildren(List<TreeSelect> children)
-    {
-        this.children = children;
-    }
-}
+package com.acupuncture.common.core.domain;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysDept;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * Treeselect树结构实体类
+ * 
+ * @author acupuncture
+ */
+public class TreeSelect implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 节点ID */
+    private Long id;
+
+    /** 节点名称 */
+    private String label;
+
+    /** 节点禁用 */
+    private boolean disabled = false;
+
+    /** 子节点 */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<TreeSelect> children;
+
+    public TreeSelect()
+    {
+
+    }
+
+    public TreeSelect(SysDept dept)
+    {
+        this.id = dept.getDeptId();
+        this.label = dept.getDeptName();
+        this.disabled = StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus());
+        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 boolean isDisabled()
+    {
+        return disabled;
+    }
+
+    public void setDisabled(boolean disabled)
+    {
+        this.disabled = disabled;
+    }
+
+    public List<TreeSelect> getChildren()
+    {
+        return children;
+    }
+
+    public void setChildren(List<TreeSelect> children)
+    {
+        this.children = children;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDept.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDept.java
index 693461b9..16af0022 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDept.java
@@ -1,203 +1,203 @@
-package com.ruoyi.common.core.domain.entity;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.validation.constraints.Email;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 部门表 sys_dept
- * 
- * @author ruoyi
- */
-public class SysDept extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 部门ID */
-    private Long deptId;
-
-    /** 父部门ID */
-    private Long parentId;
-
-    /** 祖级列表 */
-    private String ancestors;
-
-    /** 部门名称 */
-    private String deptName;
-
-    /** 显示顺序 */
-    private Integer orderNum;
-
-    /** 负责人 */
-    private String leader;
-
-    /** 联系电话 */
-    private String phone;
-
-    /** 邮箱 */
-    private String email;
-
-    /** 部门状态:0正常,1停用 */
-    private String status;
-
-    /** 删除标志(0代表存在 2代表删除) */
-    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;
-    }
-
-    @NotBlank(message = "部门名称不能为空")
-    @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
-    public String getDeptName()
-    {
-        return deptName;
-    }
-
-    public void setDeptName(String deptName)
-    {
-        this.deptName = deptName;
-    }
-
-    @NotNull(message = "显示顺序不能为空")
-    public Integer getOrderNum()
-    {
-        return orderNum;
-    }
-
-    public void setOrderNum(Integer orderNum)
-    {
-        this.orderNum = orderNum;
-    }
-
-    public String getLeader()
-    {
-        return leader;
-    }
-
-    public void setLeader(String leader)
-    {
-        this.leader = leader;
-    }
-
-    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
-    public String getPhone()
-    {
-        return phone;
-    }
-
-    public void setPhone(String phone)
-    {
-        this.phone = phone;
-    }
-
-    @Email(message = "邮箱格式不正确")
-    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
-    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;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("deptId", getDeptId())
-            .append("parentId", getParentId())
-            .append("ancestors", getAncestors())
-            .append("deptName", getDeptName())
-            .append("orderNum", getOrderNum())
-            .append("leader", getLeader())
-            .append("phone", getPhone())
-            .append("email", getEmail())
-            .append("status", getStatus())
-            .append("delFlag", getDelFlag())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 部门表 sys_dept
+ * 
+ * @author acupuncture
+ */
+public class SysDept extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 部门ID */
+    private Long deptId;
+
+    /** 父部门ID */
+    private Long parentId;
+
+    /** 祖级列表 */
+    private String ancestors;
+
+    /** 部门名称 */
+    private String deptName;
+
+    /** 显示顺序 */
+    private Integer orderNum;
+
+    /** 负责人 */
+    private String leader;
+
+    /** 联系电话 */
+    private String phone;
+
+    /** 邮箱 */
+    private String email;
+
+    /** 部门状态:0正常,1停用 */
+    private String status;
+
+    /** 删除标志(0代表存在 2代表删除) */
+    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;
+    }
+
+    @NotBlank(message = "部门名称不能为空")
+    @Size(min = 0, max = 30, message = "部门名称长度不能超过30个字符")
+    public String getDeptName()
+    {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName)
+    {
+        this.deptName = deptName;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getOrderNum()
+    {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum)
+    {
+        this.orderNum = orderNum;
+    }
+
+    public String getLeader()
+    {
+        return leader;
+    }
+
+    public void setLeader(String leader)
+    {
+        this.leader = leader;
+    }
+
+    @Size(min = 0, max = 11, message = "联系电话长度不能超过11个字符")
+    public String getPhone()
+    {
+        return phone;
+    }
+
+    public void setPhone(String phone)
+    {
+        this.phone = phone;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    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;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("deptId", getDeptId())
+            .append("parentId", getParentId())
+            .append("ancestors", getAncestors())
+            .append("deptName", getDeptName())
+            .append("orderNum", getOrderNum())
+            .append("leader", getLeader())
+            .append("phone", getPhone())
+            .append("email", getEmail())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictData.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictData.java
index e79eaa20..560c7c79 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictData.java
@@ -1,176 +1,176 @@
-package com.ruoyi.common.core.domain.entity;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 字典数据表 sys_dict_data
- * 
- * @author ruoyi
- */
-public class SysDictData extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 字典编码 */
-    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
-    private Long dictCode;
-
-    /** 字典排序 */
-    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
-    private Long dictSort;
-
-    /** 字典标签 */
-    @Excel(name = "字典标签")
-    private String dictLabel;
-
-    /** 字典键值 */
-    @Excel(name = "字典键值")
-    private String dictValue;
-
-    /** 字典类型 */
-    @Excel(name = "字典类型")
-    private String dictType;
-
-    /** 样式属性(其他样式扩展) */
-    private String cssClass;
-
-    /** 表格字典样式 */
-    private String listClass;
-
-    /** 是否默认(Y是 N否) */
-    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
-    private String isDefault;
-
-    /** 状态(0正常 1停用) */
-    @Excel(name = "状态", readConverterExp = "0=正常,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);
-    }
-
-    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;
-    }
-    
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("dictCode", getDictCode())
-            .append("dictSort", getDictSort())
-            .append("dictLabel", getDictLabel())
-            .append("dictValue", getDictValue())
-            .append("dictType", getDictType())
-            .append("cssClass", getCssClass())
-            .append("listClass", getListClass())
-            .append("isDefault", getIsDefault())
-            .append("status", getStatus())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 字典数据表 sys_dict_data
+ * 
+ * @author acupuncture
+ */
+public class SysDictData extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 字典编码 */
+    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
+    private Long dictCode;
+
+    /** 字典排序 */
+    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
+    private Long dictSort;
+
+    /** 字典标签 */
+    @Excel(name = "字典标签")
+    private String dictLabel;
+
+    /** 字典键值 */
+    @Excel(name = "字典键值")
+    private String dictValue;
+
+    /** 字典类型 */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /** 样式属性(其他样式扩展) */
+    private String cssClass;
+
+    /** 表格字典样式 */
+    private String listClass;
+
+    /** 是否默认(Y是 N否) */
+    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+    private String isDefault;
+
+    /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,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);
+    }
+
+    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;
+    }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("dictCode", getDictCode())
+            .append("dictSort", getDictSort())
+            .append("dictLabel", getDictLabel())
+            .append("dictValue", getDictValue())
+            .append("dictType", getDictType())
+            .append("cssClass", getCssClass())
+            .append("listClass", getListClass())
+            .append("isDefault", getIsDefault())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictType.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictType.java
index 0befbf43..aabbac0c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysDictType.java
@@ -1,96 +1,96 @@
-package com.ruoyi.common.core.domain.entity;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Pattern;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 字典类型表 sys_dict_type
- * 
- * @author ruoyi
- */
-public class SysDictType extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 字典主键 */
-    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
-    private Long dictId;
-
-    /** 字典名称 */
-    @Excel(name = "字典名称")
-    private String dictName;
-
-    /** 字典类型 */
-    @Excel(name = "字典类型")
-    private String dictType;
-
-    /** 状态(0正常 1停用) */
-    @Excel(name = "状态", readConverterExp = "0=正常,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个字符")
-    @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
-    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;
-    }
-    
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("dictId", getDictId())
-            .append("dictName", getDictName())
-            .append("dictType", getDictType())
-            .append("status", getStatus())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 字典类型表 sys_dict_type
+ * 
+ * @author acupuncture
+ */
+public class SysDictType extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 字典主键 */
+    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
+    private Long dictId;
+
+    /** 字典名称 */
+    @Excel(name = "字典名称")
+    private String dictName;
+
+    /** 字典类型 */
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,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个字符")
+    @Pattern(regexp = "^[a-z][a-z0-9_]*$", message = "字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)")
+    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;
+    }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("dictId", getDictId())
+            .append("dictName", getDictName())
+            .append("dictType", getDictType())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysMenu.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysMenu.java
index f0621202..2f347192 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysMenu.java
@@ -1,274 +1,274 @@
-package com.ruoyi.common.core.domain.entity;
-
-import java.util.ArrayList;
-import java.util.List;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 菜单权限表 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;
-
-    /** 父菜单ID */
-    private Long parentId;
-
-    /** 显示顺序 */
-    private Integer orderNum;
-
-    /** 路由地址 */
-    private String path;
-
-    /** 组件路径 */
-    private String component;
-
-    /** 路由参数 */
-    private String query;
-
-    /** 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义) */
-    private String routeName;
-
-    /** 是否为外链(0是 1否) */
-    private String isFrame;
-
-    /** 是否缓存(0缓存 1不缓存) */
-    private String isCache;
-
-    /** 类型(M目录 C菜单 F按钮) */
-    private String menuType;
-
-    /** 显示状态(0显示 1隐藏) */
-    private String visible;
-
-    /** 菜单状态(0正常 1停用) */
-    private String status;
-
-    /** 权限字符串 */
-    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;
-    }
-
-    @NotBlank(message = "菜单名称不能为空")
-    @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
-    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;
-    }
-
-    @NotNull(message = "显示顺序不能为空")
-    public Integer getOrderNum()
-    {
-        return orderNum;
-    }
-
-    public void setOrderNum(Integer orderNum)
-    {
-        this.orderNum = orderNum;
-    }
-
-    @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
-    public String getPath()
-    {
-        return path;
-    }
-
-    public void setPath(String path)
-    {
-        this.path = path;
-    }
-
-    @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
-    public String getComponent()
-    {
-        return component;
-    }
-
-    public void setComponent(String component)
-    {
-        this.component = component;
-    }
-
-    public String getQuery()
-    {
-        return query;
-    }
-
-    public void setQuery(String query)
-    {
-        this.query = query;
-    }
-
-    public String getRouteName()
-    {
-        return routeName;
-    }
-
-    public void setRouteName(String routeName)
-    {
-        this.routeName = routeName;
-    }
-
-    public String getIsFrame()
-    {
-        return isFrame;
-    }
-
-    public void setIsFrame(String isFrame)
-    {
-        this.isFrame = isFrame;
-    }
-
-    public String getIsCache()
-    {
-        return isCache;
-    }
-
-    public void setIsCache(String isCache)
-    {
-        this.isCache = isCache;
-    }
-
-    @NotBlank(message = "菜单类型不能为空")
-    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 getStatus()
-    {
-        return status;
-    }
-
-    public void setStatus(String status)
-    {
-        this.status = status;
-    }
-
-    @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
-    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;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("menuId", getMenuId())
-            .append("menuName", getMenuName())
-            .append("parentId", getParentId())
-            .append("orderNum", getOrderNum())
-            .append("path", getPath())
-            .append("component", getComponent())
-            .append("query", getQuery())
-            .append("routeName", getRouteName())
-            .append("isFrame", getIsFrame())
-            .append("IsCache", getIsCache())
-            .append("menuType", getMenuType())
-            .append("visible", getVisible())
-            .append("status ", getStatus())
-            .append("perms", getPerms())
-            .append("icon", getIcon())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 菜单权限表 sys_menu
+ * 
+ * @author acupuncture
+ */
+public class SysMenu extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 菜单ID */
+    private Long menuId;
+
+    /** 菜单名称 */
+    private String menuName;
+
+    /** 父菜单名称 */
+    private String parentName;
+
+    /** 父菜单ID */
+    private Long parentId;
+
+    /** 显示顺序 */
+    private Integer orderNum;
+
+    /** 路由地址 */
+    private String path;
+
+    /** 组件路径 */
+    private String component;
+
+    /** 路由参数 */
+    private String query;
+
+    /** 路由名称,默认和路由地址相同的驼峰格式(注意:因为vue3版本的router会删除名称相同路由,为避免名字的冲突,特殊情况可以自定义) */
+    private String routeName;
+
+    /** 是否为外链(0是 1否) */
+    private String isFrame;
+
+    /** 是否缓存(0缓存 1不缓存) */
+    private String isCache;
+
+    /** 类型(M目录 C菜单 F按钮) */
+    private String menuType;
+
+    /** 显示状态(0显示 1隐藏) */
+    private String visible;
+
+    /** 菜单状态(0正常 1停用) */
+    private String status;
+
+    /** 权限字符串 */
+    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;
+    }
+
+    @NotBlank(message = "菜单名称不能为空")
+    @Size(min = 0, max = 50, message = "菜单名称长度不能超过50个字符")
+    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;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getOrderNum()
+    {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum)
+    {
+        this.orderNum = orderNum;
+    }
+
+    @Size(min = 0, max = 200, message = "路由地址不能超过200个字符")
+    public String getPath()
+    {
+        return path;
+    }
+
+    public void setPath(String path)
+    {
+        this.path = path;
+    }
+
+    @Size(min = 0, max = 200, message = "组件路径不能超过255个字符")
+    public String getComponent()
+    {
+        return component;
+    }
+
+    public void setComponent(String component)
+    {
+        this.component = component;
+    }
+
+    public String getQuery()
+    {
+        return query;
+    }
+
+    public void setQuery(String query)
+    {
+        this.query = query;
+    }
+
+    public String getRouteName()
+    {
+        return routeName;
+    }
+
+    public void setRouteName(String routeName)
+    {
+        this.routeName = routeName;
+    }
+
+    public String getIsFrame()
+    {
+        return isFrame;
+    }
+
+    public void setIsFrame(String isFrame)
+    {
+        this.isFrame = isFrame;
+    }
+
+    public String getIsCache()
+    {
+        return isCache;
+    }
+
+    public void setIsCache(String isCache)
+    {
+        this.isCache = isCache;
+    }
+
+    @NotBlank(message = "菜单类型不能为空")
+    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 getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    @Size(min = 0, max = 100, message = "权限标识长度不能超过100个字符")
+    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;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("menuId", getMenuId())
+            .append("menuName", getMenuName())
+            .append("parentId", getParentId())
+            .append("orderNum", getOrderNum())
+            .append("path", getPath())
+            .append("component", getComponent())
+            .append("query", getQuery())
+            .append("routeName", getRouteName())
+            .append("isFrame", getIsFrame())
+            .append("IsCache", getIsCache())
+            .append("menuType", getMenuType())
+            .append("visible", getVisible())
+            .append("status ", getStatus())
+            .append("perms", getPerms())
+            .append("icon", getIcon())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysRole.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysRole.java
index 2396f802..63031848 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysRole.java
@@ -1,241 +1,241 @@
-package com.ruoyi.common.core.domain.entity;
-
-import java.util.Set;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 角色表 sys_role
- * 
- * @author ruoyi
- */
-public class SysRole extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 角色ID */
-    @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
-    private Long roleId;
-
-    /** 角色名称 */
-    @Excel(name = "角色名称")
-    private String roleName;
-
-    /** 角色权限 */
-    @Excel(name = "角色权限")
-    private String roleKey;
-
-    /** 角色排序 */
-    @Excel(name = "角色排序")
-    private Integer roleSort;
-
-    /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */
-    @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
-    private String dataScope;
-
-    /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */
-    private boolean menuCheckStrictly;
-
-    /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */
-    private boolean deptCheckStrictly;
-
-    /** 角色状态(0正常 1停用) */
-    @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
-    private String status;
-
-    /** 删除标志(0代表存在 2代表删除) */
-    private String delFlag;
-
-    /** 用户是否存在此角色标识 默认不存在 */
-    private boolean flag = false;
-
-    /** 菜单组 */
-    private Long[] menuIds;
-
-    /** 部门组(数据权限) */
-    private Long[] deptIds;
-
-    /** 角色菜单权限 */
-    private Set<String> permissions;
-
-    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;
-    }
-
-    @NotBlank(message = "角色名称不能为空")
-    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
-    public String getRoleName()
-    {
-        return roleName;
-    }
-
-    public void setRoleName(String roleName)
-    {
-        this.roleName = roleName;
-    }
-
-    @NotBlank(message = "权限字符不能为空")
-    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
-    public String getRoleKey()
-    {
-        return roleKey;
-    }
-
-    public void setRoleKey(String roleKey)
-    {
-        this.roleKey = roleKey;
-    }
-
-    @NotNull(message = "显示顺序不能为空")
-    public Integer getRoleSort()
-    {
-        return roleSort;
-    }
-
-    public void setRoleSort(Integer roleSort)
-    {
-        this.roleSort = roleSort;
-    }
-
-    public String getDataScope()
-    {
-        return dataScope;
-    }
-
-    public void setDataScope(String dataScope)
-    {
-        this.dataScope = dataScope;
-    }
-
-    public boolean isMenuCheckStrictly()
-    {
-        return menuCheckStrictly;
-    }
-
-    public void setMenuCheckStrictly(boolean menuCheckStrictly)
-    {
-        this.menuCheckStrictly = menuCheckStrictly;
-    }
-
-    public boolean isDeptCheckStrictly()
-    {
-        return deptCheckStrictly;
-    }
-
-    public void setDeptCheckStrictly(boolean deptCheckStrictly)
-    {
-        this.deptCheckStrictly = deptCheckStrictly;
-    }
-
-    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;
-    }
-
-    public Set<String> getPermissions()
-    {
-        return permissions;
-    }
-
-    public void setPermissions(Set<String> permissions)
-    {
-        this.permissions = permissions;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("roleId", getRoleId())
-            .append("roleName", getRoleName())
-            .append("roleKey", getRoleKey())
-            .append("roleSort", getRoleSort())
-            .append("dataScope", getDataScope())
-            .append("menuCheckStrictly", isMenuCheckStrictly())
-            .append("deptCheckStrictly", isDeptCheckStrictly())
-            .append("status", getStatus())
-            .append("delFlag", getDelFlag())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import java.util.Set;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 角色表 sys_role
+ * 
+ * @author acupuncture
+ */
+public class SysRole extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 角色ID */
+    @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
+    private Long roleId;
+
+    /** 角色名称 */
+    @Excel(name = "角色名称")
+    private String roleName;
+
+    /** 角色权限 */
+    @Excel(name = "角色权限")
+    private String roleKey;
+
+    /** 角色排序 */
+    @Excel(name = "角色排序")
+    private Integer roleSort;
+
+    /** 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限) */
+    @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+    private String dataScope;
+
+    /** 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示) */
+    private boolean menuCheckStrictly;
+
+    /** 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 ) */
+    private boolean deptCheckStrictly;
+
+    /** 角色状态(0正常 1停用) */
+    @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /** 删除标志(0代表存在 2代表删除) */
+    private String delFlag;
+
+    /** 用户是否存在此角色标识 默认不存在 */
+    private boolean flag = false;
+
+    /** 菜单组 */
+    private Long[] menuIds;
+
+    /** 部门组(数据权限) */
+    private Long[] deptIds;
+
+    /** 角色菜单权限 */
+    private Set<String> permissions;
+
+    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;
+    }
+
+    @NotBlank(message = "角色名称不能为空")
+    @Size(min = 0, max = 30, message = "角色名称长度不能超过30个字符")
+    public String getRoleName()
+    {
+        return roleName;
+    }
+
+    public void setRoleName(String roleName)
+    {
+        this.roleName = roleName;
+    }
+
+    @NotBlank(message = "权限字符不能为空")
+    @Size(min = 0, max = 100, message = "权限字符长度不能超过100个字符")
+    public String getRoleKey()
+    {
+        return roleKey;
+    }
+
+    public void setRoleKey(String roleKey)
+    {
+        this.roleKey = roleKey;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getRoleSort()
+    {
+        return roleSort;
+    }
+
+    public void setRoleSort(Integer roleSort)
+    {
+        this.roleSort = roleSort;
+    }
+
+    public String getDataScope()
+    {
+        return dataScope;
+    }
+
+    public void setDataScope(String dataScope)
+    {
+        this.dataScope = dataScope;
+    }
+
+    public boolean isMenuCheckStrictly()
+    {
+        return menuCheckStrictly;
+    }
+
+    public void setMenuCheckStrictly(boolean menuCheckStrictly)
+    {
+        this.menuCheckStrictly = menuCheckStrictly;
+    }
+
+    public boolean isDeptCheckStrictly()
+    {
+        return deptCheckStrictly;
+    }
+
+    public void setDeptCheckStrictly(boolean deptCheckStrictly)
+    {
+        this.deptCheckStrictly = deptCheckStrictly;
+    }
+
+    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;
+    }
+
+    public Set<String> getPermissions()
+    {
+        return permissions;
+    }
+
+    public void setPermissions(Set<String> permissions)
+    {
+        this.permissions = permissions;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("roleId", getRoleId())
+            .append("roleName", getRoleName())
+            .append("roleKey", getRoleKey())
+            .append("roleSort", getRoleSort())
+            .append("dataScope", getDataScope())
+            .append("menuCheckStrictly", isMenuCheckStrictly())
+            .append("deptCheckStrictly", isDeptCheckStrictly())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java
similarity index 91%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java
index c33d9124..35600b6e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/entity/SysUser.java
@@ -1,324 +1,324 @@
-package com.ruoyi.common.core.domain.entity;
-
-import java.util.Date;
-import java.util.List;
-import javax.validation.constraints.*;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.annotation.Excel.Type;
-import com.ruoyi.common.annotation.Excels;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.xss.Xss;
-
-/**
- * 用户对象 sys_user
- * 
- * @author ruoyi
- */
-public class SysUser extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 用户ID */
-    @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
-    private Long userId;
-
-    /** 部门ID */
-    @Excel(name = "部门编号", type = Type.IMPORT)
-    private Long deptId;
-
-    /** 用户账号 */
-    @Excel(name = "登录名称")
-    private String userName;
-
-    /** 用户昵称 */
-    @Excel(name = "用户名称")
-    private String nickName;
-
-    /** 用户邮箱 */
-    @Excel(name = "用户邮箱")
-    private String email;
-
-    /** 手机号码 */
-    @Excel(name = "手机号码", cellType = ColumnType.TEXT)
-    private String phonenumber;
-
-    /** 用户性别 */
-    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
-    private String sex;
-
-    /** 用户头像 */
-    private String avatar;
-
-    /** 密码 */
-    private String password;
-
-    /** 帐号状态(0正常 1停用) */
-    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
-    private String status;
-
-    /** 删除标志(0代表存在 2代表删除) */
-    private String delFlag;
-
-    /** 最后登录IP */
-    @Excel(name = "最后登录IP", type = Type.EXPORT)
-    private String loginIp;
-
-    /** 最后登录时间 */
-    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
-    private Date loginDate;
-
-    /** 部门对象 */
-    @Excels({
-        @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
-        @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
-    })
-    private SysDept dept;
-
-    /** 角色对象 */
-    private List<SysRole> roles;
-
-    /** 角色组 */
-    private Long[] roleIds;
-
-    /** 岗位组 */
-    private Long[] postIds;
-
-    /** 角色ID */
-    private Long roleId;
-
-    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;
-    }
-
-    @Xss(message = "用户昵称不能包含脚本字符")
-    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
-    public String getNickName()
-    {
-        return nickName;
-    }
-
-    public void setNickName(String nickName)
-    {
-        this.nickName = nickName;
-    }
-
-    @Xss(message = "用户账号不能包含脚本字符")
-    @NotBlank(message = "用户账号不能为空")
-    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
-    public String getUserName()
-    {
-        return userName;
-    }
-
-    public void setUserName(String userName)
-    {
-        this.userName = userName;
-    }
-
-    @Email(message = "邮箱格式不正确")
-    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
-    public String getEmail()
-    {
-        return email;
-    }
-
-    public void setEmail(String email)
-    {
-        this.email = email;
-    }
-
-    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
-    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 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;
-    }
-
-    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("deptId", getDeptId())
-            .append("userName", getUserName())
-            .append("nickName", getNickName())
-            .append("email", getEmail())
-            .append("phonenumber", getPhonenumber())
-            .append("sex", getSex())
-            .append("avatar", getAvatar())
-            .append("password", getPassword())
-            .append("status", getStatus())
-            .append("delFlag", getDelFlag())
-            .append("loginIp", getLoginIp())
-            .append("loginDate", getLoginDate())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .append("dept", getDept())
-            .toString();
-    }
-}
+package com.acupuncture.common.core.domain.entity;
+
+import java.util.Date;
+import java.util.List;
+import javax.validation.constraints.*;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.annotation.Excel.Type;
+import com.acupuncture.common.annotation.Excels;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.xss.Xss;
+
+/**
+ * 用户对象 sys_user
+ * 
+ * @author acupuncture
+ */
+public class SysUser extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 用户ID */
+    @Excel(name = "用户序号", type = Type.EXPORT, cellType = ColumnType.NUMERIC, prompt = "用户编号")
+    private Long userId;
+
+    /** 部门ID */
+    @Excel(name = "部门编号", type = Type.IMPORT)
+    private Long deptId;
+
+    /** 用户账号 */
+    @Excel(name = "登录名称")
+    private String userName;
+
+    /** 用户昵称 */
+    @Excel(name = "用户名称")
+    private String nickName;
+
+    /** 用户邮箱 */
+    @Excel(name = "用户邮箱")
+    private String email;
+
+    /** 手机号码 */
+    @Excel(name = "手机号码", cellType = ColumnType.TEXT)
+    private String phonenumber;
+
+    /** 用户性别 */
+    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+    private String sex;
+
+    /** 用户头像 */
+    private String avatar;
+
+    /** 密码 */
+    private String password;
+
+    /** 帐号状态(0正常 1停用) */
+    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /** 删除标志(0代表存在 2代表删除) */
+    private String delFlag;
+
+    /** 最后登录IP */
+    @Excel(name = "最后登录IP", type = Type.EXPORT)
+    private String loginIp;
+
+    /** 最后登录时间 */
+    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
+    private Date loginDate;
+
+    /** 部门对象 */
+    @Excels({
+        @Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT),
+        @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)
+    })
+    private SysDept dept;
+
+    /** 角色对象 */
+    private List<SysRole> roles;
+
+    /** 角色组 */
+    private Long[] roleIds;
+
+    /** 岗位组 */
+    private Long[] postIds;
+
+    /** 角色ID */
+    private Long roleId;
+
+    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;
+    }
+
+    @Xss(message = "用户昵称不能包含脚本字符")
+    @Size(min = 0, max = 30, message = "用户昵称长度不能超过30个字符")
+    public String getNickName()
+    {
+        return nickName;
+    }
+
+    public void setNickName(String nickName)
+    {
+        this.nickName = nickName;
+    }
+
+    @Xss(message = "用户账号不能包含脚本字符")
+    @NotBlank(message = "用户账号不能为空")
+    @Size(min = 0, max = 30, message = "用户账号长度不能超过30个字符")
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    @Email(message = "邮箱格式不正确")
+    @Size(min = 0, max = 50, message = "邮箱长度不能超过50个字符")
+    public String getEmail()
+    {
+        return email;
+    }
+
+    public void setEmail(String email)
+    {
+        this.email = email;
+    }
+
+    @Size(min = 0, max = 11, message = "手机号码长度不能超过11个字符")
+    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 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;
+    }
+
+    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("deptId", getDeptId())
+            .append("userName", getUserName())
+            .append("nickName", getNickName())
+            .append("email", getEmail())
+            .append("phonenumber", getPhonenumber())
+            .append("sex", getSex())
+            .append("avatar", getAvatar())
+            .append("password", getPassword())
+            .append("status", getStatus())
+            .append("delFlag", getDelFlag())
+            .append("loginIp", getLoginIp())
+            .append("loginDate", getLoginDate())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .append("dept", getDept())
+            .toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginBody.java
similarity index 87%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginBody.java
index 583b7a61..d138928a 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginBody.java
@@ -1,69 +1,69 @@
-package com.ruoyi.common.core.domain.model;
-
-/**
- * 用户登录对象
- * 
- * @author ruoyi
- */
-public class LoginBody
-{
-    /**
-     * 用户名
-     */
-    private String username;
-
-    /**
-     * 用户密码
-     */
-    private String password;
-
-    /**
-     * 验证码
-     */
-    private String code;
-
-    /**
-     * 唯一标识
-     */
-    private String uuid;
-
-    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 getCode()
-    {
-        return code;
-    }
-
-    public void setCode(String code)
-    {
-        this.code = code;
-    }
-
-    public String getUuid()
-    {
-        return uuid;
-    }
-
-    public void setUuid(String uuid)
-    {
-        this.uuid = uuid;
-    }
-}
+package com.acupuncture.common.core.domain.model;
+
+/**
+ * 用户登录对象
+ * 
+ * @author acupuncture
+ */
+public class LoginBody
+{
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 用户密码
+     */
+    private String password;
+
+    /**
+     * 验证码
+     */
+    private String code;
+
+    /**
+     * 唯一标识
+     */
+    private String uuid;
+
+    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 getCode()
+    {
+        return code;
+    }
+
+    public void setCode(String code)
+    {
+        this.code = code;
+    }
+
+    public String getUuid()
+    {
+        return uuid;
+    }
+
+    public void setUuid(String uuid)
+    {
+        this.uuid = uuid;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java
index 95e169cf..9942e695 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/LoginUser.java
@@ -1,266 +1,266 @@
-package com.ruoyi.common.core.domain.model;
-
-import com.alibaba.fastjson2.annotation.JSONField;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import org.springframework.security.core.GrantedAuthority;
-import org.springframework.security.core.userdetails.UserDetails;
-import java.util.Collection;
-import java.util.Set;
-
-/**
- * 登录用户身份权限
- * 
- * @author ruoyi
- */
-public class LoginUser implements UserDetails
-{
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 用户ID
-     */
-    private Long userId;
-
-    /**
-     * 部门ID
-     */
-    private Long deptId;
-
-    /**
-     * 用户唯一标识
-     */
-    private String token;
-
-    /**
-     * 登录时间
-     */
-    private Long loginTime;
-
-    /**
-     * 过期时间
-     */
-    private Long expireTime;
-
-    /**
-     * 登录IP地址
-     */
-    private String ipaddr;
-
-    /**
-     * 登录地点
-     */
-    private String loginLocation;
-
-    /**
-     * 浏览器类型
-     */
-    private String browser;
-
-    /**
-     * 操作系统
-     */
-    private String os;
-
-    /**
-     * 权限列表
-     */
-    private Set<String> permissions;
-
-    /**
-     * 用户信息
-     */
-    private SysUser user;
-
-    public LoginUser()
-    {
-    }
-
-    public LoginUser(SysUser user, Set<String> permissions)
-    {
-        this.user = user;
-        this.permissions = permissions;
-    }
-
-    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
-    {
-        this.userId = userId;
-        this.deptId = deptId;
-        this.user = user;
-        this.permissions = permissions;
-    }
-
-    public Long getUserId()
-    {
-        return userId;
-    }
-
-    public void setUserId(Long userId)
-    {
-        this.userId = userId;
-    }
-
-    public Long getDeptId()
-    {
-        return deptId;
-    }
-
-    public void setDeptId(Long deptId)
-    {
-        this.deptId = deptId;
-    }
-
-    public String getToken()
-    {
-        return token;
-    }
-
-    public void setToken(String token)
-    {
-        this.token = token;
-    }
-
-    @JSONField(serialize = false)
-    @Override
-    public String getPassword()
-    {
-        return user.getPassword();
-    }
-
-    @Override
-    public String getUsername()
-    {
-        return user.getUserName();
-    }
-
-    /**
-     * 账户是否未过期,过期无法验证
-     */
-    @JSONField(serialize = false)
-    @Override
-    public boolean isAccountNonExpired()
-    {
-        return true;
-    }
-
-    /**
-     * 指定用户是否解锁,锁定的用户无法进行身份验证
-     * 
-     * @return
-     */
-    @JSONField(serialize = false)
-    @Override
-    public boolean isAccountNonLocked()
-    {
-        return true;
-    }
-
-    /**
-     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
-     * 
-     * @return
-     */
-    @JSONField(serialize = false)
-    @Override
-    public boolean isCredentialsNonExpired()
-    {
-        return true;
-    }
-
-    /**
-     * 是否可用 ,禁用的用户不能身份验证
-     * 
-     * @return
-     */
-    @JSONField(serialize = false)
-    @Override
-    public boolean isEnabled()
-    {
-        return true;
-    }
-
-    public Long getLoginTime()
-    {
-        return loginTime;
-    }
-
-    public void setLoginTime(Long loginTime)
-    {
-        this.loginTime = loginTime;
-    }
-
-    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 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;
-    }
-}
+package com.acupuncture.common.core.domain.model;
+
+import com.alibaba.fastjson2.annotation.JSONField;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * 登录用户身份权限
+ * 
+ * @author acupuncture
+ */
+public class LoginUser implements UserDetails
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    private Long userId;
+
+    /**
+     * 部门ID
+     */
+    private Long deptId;
+
+    /**
+     * 用户唯一标识
+     */
+    private String token;
+
+    /**
+     * 登录时间
+     */
+    private Long loginTime;
+
+    /**
+     * 过期时间
+     */
+    private Long expireTime;
+
+    /**
+     * 登录IP地址
+     */
+    private String ipaddr;
+
+    /**
+     * 登录地点
+     */
+    private String loginLocation;
+
+    /**
+     * 浏览器类型
+     */
+    private String browser;
+
+    /**
+     * 操作系统
+     */
+    private String os;
+
+    /**
+     * 权限列表
+     */
+    private Set<String> permissions;
+
+    /**
+     * 用户信息
+     */
+    private SysUser user;
+
+    public LoginUser()
+    {
+    }
+
+    public LoginUser(SysUser user, Set<String> permissions)
+    {
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    public LoginUser(Long userId, Long deptId, SysUser user, Set<String> permissions)
+    {
+        this.userId = userId;
+        this.deptId = deptId;
+        this.user = user;
+        this.permissions = permissions;
+    }
+
+    public Long getUserId()
+    {
+        return userId;
+    }
+
+    public void setUserId(Long userId)
+    {
+        this.userId = userId;
+    }
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public String getToken()
+    {
+        return token;
+    }
+
+    public void setToken(String token)
+    {
+        this.token = token;
+    }
+
+    @JSONField(serialize = false)
+    @Override
+    public String getPassword()
+    {
+        return user.getPassword();
+    }
+
+    @Override
+    public String getUsername()
+    {
+        return user.getUserName();
+    }
+
+    /**
+     * 账户是否未过期,过期无法验证
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isAccountNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 指定用户是否解锁,锁定的用户无法进行身份验证
+     * 
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isAccountNonLocked()
+    {
+        return true;
+    }
+
+    /**
+     * 指示是否已过期的用户的凭据(密码),过期的凭据防止认证
+     * 
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isCredentialsNonExpired()
+    {
+        return true;
+    }
+
+    /**
+     * 是否可用 ,禁用的用户不能身份验证
+     * 
+     * @return
+     */
+    @JSONField(serialize = false)
+    @Override
+    public boolean isEnabled()
+    {
+        return true;
+    }
+
+    public Long getLoginTime()
+    {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime)
+    {
+        this.loginTime = loginTime;
+    }
+
+    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 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-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/RegisterBody.java
similarity index 53%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/RegisterBody.java
index 5baa8878..eb09fe73 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/domain/model/RegisterBody.java
@@ -1,11 +1,11 @@
-package com.ruoyi.common.core.domain.model;
-
-/**
- * 用户注册对象
- * 
- * @author ruoyi
- */
-public class RegisterBody extends LoginBody
-{
-
-}
+package com.acupuncture.common.core.domain.model;
+
+/**
+ * 用户注册对象
+ * 
+ * @author acupuncture
+ */
+public class RegisterBody extends LoginBody
+{
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/PageDomain.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/page/PageDomain.java
index 8966cb4c..69c30492 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/PageDomain.java
@@ -1,11 +1,11 @@
-package com.ruoyi.common.core.page;
+package com.acupuncture.common.core.page;
 
-import com.ruoyi.common.utils.StringUtils;
+import com.acupuncture.common.utils.StringUtils;
 
 /**
  * 分页数据
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class PageDomain
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableDataInfo.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableDataInfo.java
index a3487b8e..73c8a650 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableDataInfo.java
@@ -1,85 +1,85 @@
-package com.ruoyi.common.core.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 String 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 String getMsg()
-    {
-        return msg;
-    }
-
-    public void setMsg(String msg)
-    {
-        this.msg = msg;
-    }
-}
+package com.acupuncture.common.core.page;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 表格分页数据对象
+ * 
+ * @author acupuncture
+ */
+public class TableDataInfo implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 总记录数 */
+    private long total;
+
+    /** 列表数据 */
+    private List<?> rows;
+
+    /** 消息状态码 */
+    private int code;
+
+    /** 消息内容 */
+    private String 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 String getMsg()
+    {
+        return msg;
+    }
+
+    public void setMsg(String msg)
+    {
+        this.msg = msg;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableSupport.java
similarity index 86%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableSupport.java
index 62ac4f96..4f6eea48 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/page/TableSupport.java
@@ -1,56 +1,56 @@
-package com.ruoyi.common.core.page;
-
-import com.ruoyi.common.core.text.Convert;
-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 final String REASONABLE = "reasonable";
-
-    /**
-     * 封装分页对象
-     */
-    public static PageDomain getPageDomain()
-    {
-        PageDomain pageDomain = new PageDomain();
-        pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
-        pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
-        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
-        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
-        pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
-        return pageDomain;
-    }
-
-    public static PageDomain buildPageRequest()
-    {
-        return getPageDomain();
-    }
-}
+package com.acupuncture.common.core.page;
+
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.utils.ServletUtils;
+
+/**
+ * 表格数据处理
+ * 
+ * @author acupuncture
+ */
+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 final String REASONABLE = "reasonable";
+
+    /**
+     * 封装分页对象
+     */
+    public static PageDomain getPageDomain()
+    {
+        PageDomain pageDomain = new PageDomain();
+        pageDomain.setPageNum(Convert.toInt(ServletUtils.getParameter(PAGE_NUM), 1));
+        pageDomain.setPageSize(Convert.toInt(ServletUtils.getParameter(PAGE_SIZE), 10));
+        pageDomain.setOrderByColumn(ServletUtils.getParameter(ORDER_BY_COLUMN));
+        pageDomain.setIsAsc(ServletUtils.getParameter(IS_ASC));
+        pageDomain.setReasonable(ServletUtils.getParameterToBool(REASONABLE));
+        return pageDomain;
+    }
+
+    public static PageDomain buildPageRequest()
+    {
+        return getPageDomain();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/redis/RedisCache.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/redis/RedisCache.java
index d0a6de49..d12a2923 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/redis/RedisCache.java
@@ -1,268 +1,268 @@
-package com.ruoyi.common.core.redis;
-
-import java.util.Collection;
-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.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、String、实体类等
-     *
-     * @param key 缓存的键值
-     * @param value 缓存的值
-     */
-    public <T> void setCacheObject(final String key, final T value)
-    {
-        redisTemplate.opsForValue().set(key, value);
-    }
-
-    /**
-     * 缓存基本的对象,Integer、String、实体类等
-     *
-     * @param key 缓存的键值
-     * @param value 缓存的值
-     * @param timeout 时间
-     * @param timeUnit 时间颗粒度
-     */
-    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
-    {
-        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
-    }
-
-    /**
-     * 设置有效时间
-     *
-     * @param key Redis键
-     * @param timeout 超时时间
-     * @return true=设置成功;false=设置失败
-     */
-    public boolean expire(final String key, final long timeout)
-    {
-        return expire(key, timeout, TimeUnit.SECONDS);
-    }
-
-    /**
-     * 设置有效时间
-     *
-     * @param key Redis键
-     * @param timeout 超时时间
-     * @param unit 时间单位
-     * @return true=设置成功;false=设置失败
-     */
-    public boolean expire(final String key, final long timeout, final TimeUnit unit)
-    {
-        return redisTemplate.expire(key, timeout, unit);
-    }
-
-    /**
-     * 获取有效时间
-     *
-     * @param key Redis键
-     * @return 有效时间
-     */
-    public long getExpire(final String key)
-    {
-        return redisTemplate.getExpire(key);
-    }
-
-    /**
-     * 判断 key是否存在
-     *
-     * @param key 键
-     * @return true 存在 false不存在
-     */
-    public Boolean hasKey(String key)
-    {
-        return redisTemplate.hasKey(key);
-    }
-
-    /**
-     * 获得缓存的基本对象。
-     *
-     * @param key 缓存键值
-     * @return 缓存键值对应的数据
-     */
-    public <T> T getCacheObject(final String key)
-    {
-        ValueOperations<String, T> operation = redisTemplate.opsForValue();
-        return operation.get(key);
-    }
-
-    /**
-     * 删除单个对象
-     *
-     * @param key
-     */
-    public boolean deleteObject(final String key)
-    {
-        return redisTemplate.delete(key);
-    }
-
-    /**
-     * 删除集合对象
-     *
-     * @param collection 多个对象
-     * @return
-     */
-    public boolean deleteObject(final Collection collection)
-    {
-        return redisTemplate.delete(collection) > 0;
-    }
-
-    /**
-     * 缓存List数据
-     *
-     * @param key 缓存的键值
-     * @param dataList 待缓存的List数据
-     * @return 缓存的对象
-     */
-    public <T> long setCacheList(final String key, final List<T> dataList)
-    {
-        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
-        return count == null ? 0 : count;
-    }
-
-    /**
-     * 获得缓存的list对象
-     *
-     * @param key 缓存的键值
-     * @return 缓存键值对应的数据
-     */
-    public <T> List<T> getCacheList(final String key)
-    {
-        return redisTemplate.opsForList().range(key, 0, -1);
-    }
-
-    /**
-     * 缓存Set
-     *
-     * @param key 缓存键值
-     * @param dataSet 缓存的数据
-     * @return 缓存数据的对象
-     */
-    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
-    {
-        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
-        Iterator<T> it = dataSet.iterator();
-        while (it.hasNext())
-        {
-            setOperation.add(it.next());
-        }
-        return setOperation;
-    }
-
-    /**
-     * 获得缓存的set
-     *
-     * @param key
-     * @return
-     */
-    public <T> Set<T> getCacheSet(final String key)
-    {
-        return redisTemplate.opsForSet().members(key);
-    }
-
-    /**
-     * 缓存Map
-     *
-     * @param key
-     * @param dataMap
-     */
-    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
-    {
-        if (dataMap != null) {
-            redisTemplate.opsForHash().putAll(key, dataMap);
-        }
-    }
-
-    /**
-     * 获得缓存的Map
-     *
-     * @param key
-     * @return
-     */
-    public <T> Map<String, T> getCacheMap(final String key)
-    {
-        return redisTemplate.opsForHash().entries(key);
-    }
-
-    /**
-     * 往Hash中存入数据
-     *
-     * @param key Redis键
-     * @param hKey Hash键
-     * @param value 值
-     */
-    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
-    {
-        redisTemplate.opsForHash().put(key, hKey, value);
-    }
-
-    /**
-     * 获取Hash中的数据
-     *
-     * @param key Redis键
-     * @param hKey Hash键
-     * @return Hash中的对象
-     */
-    public <T> T getCacheMapValue(final String key, final String hKey)
-    {
-        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
-        return opsForHash.get(key, hKey);
-    }
-
-    /**
-     * 获取多个Hash中的数据
-     *
-     * @param key Redis键
-     * @param hKeys Hash键集合
-     * @return Hash对象集合
-     */
-    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
-    {
-        return redisTemplate.opsForHash().multiGet(key, hKeys);
-    }
-
-    /**
-     * 删除Hash中的某条数据
-     *
-     * @param key Redis键
-     * @param hKey Hash键
-     * @return 是否成功
-     */
-    public boolean deleteCacheMapValue(final String key, final String hKey)
-    {
-        return redisTemplate.opsForHash().delete(key, hKey) > 0;
-    }
-
-    /**
-     * 获得缓存的基本对象列表
-     *
-     * @param pattern 字符串前缀
-     * @return 对象列表
-     */
-    public Collection<String> keys(final String pattern)
-    {
-        return redisTemplate.keys(pattern);
-    }
-}
+package com.acupuncture.common.core.redis;
+
+import java.util.Collection;
+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.RedisTemplate;
+import org.springframework.data.redis.core.ValueOperations;
+import org.springframework.stereotype.Component;
+
+/**
+ * spring redis 工具类
+ *
+ * @author acupuncture
+ **/
+@SuppressWarnings(value = { "unchecked", "rawtypes" })
+@Component
+public class RedisCache
+{
+    @Autowired
+    public RedisTemplate redisTemplate;
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     */
+    public <T> void setCacheObject(final String key, final T value)
+    {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缓存基本的对象,Integer、String、实体类等
+     *
+     * @param key 缓存的键值
+     * @param value 缓存的值
+     * @param timeout 时间
+     * @param timeUnit 时间颗粒度
+     */
+    public <T> void setCacheObject(final String key, final T value, final Integer timeout, final TimeUnit timeUnit)
+    {
+        redisTemplate.opsForValue().set(key, value, timeout, timeUnit);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout)
+    {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 设置有效时间
+     *
+     * @param key Redis键
+     * @param timeout 超时时间
+     * @param unit 时间单位
+     * @return true=设置成功;false=设置失败
+     */
+    public boolean expire(final String key, final long timeout, final TimeUnit unit)
+    {
+        return redisTemplate.expire(key, timeout, unit);
+    }
+
+    /**
+     * 获取有效时间
+     *
+     * @param key Redis键
+     * @return 有效时间
+     */
+    public long getExpire(final String key)
+    {
+        return redisTemplate.getExpire(key);
+    }
+
+    /**
+     * 判断 key是否存在
+     *
+     * @param key 键
+     * @return true 存在 false不存在
+     */
+    public Boolean hasKey(String key)
+    {
+        return redisTemplate.hasKey(key);
+    }
+
+    /**
+     * 获得缓存的基本对象。
+     *
+     * @param key 缓存键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> T getCacheObject(final String key)
+    {
+        ValueOperations<String, T> operation = redisTemplate.opsForValue();
+        return operation.get(key);
+    }
+
+    /**
+     * 删除单个对象
+     *
+     * @param key
+     */
+    public boolean deleteObject(final String key)
+    {
+        return redisTemplate.delete(key);
+    }
+
+    /**
+     * 删除集合对象
+     *
+     * @param collection 多个对象
+     * @return
+     */
+    public boolean deleteObject(final Collection collection)
+    {
+        return redisTemplate.delete(collection) > 0;
+    }
+
+    /**
+     * 缓存List数据
+     *
+     * @param key 缓存的键值
+     * @param dataList 待缓存的List数据
+     * @return 缓存的对象
+     */
+    public <T> long setCacheList(final String key, final List<T> dataList)
+    {
+        Long count = redisTemplate.opsForList().rightPushAll(key, dataList);
+        return count == null ? 0 : count;
+    }
+
+    /**
+     * 获得缓存的list对象
+     *
+     * @param key 缓存的键值
+     * @return 缓存键值对应的数据
+     */
+    public <T> List<T> getCacheList(final String key)
+    {
+        return redisTemplate.opsForList().range(key, 0, -1);
+    }
+
+    /**
+     * 缓存Set
+     *
+     * @param key 缓存键值
+     * @param dataSet 缓存的数据
+     * @return 缓存数据的对象
+     */
+    public <T> BoundSetOperations<String, T> setCacheSet(final String key, final Set<T> dataSet)
+    {
+        BoundSetOperations<String, T> setOperation = redisTemplate.boundSetOps(key);
+        Iterator<T> it = dataSet.iterator();
+        while (it.hasNext())
+        {
+            setOperation.add(it.next());
+        }
+        return setOperation;
+    }
+
+    /**
+     * 获得缓存的set
+     *
+     * @param key
+     * @return
+     */
+    public <T> Set<T> getCacheSet(final String key)
+    {
+        return redisTemplate.opsForSet().members(key);
+    }
+
+    /**
+     * 缓存Map
+     *
+     * @param key
+     * @param dataMap
+     */
+    public <T> void setCacheMap(final String key, final Map<String, T> dataMap)
+    {
+        if (dataMap != null) {
+            redisTemplate.opsForHash().putAll(key, dataMap);
+        }
+    }
+
+    /**
+     * 获得缓存的Map
+     *
+     * @param key
+     * @return
+     */
+    public <T> Map<String, T> getCacheMap(final String key)
+    {
+        return redisTemplate.opsForHash().entries(key);
+    }
+
+    /**
+     * 往Hash中存入数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @param value 值
+     */
+    public <T> void setCacheMapValue(final String key, final String hKey, final T value)
+    {
+        redisTemplate.opsForHash().put(key, hKey, value);
+    }
+
+    /**
+     * 获取Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @return Hash中的对象
+     */
+    public <T> T getCacheMapValue(final String key, final String hKey)
+    {
+        HashOperations<String, String, T> opsForHash = redisTemplate.opsForHash();
+        return opsForHash.get(key, hKey);
+    }
+
+    /**
+     * 获取多个Hash中的数据
+     *
+     * @param key Redis键
+     * @param hKeys Hash键集合
+     * @return Hash对象集合
+     */
+    public <T> List<T> getMultiCacheMapValue(final String key, final Collection<Object> hKeys)
+    {
+        return redisTemplate.opsForHash().multiGet(key, hKeys);
+    }
+
+    /**
+     * 删除Hash中的某条数据
+     *
+     * @param key Redis键
+     * @param hKey Hash键
+     * @return 是否成功
+     */
+    public boolean deleteCacheMapValue(final String key, final String hKey)
+    {
+        return redisTemplate.opsForHash().delete(key, hKey) > 0;
+    }
+
+    /**
+     * 获得缓存的基本对象列表
+     *
+     * @param pattern 字符串前缀
+     * @return 对象列表
+     */
+    public Collection<String> keys(final String pattern)
+    {
+        return redisTemplate.keys(pattern);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/CharsetKit.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/text/CharsetKit.java
index 4fa575ce..ce640531 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/CharsetKit.java
@@ -1,86 +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);
-
-    /**
-     * 转换为Charset对象
-     * 
-     * @param charset 字符集,为空则返回默认字符集
-     * @return Charset
-     */
-    public static Charset charset(String charset)
-    {
-        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
-    }
-
-    /**
-     * 转换字符串的字符集编码
-     * 
-     * @param source 字符串
-     * @param srcCharset 源字符集,默认ISO-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 源字符集,默认ISO-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)
-        {
-            destCharset = 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();
-    }
-}
+package com.acupuncture.common.core.text;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 字符集工具类
+ * 
+ * @author acupuncture
+ */
+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);
+
+    /**
+     * 转换为Charset对象
+     * 
+     * @param charset 字符集,为空则返回默认字符集
+     * @return Charset
+     */
+    public static Charset charset(String charset)
+    {
+        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
+    }
+
+    /**
+     * 转换字符串的字符集编码
+     * 
+     * @param source 字符串
+     * @param srcCharset 源字符集,默认ISO-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 源字符集,默认ISO-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)
+        {
+            destCharset = 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-common/src/main/java/com/ruoyi/common/core/text/Convert.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/Convert.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/text/Convert.java
index 938d0c9f..7724c2e2 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/Convert.java
@@ -1,1010 +1,1010 @@
-package com.ruoyi.common.core.text;
-
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.math.RoundingMode;
-import java.nio.ByteBuffer;
-import java.nio.charset.Charset;
-import java.text.NumberFormat;
-import java.util.Set;
-import com.ruoyi.common.utils.StringUtils;
-import org.apache.commons.lang3.ArrayUtils;
-
-/**
- * 类型转换器
- *
- * @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);
-    }
-
-    /**
-     * 转换为byte<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;
-        }
-    }
-
-    /**
-     * 转换为byte<br>
-     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Byte toByte(Object value)
-    {
-        return toByte(value, null);
-    }
-
-    /**
-     * 转换为Short<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;
-        }
-    }
-
-    /**
-     * 转换为Short<br>
-     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Short toShort(Object value)
-    {
-        return toShort(value, null);
-    }
-
-    /**
-     * 转换为Number<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;
-        }
-    }
-
-    /**
-     * 转换为Number<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Number toNumber(Object value)
-    {
-        return toNumber(value, null);
-    }
-
-    /**
-     * 转换为int<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;
-        }
-    }
-
-    /**
-     * 转换为int<br>
-     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Integer toInt(Object value)
-    {
-        return toInt(value, null);
-    }
-
-    /**
-     * 转换为Integer数组<br>
-     *
-     * @param str 被转换的值
-     * @return 结果
-     */
-    public static Integer[] toIntArray(String str)
-    {
-        return toIntArray(",", str);
-    }
-
-    /**
-     * 转换为Long数组<br>
-     *
-     * @param str 被转换的值
-     * @return 结果
-     */
-    public static Long[] toLongArray(String str)
-    {
-        return toLongArray(",", str);
-    }
-
-    /**
-     * 转换为Integer数组<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;
-    }
-
-    /**
-     * 转换为Long数组<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;
-    }
-
-    /**
-     * 转换为String数组<br>
-     *
-     * @param str 被转换的值
-     * @return 结果
-     */
-    public static String[] toStrArray(String str)
-    {
-        if (StringUtils.isEmpty(str))
-        {
-            return new String[] {};
-        }
-        return toStrArray(",", str);
-    }
-
-    /**
-     * 转换为String数组<br>
-     *
-     * @param split 分隔符
-     * @param split 被转换的值
-     * @return 结果
-     */
-    public static String[] toStrArray(String split, String str)
-    {
-        return str.split(split);
-    }
-
-    /**
-     * 转换为long<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;
-        }
-    }
-
-    /**
-     * 转换为long<br>
-     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Long toLong(Object value)
-    {
-        return toLong(value, null);
-    }
-
-    /**
-     * 转换为double<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;
-        }
-    }
-
-    /**
-     * 转换为double<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Double toDouble(Object value)
-    {
-        return toDouble(value, null);
-    }
-
-    /**
-     * 转换为Float<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;
-        }
-    }
-
-    /**
-     * 转换为Float<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Float toFloat(Object value)
-    {
-        return toFloat(value, null);
-    }
-
-    /**
-     * 转换为boolean<br>
-     * String支持的值为:true、false、yes、ok、no,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":
-            case "yes":
-            case "ok":
-            case "1":
-                return true;
-            case "false":
-            case "no":
-            case "0":
-                return false;
-            default:
-                return defaultValue;
-        }
-    }
-
-    /**
-     * 转换为boolean<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static Boolean toBool(Object value)
-    {
-        return toBool(value, null);
-    }
-
-    /**
-     * 转换为Enum对象<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<br>
-     *
-     * @param clazz Enum的Class
-     * @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;
-        }
-    }
-
-    /**
-     * 转换为Enum对象<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     *
-     * @param clazz Enum的Class
-     * @param value 值
-     * @return Enum
-     */
-    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
-    {
-        return toEnum(clazz, value, null);
-    }
-
-    /**
-     * 转换为BigInteger<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;
-        }
-    }
-
-    /**
-     * 转换为BigInteger<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static BigInteger toBigInteger(Object value)
-    {
-        return toBigInteger(value, null);
-    }
-
-    /**
-     * 转换为BigDecimal<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 BigDecimal.valueOf((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;
-        }
-    }
-
-    /**
-     * 转换为BigDecimal<br>
-     * 如果给定的值为空,或者转换失败,返回默认值<br>
-     * 转换失败不会报错
-     *
-     * @param value 被转换的值
-     * @return 结果
-     */
-    public static BigDecimal toBigDecimal(Object value)
-    {
-        return toBigDecimal(value, null);
-    }
-
-    /**
-     * 将对象转为字符串<br>
-     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
-     *
-     * @param obj 对象
-     * @return 字符串
-     */
-    public static String utf8Str(Object obj)
-    {
-        return str(obj, CharsetKit.CHARSET_UTF_8);
-    }
-
-    /**
-     * 将对象转为字符串<br>
-     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
-     *
-     * @param obj 对象
-     * @param charsetName 字符集
-     * @return 字符串
-     */
-    public static String str(Object obj, String charsetName)
-    {
-        return str(obj, Charset.forName(charsetName));
-    }
-
-    /**
-     * 将对象转为字符串<br>
-     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 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[])
-        {
-            return str((byte[]) obj, charset);
-        }
-        else if (obj instanceof Byte[])
-        {
-            byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
-            return str(bytes, charset);
-        }
-        else if (obj instanceof ByteBuffer)
-        {
-            return str((ByteBuffer) obj, charset);
-        }
-        return obj.toString();
-    }
-
-    /**
-     * 将byte数组转为字符串
-     *
-     * @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));
-    }
-
-    /**
-     * 解码字节码
-     *
-     * @param data 字符串
-     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
-     * @return 解码后的字符串
-     */
-    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++)
-        {
-            // 优化double计算精度丢失问题
-            BigDecimal nNum = new BigDecimal(n);
-            BigDecimal decimal = new BigDecimal(10);
-            BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
-            double d = scale.doubleValue();
-            s += (digit[(int) (Math.floor(d * 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("^整$", "零元整");
-    }
-}
+package com.acupuncture.common.core.text;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.math.RoundingMode;
+import java.nio.ByteBuffer;
+import java.nio.charset.Charset;
+import java.text.NumberFormat;
+import java.util.Set;
+import com.acupuncture.common.utils.StringUtils;
+import org.apache.commons.lang3.ArrayUtils;
+
+/**
+ * 类型转换器
+ *
+ * @author acupuncture
+ */
+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);
+    }
+
+    /**
+     * 转换为byte<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;
+        }
+    }
+
+    /**
+     * 转换为byte<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Byte toByte(Object value)
+    {
+        return toByte(value, null);
+    }
+
+    /**
+     * 转换为Short<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;
+        }
+    }
+
+    /**
+     * 转换为Short<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Short toShort(Object value)
+    {
+        return toShort(value, null);
+    }
+
+    /**
+     * 转换为Number<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;
+        }
+    }
+
+    /**
+     * 转换为Number<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Number toNumber(Object value)
+    {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 转换为int<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;
+        }
+    }
+
+    /**
+     * 转换为int<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Integer toInt(Object value)
+    {
+        return toInt(value, null);
+    }
+
+    /**
+     * 转换为Integer数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Integer[] toIntArray(String str)
+    {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 转换为Long数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static Long[] toLongArray(String str)
+    {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 转换为Integer数组<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;
+    }
+
+    /**
+     * 转换为Long数组<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;
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param str 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new String[] {};
+        }
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 转换为String数组<br>
+     *
+     * @param split 分隔符
+     * @param split 被转换的值
+     * @return 结果
+     */
+    public static String[] toStrArray(String split, String str)
+    {
+        return str.split(split);
+    }
+
+    /**
+     * 转换为long<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;
+        }
+    }
+
+    /**
+     * 转换为long<br>
+     * 如果给定的值为<code>null</code>,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Long toLong(Object value)
+    {
+        return toLong(value, null);
+    }
+
+    /**
+     * 转换为double<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;
+        }
+    }
+
+    /**
+     * 转换为double<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Double toDouble(Object value)
+    {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 转换为Float<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;
+        }
+    }
+
+    /**
+     * 转换为Float<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Float toFloat(Object value)
+    {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 转换为boolean<br>
+     * String支持的值为:true、false、yes、ok、no,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":
+            case "yes":
+            case "ok":
+            case "1":
+                return true;
+            case "false":
+            case "no":
+            case "0":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 转换为boolean<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static Boolean toBool(Object value)
+    {
+        return toBool(value, null);
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     *
+     * @param clazz Enum的Class
+     * @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;
+        }
+    }
+
+    /**
+     * 转换为Enum对象<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     *
+     * @param clazz Enum的Class
+     * @param value 值
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
+    {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 转换为BigInteger<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;
+        }
+    }
+
+    /**
+     * 转换为BigInteger<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<code>null</code><br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigInteger toBigInteger(Object value)
+    {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 转换为BigDecimal<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 BigDecimal.valueOf((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;
+        }
+    }
+
+    /**
+     * 转换为BigDecimal<br>
+     * 如果给定的值为空,或者转换失败,返回默认值<br>
+     * 转换失败不会报错
+     *
+     * @param value 被转换的值
+     * @return 结果
+     */
+    public static BigDecimal toBigDecimal(Object value)
+    {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj 对象
+     * @return 字符串
+     */
+    public static String utf8Str(Object obj)
+    {
+        return str(obj, CharsetKit.CHARSET_UTF_8);
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 2、对象数组会调用Arrays.toString方法
+     *
+     * @param obj 对象
+     * @param charsetName 字符集
+     * @return 字符串
+     */
+    public static String str(Object obj, String charsetName)
+    {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 将对象转为字符串<br>
+     * 1、Byte数组和ByteBuffer会被转换为对应字符串的数组 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[])
+        {
+            return str((byte[]) obj, charset);
+        }
+        else if (obj instanceof Byte[])
+        {
+            byte[] bytes = ArrayUtils.toPrimitive((Byte[]) obj);
+            return str(bytes, charset);
+        }
+        else if (obj instanceof ByteBuffer)
+        {
+            return str((ByteBuffer) obj, charset);
+        }
+        return obj.toString();
+    }
+
+    /**
+     * 将byte数组转为字符串
+     *
+     * @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));
+    }
+
+    /**
+     * 解码字节码
+     *
+     * @param data 字符串
+     * @param charset 字符集,如果此字段为空,则解码的结果取决于平台
+     * @return 解码后的字符串
+     */
+    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++)
+        {
+            // 优化double计算精度丢失问题
+            BigDecimal nNum = new BigDecimal(n);
+            BigDecimal decimal = new BigDecimal(10);
+            BigDecimal scale = nNum.multiply(decimal).setScale(2, RoundingMode.HALF_EVEN);
+            double d = scale.doubleValue();
+            s += (digit[(int) (Math.floor(d * 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-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/StrFormatter.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/core/text/StrFormatter.java
index dbf3e237..95654b91 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/core/text/StrFormatter.java
@@ -1,92 +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>
-     * 通常使用:format("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
-                {
-                    // 正常占位符
-                    sbuf.append(strPattern, handledPosition, delimIndex);
-                    sbuf.append(Convert.utf8Str(argArray[argIndex]));
-                    handledPosition = delimIndex + 2;
-                }
-            }
-        }
-        // 加入最后一个占位符后所有的字符
-        sbuf.append(strPattern, handledPosition, strPattern.length());
-
-        return sbuf.toString();
-    }
-}
+package com.acupuncture.common.core.text;
+
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 字符串格式化
+ * 
+ * @author acupuncture
+ */
+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>
+     * 通常使用:format("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
+                {
+                    // 正常占位符
+                    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-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessStatus.java
similarity index 68%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessStatus.java
index 78188fc1..7453bc70 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessStatus.java
@@ -1,20 +1,20 @@
-package com.ruoyi.common.enums;
-
-/**
- * 操作状态
- * 
- * @author ruoyi
- *
- */
-public enum BusinessStatus
-{
-    /**
-     * 成功
-     */
-    SUCCESS,
-
-    /**
-     * 失败
-     */
-    FAIL,
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 操作状态
+ * 
+ * @author acupuncture
+ *
+ */
+public enum BusinessStatus
+{
+    /**
+     * 成功
+     */
+    SUCCESS,
+
+    /**
+     * 失败
+     */
+    FAIL,
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessType.java
similarity index 82%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessType.java
index 2bbeaf7d..5c5ae713 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/BusinessType.java
@@ -1,59 +1,59 @@
-package com.ruoyi.common.enums;
-
-/**
- * 业务操作类型
- * 
- * @author ruoyi
- */
-public enum BusinessType
-{
-    /**
-     * 其它
-     */
-    OTHER,
-
-    /**
-     * 新增
-     */
-    INSERT,
-
-    /**
-     * 修改
-     */
-    UPDATE,
-
-    /**
-     * 删除
-     */
-    DELETE,
-
-    /**
-     * 授权
-     */
-    GRANT,
-
-    /**
-     * 导出
-     */
-    EXPORT,
-
-    /**
-     * 导入
-     */
-    IMPORT,
-
-    /**
-     * 强退
-     */
-    FORCE,
-
-    /**
-     * 生成代码
-     */
-    GENCODE,
-    
-    /**
-     * 清空数据
-     */
-    CLEAN,
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 业务操作类型
+ * 
+ * @author acupuncture
+ */
+public enum BusinessType
+{
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 新增
+     */
+    INSERT,
+
+    /**
+     * 修改
+     */
+    UPDATE,
+
+    /**
+     * 删除
+     */
+    DELETE,
+
+    /**
+     * 授权
+     */
+    GRANT,
+
+    /**
+     * 导出
+     */
+    EXPORT,
+
+    /**
+     * 导入
+     */
+    IMPORT,
+
+    /**
+     * 强退
+     */
+    FORCE,
+
+    /**
+     * 生成代码
+     */
+    GENCODE,
+    
+    /**
+     * 清空数据
+     */
+    CLEAN,
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/DataSourceType.java
similarity index 67%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/DataSourceType.java
index 4b5341d1..dcae4bb8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/DataSourceType.java
@@ -1,19 +1,19 @@
-package com.ruoyi.common.enums;
-
-/**
- * 数据源
- * 
- * @author ruoyi
- */
-public enum DataSourceType
-{
-    /**
-     * 主库
-     */
-    MASTER,
-
-    /**
-     * 从库
-     */
-    SLAVE
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 数据源
+ * 
+ * @author acupuncture
+ */
+public enum DataSourceType
+{
+    /**
+     * 主库
+     */
+    MASTER,
+
+    /**
+     * 从库
+     */
+    SLAVE
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/DesensitizedType.java
similarity index 91%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/DesensitizedType.java
index 07f02eeb..230d592e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/DesensitizedType.java
@@ -1,12 +1,12 @@
-package com.ruoyi.common.enums;
+package com.acupuncture.common.enums;
 
 import java.util.function.Function;
-import com.ruoyi.common.utils.DesensitizedUtil;
+import com.acupuncture.common.utils.DesensitizedUtil;
 
 /**
  * 脱敏类型
  *
- * @author ruoyi
+ * @author acupuncture
  */
 public enum DesensitizedType
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/HttpMethod.java
similarity index 88%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/HttpMethod.java
index 2fa9f867..07267d73 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/HttpMethod.java
@@ -1,36 +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));
-    }
-}
+package com.acupuncture.common.enums;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.lang.Nullable;
+
+/**
+ * 请求方式
+ *
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/LimitType.java
similarity index 71%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/LimitType.java
index ad01659d..28fe866c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/LimitType.java
@@ -1,20 +1,20 @@
-package com.ruoyi.common.enums;
-
-/**
- * 限流类型
- *
- * @author ruoyi
- */
-
-public enum LimitType
-{
-    /**
-     * 默认策略全局限流
-     */
-    DEFAULT,
-
-    /**
-     * 根据请求者IP进行限流
-     */
-    IP
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 限流类型
+ *
+ * @author acupuncture
+ */
+
+public enum LimitType
+{
+    /**
+     * 默认策略全局限流
+     */
+    DEFAULT,
+
+    /**
+     * 根据请求者IP进行限流
+     */
+    IP
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/OperatorType.java
similarity index 73%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/OperatorType.java
index 06532af8..cdbb1de0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/OperatorType.java
@@ -1,24 +1,24 @@
-package com.ruoyi.common.enums;
-
-/**
- * 操作人类别
- * 
- * @author ruoyi
- */
-public enum OperatorType
-{
-    /**
-     * 其它
-     */
-    OTHER,
-
-    /**
-     * 后台用户
-     */
-    MANAGE,
-
-    /**
-     * 手机端用户
-     */
-    MOBILE
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 操作人类别
+ * 
+ * @author acupuncture
+ */
+public enum OperatorType
+{
+    /**
+     * 其它
+     */
+    OTHER,
+
+    /**
+     * 后台用户
+     */
+    MANAGE,
+
+    /**
+     * 手机端用户
+     */
+    MOBILE
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java b/acupuncture-common/src/main/java/com/acupuncture/common/enums/UserStatus.java
similarity index 84%
rename from ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/enums/UserStatus.java
index a4613ff9..c9468192 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/enums/UserStatus.java
@@ -1,30 +1,30 @@
-package com.ruoyi.common.enums;
-
-/**
- * 用户状态
- * 
- * @author ruoyi
- */
-public enum UserStatus
-{
-    OK("0", "正常"), 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;
-    }
-}
+package com.acupuncture.common.enums;
+
+/**
+ * 用户状态
+ * 
+ * @author acupuncture
+ */
+public enum UserStatus
+{
+    OK("0", "正常"), 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-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/DemoModeException.java
similarity index 73%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/DemoModeException.java
index 57bffc47..97ff8dbc 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/DemoModeException.java
@@ -1,15 +1,15 @@
-package com.ruoyi.common.exception;
-
-/**
- * 演示模式异常
- * 
- * @author ruoyi
- */
-public class DemoModeException extends RuntimeException
-{
-    private static final long serialVersionUID = 1L;
-
-    public DemoModeException()
-    {
-    }
-}
+package com.acupuncture.common.exception;
+
+/**
+ * 演示模式异常
+ * 
+ * @author acupuncture
+ */
+public class DemoModeException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    public DemoModeException()
+    {
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/GlobalException.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/GlobalException.java
index 9f0dec4a..9385d554 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/GlobalException.java
@@ -1,58 +1,58 @@
-package com.ruoyi.common.exception;
-
-/**
- * 全局异常
- * 
- * @author ruoyi
- */
-public class GlobalException extends RuntimeException
-{
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 错误提示
-     */
-    private String message;
-
-    /**
-     * 错误明细,内部调试错误
-     *
-     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
-     */
-    private String detailMessage;
-
-    /**
-     * 空构造方法,避免反序列化问题
-     */
-    public GlobalException()
-    {
-    }
-
-    public GlobalException(String message)
-    {
-        this.message = message;
-    }
-
-    public String getDetailMessage()
-    {
-        return detailMessage;
-    }
-
-    public GlobalException setDetailMessage(String detailMessage)
-    {
-        this.detailMessage = detailMessage;
-        return this;
-    }
-
-    @Override
-    public String getMessage()
-    {
-        return message;
-    }
-
-    public GlobalException setMessage(String message)
-    {
-        this.message = message;
-        return this;
-    }
+package com.acupuncture.common.exception;
+
+/**
+ * 全局异常
+ * 
+ * @author acupuncture
+ */
+public class GlobalException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 错误明细,内部调试错误
+     *
+     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
+     */
+    private String detailMessage;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public GlobalException()
+    {
+    }
+
+    public GlobalException(String message)
+    {
+        this.message = message;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    public GlobalException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public GlobalException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/ServiceException.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/ServiceException.java
index a9247b57..ec8e6563 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/ServiceException.java
@@ -1,74 +1,74 @@
-package com.ruoyi.common.exception;
-
-/**
- * 业务异常
- * 
- * @author ruoyi
- */
-public final class ServiceException extends RuntimeException
-{
-    private static final long serialVersionUID = 1L;
-
-    /**
-     * 错误码
-     */
-    private Integer code;
-
-    /**
-     * 错误提示
-     */
-    private String message;
-
-    /**
-     * 错误明细,内部调试错误
-     *
-     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
-     */
-    private String detailMessage;
-
-    /**
-     * 空构造方法,避免反序列化问题
-     */
-    public ServiceException()
-    {
-    }
-
-    public ServiceException(String message)
-    {
-        this.message = message;
-    }
-
-    public ServiceException(String message, Integer code)
-    {
-        this.message = message;
-        this.code = code;
-    }
-
-    public String getDetailMessage()
-    {
-        return detailMessage;
-    }
-
-    @Override
-    public String getMessage()
-    {
-        return message;
-    }
-
-    public Integer getCode()
-    {
-        return code;
-    }
-
-    public ServiceException setMessage(String message)
-    {
-        this.message = message;
-        return this;
-    }
-
-    public ServiceException setDetailMessage(String detailMessage)
-    {
-        this.detailMessage = detailMessage;
-        return this;
-    }
+package com.acupuncture.common.exception;
+
+/**
+ * 业务异常
+ * 
+ * @author acupuncture
+ */
+public final class ServiceException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误码
+     */
+    private Integer code;
+
+    /**
+     * 错误提示
+     */
+    private String message;
+
+    /**
+     * 错误明细,内部调试错误
+     *
+     * 和 {@link CommonResult#getDetailMessage()} 一致的设计
+     */
+    private String detailMessage;
+
+    /**
+     * 空构造方法,避免反序列化问题
+     */
+    public ServiceException()
+    {
+    }
+
+    public ServiceException(String message)
+    {
+        this.message = message;
+    }
+
+    public ServiceException(String message, Integer code)
+    {
+        this.message = message;
+        this.code = code;
+    }
+
+    public String getDetailMessage()
+    {
+        return detailMessage;
+    }
+
+    @Override
+    public String getMessage()
+    {
+        return message;
+    }
+
+    public Integer getCode()
+    {
+        return code;
+    }
+
+    public ServiceException setMessage(String message)
+    {
+        this.message = message;
+        return this;
+    }
+
+    public ServiceException setDetailMessage(String detailMessage)
+    {
+        this.detailMessage = detailMessage;
+        return this;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/UtilException.java
similarity index 84%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/UtilException.java
index a544fb64..b189de37 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/UtilException.java
@@ -1,26 +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);
-    }
-}
+package com.acupuncture.common.exception;
+
+/**
+ * 工具类异常
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/base/BaseException.java
similarity index 87%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/base/BaseException.java
index 3dd2c1ee..5c747b17 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/base/BaseException.java
@@ -1,97 +1,97 @@
-package com.ruoyi.common.exception.base;
-
-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;
-    }
-}
+package com.acupuncture.common.exception.base;
+
+import com.acupuncture.common.utils.MessageUtils;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 基础异常
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/file/FileException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileException.java
similarity index 65%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileException.java
index ed14af12..d1c1bc44 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileException.java
@@ -1,19 +1,19 @@
-package com.ruoyi.common.exception.file;
-
-import com.ruoyi.common.exception.base.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);
-    }
-
-}
+package com.acupuncture.common.exception.file;
+
+import com.acupuncture.common.exception.base.BaseException;
+
+/**
+ * 文件信息异常类
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileNameLengthLimitExceededException.java
similarity index 82%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileNameLengthLimitExceededException.java
index 44941b8b..f84efb10 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileNameLengthLimitExceededException.java
@@ -1,16 +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 });
-    }
-}
+package com.acupuncture.common.exception.file;
+
+/**
+ * 文件名称超长限制异常类
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileSizeLimitExceededException.java
similarity index 81%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileSizeLimitExceededException.java
index f855e72f..0c9d6916 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileSizeLimitExceededException.java
@@ -1,16 +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 });
-    }
-}
+package com.acupuncture.common.exception.file;
+
+/**
+ * 文件名大小限制异常类
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileUploadException.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileUploadException.java
index f45e7ef4..96927ea5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/FileUploadException.java
@@ -1,4 +1,4 @@
-package com.ruoyi.common.exception.file;
+package com.acupuncture.common.exception.file;
 
 import java.io.PrintStream;
 import java.io.PrintWriter;
@@ -6,7 +6,7 @@ import java.io.PrintWriter;
 /**
  * 文件上传异常类
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class FileUploadException extends Exception
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/InvalidExtensionException.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/file/InvalidExtensionException.java
index f3e9c331..fa010d01 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/file/InvalidExtensionException.java
@@ -1,80 +1,80 @@
-package com.ruoyi.common.exception.file;
-
-import java.util.Arrays;
-
-/**
- * 文件上传 误异常类
- * 
- * @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 + "]后缀[" + 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);
-        }
-    }
-
-    public static class InvalidVideoExtensionException extends InvalidExtensionException
-    {
-        private static final long serialVersionUID = 1L;
-
-        public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
-        {
-            super(allowedExtension, extension, filename);
-        }
-    }
-}
+package com.acupuncture.common.exception.file;
+
+import java.util.Arrays;
+
+/**
+ * 文件上传 误异常类
+ * 
+ * @author acupuncture
+ */
+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 + "]后缀[" + 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);
+        }
+    }
+
+    public static class InvalidVideoExtensionException extends InvalidExtensionException
+    {
+        private static final long serialVersionUID = 1L;
+
+        public InvalidVideoExtensionException(String[] allowedExtension, String extension, String filename)
+        {
+            super(allowedExtension, extension, filename);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/job/TaskException.java
similarity index 86%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/job/TaskException.java
index 14b2361d..5a1f2cc3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/job/TaskException.java
@@ -1,34 +1,34 @@
-package com.ruoyi.common.exception.job;
-
-/**
- * 计划策略异常
- * 
- * @author ruoyi
- */
-public class TaskException extends Exception
-{
-    private static final long serialVersionUID = 1L;
-
-    private Code code;
-
-    public TaskException(String msg, Code code)
-    {
-        this(msg, code, null);
-    }
-
-    public TaskException(String msg, Code code, Exception nestedEx)
-    {
-        super(msg, nestedEx);
-        this.code = code;
-    }
-
-    public Code getCode()
-    {
-        return code;
-    }
-
-    public enum Code
-    {
-        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
-    }
+package com.acupuncture.common.exception.job;
+
+/**
+ * 计划策略异常
+ * 
+ * @author acupuncture
+ */
+public class TaskException extends Exception
+{
+    private static final long serialVersionUID = 1L;
+
+    private Code code;
+
+    public TaskException(String msg, Code code)
+    {
+        this(msg, code, null);
+    }
+
+    public TaskException(String msg, Code code, Exception nestedEx)
+    {
+        super(msg, nestedEx);
+        this.code = code;
+    }
+
+    public Code getCode()
+    {
+        return code;
+    }
+
+    public enum Code
+    {
+        TASK_EXISTS, NO_TASK_EXISTS, TASK_ALREADY_STARTED, UNKNOWN, CONFIG_ERROR, TASK_NODE_NOT_AVAILABLE
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/BlackListException.java
similarity index 76%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/BlackListException.java
index 2bf50386..70ee9f54 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/BlackListException.java
@@ -1,9 +1,9 @@
-package com.ruoyi.common.exception.user;
+package com.acupuncture.common.exception.user;
 
 /**
  * 黑名单IP异常类
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class BlackListException extends UserException
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaException.java
similarity index 76%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaException.java
index e3334ae3..eaf2f162 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaException.java
@@ -1,16 +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);
-    }
-}
+package com.acupuncture.common.exception.user;
+
+/**
+ * 验证码错误异常类
+ * 
+ * @author acupuncture
+ */
+public class CaptchaException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaException()
+    {
+        super("user.jcaptcha.error", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaExpireException.java
similarity index 77%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaExpireException.java
index 5e6fd0f7..4d6ac371 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/CaptchaExpireException.java
@@ -1,16 +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);
-    }
-}
+package com.acupuncture.common.exception.user;
+
+/**
+ * 验证码失效异常类
+ * 
+ * @author acupuncture
+ */
+public class CaptchaExpireException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaExpireException()
+    {
+        super("user.jcaptcha.expire", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserException.java
similarity index 65%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserException.java
index 79160d86..b4cf60c1 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserException.java
@@ -1,18 +1,18 @@
-package com.ruoyi.common.exception.user;
-
-import com.ruoyi.common.exception.base.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);
-    }
-}
+package com.acupuncture.common.exception.user;
+
+import com.acupuncture.common.exception.base.BaseException;
+
+/**
+ * 用户信息异常类
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserNotExistsException.java
similarity index 77%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserNotExistsException.java
index eff81812..3ad9965d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserNotExistsException.java
@@ -1,9 +1,9 @@
-package com.ruoyi.common.exception.user;
+package com.acupuncture.common.exception.user;
 
 /**
  * 用户不存在异常类
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class UserNotExistsException extends UserException
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordNotMatchException.java
similarity index 79%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordNotMatchException.java
index 71449e29..b01ba7eb 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordNotMatchException.java
@@ -1,16 +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);
-    }
-}
+package com.acupuncture.common.exception.user;
+
+/**
+ * 用户密码不正确或不符合规范异常类
+ * 
+ * @author acupuncture
+ */
+public class UserPasswordNotMatchException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserPasswordNotMatchException()
+    {
+        super("user.password.not.match", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordRetryLimitExceedException.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordRetryLimitExceedException.java
index 0de8d240..ce61f76f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/exception/user/UserPasswordRetryLimitExceedException.java
@@ -1,16 +1,16 @@
-package com.ruoyi.common.exception.user;
-
-/**
- * 用户错误最大次数异常类
- * 
- * @author ruoyi
- */
-public class UserPasswordRetryLimitExceedException extends UserException
-{
-    private static final long serialVersionUID = 1L;
-
-    public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
-    {
-        super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime });
-    }
-}
+package com.acupuncture.common.exception.user;
+
+/**
+ * 用户错误最大次数异常类
+ * 
+ * @author acupuncture
+ */
+public class UserPasswordRetryLimitExceedException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserPasswordRetryLimitExceedException(int retryLimitCount, int lockTime)
+    {
+        super("user.password.retry.limit.exceed", new Object[] { retryLimitCount, lockTime });
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java b/acupuncture-common/src/main/java/com/acupuncture/common/filter/PropertyPreExcludeFilter.java
similarity index 85%
rename from ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/filter/PropertyPreExcludeFilter.java
index 4cde4a91..87d58880 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/filter/PropertyPreExcludeFilter.java
@@ -1,24 +1,24 @@
-package com.ruoyi.common.filter;
-
-import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
-
-/**
- * 排除JSON敏感属性
- * 
- * @author ruoyi
- */
-public class PropertyPreExcludeFilter extends SimplePropertyPreFilter
-{
-    public PropertyPreExcludeFilter()
-    {
-    }
-
-    public PropertyPreExcludeFilter addExcludes(String... filters)
-    {
-        for (int i = 0; i < filters.length; i++)
-        {
-            this.getExcludes().add(filters[i]);
-        }
-        return this;
-    }
-}
+package com.acupuncture.common.filter;
+
+import com.alibaba.fastjson2.filter.SimplePropertyPreFilter;
+
+/**
+ * 排除JSON敏感属性
+ * 
+ * @author acupuncture
+ */
+public class PropertyPreExcludeFilter extends SimplePropertyPreFilter
+{
+    public PropertyPreExcludeFilter()
+    {
+    }
+
+    public PropertyPreExcludeFilter addExcludes(String... filters)
+    {
+        for (int i = 0; i < filters.length; i++)
+        {
+            this.getExcludes().add(filters[i]);
+        }
+        return this;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatableFilter.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatableFilter.java
index 3946d48d..998d4dd9 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatableFilter.java
@@ -1,52 +1,52 @@
-package com.ruoyi.common.filter;
-
-import java.io.IOException;
-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 org.springframework.http.MediaType;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * Repeatable 过滤器
- * 
- * @author ruoyi
- */
-public class RepeatableFilter implements Filter
-{
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-
-    }
-
-    @Override
-    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
-            throws IOException, ServletException
-    {
-        ServletRequest requestWrapper = null;
-        if (request instanceof HttpServletRequest
-                && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
-        {
-            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
-        }
-        if (null == requestWrapper)
-        {
-            chain.doFilter(request, response);
-        }
-        else
-        {
-            chain.doFilter(requestWrapper, response);
-        }
-    }
-
-    @Override
-    public void destroy()
-    {
-
-    }
-}
+package com.acupuncture.common.filter;
+
+import java.io.IOException;
+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 org.springframework.http.MediaType;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * Repeatable 过滤器
+ * 
+ * @author acupuncture
+ */
+public class RepeatableFilter implements Filter
+{
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+
+    }
+
+    @Override
+    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+            throws IOException, ServletException
+    {
+        ServletRequest requestWrapper = null;
+        if (request instanceof HttpServletRequest
+                && StringUtils.startsWithIgnoreCase(request.getContentType(), MediaType.APPLICATION_JSON_VALUE))
+        {
+            requestWrapper = new RepeatedlyRequestWrapper((HttpServletRequest) request, response);
+        }
+        if (null == requestWrapper)
+        {
+            chain.doFilter(request, response);
+        }
+        else
+        {
+            chain.doFilter(requestWrapper, response);
+        }
+    }
+
+    @Override
+    public void destroy()
+    {
+
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java b/acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatedlyRequestWrapper.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatedlyRequestWrapper.java
index ca822ede..bacc29ed 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/filter/RepeatedlyRequestWrapper.java
@@ -1,76 +1,76 @@
-package com.ruoyi.common.filter;
-
-import java.io.BufferedReader;
-import java.io.ByteArrayInputStream;
-import java.io.IOException;
-import java.io.InputStreamReader;
-import javax.servlet.ReadListener;
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletResponse;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletRequestWrapper;
-import com.ruoyi.common.utils.http.HttpHelper;
-import com.ruoyi.common.constant.Constants;
-
-/**
- * 构建可重复读取inputStream的request
- * 
- * @author ruoyi
- */
-public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
-{
-    private final byte[] body;
-
-    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
-    {
-        super(request);
-        request.setCharacterEncoding(Constants.UTF8);
-        response.setCharacterEncoding(Constants.UTF8);
-
-        body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8);
-    }
-
-    @Override
-    public BufferedReader getReader() throws IOException
-    {
-        return new BufferedReader(new InputStreamReader(getInputStream()));
-    }
-
-    @Override
-    public ServletInputStream getInputStream() throws IOException
-    {
-        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
-        return new ServletInputStream()
-        {
-            @Override
-            public int read() throws IOException
-            {
-                return bais.read();
-            }
-
-            @Override
-            public int available() throws IOException
-            {
-                return body.length;
-            }
-
-            @Override
-            public boolean isFinished()
-            {
-                return false;
-            }
-
-            @Override
-            public boolean isReady()
-            {
-                return false;
-            }
-
-            @Override
-            public void setReadListener(ReadListener readListener)
-            {
-
-            }
-        };
-    }
-}
+package com.acupuncture.common.filter;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import javax.servlet.ReadListener;
+import javax.servlet.ServletInputStream;
+import javax.servlet.ServletResponse;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletRequestWrapper;
+import com.acupuncture.common.utils.http.HttpHelper;
+import com.acupuncture.common.constant.Constants;
+
+/**
+ * 构建可重复读取inputStream的request
+ * 
+ * @author acupuncture
+ */
+public class RepeatedlyRequestWrapper extends HttpServletRequestWrapper
+{
+    private final byte[] body;
+
+    public RepeatedlyRequestWrapper(HttpServletRequest request, ServletResponse response) throws IOException
+    {
+        super(request);
+        request.setCharacterEncoding(Constants.UTF8);
+        response.setCharacterEncoding(Constants.UTF8);
+
+        body = HttpHelper.getBodyString(request).getBytes(Constants.UTF8);
+    }
+
+    @Override
+    public BufferedReader getReader() throws IOException
+    {
+        return new BufferedReader(new InputStreamReader(getInputStream()));
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+        final ByteArrayInputStream bais = new ByteArrayInputStream(body);
+        return new ServletInputStream()
+        {
+            @Override
+            public int read() throws IOException
+            {
+                return bais.read();
+            }
+
+            @Override
+            public int available() throws IOException
+            {
+                return body.length;
+            }
+
+            @Override
+            public boolean isFinished()
+            {
+                return false;
+            }
+
+            @Override
+            public boolean isReady()
+            {
+                return false;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener)
+            {
+
+            }
+        };
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java b/acupuncture-common/src/main/java/com/acupuncture/common/filter/XssFilter.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/filter/XssFilter.java
index b4eaabcb..144d1291 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/filter/XssFilter.java
@@ -1,75 +1,75 @@
-package com.ruoyi.common.filter;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
-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;
-import com.ruoyi.common.enums.HttpMethod;
-
-/**
- * 防止XSS攻击的过滤器
- * 
- * @author ruoyi
- */
-public class XssFilter implements Filter
-{
-    /**
-     * 排除链接
-     */
-    public List<String> excludes = new ArrayList<>();
-
-    @Override
-    public void init(FilterConfig filterConfig) throws ServletException
-    {
-        String tempExcludes = filterConfig.getInitParameter("excludes");
-        if (StringUtils.isNotEmpty(tempExcludes))
-        {
-            String[] urls = tempExcludes.split(",");
-            for (String url : urls)
-            {
-                excludes.add(url);
-            }
-        }
-    }
-
-    @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)
-    {
-        String url = request.getServletPath();
-        String method = request.getMethod();
-        // GET DELETE 不过滤
-        if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method))
-        {
-            return true;
-        }
-        return StringUtils.matches(url, excludes);
-    }
-
-    @Override
-    public void destroy()
-    {
-
-    }
+package com.acupuncture.common.filter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+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.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.enums.HttpMethod;
+
+/**
+ * 防止XSS攻击的过滤器
+ * 
+ * @author acupuncture
+ */
+public class XssFilter implements Filter
+{
+    /**
+     * 排除链接
+     */
+    public List<String> excludes = new ArrayList<>();
+
+    @Override
+    public void init(FilterConfig filterConfig) throws ServletException
+    {
+        String tempExcludes = filterConfig.getInitParameter("excludes");
+        if (StringUtils.isNotEmpty(tempExcludes))
+        {
+            String[] urls = tempExcludes.split(",");
+            for (String url : urls)
+            {
+                excludes.add(url);
+            }
+        }
+    }
+
+    @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)
+    {
+        String url = request.getServletPath();
+        String method = request.getMethod();
+        // GET DELETE 不过滤
+        if (method == null || HttpMethod.GET.matches(method) || HttpMethod.DELETE.matches(method))
+        {
+            return true;
+        }
+        return StringUtils.matches(url, excludes);
+    }
+
+    @Override
+    public void destroy()
+    {
+
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java b/acupuncture-common/src/main/java/com/acupuncture/common/filter/XssHttpServletRequestWrapper.java
similarity index 91%
rename from ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/filter/XssHttpServletRequestWrapper.java
index e0cc40a8..0a3e241e 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/filter/XssHttpServletRequestWrapper.java
@@ -1,111 +1,111 @@
-package com.ruoyi.common.filter;
-
-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[] escapesValues = new String[length];
-            for (int i = 0; i < length; i++)
-            {
-                // 防xss攻击和过滤前后空格
-                escapesValues[i] = EscapeUtil.clean(values[i]).trim();
-            }
-            return escapesValues;
-        }
-        return super.getParameterValues(name);
-    }
-
-    @Override
-    public ServletInputStream getInputStream() throws IOException
-    {
-        // 非json类型,直接返回
-        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();
-        byte[] jsonBytes = json.getBytes("utf-8");
-        final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
-        return new ServletInputStream()
-        {
-            @Override
-            public boolean isFinished()
-            {
-                return true;
-            }
-
-            @Override
-            public boolean isReady()
-            {
-                return true;
-            }
-
-            @Override
-            public int available() throws IOException
-            {
-                return jsonBytes.length;
-            }
-
-            @Override
-            public void setReadListener(ReadListener readListener)
-            {
-            }
-
-            @Override
-            public int read() throws IOException
-            {
-                return bis.read();
-            }
-        };
-    }
-
-    /**
-     * 是否是Json请求
-     * 
-     * @param request
-     */
-    public boolean isJsonRequest()
-    {
-        String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
-        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
-    }
+package com.acupuncture.common.filter;
+
+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.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.html.EscapeUtil;
+
+/**
+ * XSS过滤处理
+ * 
+ * @author acupuncture
+ */
+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[] escapesValues = new String[length];
+            for (int i = 0; i < length; i++)
+            {
+                // 防xss攻击和过滤前后空格
+                escapesValues[i] = EscapeUtil.clean(values[i]).trim();
+            }
+            return escapesValues;
+        }
+        return super.getParameterValues(name);
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+        // 非json类型,直接返回
+        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();
+        byte[] jsonBytes = json.getBytes("utf-8");
+        final ByteArrayInputStream bis = new ByteArrayInputStream(jsonBytes);
+        return new ServletInputStream()
+        {
+            @Override
+            public boolean isFinished()
+            {
+                return true;
+            }
+
+            @Override
+            public boolean isReady()
+            {
+                return true;
+            }
+
+            @Override
+            public int available() throws IOException
+            {
+                return jsonBytes.length;
+            }
+
+            @Override
+            public void setReadListener(ReadListener readListener)
+            {
+            }
+
+            @Override
+            public int read() throws IOException
+            {
+                return bis.read();
+            }
+        };
+    }
+
+    /**
+     * 是否是Json请求
+     * 
+     * @param request
+     */
+    public boolean isJsonRequest()
+    {
+        String header = super.getHeader(HttpHeaders.CONTENT_TYPE);
+        return StringUtils.startsWithIgnoreCase(header, MediaType.APPLICATION_JSON_VALUE);
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/Arith.java
similarity index 98%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/Arith.java
index b6326c2b..c1f8a078 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/Arith.java
@@ -1,4 +1,4 @@
-package com.ruoyi.common.utils;
+package com.acupuncture.common.utils;
 
 import java.math.BigDecimal;
 import java.math.RoundingMode;
@@ -6,7 +6,7 @@ import java.math.RoundingMode;
 /**
  * 精确的浮点数运算
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class Arith
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DateUtils.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/DateUtils.java
index 20dbbb74..73784cf1 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DateUtils.java
@@ -1,191 +1,191 @@
-package com.ruoyi.common.utils;
-
-import java.lang.management.ManagementFactory;
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.time.LocalTime;
-import java.time.ZoneId;
-import java.time.ZonedDateTime;
-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();
-    }
-
-    /**
-     * 获取当前日期, 默认格式为yyyy-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 int differentDaysByMillisecond(Date date1, Date date2)
-    {
-        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
-    }
-
-    /**
-     * 计算时间差
-     *
-     * @param endDate 最后时间
-     * @param startTime 开始时间
-     * @return 时间差(天/小时/分钟)
-     */
-    public static String timeDistance(Date endDate, Date startTime)
-    {
-        long nd = 1000 * 24 * 60 * 60;
-        long nh = 1000 * 60 * 60;
-        long nm = 1000 * 60;
-        // long ns = 1000;
-        // 获得两个时间的毫秒时间差异
-        long diff = endDate.getTime() - startTime.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 + "分钟";
-    }
-
-    /**
-     * 增加 LocalDateTime ==> Date
-     */
-    public static Date toDate(LocalDateTime temporalAccessor)
-    {
-        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
-        return Date.from(zdt.toInstant());
-    }
-
-    /**
-     * 增加 LocalDate ==> Date
-     */
-    public static Date toDate(LocalDate temporalAccessor)
-    {
-        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
-        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
-        return Date.from(zdt.toInstant());
-    }
-}
+package com.acupuncture.common.utils;
+
+import java.lang.management.ManagementFactory;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.LocalTime;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.util.Date;
+import org.apache.commons.lang3.time.DateFormatUtils;
+
+/**
+ * 时间工具类
+ * 
+ * @author acupuncture
+ */
+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();
+    }
+
+    /**
+     * 获取当前日期, 默认格式为yyyy-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 int differentDaysByMillisecond(Date date1, Date date2)
+    {
+        return Math.abs((int) ((date2.getTime() - date1.getTime()) / (1000 * 3600 * 24)));
+    }
+
+    /**
+     * 计算时间差
+     *
+     * @param endDate 最后时间
+     * @param startTime 开始时间
+     * @return 时间差(天/小时/分钟)
+     */
+    public static String timeDistance(Date endDate, Date startTime)
+    {
+        long nd = 1000 * 24 * 60 * 60;
+        long nh = 1000 * 60 * 60;
+        long nm = 1000 * 60;
+        // long ns = 1000;
+        // 获得两个时间的毫秒时间差异
+        long diff = endDate.getTime() - startTime.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 + "分钟";
+    }
+
+    /**
+     * 增加 LocalDateTime ==> Date
+     */
+    public static Date toDate(LocalDateTime temporalAccessor)
+    {
+        ZonedDateTime zdt = temporalAccessor.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+
+    /**
+     * 增加 LocalDate ==> Date
+     */
+    public static Date toDate(LocalDate temporalAccessor)
+    {
+        LocalDateTime localDateTime = LocalDateTime.of(temporalAccessor, LocalTime.of(0, 0, 0));
+        ZonedDateTime zdt = localDateTime.atZone(ZoneId.systemDefault());
+        return Date.from(zdt.toInstant());
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DesensitizedUtil.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/DesensitizedUtil.java
index f8a4c022..36ae6404 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DesensitizedUtil.java
@@ -1,9 +1,9 @@
-package com.ruoyi.common.utils;
+package com.acupuncture.common.utils;
 
 /**
  * 脱敏工具类
  *
- * @author ruoyi
+ * @author acupuncture
  */
 public class DesensitizedUtil
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DictUtils.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/DictUtils.java
index 8204f133..c9b58538 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/DictUtils.java
@@ -1,239 +1,239 @@
-package com.ruoyi.common.utils;
-
-import java.util.Collection;
-import java.util.List;
-import com.alibaba.fastjson2.JSONArray;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.utils.spring.SpringUtils;
-
-/**
- * 字典工具类
- * 
- * @author ruoyi
- */
-public class DictUtils
-{
-    /**
-     * 分隔符
-     */
-    public static final String SEPARATOR = ",";
-
-    /**
-     * 设置字典缓存
-     * 
-     * @param key 参数键
-     * @param dictDatas 字典数据列表
-     */
-    public static void setDictCache(String key, List<SysDictData> dictDatas)
-    {
-        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
-    }
-
-    /**
-     * 获取字典缓存
-     * 
-     * @param key 参数键
-     * @return dictDatas 字典数据列表
-     */
-    public static List<SysDictData> getDictCache(String key)
-    {
-        JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
-        if (StringUtils.isNotNull(arrayCache))
-        {
-            return arrayCache.toList(SysDictData.class);
-        }
-        return null;
-    }
-
-    /**
-     * 根据字典类型和字典值获取字典标签
-     * 
-     * @param dictType 字典类型
-     * @param dictValue 字典值
-     * @return 字典标签
-     */
-    public static String getDictLabel(String dictType, String dictValue)
-    {
-        if (StringUtils.isEmpty(dictValue))
-        {
-            return StringUtils.EMPTY;
-        }
-        return getDictLabel(dictType, dictValue, SEPARATOR);
-    }
-
-    /**
-     * 根据字典类型和字典标签获取字典值
-     * 
-     * @param dictType 字典类型
-     * @param dictLabel 字典标签
-     * @return 字典值
-     */
-    public static String getDictValue(String dictType, String dictLabel)
-    {
-        if (StringUtils.isEmpty(dictLabel))
-        {
-            return StringUtils.EMPTY;
-        }
-        return getDictValue(dictType, dictLabel, SEPARATOR);
-    }
-
-    /**
-     * 根据字典类型和字典值获取字典标签
-     * 
-     * @param dictType 字典类型
-     * @param dictValue 字典值
-     * @param separator 分隔符
-     * @return 字典标签
-     */
-    public static String getDictLabel(String dictType, String dictValue, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-        if (StringUtils.isNull(datas))
-        {
-            return StringUtils.EMPTY;
-        }
-        if (StringUtils.containsAny(separator, dictValue))
-        {
-            for (SysDictData dict : datas)
-            {
-                for (String value : dictValue.split(separator))
-                {
-                    if (value.equals(dict.getDictValue()))
-                    {
-                        propertyString.append(dict.getDictLabel()).append(separator);
-                        break;
-                    }
-                }
-            }
-        }
-        else
-        {
-            for (SysDictData dict : datas)
-            {
-                if (dictValue.equals(dict.getDictValue()))
-                {
-                    return dict.getDictLabel();
-                }
-            }
-        }
-        return StringUtils.stripEnd(propertyString.toString(), separator);
-    }
-
-    /**
-     * 根据字典类型和字典标签获取字典值
-     * 
-     * @param dictType 字典类型
-     * @param dictLabel 字典标签
-     * @param separator 分隔符
-     * @return 字典值
-     */
-    public static String getDictValue(String dictType, String dictLabel, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-        if (StringUtils.isNull(datas))
-        {
-            return StringUtils.EMPTY;
-        }
-        if (StringUtils.containsAny(separator, dictLabel))
-        {
-            for (SysDictData dict : datas)
-            {
-                for (String label : dictLabel.split(separator))
-                {
-                    if (label.equals(dict.getDictLabel()))
-                    {
-                        propertyString.append(dict.getDictValue()).append(separator);
-                        break;
-                    }
-                }
-            }
-        }
-        else
-        {
-            for (SysDictData dict : datas)
-            {
-                if (dictLabel.equals(dict.getDictLabel()))
-                {
-                    return dict.getDictValue();
-                }
-            }
-        }
-        return StringUtils.stripEnd(propertyString.toString(), separator);
-    }
-
-    /**
-     * 根据字典类型获取字典所有值
-     *
-     * @param dictType 字典类型
-     * @return 字典值
-     */
-    public static String getDictValues(String dictType)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-        if (StringUtils.isNull(datas))
-        {
-            return StringUtils.EMPTY;
-        }
-        for (SysDictData dict : datas)
-        {
-            propertyString.append(dict.getDictValue()).append(SEPARATOR);
-        }
-        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
-    }
-
-    /**
-     * 根据字典类型获取字典所有标签
-     *
-     * @param dictType 字典类型
-     * @return 字典值
-     */
-    public static String getDictLabels(String dictType)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        List<SysDictData> datas = getDictCache(dictType);
-        if (StringUtils.isNull(datas))
-        {
-            return StringUtils.EMPTY;
-        }
-        for (SysDictData dict : datas)
-        {
-            propertyString.append(dict.getDictLabel()).append(SEPARATOR);
-        }
-        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
-    }
-
-    /**
-     * 删除指定字典缓存
-     * 
-     * @param key 字典键
-     */
-    public static void removeDictCache(String key)
-    {
-        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
-    }
-
-    /**
-     * 清空字典缓存
-     */
-    public static void clearDictCache()
-    {
-        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
-        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
-    }
-
-    /**
-     * 设置cache key
-     * 
-     * @param configKey 参数键
-     * @return 缓存键key
-     */
-    public static String getCacheKey(String configKey)
-    {
-        return CacheConstants.SYS_DICT_KEY + configKey;
-    }
-}
+package com.acupuncture.common.utils;
+
+import java.util.Collection;
+import java.util.List;
+import com.alibaba.fastjson2.JSONArray;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.utils.spring.SpringUtils;
+
+/**
+ * 字典工具类
+ * 
+ * @author acupuncture
+ */
+public class DictUtils
+{
+    /**
+     * 分隔符
+     */
+    public static final String SEPARATOR = ",";
+
+    /**
+     * 设置字典缓存
+     * 
+     * @param key 参数键
+     * @param dictDatas 字典数据列表
+     */
+    public static void setDictCache(String key, List<SysDictData> dictDatas)
+    {
+        SpringUtils.getBean(RedisCache.class).setCacheObject(getCacheKey(key), dictDatas);
+    }
+
+    /**
+     * 获取字典缓存
+     * 
+     * @param key 参数键
+     * @return dictDatas 字典数据列表
+     */
+    public static List<SysDictData> getDictCache(String key)
+    {
+        JSONArray arrayCache = SpringUtils.getBean(RedisCache.class).getCacheObject(getCacheKey(key));
+        if (StringUtils.isNotNull(arrayCache))
+        {
+            return arrayCache.toList(SysDictData.class);
+        }
+        return null;
+    }
+
+    /**
+     * 根据字典类型和字典值获取字典标签
+     * 
+     * @param dictType 字典类型
+     * @param dictValue 字典值
+     * @return 字典标签
+     */
+    public static String getDictLabel(String dictType, String dictValue)
+    {
+        if (StringUtils.isEmpty(dictValue))
+        {
+            return StringUtils.EMPTY;
+        }
+        return getDictLabel(dictType, dictValue, SEPARATOR);
+    }
+
+    /**
+     * 根据字典类型和字典标签获取字典值
+     * 
+     * @param dictType 字典类型
+     * @param dictLabel 字典标签
+     * @return 字典值
+     */
+    public static String getDictValue(String dictType, String dictLabel)
+    {
+        if (StringUtils.isEmpty(dictLabel))
+        {
+            return StringUtils.EMPTY;
+        }
+        return getDictValue(dictType, dictLabel, SEPARATOR);
+    }
+
+    /**
+     * 根据字典类型和字典值获取字典标签
+     * 
+     * @param dictType 字典类型
+     * @param dictValue 字典值
+     * @param separator 分隔符
+     * @return 字典标签
+     */
+    public static String getDictLabel(String dictType, String dictValue, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isNull(datas))
+        {
+            return StringUtils.EMPTY;
+        }
+        if (StringUtils.containsAny(separator, dictValue))
+        {
+            for (SysDictData dict : datas)
+            {
+                for (String value : dictValue.split(separator))
+                {
+                    if (value.equals(dict.getDictValue()))
+                    {
+                        propertyString.append(dict.getDictLabel()).append(separator);
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            for (SysDictData dict : datas)
+            {
+                if (dictValue.equals(dict.getDictValue()))
+                {
+                    return dict.getDictLabel();
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 根据字典类型和字典标签获取字典值
+     * 
+     * @param dictType 字典类型
+     * @param dictLabel 字典标签
+     * @param separator 分隔符
+     * @return 字典值
+     */
+    public static String getDictValue(String dictType, String dictLabel, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isNull(datas))
+        {
+            return StringUtils.EMPTY;
+        }
+        if (StringUtils.containsAny(separator, dictLabel))
+        {
+            for (SysDictData dict : datas)
+            {
+                for (String label : dictLabel.split(separator))
+                {
+                    if (label.equals(dict.getDictLabel()))
+                    {
+                        propertyString.append(dict.getDictValue()).append(separator);
+                        break;
+                    }
+                }
+            }
+        }
+        else
+        {
+            for (SysDictData dict : datas)
+            {
+                if (dictLabel.equals(dict.getDictLabel()))
+                {
+                    return dict.getDictValue();
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 根据字典类型获取字典所有值
+     *
+     * @param dictType 字典类型
+     * @return 字典值
+     */
+    public static String getDictValues(String dictType)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isNull(datas))
+        {
+            return StringUtils.EMPTY;
+        }
+        for (SysDictData dict : datas)
+        {
+            propertyString.append(dict.getDictValue()).append(SEPARATOR);
+        }
+        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
+    }
+
+    /**
+     * 根据字典类型获取字典所有标签
+     *
+     * @param dictType 字典类型
+     * @return 字典值
+     */
+    public static String getDictLabels(String dictType)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        List<SysDictData> datas = getDictCache(dictType);
+        if (StringUtils.isNull(datas))
+        {
+            return StringUtils.EMPTY;
+        }
+        for (SysDictData dict : datas)
+        {
+            propertyString.append(dict.getDictLabel()).append(SEPARATOR);
+        }
+        return StringUtils.stripEnd(propertyString.toString(), SEPARATOR);
+    }
+
+    /**
+     * 删除指定字典缓存
+     * 
+     * @param key 字典键
+     */
+    public static void removeDictCache(String key)
+    {
+        SpringUtils.getBean(RedisCache.class).deleteObject(getCacheKey(key));
+    }
+
+    /**
+     * 清空字典缓存
+     */
+    public static void clearDictCache()
+    {
+        Collection<String> keys = SpringUtils.getBean(RedisCache.class).keys(CacheConstants.SYS_DICT_KEY + "*");
+        SpringUtils.getBean(RedisCache.class).deleteObject(keys);
+    }
+
+    /**
+     * 设置cache key
+     * 
+     * @param configKey 参数键
+     * @return 缓存键key
+     */
+    public static String getCacheKey(String configKey)
+    {
+        return CacheConstants.SYS_DICT_KEY + configKey;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ExceptionUtil.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/ExceptionUtil.java
index 50b10fe8..88a961c3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ExceptionUtil.java
@@ -1,39 +1,39 @@
-package com.ruoyi.common.utils;
-
-import java.io.PrintWriter;
-import java.io.StringWriter;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-
-/**
- * 错误信息处理类。
- *
- * @author ruoyi
- */
-public class ExceptionUtil
-{
-    /**
-     * 获取exception的详细错误信息。
-     */
-    public static String getExceptionMessage(Throwable e)
-    {
-        StringWriter sw = new StringWriter();
-        e.printStackTrace(new PrintWriter(sw, true));
-        return sw.toString();
-    }
-
-    public static String getRootErrorMessage(Exception e)
-    {
-        Throwable root = ExceptionUtils.getRootCause(e);
-        root = (root == null ? e : root);
-        if (root == null)
-        {
-            return "";
-        }
-        String msg = root.getMessage();
-        if (msg == null)
-        {
-            return "null";
-        }
-        return StringUtils.defaultString(msg);
-    }
-}
+package com.acupuncture.common.utils;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+
+/**
+ * 错误信息处理类。
+ *
+ * @author acupuncture
+ */
+public class ExceptionUtil
+{
+    /**
+     * 获取exception的详细错误信息。
+     */
+    public static String getExceptionMessage(Throwable e)
+    {
+        StringWriter sw = new StringWriter();
+        e.printStackTrace(new PrintWriter(sw, true));
+        return sw.toString();
+    }
+
+    public static String getRootErrorMessage(Exception e)
+    {
+        Throwable root = ExceptionUtils.getRootCause(e);
+        root = (root == null ? e : root);
+        if (root == null)
+        {
+            return "";
+        }
+        String msg = root.getMessage();
+        if (msg == null)
+        {
+            return "null";
+        }
+        return StringUtils.defaultString(msg);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/LogUtils.java
similarity index 78%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/LogUtils.java
index e415c9c3..01b9fbf3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/LogUtils.java
@@ -1,18 +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() + "]";
-    }
-}
+package com.acupuncture.common.utils;
+
+/**
+ * 处理并记录日志文件
+ * 
+ * @author acupuncture
+ */
+public class LogUtils
+{
+    public static String getBlock(Object msg)
+    {
+        if (msg == null)
+        {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/MessageUtils.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/MessageUtils.java
index 5f2d9ea2..eb7264e4 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/MessageUtils.java
@@ -1,26 +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
-{
-    /**
-     * 根据消息键和参数 获取消息 委托给spring 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());
-    }
-}
+package com.acupuncture.common.utils;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+import com.acupuncture.common.utils.spring.SpringUtils;
+
+/**
+ * 获取i18n资源文件
+ * 
+ * @author acupuncture
+ */
+public class MessageUtils
+{
+    /**
+     * 根据消息键和参数 获取消息 委托给spring 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-common/src/main/java/com/ruoyi/common/utils/PageUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/PageUtils.java
similarity index 77%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/PageUtils.java
index 70e9b08f..eea98910 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/PageUtils.java
@@ -1,14 +1,14 @@
-package com.ruoyi.common.utils;
+package com.acupuncture.common.utils;
 
 import com.github.pagehelper.PageHelper;
-import com.ruoyi.common.core.page.PageDomain;
-import com.ruoyi.common.core.page.TableSupport;
-import com.ruoyi.common.utils.sql.SqlUtil;
+import com.acupuncture.common.core.page.PageDomain;
+import com.acupuncture.common.core.page.TableSupport;
+import com.acupuncture.common.utils.sql.SqlUtil;
 
 /**
  * 分页工具类
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 public class PageUtils extends PageHelper
 {
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/SecurityUtils.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/SecurityUtils.java
index 3898cfad..53b79d53 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/SecurityUtils.java
@@ -1,178 +1,178 @@
-package com.ruoyi.common.utils;
-
-import java.util.Collection;
-import java.util.List;
-import java.util.stream.Collectors;
-import org.springframework.security.core.Authentication;
-import org.springframework.security.core.context.SecurityContextHolder;
-import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
-import org.springframework.util.PatternMatchUtils;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.HttpStatus;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.exception.ServiceException;
-
-/**
- * 安全服务工具类
- * 
- * @author ruoyi
- */
-public class SecurityUtils
-{
-
-    /**
-     * 用户ID
-     **/
-    public static Long getUserId()
-    {
-        try
-        {
-            return getLoginUser().getUserId();
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
-        }
-    }
-
-    /**
-     * 获取部门ID
-     **/
-    public static Long getDeptId()
-    {
-        try
-        {
-            return getLoginUser().getDeptId();
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
-        }
-    }
-
-    /**
-     * 获取用户账户
-     **/
-    public static String getUsername()
-    {
-        try
-        {
-            return getLoginUser().getUsername();
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
-        }
-    }
-
-    /**
-     * 获取用户
-     **/
-    public static LoginUser getLoginUser()
-    {
-        try
-        {
-            return (LoginUser) getAuthentication().getPrincipal();
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("获取用户信息异常", 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;
-    }
-
-    /**
-     * 验证用户是否具备某权限
-     * 
-     * @param permission 权限字符串
-     * @return 用户是否具备某权限
-     */
-    public static boolean hasPermi(String permission)
-    {
-        return hasPermi(getLoginUser().getPermissions(), permission);
-    }
-
-    /**
-     * 判断是否包含权限
-     * 
-     * @param authorities 权限列表
-     * @param permission 权限字符串
-     * @return 用户是否具备某权限
-     */
-    public static boolean hasPermi(Collection<String> authorities, String permission)
-    {
-        return authorities.stream().filter(StringUtils::hasText)
-                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
-    }
-
-    /**
-     * 验证用户是否拥有某个角色
-     * 
-     * @param role 角色标识
-     * @return 用户是否具备某角色
-     */
-    public static boolean hasRole(String role)
-    {
-        List<SysRole> roleList = getLoginUser().getUser().getRoles();
-        Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
-        return hasRole(roles, role);
-    }
-
-    /**
-     * 判断是否包含角色
-     * 
-     * @param roles 角色列表
-     * @param role 角色
-     * @return 用户是否具备某角色权限
-     */
-    public static boolean hasRole(Collection<String> roles, String role)
-    {
-        return roles.stream().filter(StringUtils::hasText)
-                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
-    }
-
-}
+package com.acupuncture.common.utils;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.stream.Collectors;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.util.PatternMatchUtils;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.HttpStatus;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.exception.ServiceException;
+
+/**
+ * 安全服务工具类
+ * 
+ * @author acupuncture
+ */
+public class SecurityUtils
+{
+
+    /**
+     * 用户ID
+     **/
+    public static Long getUserId()
+    {
+        try
+        {
+            return getLoginUser().getUserId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("获取用户ID异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取部门ID
+     **/
+    public static Long getDeptId()
+    {
+        try
+        {
+            return getLoginUser().getDeptId();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("获取部门ID异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取用户账户
+     **/
+    public static String getUsername()
+    {
+        try
+        {
+            return getLoginUser().getUsername();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("获取用户账户异常", HttpStatus.UNAUTHORIZED);
+        }
+    }
+
+    /**
+     * 获取用户
+     **/
+    public static LoginUser getLoginUser()
+    {
+        try
+        {
+            return (LoginUser) getAuthentication().getPrincipal();
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("获取用户信息异常", 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;
+    }
+
+    /**
+     * 验证用户是否具备某权限
+     * 
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    public static boolean hasPermi(String permission)
+    {
+        return hasPermi(getLoginUser().getPermissions(), permission);
+    }
+
+    /**
+     * 判断是否包含权限
+     * 
+     * @param authorities 权限列表
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    public static boolean hasPermi(Collection<String> authorities, String permission)
+    {
+        return authorities.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.ALL_PERMISSION.equals(x) || PatternMatchUtils.simpleMatch(x, permission));
+    }
+
+    /**
+     * 验证用户是否拥有某个角色
+     * 
+     * @param role 角色标识
+     * @return 用户是否具备某角色
+     */
+    public static boolean hasRole(String role)
+    {
+        List<SysRole> roleList = getLoginUser().getUser().getRoles();
+        Collection<String> roles = roleList.stream().map(SysRole::getRoleKey).collect(Collectors.toSet());
+        return hasRole(roles, role);
+    }
+
+    /**
+     * 判断是否包含角色
+     * 
+     * @param roles 角色列表
+     * @param role 角色
+     * @return 用户是否具备某角色权限
+     */
+    public static boolean hasRole(Collection<String> roles, String role)
+    {
+        return roles.stream().filter(StringUtils::hasText)
+                .anyMatch(x -> Constants.SUPER_ADMIN.equals(x) || PatternMatchUtils.simpleMatch(x, role));
+    }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ServletUtils.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/ServletUtils.java
index 292b8dac..17749ae1 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ServletUtils.java
@@ -1,218 +1,218 @@
-package com.ruoyi.common.utils;
-
-import java.io.IOException;
-import java.io.UnsupportedEncodingException;
-import java.net.URLDecoder;
-import java.net.URLEncoder;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.Map;
-import javax.servlet.ServletRequest;
-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.constant.Constants;
-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);
-    }
-
-    /**
-     * 获取Boolean参数
-     */
-    public static Boolean getParameterToBool(String name)
-    {
-        return Convert.toBool(getRequest().getParameter(name));
-    }
-
-    /**
-     * 获取Boolean参数
-     */
-    public static Boolean getParameterToBool(String name, Boolean defaultValue)
-    {
-        return Convert.toBool(getRequest().getParameter(name), defaultValue);
-    }
-
-    /**
-     * 获得所有请求参数
-     *
-     * @param request 请求对象{@link ServletRequest}
-     * @return Map
-     */
-    public static Map<String, String[]> getParams(ServletRequest request)
-    {
-        final Map<String, String[]> map = request.getParameterMap();
-        return Collections.unmodifiableMap(map);
-    }
-
-    /**
-     * 获得所有请求参数
-     *
-     * @param request 请求对象{@link ServletRequest}
-     * @return Map
-     */
-    public static Map<String, String> getParamMap(ServletRequest request)
-    {
-        Map<String, String> params = new HashMap<>();
-        for (Map.Entry<String, String[]> entry : getParams(request).entrySet())
-        {
-            params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
-        }
-        return params;
-    }
-
-    /**
-     * 获取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 待渲染的字符串
-     */
-    public static void 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();
-        }
-    }
-
-    /**
-     * 是否是Ajax异步请求
-     * 
-     * @param request
-     */
-    public static boolean isAjaxRequest(HttpServletRequest request)
-    {
-        String accept = request.getHeader("accept");
-        if (accept != null && accept.contains("application/json"))
-        {
-            return true;
-        }
-
-        String xRequestedWith = request.getHeader("X-Requested-With");
-        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
-        {
-            return true;
-        }
-
-        String uri = request.getRequestURI();
-        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
-        {
-            return true;
-        }
-
-        String ajax = request.getParameter("__ajax");
-        return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
-    }
-
-    /**
-     * 内容编码
-     * 
-     * @param str 内容
-     * @return 编码后的内容
-     */
-    public static String urlEncode(String str)
-    {
-        try
-        {
-            return URLEncoder.encode(str, Constants.UTF8);
-        }
-        catch (UnsupportedEncodingException e)
-        {
-            return StringUtils.EMPTY;
-        }
-    }
-
-    /**
-     * 内容解码
-     * 
-     * @param str 内容
-     * @return 解码后的内容
-     */
-    public static String urlDecode(String str)
-    {
-        try
-        {
-            return URLDecoder.decode(str, Constants.UTF8);
-        }
-        catch (UnsupportedEncodingException e)
-        {
-            return StringUtils.EMPTY;
-        }
-    }
-}
+package com.acupuncture.common.utils;
+
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+import java.net.URLEncoder;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import javax.servlet.ServletRequest;
+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.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.text.Convert;
+
+/**
+ * 客户端工具类
+ * 
+ * @author acupuncture
+ */
+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);
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name)
+    {
+        return Convert.toBool(getRequest().getParameter(name));
+    }
+
+    /**
+     * 获取Boolean参数
+     */
+    public static Boolean getParameterToBool(String name, Boolean defaultValue)
+    {
+        return Convert.toBool(getRequest().getParameter(name), defaultValue);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String[]> getParams(ServletRequest request)
+    {
+        final Map<String, String[]> map = request.getParameterMap();
+        return Collections.unmodifiableMap(map);
+    }
+
+    /**
+     * 获得所有请求参数
+     *
+     * @param request 请求对象{@link ServletRequest}
+     * @return Map
+     */
+    public static Map<String, String> getParamMap(ServletRequest request)
+    {
+        Map<String, String> params = new HashMap<>();
+        for (Map.Entry<String, String[]> entry : getParams(request).entrySet())
+        {
+            params.put(entry.getKey(), StringUtils.join(entry.getValue(), ","));
+        }
+        return params;
+    }
+
+    /**
+     * 获取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 待渲染的字符串
+     */
+    public static void 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();
+        }
+    }
+
+    /**
+     * 是否是Ajax异步请求
+     * 
+     * @param request
+     */
+    public static boolean isAjaxRequest(HttpServletRequest request)
+    {
+        String accept = request.getHeader("accept");
+        if (accept != null && accept.contains("application/json"))
+        {
+            return true;
+        }
+
+        String xRequestedWith = request.getHeader("X-Requested-With");
+        if (xRequestedWith != null && xRequestedWith.contains("XMLHttpRequest"))
+        {
+            return true;
+        }
+
+        String uri = request.getRequestURI();
+        if (StringUtils.inStringIgnoreCase(uri, ".json", ".xml"))
+        {
+            return true;
+        }
+
+        String ajax = request.getParameter("__ajax");
+        return StringUtils.inStringIgnoreCase(ajax, "json", "xml");
+    }
+
+    /**
+     * 内容编码
+     * 
+     * @param str 内容
+     * @return 编码后的内容
+     */
+    public static String urlEncode(String str)
+    {
+        try
+        {
+            return URLEncoder.encode(str, Constants.UTF8);
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            return StringUtils.EMPTY;
+        }
+    }
+
+    /**
+     * 内容解码
+     * 
+     * @param str 内容
+     * @return 解码后的内容
+     */
+    public static String urlDecode(String str)
+    {
+        try
+        {
+            return URLDecoder.decode(str, Constants.UTF8);
+        }
+        catch (UnsupportedEncodingException e)
+        {
+            return StringUtils.EMPTY;
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/StringUtils.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/StringUtils.java
index fc6c6b5e..ad7ad3b3 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/StringUtils.java
@@ -1,684 +1,684 @@
-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 org.springframework.util.AntPathMatcher;
-import com.ruoyi.common.constant.Constants;
-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 = '_';
-
-    /** 星号 */
-    private static final char ASTERISK = '*';
-
-    /**
-     * 获取参数不为空值
-     * 
-     * @param value defaultValue 要判断的value
-     * @return value 返回值
-     */
-    public static <T> T nvl(T value, T defaultValue)
-    {
-        return value != null ? value : defaultValue;
-    }
-
-    /**
-     * * 判断一个Collection是否为空, 包含List,Set,Queue
-     * 
-     * @param coll 要判断的Collection
-     * @return true:为空 false:非空
-     */
-    public static boolean isEmpty(Collection<?> coll)
-    {
-        return isNull(coll) || coll.isEmpty();
-    }
-
-    /**
-     * * 判断一个Collection是否非空,包含List,Set,Queue
-     * 
-     * @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);
-    }
-
-    /**
-     * * 判断一个Map是否为空
-     * 
-     * @param map 要判断的Map
-     * @return true:为空 false:非空
-     */
-    public static boolean isEmpty(Map<?, ?> map)
-    {
-        return isNull(map) || map.isEmpty();
-    }
-
-    /**
-     * * 判断一个Map是否为空
-     * 
-     * @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);
-    }
-
-    /**
-     * * 判断一个对象是否是数组类型(Java基本型别的数组)
-     * 
-     * @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 startInclude 开始位置(包含)
-     * @param endExclude 结束位置(不包含)
-     * @return 替换后的字符串
-     */
-    public static String hide(CharSequence str, int startInclude, int endExclude)
-    {
-        if (isEmpty(str))
-        {
-            return NULLSTR;
-        }
-        final int strLength = str.length();
-        if (startInclude > strLength)
-        {
-            return NULLSTR;
-        }
-        if (endExclude > strLength)
-        {
-            endExclude = strLength;
-        }
-        if (startInclude > endExclude)
-        {
-            // 如果起始位置大于结束位置,不替换
-            return NULLSTR;
-        }
-        final char[] chars = new char[strLength];
-        for (int i = 0; i < strLength; i++)
-        {
-            if (i >= startInclude && i < endExclude)
-            {
-                chars[i] = ASTERISK;
-            }
-            else
-            {
-                chars[i] = str.charAt(i);
-            }
-        }
-        return new String(chars);
-    }
-
-    /**
-     * 截取字符串
-     * 
-     * @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);
-    }
-
-    /**
-     * 判断是否为空,并且不是空白字符
-     * 
-     * @param str 要判断的value
-     * @return 结果
-     */
-    public static boolean hasText(String str)
-    {
-        return (str != null && !str.isEmpty() && containsText(str));
-    }
-
-    private static boolean containsText(CharSequence str)
-    {
-        int strLen = str.length();
-        for (int i = 0; i < strLen; i++)
-        {
-            if (!Character.isWhitespace(str.charAt(i)))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * 格式化文本, {} 表示占位符<br>
-     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
-     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
-     * 例:<br>
-     * 通常使用:format("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);
-    }
-
-    /**
-     * 是否为http(s)://开头
-     * 
-     * @param link 链接
-     * @return 结果
-     */
-    public static boolean ishttp(String link)
-    {
-        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
-    }
-
-    /**
-     * 字符串转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;
-    }
-
-    /**
-     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
-     *
-     * @param collection 给定的集合
-     * @param array 给定的数组
-     * @return boolean 结果
-     */
-    public static boolean containsAny(Collection<String> collection, String... array)
-    {
-        if (isEmpty(collection) || isEmpty(array))
-        {
-            return false;
-        }
-        else
-        {
-            for (String str : array)
-            {
-                if (collection.contains(str))
-                {
-                    return true;
-                }
-            }
-            return false;
-        }
-    }
-
-    /**
-     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
-     *
-     * @param cs 指定字符串
-     * @param searchCharSequences 需要检查的字符串数组
-     * @return 是否包含任意一个字符串
-     */
-    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
-    {
-        if (isEmpty(cs) || isEmpty(searchCharSequences))
-        {
-            return false;
-        }
-        for (CharSequence testStr : searchCharSequences)
-        {
-            if (containsIgnoreCase(cs, testStr))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * 驼峰转下划线命名
-     */
-    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;
-    }
-
-    /**
-     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_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();
-    }
-
-    /**
-     * 驼峰式命名法
-     * 例如:user_name->userName
-     */
-    public static String toCamelCase(String s)
-    {
-        if (s == null)
-        {
-            return null;
-        }
-        if (s.indexOf(SEPARATOR) == -1)
-        {
-            return s;
-        }
-        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();
-    }
-
-    /**
-     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
-     * 
-     * @param str 指定字符串
-     * @param strs 需要检查的字符串数组
-     * @return 是否匹配
-     */
-    public static boolean matches(String str, List<String> strs)
-    {
-        if (isEmpty(str) || isEmpty(strs))
-        {
-            return false;
-        }
-        for (String pattern : strs)
-        {
-            if (isMatch(pattern, str))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    /**
-     * 判断url是否与规则配置: 
-     * ? 表示单个字符; 
-     * * 表示一层路径内的任意字符串,不可跨层级; 
-     * ** 表示任意层路径;
-     * 
-     * @param pattern 匹配规则
-     * @param url 需要匹配的url
-     * @return
-     */
-    public static boolean isMatch(String pattern, String url)
-    {
-        AntPathMatcher matcher = new AntPathMatcher();
-        return matcher.match(pattern, url);
-    }
-
-    @SuppressWarnings("unchecked")
-    public static <T> T cast(Object obj)
-    {
-        return (T) obj;
-    }
-
-    /**
-     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
-     * 
-     * @param num 数字对象
-     * @param size 字符串指定长度
-     * @return 返回数字的字符串格式,该字符串为指定长度。
-     */
-    public static final String padl(final Number num, final int size)
-    {
-        return padl(num.toString(), size, '0');
-    }
-
-    /**
-     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
-     * 
-     * @param s 原始字符串
-     * @param size 字符串指定长度
-     * @param c 用于补齐的字符
-     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
-     */
-    public static final String padl(final String s, final int size, final char c)
-    {
-        final StringBuilder sb = new StringBuilder(size);
-        if (s != null)
-        {
-            final int len = s.length();
-            if (s.length() <= size)
-            {
-                for (int i = size - len; i > 0; i--)
-                {
-                    sb.append(c);
-                }
-                sb.append(s);
-            }
-            else
-            {
-                return s.substring(len - size, len);
-            }
-        }
-        else
-        {
-            for (int i = size; i > 0; i--)
-            {
-                sb.append(c);
-            }
-        }
-        return sb.toString();
-    }
+package com.acupuncture.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 org.springframework.util.AntPathMatcher;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.text.StrFormatter;
+
+/**
+ * 字符串工具类
+ * 
+ * @author acupuncture
+ */
+public class StringUtils extends org.apache.commons.lang3.StringUtils
+{
+    /** 空字符串 */
+    private static final String NULLSTR = "";
+
+    /** 下划线 */
+    private static final char SEPARATOR = '_';
+
+    /** 星号 */
+    private static final char ASTERISK = '*';
+
+    /**
+     * 获取参数不为空值
+     * 
+     * @param value defaultValue 要判断的value
+     * @return value 返回值
+     */
+    public static <T> T nvl(T value, T defaultValue)
+    {
+        return value != null ? value : defaultValue;
+    }
+
+    /**
+     * * 判断一个Collection是否为空, 包含List,Set,Queue
+     * 
+     * @param coll 要判断的Collection
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Collection<?> coll)
+    {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 判断一个Collection是否非空,包含List,Set,Queue
+     * 
+     * @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);
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     * 
+     * @param map 要判断的Map
+     * @return true:为空 false:非空
+     */
+    public static boolean isEmpty(Map<?, ?> map)
+    {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 判断一个Map是否为空
+     * 
+     * @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);
+    }
+
+    /**
+     * * 判断一个对象是否是数组类型(Java基本型别的数组)
+     * 
+     * @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 startInclude 开始位置(包含)
+     * @param endExclude 结束位置(不包含)
+     * @return 替换后的字符串
+     */
+    public static String hide(CharSequence str, int startInclude, int endExclude)
+    {
+        if (isEmpty(str))
+        {
+            return NULLSTR;
+        }
+        final int strLength = str.length();
+        if (startInclude > strLength)
+        {
+            return NULLSTR;
+        }
+        if (endExclude > strLength)
+        {
+            endExclude = strLength;
+        }
+        if (startInclude > endExclude)
+        {
+            // 如果起始位置大于结束位置,不替换
+            return NULLSTR;
+        }
+        final char[] chars = new char[strLength];
+        for (int i = 0; i < strLength; i++)
+        {
+            if (i >= startInclude && i < endExclude)
+            {
+                chars[i] = ASTERISK;
+            }
+            else
+            {
+                chars[i] = str.charAt(i);
+            }
+        }
+        return new String(chars);
+    }
+
+    /**
+     * 截取字符串
+     * 
+     * @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);
+    }
+
+    /**
+     * 判断是否为空,并且不是空白字符
+     * 
+     * @param str 要判断的value
+     * @return 结果
+     */
+    public static boolean hasText(String str)
+    {
+        return (str != null && !str.isEmpty() && containsText(str));
+    }
+
+    private static boolean containsText(CharSequence str)
+    {
+        int strLen = str.length();
+        for (int i = 0; i < strLen; i++)
+        {
+            if (!Character.isWhitespace(str.charAt(i)))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 格式化文本, {} 表示占位符<br>
+     * 此方法只是简单将占位符 {} 按照顺序替换为参数<br>
+     * 如果想输出 {} 使用 \\转义 { 即可,如果想输出 {} 之前的 \ 使用双转义符 \\\\ 即可<br>
+     * 例:<br>
+     * 通常使用:format("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);
+    }
+
+    /**
+     * 是否为http(s)://开头
+     * 
+     * @param link 链接
+     * @return 结果
+     */
+    public static boolean ishttp(String link)
+    {
+        return StringUtils.startsWithAny(link, Constants.HTTP, Constants.HTTPS);
+    }
+
+    /**
+     * 字符串转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;
+    }
+
+    /**
+     * 判断给定的collection列表中是否包含数组array 判断给定的数组array中是否包含给定的元素value
+     *
+     * @param collection 给定的集合
+     * @param array 给定的数组
+     * @return boolean 结果
+     */
+    public static boolean containsAny(Collection<String> collection, String... array)
+    {
+        if (isEmpty(collection) || isEmpty(array))
+        {
+            return false;
+        }
+        else
+        {
+            for (String str : array)
+            {
+                if (collection.contains(str))
+                {
+                    return true;
+                }
+            }
+            return false;
+        }
+    }
+
+    /**
+     * 查找指定字符串是否包含指定字符串列表中的任意一个字符串同时串忽略大小写
+     *
+     * @param cs 指定字符串
+     * @param searchCharSequences 需要检查的字符串数组
+     * @return 是否包含任意一个字符串
+     */
+    public static boolean containsAnyIgnoreCase(CharSequence cs, CharSequence... searchCharSequences)
+    {
+        if (isEmpty(cs) || isEmpty(searchCharSequences))
+        {
+            return false;
+        }
+        for (CharSequence testStr : searchCharSequences)
+        {
+            if (containsIgnoreCase(cs, testStr))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 驼峰转下划线命名
+     */
+    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;
+    }
+
+    /**
+     * 将下划线大写方式命名的字符串转换为驼峰式。如果转换前的下划线大写方式命名的字符串为空,则返回空字符串。 例如:HELLO_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();
+    }
+
+    /**
+     * 驼峰式命名法
+     * 例如:user_name->userName
+     */
+    public static String toCamelCase(String s)
+    {
+        if (s == null)
+        {
+            return null;
+        }
+        if (s.indexOf(SEPARATOR) == -1)
+        {
+            return s;
+        }
+        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();
+    }
+
+    /**
+     * 查找指定字符串是否匹配指定字符串列表中的任意一个字符串
+     * 
+     * @param str 指定字符串
+     * @param strs 需要检查的字符串数组
+     * @return 是否匹配
+     */
+    public static boolean matches(String str, List<String> strs)
+    {
+        if (isEmpty(str) || isEmpty(strs))
+        {
+            return false;
+        }
+        for (String pattern : strs)
+        {
+            if (isMatch(pattern, str))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * 判断url是否与规则配置: 
+     * ? 表示单个字符; 
+     * * 表示一层路径内的任意字符串,不可跨层级; 
+     * ** 表示任意层路径;
+     * 
+     * @param pattern 匹配规则
+     * @param url 需要匹配的url
+     * @return
+     */
+    public static boolean isMatch(String pattern, String url)
+    {
+        AntPathMatcher matcher = new AntPathMatcher();
+        return matcher.match(pattern, url);
+    }
+
+    @SuppressWarnings("unchecked")
+    public static <T> T cast(Object obj)
+    {
+        return (T) obj;
+    }
+
+    /**
+     * 数字左边补齐0,使之达到指定长度。注意,如果数字转换为字符串后,长度大于size,则只保留 最后size个字符。
+     * 
+     * @param num 数字对象
+     * @param size 字符串指定长度
+     * @return 返回数字的字符串格式,该字符串为指定长度。
+     */
+    public static final String padl(final Number num, final int size)
+    {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 字符串左补齐。如果原始字符串s长度大于size,则只保留最后size个字符。
+     * 
+     * @param s 原始字符串
+     * @param size 字符串指定长度
+     * @param c 用于补齐的字符
+     * @return 返回指定长度的字符串,由原字符串左补齐或截取得到。
+     */
+    public static final String padl(final String s, final int size, final char c)
+    {
+        final StringBuilder sb = new StringBuilder(size);
+        if (s != null)
+        {
+            final int len = s.length();
+            if (s.length() <= size)
+            {
+                for (int i = size - len; i > 0; i--)
+                {
+                    sb.append(c);
+                }
+                sb.append(s);
+            }
+            else
+            {
+                return s.substring(len - size, len);
+            }
+        }
+        else
+        {
+            for (int i = size; i > 0; i--)
+            {
+                sb.append(c);
+            }
+        }
+        return sb.toString();
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/Threads.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/Threads.java
index f3493528..c5047581 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/Threads.java
@@ -1,99 +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;
-        }
-    }
-
-    /**
-     * 停止线程池
-     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
-     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
-     * 如果仍然超時,則強制退出.
-     * 另对在shutdown时线程本身被调用中断做了处理.
-     */
-    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);
-        }
-    }
-}
+package com.acupuncture.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 acupuncture
+ */
+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;
+        }
+    }
+
+    /**
+     * 停止线程池
+     * 先使用shutdown, 停止接收新任务并尝试完成所有已存在任务.
+     * 如果超时, 则调用shutdownNow, 取消在workQueue中Pending的任务,并中断所有阻塞函数.
+     * 如果仍然超時,則強制退出.
+     * 另对在shutdown时线程本身被调用中断做了处理.
+     */
+    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-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanUtils.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanUtils.java
index 51cdc2fb..f911a606 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanUtils.java
@@ -1,110 +1,110 @@
-package com.ruoyi.common.utils.bean;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * Bean 工具类
- * 
- * @author ruoyi
- */
-public class BeanUtils extends org.springframework.beans.BeanUtils
-{
-    /** Bean方法名中属性名开始的下标 */
-    private static final int BEAN_METHOD_PROP_INDEX = 3;
-
-    /** * 匹配getter方法的正则表达式 */
-    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
-
-    /** * 匹配setter方法的正则表达式 */
-    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
-
-    /**
-     * Bean属性复制工具方法。
-     * 
-     * @param dest 目标对象
-     * @param src 源对象
-     */
-    public static void copyBeanProp(Object dest, Object src)
-    {
-        try
-        {
-            copyProperties(src, dest);
-        }
-        catch (Exception e)
-        {
-            e.printStackTrace();
-        }
-    }
-
-    /**
-     * 获取对象的setter方法。
-     * 
-     * @param obj 对象
-     * @return 对象的setter方法列表
-     */
-    public static List<Method> getSetterMethods(Object obj)
-    {
-        // setter方法列表
-        List<Method> setterMethods = new ArrayList<Method>();
-
-        // 获取所有方法
-        Method[] methods = obj.getClass().getMethods();
-
-        // 查找setter方法
-
-        for (Method method : methods)
-        {
-            Matcher m = SET_PATTERN.matcher(method.getName());
-            if (m.matches() && (method.getParameterTypes().length == 1))
-            {
-                setterMethods.add(method);
-            }
-        }
-        // 返回setter方法列表
-        return setterMethods;
-    }
-
-    /**
-     * 获取对象的getter方法。
-     * 
-     * @param obj 对象
-     * @return 对象的getter方法列表
-     */
-
-    public static List<Method> getGetterMethods(Object obj)
-    {
-        // getter方法列表
-        List<Method> getterMethods = new ArrayList<Method>();
-        // 获取所有方法
-        Method[] methods = obj.getClass().getMethods();
-        // 查找getter方法
-        for (Method method : methods)
-        {
-            Matcher m = GET_PATTERN.matcher(method.getName());
-            if (m.matches() && (method.getParameterTypes().length == 0))
-            {
-                getterMethods.add(method);
-            }
-        }
-        // 返回getter方法列表
-        return getterMethods;
-    }
-
-    /**
-     * 检查Bean方法名中的属性名是否相等。<br>
-     * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
-     * 
-     * @param m1 方法名1
-     * @param m2 方法名2
-     * @return 属性名一样返回true,否则返回false
-     */
-
-    public static boolean isMethodPropEquals(String m1, String m2)
-    {
-        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
-    }
-}
+package com.acupuncture.common.utils.bean;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * Bean 工具类
+ * 
+ * @author acupuncture
+ */
+public class BeanUtils extends org.springframework.beans.BeanUtils
+{
+    /** Bean方法名中属性名开始的下标 */
+    private static final int BEAN_METHOD_PROP_INDEX = 3;
+
+    /** * 匹配getter方法的正则表达式 */
+    private static final Pattern GET_PATTERN = Pattern.compile("get(\\p{javaUpperCase}\\w*)");
+
+    /** * 匹配setter方法的正则表达式 */
+    private static final Pattern SET_PATTERN = Pattern.compile("set(\\p{javaUpperCase}\\w*)");
+
+    /**
+     * Bean属性复制工具方法。
+     * 
+     * @param dest 目标对象
+     * @param src 源对象
+     */
+    public static void copyBeanProp(Object dest, Object src)
+    {
+        try
+        {
+            copyProperties(src, dest);
+        }
+        catch (Exception e)
+        {
+            e.printStackTrace();
+        }
+    }
+
+    /**
+     * 获取对象的setter方法。
+     * 
+     * @param obj 对象
+     * @return 对象的setter方法列表
+     */
+    public static List<Method> getSetterMethods(Object obj)
+    {
+        // setter方法列表
+        List<Method> setterMethods = new ArrayList<Method>();
+
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+
+        // 查找setter方法
+
+        for (Method method : methods)
+        {
+            Matcher m = SET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 1))
+            {
+                setterMethods.add(method);
+            }
+        }
+        // 返回setter方法列表
+        return setterMethods;
+    }
+
+    /**
+     * 获取对象的getter方法。
+     * 
+     * @param obj 对象
+     * @return 对象的getter方法列表
+     */
+
+    public static List<Method> getGetterMethods(Object obj)
+    {
+        // getter方法列表
+        List<Method> getterMethods = new ArrayList<Method>();
+        // 获取所有方法
+        Method[] methods = obj.getClass().getMethods();
+        // 查找getter方法
+        for (Method method : methods)
+        {
+            Matcher m = GET_PATTERN.matcher(method.getName());
+            if (m.matches() && (method.getParameterTypes().length == 0))
+            {
+                getterMethods.add(method);
+            }
+        }
+        // 返回getter方法列表
+        return getterMethods;
+    }
+
+    /**
+     * 检查Bean方法名中的属性名是否相等。<br>
+     * 如getName()和setName()属性名一样,getName()和setAge()属性名不一样。
+     * 
+     * @param m1 方法名1
+     * @param m2 方法名2
+     * @return 属性名一样返回true,否则返回false
+     */
+
+    public static boolean isMethodPropEquals(String m1, String m2)
+    {
+        return m1.substring(BEAN_METHOD_PROP_INDEX).equals(m2.substring(BEAN_METHOD_PROP_INDEX));
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanValidators.java
similarity index 88%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanValidators.java
index d9821e0e..74712d53 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/bean/BeanValidators.java
@@ -1,24 +1,24 @@
-package com.ruoyi.common.utils.bean;
-
-import java.util.Set;
-import javax.validation.ConstraintViolation;
-import javax.validation.ConstraintViolationException;
-import javax.validation.Validator;
-
-/**
- * bean对象属性验证
- * 
- * @author ruoyi
- */
-public class BeanValidators
-{
-    public static void validateWithException(Validator validator, Object object, Class<?>... groups)
-            throws ConstraintViolationException
-    {
-        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
-        if (!constraintViolations.isEmpty())
-        {
-            throw new ConstraintViolationException(constraintViolations);
-        }
-    }
-}
+package com.acupuncture.common.utils.bean;
+
+import java.util.Set;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import javax.validation.Validator;
+
+/**
+ * bean对象属性验证
+ * 
+ * @author acupuncture
+ */
+public class BeanValidators
+{
+    public static void validateWithException(Validator validator, Object object, Class<?>... groups)
+            throws ConstraintViolationException
+    {
+        Set<ConstraintViolation<Object>> constraintViolations = validator.validate(object, groups);
+        if (!constraintViolations.isEmpty())
+        {
+            throw new ConstraintViolationException(constraintViolations);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileTypeUtils.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileTypeUtils.java
index 25f53066..45ccc1ae 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileTypeUtils.java
@@ -1,76 +1,76 @@
-package com.ruoyi.common.utils.file;
-
-import java.io.File;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * 文件类型工具类
- *
- * @author ruoyi
- */
-public class FileTypeUtils
-{
-    /**
-     * 获取文件类型
-     * <p>
-     * 例如: ruoyi.txt, 返回: txt
-     * 
-     * @param file 文件名
-     * @return 后缀(不含".")
-     */
-    public static String getFileType(File file)
-    {
-        if (null == file)
-        {
-            return StringUtils.EMPTY;
-        }
-        return getFileType(file.getName());
-    }
-
-    /**
-     * 获取文件类型
-     * <p>
-     * 例如: ruoyi.txt, 返回: txt
-     *
-     * @param fileName 文件名
-     * @return 后缀(不含".")
-     */
-    public static String getFileType(String fileName)
-    {
-        int separatorIndex = fileName.lastIndexOf(".");
-        if (separatorIndex < 0)
-        {
-            return "";
-        }
-        return fileName.substring(separatorIndex + 1).toLowerCase();
-    }
-
-    /**
-     * 获取文件类型
-     * 
-     * @param photoByte 文件字节码
-     * @return 后缀(不含".")
-     */
-    public static String getFileExtendName(byte[] photoByte)
-    {
-        String strFileExtendName = "JPG";
-        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
-                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
-        {
-            strFileExtendName = "GIF";
-        }
-        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
-        {
-            strFileExtendName = "JPG";
-        }
-        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
-        {
-            strFileExtendName = "BMP";
-        }
-        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
-        {
-            strFileExtendName = "PNG";
-        }
-        return strFileExtendName;
-    }
+package com.acupuncture.common.utils.file;
+
+import java.io.File;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 文件类型工具类
+ *
+ * @author acupuncture
+ */
+public class FileTypeUtils
+{
+    /**
+     * 获取文件类型
+     * <p>
+     * 例如: acupuncture.txt, 返回: txt
+     * 
+     * @param file 文件名
+     * @return 后缀(不含".")
+     */
+    public static String getFileType(File file)
+    {
+        if (null == file)
+        {
+            return StringUtils.EMPTY;
+        }
+        return getFileType(file.getName());
+    }
+
+    /**
+     * 获取文件类型
+     * <p>
+     * 例如: acupuncture.txt, 返回: txt
+     *
+     * @param fileName 文件名
+     * @return 后缀(不含".")
+     */
+    public static String getFileType(String fileName)
+    {
+        int separatorIndex = fileName.lastIndexOf(".");
+        if (separatorIndex < 0)
+        {
+            return "";
+        }
+        return fileName.substring(separatorIndex + 1).toLowerCase();
+    }
+
+    /**
+     * 获取文件类型
+     * 
+     * @param photoByte 文件字节码
+     * @return 后缀(不含".")
+     */
+    public static String getFileExtendName(byte[] photoByte)
+    {
+        String strFileExtendName = "JPG";
+        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
+                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
+        {
+            strFileExtendName = "GIF";
+        }
+        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
+        {
+            strFileExtendName = "JPG";
+        }
+        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
+        {
+            strFileExtendName = "BMP";
+        }
+        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
+        {
+            strFileExtendName = "PNG";
+        }
+        return strFileExtendName;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUploadUtils.java
similarity index 90%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUploadUtils.java
index 5a0ef640..21937f62 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUploadUtils.java
@@ -1,232 +1,232 @@
-package com.ruoyi.common.utils.file;
-
-import java.io.File;
-import java.io.IOException;
-import java.nio.file.Paths;
-import java.util.Objects;
-import org.apache.commons.io.FilenameUtils;
-import org.springframework.web.multipart.MultipartFile;
-import com.ruoyi.common.config.RuoYiConfig;
-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.uuid.Seq;
-
-/**
- * 文件上传工具类
- *
- * @author ruoyi
- */
-public class FileUploadUtils
-{
-    /**
-     * 默认大小 50M
-     */
-    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
-
-    /**
-     * 默认的文件名最大长度 100
-     */
-    public static final int DEFAULT_FILE_NAME_LENGTH = 100;
-
-    /**
-     * 默认上传的地址
-     */
-    private static String defaultBaseDir = RuoYiConfig.getProfile();
-
-    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 allowedExtension 上传文件类型
-     * @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 = Objects.requireNonNull(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);
-
-        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
-        file.transferTo(Paths.get(absPath));
-        return getPathFileName(baseDir, fileName);
-    }
-
-    /**
-     * 编码文件名
-     */
-    public static final String extractFilename(MultipartFile file)
-    {
-        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
-                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
-    }
-
-    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
-    {
-        File desc = new File(uploadDir + File.separator + fileName);
-
-        if (!desc.exists())
-        {
-            if (!desc.getParentFile().exists())
-            {
-                desc.getParentFile().mkdirs();
-            }
-        }
-        return desc;
-    }
-
-    public static final String getPathFileName(String uploadDir, String fileName) throws IOException
-    {
-        int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
-        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
-        return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + 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 (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 if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
-            {
-                throw new InvalidExtensionException.InvalidVideoExtensionException(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(Objects.requireNonNull(file.getContentType()));
-        }
-        return extension;
-    }
-}
+package com.acupuncture.common.utils.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.Objects;
+import org.apache.commons.io.FilenameUtils;
+import org.springframework.web.multipart.MultipartFile;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.exception.file.FileNameLengthLimitExceededException;
+import com.acupuncture.common.exception.file.FileSizeLimitExceededException;
+import com.acupuncture.common.exception.file.InvalidExtensionException;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.uuid.Seq;
+
+/**
+ * 文件上传工具类
+ *
+ * @author acupuncture
+ */
+public class FileUploadUtils
+{
+    /**
+     * 默认大小 50M
+     */
+    public static final long DEFAULT_MAX_SIZE = 50 * 1024 * 1024L;
+
+    /**
+     * 默认的文件名最大长度 100
+     */
+    public static final int DEFAULT_FILE_NAME_LENGTH = 100;
+
+    /**
+     * 默认上传的地址
+     */
+    private static String defaultBaseDir = RuoYiConfig.getProfile();
+
+    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 allowedExtension 上传文件类型
+     * @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 = Objects.requireNonNull(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);
+
+        String absPath = getAbsoluteFile(baseDir, fileName).getAbsolutePath();
+        file.transferTo(Paths.get(absPath));
+        return getPathFileName(baseDir, fileName);
+    }
+
+    /**
+     * 编码文件名
+     */
+    public static final String extractFilename(MultipartFile file)
+    {
+        return StringUtils.format("{}/{}_{}.{}", DateUtils.datePath(),
+                FilenameUtils.getBaseName(file.getOriginalFilename()), Seq.getId(Seq.uploadSeqType), getExtension(file));
+    }
+
+    public static final File getAbsoluteFile(String uploadDir, String fileName) throws IOException
+    {
+        File desc = new File(uploadDir + File.separator + fileName);
+
+        if (!desc.exists())
+        {
+            if (!desc.getParentFile().exists())
+            {
+                desc.getParentFile().mkdirs();
+            }
+        }
+        return desc;
+    }
+
+    public static final String getPathFileName(String uploadDir, String fileName) throws IOException
+    {
+        int dirLastIndex = RuoYiConfig.getProfile().length() + 1;
+        String currentDir = StringUtils.substring(uploadDir, dirLastIndex);
+        return Constants.RESOURCE_PREFIX + "/" + currentDir + "/" + 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 (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 if (allowedExtension == MimeTypeUtils.VIDEO_EXTENSION)
+            {
+                throw new InvalidExtensionException.InvalidVideoExtensionException(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(Objects.requireNonNull(file.getContentType()));
+        }
+        return extension;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUtils.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUtils.java
index 5c96f7cb..0dc6ee13 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/FileUtils.java
@@ -1,291 +1,291 @@
-package com.ruoyi.common.utils.file;
-
-import java.io.File;
-import java.io.FileInputStream;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.OutputStream;
-import java.io.UnsupportedEncodingException;
-import java.net.URLEncoder;
-import java.nio.charset.StandardCharsets;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
-import org.apache.commons.lang3.ArrayUtils;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.uuid.IdUtils;
-import org.apache.commons.io.FilenameUtils;
-
-/**
- * 文件处理工具类
- * 
- * @author ruoyi
- */
-public class FileUtils
-{
-    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
-
-    /**
-     * 输出指定文件的byte数组
-     * 
-     * @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
-        {
-            IOUtils.close(os);
-            IOUtils.close(fis);
-        }
-    }
-
-    /**
-     * 写数据到文件中
-     *
-     * @param data 数据
-     * @return 目标文件
-     * @throws IOException IO异常
-     */
-    public static String writeImportBytes(byte[] data) throws IOException
-    {
-        return writeBytes(data, RuoYiConfig.getImportPath());
-    }
-
-    /**
-     * 写数据到文件中
-     *
-     * @param data 数据
-     * @param uploadDir 目标文件
-     * @return 目标文件
-     * @throws IOException IO异常
-     */
-    public static String writeBytes(byte[] data, String uploadDir) throws IOException
-    {
-        FileOutputStream fos = null;
-        String pathName = "";
-        try
-        {
-            String extension = getFileExtendName(data);
-            pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
-            File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
-            fos = new FileOutputStream(file);
-            fos.write(data);
-        }
-        finally
-        {
-            IOUtils.close(fos);
-        }
-        return FileUploadUtils.getPathFileName(uploadDir, pathName);
-    }
-
-    /**
-     * 删除文件
-     * 
-     * @param filePath 文件
-     * @return
-     */
-    public static boolean deleteFile(String filePath)
-    {
-        boolean flag = false;
-        File file = new File(filePath);
-        // 路径为文件且不为空则进行删除
-        if (file.isFile() && file.exists())
-        {
-            flag = file.delete();
-        }
-        return flag;
-    }
-
-    /**
-     * 文件名称验证
-     * 
-     * @param filename 文件名称
-     * @return true 正常 false 非法
-     */
-    public static boolean isValidFilename(String filename)
-    {
-        return filename.matches(FILENAME_PATTERN);
-    }
-
-    /**
-     * 检查文件是否可下载
-     * 
-     * @param resource 需要下载的文件
-     * @return true 正常 false 非法
-     */
-    public static boolean checkAllowDownload(String resource)
-    {
-        // 禁止目录上跳级别
-        if (StringUtils.contains(resource, ".."))
-        {
-            return false;
-        }
-
-        // 检查允许下载的文件规则
-        if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
-        {
-            return true;
-        }
-
-        // 不在允许下载的文件规则
-        return false;
-    }
-
-    /**
-     * 下载文件名重新编码
-     * 
-     * @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;
-    }
-
-    /**
-     * 下载文件名重新编码
-     *
-     * @param response 响应对象
-     * @param realFileName 真实文件名
-     */
-    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
-    {
-        String percentEncodedFileName = percentEncode(realFileName);
-
-        StringBuilder contentDispositionValue = new StringBuilder();
-        contentDispositionValue.append("attachment; filename=")
-                .append(percentEncodedFileName)
-                .append(";")
-                .append("filename*=")
-                .append("utf-8''")
-                .append(percentEncodedFileName);
-
-        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
-        response.setHeader("Content-disposition", contentDispositionValue.toString());
-        response.setHeader("download-filename", percentEncodedFileName);
-    }
-
-    /**
-     * 百分号编码工具方法
-     *
-     * @param s 需要百分号编码的字符串
-     * @return 百分号编码后的字符串
-     */
-    public static String percentEncode(String s) throws UnsupportedEncodingException
-    {
-        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
-        return encode.replaceAll("\\+", "%20");
-    }
-
-    /**
-     * 获取图像后缀
-     * 
-     * @param photoByte 图像数据
-     * @return 后缀名
-     */
-    public static String getFileExtendName(byte[] photoByte)
-    {
-        String strFileExtendName = "jpg";
-        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
-                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
-        {
-            strFileExtendName = "gif";
-        }
-        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
-        {
-            strFileExtendName = "jpg";
-        }
-        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
-        {
-            strFileExtendName = "bmp";
-        }
-        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
-        {
-            strFileExtendName = "png";
-        }
-        return strFileExtendName;
-    }
-
-    /**
-     * 获取文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi.png
-     * 
-     * @param fileName 路径名称
-     * @return 没有文件路径的名称
-     */
-    public static String getName(String fileName)
-    {
-        if (fileName == null)
-        {
-            return null;
-        }
-        int lastUnixPos = fileName.lastIndexOf('/');
-        int lastWindowsPos = fileName.lastIndexOf('\\');
-        int index = Math.max(lastUnixPos, lastWindowsPos);
-        return fileName.substring(index + 1);
-    }
-
-    /**
-     * 获取不带后缀文件名称 /profile/upload/2022/04/16/ruoyi.png -- ruoyi
-     * 
-     * @param fileName 路径名称
-     * @return 没有文件路径和后缀的名称
-     */
-    public static String getNameNotSuffix(String fileName)
-    {
-        if (fileName == null)
-        {
-            return null;
-        }
-        String baseName = FilenameUtils.getBaseName(fileName);
-        return baseName;
-    }
-}
+package com.acupuncture.common.utils.file;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.UnsupportedEncodingException;
+import java.net.URLEncoder;
+import java.nio.charset.StandardCharsets;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.uuid.IdUtils;
+import org.apache.commons.io.FilenameUtils;
+
+/**
+ * 文件处理工具类
+ * 
+ * @author acupuncture
+ */
+public class FileUtils
+{
+    public static String FILENAME_PATTERN = "[a-zA-Z0-9_\\-\\|\\.\\u4e00-\\u9fa5]+";
+
+    /**
+     * 输出指定文件的byte数组
+     * 
+     * @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
+        {
+            IOUtils.close(os);
+            IOUtils.close(fis);
+        }
+    }
+
+    /**
+     * 写数据到文件中
+     *
+     * @param data 数据
+     * @return 目标文件
+     * @throws IOException IO异常
+     */
+    public static String writeImportBytes(byte[] data) throws IOException
+    {
+        return writeBytes(data, RuoYiConfig.getImportPath());
+    }
+
+    /**
+     * 写数据到文件中
+     *
+     * @param data 数据
+     * @param uploadDir 目标文件
+     * @return 目标文件
+     * @throws IOException IO异常
+     */
+    public static String writeBytes(byte[] data, String uploadDir) throws IOException
+    {
+        FileOutputStream fos = null;
+        String pathName = "";
+        try
+        {
+            String extension = getFileExtendName(data);
+            pathName = DateUtils.datePath() + "/" + IdUtils.fastUUID() + "." + extension;
+            File file = FileUploadUtils.getAbsoluteFile(uploadDir, pathName);
+            fos = new FileOutputStream(file);
+            fos.write(data);
+        }
+        finally
+        {
+            IOUtils.close(fos);
+        }
+        return FileUploadUtils.getPathFileName(uploadDir, pathName);
+    }
+
+    /**
+     * 删除文件
+     * 
+     * @param filePath 文件
+     * @return
+     */
+    public static boolean deleteFile(String filePath)
+    {
+        boolean flag = false;
+        File file = new File(filePath);
+        // 路径为文件且不为空则进行删除
+        if (file.isFile() && file.exists())
+        {
+            flag = file.delete();
+        }
+        return flag;
+    }
+
+    /**
+     * 文件名称验证
+     * 
+     * @param filename 文件名称
+     * @return true 正常 false 非法
+     */
+    public static boolean isValidFilename(String filename)
+    {
+        return filename.matches(FILENAME_PATTERN);
+    }
+
+    /**
+     * 检查文件是否可下载
+     * 
+     * @param resource 需要下载的文件
+     * @return true 正常 false 非法
+     */
+    public static boolean checkAllowDownload(String resource)
+    {
+        // 禁止目录上跳级别
+        if (StringUtils.contains(resource, ".."))
+        {
+            return false;
+        }
+
+        // 检查允许下载的文件规则
+        if (ArrayUtils.contains(MimeTypeUtils.DEFAULT_ALLOWED_EXTENSION, FileTypeUtils.getFileType(resource)))
+        {
+            return true;
+        }
+
+        // 不在允许下载的文件规则
+        return false;
+    }
+
+    /**
+     * 下载文件名重新编码
+     * 
+     * @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;
+    }
+
+    /**
+     * 下载文件名重新编码
+     *
+     * @param response 响应对象
+     * @param realFileName 真实文件名
+     */
+    public static void setAttachmentResponseHeader(HttpServletResponse response, String realFileName) throws UnsupportedEncodingException
+    {
+        String percentEncodedFileName = percentEncode(realFileName);
+
+        StringBuilder contentDispositionValue = new StringBuilder();
+        contentDispositionValue.append("attachment; filename=")
+                .append(percentEncodedFileName)
+                .append(";")
+                .append("filename*=")
+                .append("utf-8''")
+                .append(percentEncodedFileName);
+
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition,download-filename");
+        response.setHeader("Content-disposition", contentDispositionValue.toString());
+        response.setHeader("download-filename", percentEncodedFileName);
+    }
+
+    /**
+     * 百分号编码工具方法
+     *
+     * @param s 需要百分号编码的字符串
+     * @return 百分号编码后的字符串
+     */
+    public static String percentEncode(String s) throws UnsupportedEncodingException
+    {
+        String encode = URLEncoder.encode(s, StandardCharsets.UTF_8.toString());
+        return encode.replaceAll("\\+", "%20");
+    }
+
+    /**
+     * 获取图像后缀
+     * 
+     * @param photoByte 图像数据
+     * @return 后缀名
+     */
+    public static String getFileExtendName(byte[] photoByte)
+    {
+        String strFileExtendName = "jpg";
+        if ((photoByte[0] == 71) && (photoByte[1] == 73) && (photoByte[2] == 70) && (photoByte[3] == 56)
+                && ((photoByte[4] == 55) || (photoByte[4] == 57)) && (photoByte[5] == 97))
+        {
+            strFileExtendName = "gif";
+        }
+        else if ((photoByte[6] == 74) && (photoByte[7] == 70) && (photoByte[8] == 73) && (photoByte[9] == 70))
+        {
+            strFileExtendName = "jpg";
+        }
+        else if ((photoByte[0] == 66) && (photoByte[1] == 77))
+        {
+            strFileExtendName = "bmp";
+        }
+        else if ((photoByte[1] == 80) && (photoByte[2] == 78) && (photoByte[3] == 71))
+        {
+            strFileExtendName = "png";
+        }
+        return strFileExtendName;
+    }
+
+    /**
+     * 获取文件名称 /profile/upload/2022/04/16/acupuncture.png -- acupuncture.png
+     * 
+     * @param fileName 路径名称
+     * @return 没有文件路径的名称
+     */
+    public static String getName(String fileName)
+    {
+        if (fileName == null)
+        {
+            return null;
+        }
+        int lastUnixPos = fileName.lastIndexOf('/');
+        int lastWindowsPos = fileName.lastIndexOf('\\');
+        int index = Math.max(lastUnixPos, lastWindowsPos);
+        return fileName.substring(index + 1);
+    }
+
+    /**
+     * 获取不带后缀文件名称 /profile/upload/2022/04/16/acupuncture.png -- acupuncture
+     * 
+     * @param fileName 路径名称
+     * @return 没有文件路径和后缀的名称
+     */
+    public static String getNameNotSuffix(String fileName)
+    {
+        if (fileName == null)
+        {
+            return null;
+        }
+        String baseName = FilenameUtils.getBaseName(fileName);
+        return baseName;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/ImageUtils.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/file/ImageUtils.java
index 9687bf3b..c58e22a9 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/ImageUtils.java
@@ -1,98 +1,98 @@
-package com.ruoyi.common.utils.file;
-
-import java.io.ByteArrayInputStream;
-import java.io.FileInputStream;
-import java.io.InputStream;
-import java.net.URL;
-import java.net.URLConnection;
-import java.util.Arrays;
-import org.apache.poi.util.IOUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 图片处理工具类
- *
- * @author ruoyi
- */
-public class ImageUtils
-{
-    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
-
-    public static byte[] getImage(String imagePath)
-    {
-        InputStream is = getFile(imagePath);
-        try
-        {
-            return IOUtils.toByteArray(is);
-        }
-        catch (Exception e)
-        {
-            log.error("图片加载异常 {}", e);
-            return null;
-        }
-        finally
-        {
-            IOUtils.closeQuietly(is);
-        }
-    }
-
-    public static InputStream getFile(String imagePath)
-    {
-        try
-        {
-            byte[] result = readFile(imagePath);
-            result = Arrays.copyOf(result, result.length);
-            return new ByteArrayInputStream(result);
-        }
-        catch (Exception e)
-        {
-            log.error("获取图片异常 {}", e);
-        }
-        return null;
-    }
-
-    /**
-     * 读取文件为字节数据
-     * 
-     * @param url 地址
-     * @return 字节数据
-     */
-    public static byte[] readFile(String url)
-    {
-        InputStream in = null;
-        try
-        {
-            if (url.startsWith("http"))
-            {
-                // 网络地址
-                URL urlObj = new URL(url);
-                URLConnection urlConnection = urlObj.openConnection();
-                urlConnection.setConnectTimeout(30 * 1000);
-                urlConnection.setReadTimeout(60 * 1000);
-                urlConnection.setDoInput(true);
-                in = urlConnection.getInputStream();
-            }
-            else
-            {
-                // 本机地址
-                String localPath = RuoYiConfig.getProfile();
-                String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
-                in = new FileInputStream(downloadPath);
-            }
-            return IOUtils.toByteArray(in);
-        }
-        catch (Exception e)
-        {
-            log.error("获取文件路径异常 {}", e);
-            return null;
-        }
-        finally
-        {
-            IOUtils.closeQuietly(in);
-        }
-    }
-}
+package com.acupuncture.common.utils.file;
+
+import java.io.ByteArrayInputStream;
+import java.io.FileInputStream;
+import java.io.InputStream;
+import java.net.URL;
+import java.net.URLConnection;
+import java.util.Arrays;
+import org.apache.poi.util.IOUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 图片处理工具类
+ *
+ * @author acupuncture
+ */
+public class ImageUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(ImageUtils.class);
+
+    public static byte[] getImage(String imagePath)
+    {
+        InputStream is = getFile(imagePath);
+        try
+        {
+            return IOUtils.toByteArray(is);
+        }
+        catch (Exception e)
+        {
+            log.error("图片加载异常 {}", e);
+            return null;
+        }
+        finally
+        {
+            IOUtils.closeQuietly(is);
+        }
+    }
+
+    public static InputStream getFile(String imagePath)
+    {
+        try
+        {
+            byte[] result = readFile(imagePath);
+            result = Arrays.copyOf(result, result.length);
+            return new ByteArrayInputStream(result);
+        }
+        catch (Exception e)
+        {
+            log.error("获取图片异常 {}", e);
+        }
+        return null;
+    }
+
+    /**
+     * 读取文件为字节数据
+     * 
+     * @param url 地址
+     * @return 字节数据
+     */
+    public static byte[] readFile(String url)
+    {
+        InputStream in = null;
+        try
+        {
+            if (url.startsWith("http"))
+            {
+                // 网络地址
+                URL urlObj = new URL(url);
+                URLConnection urlConnection = urlObj.openConnection();
+                urlConnection.setConnectTimeout(30 * 1000);
+                urlConnection.setReadTimeout(60 * 1000);
+                urlConnection.setDoInput(true);
+                in = urlConnection.getInputStream();
+            }
+            else
+            {
+                // 本机地址
+                String localPath = RuoYiConfig.getProfile();
+                String downloadPath = localPath + StringUtils.substringAfter(url, Constants.RESOURCE_PREFIX);
+                in = new FileInputStream(downloadPath);
+            }
+            return IOUtils.toByteArray(in);
+        }
+        catch (Exception e)
+        {
+            log.error("获取文件路径异常 {}", e);
+            return null;
+        }
+        finally
+        {
+            IOUtils.closeQuietly(in);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/MimeTypeUtils.java
similarity index 93%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/file/MimeTypeUtils.java
index 59358152..1d18f036 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/file/MimeTypeUtils.java
@@ -1,59 +1,59 @@
-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[] VIDEO_EXTENSION = { "mp4", "avi", "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",
-            // 视频格式
-            "mp4", "avi", "rmvb",
-            // 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 "";
-        }
-    }
-}
+package com.acupuncture.common.utils.file;
+
+/**
+ * 媒体类型工具类
+ * 
+ * @author acupuncture
+ */
+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[] VIDEO_EXTENSION = { "mp4", "avi", "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",
+            // 视频格式
+            "mp4", "avi", "rmvb",
+            // 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-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/html/EscapeUtil.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/html/EscapeUtil.java
index dda96c32..e448299c 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/html/EscapeUtil.java
@@ -1,167 +1,167 @@
-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);
-    }
-
-    /**
-     * 清除所有HTML标签,但是不删除标签内的内容
-     * 
-     * @param content 文本
-     * @return 清除标签后的文本
-     */
-    public static String clean(String content)
-    {
-        return new HTMLFilter().filter(content);
-    }
-
-    /**
-     * Escape编码
-     * 
-     * @param text 被编码的文本
-     * @return 编码后的字符
-     */
-    private static String encode(String text)
-    {
-        if (StringUtils.isEmpty(text))
-        {
-            return StringUtils.EMPTY;
-        }
-
-        final StringBuilder tmp = new StringBuilder(text.length() * 6);
-        char c;
-        for (int i = 0; i < text.length(); i++)
-        {
-            c = text.charAt(i);
-            if (c < 256)
-            {
-                tmp.append("%");
-                if (c < 16)
-                {
-                    tmp.append("0");
-                }
-                tmp.append(Integer.toString(c, 16));
-            }
-            else
-            {
-                tmp.append("%u");
-                if (c <= 0xfff)
-                {
-                    // issue#I49JU8@Gitee
-                    tmp.append("0");
-                }
-                tmp.append(Integer.toString(c, 16));
-            }
-        }
-        return tmp.toString();
-    }
-
-    /**
-     * Escape解码
-     * 
-     * @param content 被转义的内容
-     * @return 解码后的字符串
-     */
-    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>";
-        String escape = EscapeUtil.escape(html);
-        // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
-        // String html = "<123";
-        // String html = "123>";
-        System.out.println("clean: " + EscapeUtil.clean(html));
-        System.out.println("escape: " + escape);
-        System.out.println("unescape: " + EscapeUtil.unescape(escape));
-    }
-}
+package com.acupuncture.common.utils.html;
+
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 转义和反转义工具类
+ * 
+ * @author acupuncture
+ */
+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);
+    }
+
+    /**
+     * 清除所有HTML标签,但是不删除标签内的内容
+     * 
+     * @param content 文本
+     * @return 清除标签后的文本
+     */
+    public static String clean(String content)
+    {
+        return new HTMLFilter().filter(content);
+    }
+
+    /**
+     * Escape编码
+     * 
+     * @param text 被编码的文本
+     * @return 编码后的字符
+     */
+    private static String encode(String text)
+    {
+        if (StringUtils.isEmpty(text))
+        {
+            return StringUtils.EMPTY;
+        }
+
+        final StringBuilder tmp = new StringBuilder(text.length() * 6);
+        char c;
+        for (int i = 0; i < text.length(); i++)
+        {
+            c = text.charAt(i);
+            if (c < 256)
+            {
+                tmp.append("%");
+                if (c < 16)
+                {
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
+            }
+            else
+            {
+                tmp.append("%u");
+                if (c <= 0xfff)
+                {
+                    // issue#I49JU8@Gitee
+                    tmp.append("0");
+                }
+                tmp.append(Integer.toString(c, 16));
+            }
+        }
+        return tmp.toString();
+    }
+
+    /**
+     * Escape解码
+     * 
+     * @param content 被转义的内容
+     * @return 解码后的字符串
+     */
+    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>";
+        String escape = EscapeUtil.escape(html);
+        // String html = "<scr<script>ipt>alert(\"XSS\")</scr<script>ipt>";
+        // String html = "<123";
+        // String html = "123>";
+        System.out.println("clean: " + EscapeUtil.clean(html));
+        System.out.println("escape: " + escape);
+        System.out.println("unescape: " + EscapeUtil.unescape(escape));
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/html/HTMLFilter.java
similarity index 96%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/html/HTMLFilter.java
index 587ee6f6..5552c490 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/html/HTMLFilter.java
@@ -1,570 +1,570 @@
-package com.ruoyi.common.utils.html;
-
-import java.util.ArrayList;
-import java.util.Collections;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentMap;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * HTML过滤器,用于去除XSS漏洞隐患。
- *
- * @author ruoyi
- */
-public final class HTMLFilter
-{
-    /**
-     * regex flag union representing /si modifiers in php
-     **/
-    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
-    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
-    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
-    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
-    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
-    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
-    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
-    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
-    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
-    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
-    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
-    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
-    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
-    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
-    private static final Pattern P_END_ARROW = Pattern.compile("^>");
-    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
-    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
-    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
-    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
-    private static final Pattern P_AMP = Pattern.compile("&");
-    private static final Pattern P_QUOTE = Pattern.compile("\"");
-    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
-    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
-    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
-
-    // @xxx could grow large... maybe use sesat's ReferenceMap
-    private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
-    private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
-
-    /**
-     * set of allowed html elements, along with allowed attributes for each element
-     **/
-    private final Map<String, List<String>> vAllowed;
-    /**
-     * counts of open tags for each (allowable) html element
-     **/
-    private final Map<String, Integer> vTagCounts = new HashMap<>();
-
-    /**
-     * html elements which must always be self-closing (e.g. "<img />")
-     **/
-    private final String[] vSelfClosingTags;
-    /**
-     * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
-     **/
-    private final String[] vNeedClosingTags;
-    /**
-     * set of disallowed html elements
-     **/
-    private final String[] vDisallowed;
-    /**
-     * attributes which should be checked for valid protocols
-     **/
-    private final String[] vProtocolAtts;
-    /**
-     * allowed protocols
-     **/
-    private final String[] vAllowedProtocols;
-    /**
-     * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
-     **/
-    private final String[] vRemoveBlanks;
-    /**
-     * entities allowed within html markup
-     **/
-    private final String[] vAllowedEntities;
-    /**
-     * flag determining whether comments are allowed in input String.
-     */
-    private final boolean stripComment;
-    private final boolean encodeQuotes;
-    /**
-     * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
-     * becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
-     */
-    private final boolean alwaysMakeTags;
-
-    /**
-     * Default constructor.
-     */
-    public HTMLFilter()
-    {
-        vAllowed = new HashMap<>();
-
-        final ArrayList<String> a_atts = new ArrayList<>();
-        a_atts.add("href");
-        a_atts.add("target");
-        vAllowed.put("a", a_atts);
-
-        final ArrayList<String> img_atts = new ArrayList<>();
-        img_atts.add("src");
-        img_atts.add("width");
-        img_atts.add("height");
-        img_atts.add("alt");
-        vAllowed.put("img", img_atts);
-
-        final ArrayList<String> no_atts = new ArrayList<>();
-        vAllowed.put("b", no_atts);
-        vAllowed.put("strong", no_atts);
-        vAllowed.put("i", no_atts);
-        vAllowed.put("em", no_atts);
-
-        vSelfClosingTags = new String[] { "img" };
-        vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
-        vDisallowed = new String[] {};
-        vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
-        vProtocolAtts = new String[] { "src", "href" };
-        vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
-        vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
-        stripComment = true;
-        encodeQuotes = true;
-        alwaysMakeTags = false;
-    }
-
-    /**
-     * Map-parameter configurable constructor.
-     *
-     * @param conf map containing configuration. keys match field names.
-     */
-    @SuppressWarnings("unchecked")
-    public HTMLFilter(final Map<String, Object> conf)
-    {
-
-        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
-        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
-        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
-        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
-        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
-        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
-        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
-        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
-
-        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
-        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
-        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
-        vDisallowed = (String[]) conf.get("vDisallowed");
-        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
-        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
-        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
-        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
-        stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
-        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
-        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
-    }
-
-    private void reset()
-    {
-        vTagCounts.clear();
-    }
-
-    // ---------------------------------------------------------------
-    // my versions of some PHP library functions
-    public static String chr(final int decimal)
-    {
-        return String.valueOf((char) decimal);
-    }
-
-    public static String htmlSpecialChars(final String s)
-    {
-        String result = s;
-        result = regexReplace(P_AMP, "&amp;", result);
-        result = regexReplace(P_QUOTE, "&quot;", result);
-        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
-        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
-        return result;
-    }
-
-    // ---------------------------------------------------------------
-
-    /**
-     * given a user submitted input String, filter out any invalid or restricted html.
-     *
-     * @param input text (i.e. submitted by a user) than may contain html
-     * @return "clean" version of input, with only valid, whitelisted html elements allowed
-     */
-    public String filter(final String input)
-    {
-        reset();
-        String s = input;
-
-        s = escapeComments(s);
-
-        s = balanceHTML(s);
-
-        s = checkTags(s);
-
-        s = processRemoveBlanks(s);
-
-        // s = validateEntities(s);
-
-        return s;
-    }
-
-    public boolean isAlwaysMakeTags()
-    {
-        return alwaysMakeTags;
-    }
-
-    public boolean isStripComments()
-    {
-        return stripComment;
-    }
-
-    private String escapeComments(final String s)
-    {
-        final Matcher m = P_COMMENTS.matcher(s);
-        final StringBuffer buf = new StringBuffer();
-        if (m.find())
-        {
-            final String match = m.group(1); // (.*?)
-            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
-        }
-        m.appendTail(buf);
-
-        return buf.toString();
-    }
-
-    private String balanceHTML(String s)
-    {
-        if (alwaysMakeTags)
-        {
-            //
-            // try and form html
-            //
-            s = regexReplace(P_END_ARROW, "", s);
-            // 不追加结束标签
-            s = regexReplace(P_BODY_TO_END, "<$1>", s);
-            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
-
-        }
-        else
-        {
-            //
-            // escape stray brackets
-            //
-            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
-            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
-
-            //
-            // the last regexp causes '<>' entities to appear
-            // (we need to do a lookahead assertion so that the last bracket can
-            // be used in the next pass of the regexp)
-            //
-            s = regexReplace(P_BOTH_ARROWS, "", s);
-        }
-
-        return s;
-    }
-
-    private String checkTags(String s)
-    {
-        Matcher m = P_TAGS.matcher(s);
-
-        final StringBuffer buf = new StringBuffer();
-        while (m.find())
-        {
-            String replaceStr = m.group(1);
-            replaceStr = processTag(replaceStr);
-            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
-        }
-        m.appendTail(buf);
-
-        // these get tallied in processTag
-        // (remember to reset before subsequent calls to filter method)
-        final StringBuilder sBuilder = new StringBuilder(buf.toString());
-        for (String key : vTagCounts.keySet())
-        {
-            for (int ii = 0; ii < vTagCounts.get(key); ii++)
-            {
-                sBuilder.append("</").append(key).append(">");
-            }
-        }
-        s = sBuilder.toString();
-
-        return s;
-    }
-
-    private String processRemoveBlanks(final String s)
-    {
-        String result = s;
-        for (String tag : vRemoveBlanks)
-        {
-            if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
-            {
-                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
-            }
-            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
-            if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
-            {
-                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
-            }
-            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
-        }
-
-        return result;
-    }
-
-    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
-    {
-        Matcher m = regex_pattern.matcher(s);
-        return m.replaceAll(replacement);
-    }
-
-    private String processTag(final String s)
-    {
-        // ending tags
-        Matcher m = P_END_TAG.matcher(s);
-        if (m.find())
-        {
-            final String name = m.group(1).toLowerCase();
-            if (allowed(name))
-            {
-                if (!inArray(name, vSelfClosingTags))
-                {
-                    if (vTagCounts.containsKey(name))
-                    {
-                        vTagCounts.put(name, vTagCounts.get(name) - 1);
-                        return "</" + name + ">";
-                    }
-                }
-            }
-        }
-
-        // starting tags
-        m = P_START_TAG.matcher(s);
-        if (m.find())
-        {
-            final String name = m.group(1).toLowerCase();
-            final String body = m.group(2);
-            String ending = m.group(3);
-
-            // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
-            if (allowed(name))
-            {
-                final StringBuilder params = new StringBuilder();
-
-                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
-                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
-                final List<String> paramNames = new ArrayList<>();
-                final List<String> paramValues = new ArrayList<>();
-                while (m2.find())
-                {
-                    paramNames.add(m2.group(1)); // ([a-z0-9]+)
-                    paramValues.add(m2.group(3)); // (.*?)
-                }
-                while (m3.find())
-                {
-                    paramNames.add(m3.group(1)); // ([a-z0-9]+)
-                    paramValues.add(m3.group(3)); // ([^\"\\s']+)
-                }
-
-                String paramName, paramValue;
-                for (int ii = 0; ii < paramNames.size(); ii++)
-                {
-                    paramName = paramNames.get(ii).toLowerCase();
-                    paramValue = paramValues.get(ii);
-
-                    // debug( "paramName='" + paramName + "'" );
-                    // debug( "paramValue='" + paramValue + "'" );
-                    // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
-
-                    if (allowedAttribute(name, paramName))
-                    {
-                        if (inArray(paramName, vProtocolAtts))
-                        {
-                            paramValue = processParamProtocol(paramValue);
-                        }
-                        params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
-                    }
-                }
-
-                if (inArray(name, vSelfClosingTags))
-                {
-                    ending = " /";
-                }
-
-                if (inArray(name, vNeedClosingTags))
-                {
-                    ending = "";
-                }
-
-                if (ending == null || ending.length() < 1)
-                {
-                    if (vTagCounts.containsKey(name))
-                    {
-                        vTagCounts.put(name, vTagCounts.get(name) + 1);
-                    }
-                    else
-                    {
-                        vTagCounts.put(name, 1);
-                    }
-                }
-                else
-                {
-                    ending = " /";
-                }
-                return "<" + name + params + ending + ">";
-            }
-            else
-            {
-                return "";
-            }
-        }
-
-        // comments
-        m = P_COMMENT.matcher(s);
-        if (!stripComment && m.find())
-        {
-            return "<" + m.group() + ">";
-        }
-
-        return "";
-    }
-
-    private String processParamProtocol(String s)
-    {
-        s = decodeEntities(s);
-        final Matcher m = P_PROTOCOL.matcher(s);
-        if (m.find())
-        {
-            final String protocol = m.group(1);
-            if (!inArray(protocol, vAllowedProtocols))
-            {
-                // bad protocol, turn into local anchor link instead
-                s = "#" + s.substring(protocol.length() + 1);
-                if (s.startsWith("#//"))
-                {
-                    s = "#" + s.substring(3);
-                }
-            }
-        }
-
-        return s;
-    }
-
-    private String decodeEntities(String s)
-    {
-        StringBuffer buf = new StringBuffer();
-
-        Matcher m = P_ENTITY.matcher(s);
-        while (m.find())
-        {
-            final String match = m.group(1);
-            final int decimal = Integer.decode(match).intValue();
-            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
-        }
-        m.appendTail(buf);
-        s = buf.toString();
-
-        buf = new StringBuffer();
-        m = P_ENTITY_UNICODE.matcher(s);
-        while (m.find())
-        {
-            final String match = m.group(1);
-            final int decimal = Integer.valueOf(match, 16).intValue();
-            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
-        }
-        m.appendTail(buf);
-        s = buf.toString();
-
-        buf = new StringBuffer();
-        m = P_ENCODE.matcher(s);
-        while (m.find())
-        {
-            final String match = m.group(1);
-            final int decimal = Integer.valueOf(match, 16).intValue();
-            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
-        }
-        m.appendTail(buf);
-        s = buf.toString();
-
-        s = validateEntities(s);
-        return s;
-    }
-
-    private String validateEntities(final String s)
-    {
-        StringBuffer buf = new StringBuffer();
-
-        // validate entities throughout the string
-        Matcher m = P_VALID_ENTITIES.matcher(s);
-        while (m.find())
-        {
-            final String one = m.group(1); // ([^&;]*)
-            final String two = m.group(2); // (?=(;|&|$))
-            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
-        }
-        m.appendTail(buf);
-
-        return encodeQuotes(buf.toString());
-    }
-
-    private String encodeQuotes(final String s)
-    {
-        if (encodeQuotes)
-        {
-            StringBuffer buf = new StringBuffer();
-            Matcher m = P_VALID_QUOTES.matcher(s);
-            while (m.find())
-            {
-                final String one = m.group(1); // (>|^)
-                final String two = m.group(2); // ([^<]+?)
-                final String three = m.group(3); // (<|$)
-                // 不替换双引号为&quot;,防止json格式无效 regexReplace(P_QUOTE, "&quot;", two)
-                m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
-            }
-            m.appendTail(buf);
-            return buf.toString();
-        }
-        else
-        {
-            return s;
-        }
-    }
-
-    private String checkEntity(final String preamble, final String term)
-    {
-
-        return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
-    }
-
-    private boolean isValidEntity(final String entity)
-    {
-        return inArray(entity, vAllowedEntities);
-    }
-
-    private static boolean inArray(final String s, final String[] array)
-    {
-        for (String item : array)
-        {
-            if (item != null && item.equals(s))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
-
-    private boolean allowed(final String name)
-    {
-        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
-    }
-
-    private boolean allowedAttribute(final String name, final String paramName)
-    {
-        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
-    }
+package com.acupuncture.common.utils.html;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * HTML过滤器,用于去除XSS漏洞隐患。
+ *
+ * @author acupuncture
+ */
+public final class HTMLFilter
+{
+    /**
+     * regex flag union representing /si modifiers in php
+     **/
+    private static final int REGEX_FLAGS_SI = Pattern.CASE_INSENSITIVE | Pattern.DOTALL;
+    private static final Pattern P_COMMENTS = Pattern.compile("<!--(.*?)-->", Pattern.DOTALL);
+    private static final Pattern P_COMMENT = Pattern.compile("^!--(.*)--$", REGEX_FLAGS_SI);
+    private static final Pattern P_TAGS = Pattern.compile("<(.*?)>", Pattern.DOTALL);
+    private static final Pattern P_END_TAG = Pattern.compile("^/([a-z0-9]+)", REGEX_FLAGS_SI);
+    private static final Pattern P_START_TAG = Pattern.compile("^([a-z0-9]+)(.*?)(/?)$", REGEX_FLAGS_SI);
+    private static final Pattern P_QUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)=([\"'])(.*?)\\2", REGEX_FLAGS_SI);
+    private static final Pattern P_UNQUOTED_ATTRIBUTES = Pattern.compile("([a-z0-9]+)(=)([^\"\\s']+)", REGEX_FLAGS_SI);
+    private static final Pattern P_PROTOCOL = Pattern.compile("^([^:]+):", REGEX_FLAGS_SI);
+    private static final Pattern P_ENTITY = Pattern.compile("&#(\\d+);?");
+    private static final Pattern P_ENTITY_UNICODE = Pattern.compile("&#x([0-9a-f]+);?");
+    private static final Pattern P_ENCODE = Pattern.compile("%([0-9a-f]{2});?");
+    private static final Pattern P_VALID_ENTITIES = Pattern.compile("&([^&;]*)(?=(;|&|$))");
+    private static final Pattern P_VALID_QUOTES = Pattern.compile("(>|^)([^<]+?)(<|$)", Pattern.DOTALL);
+    private static final Pattern P_END_ARROW = Pattern.compile("^>");
+    private static final Pattern P_BODY_TO_END = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_XML_CONTENT = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_STRAY_LEFT_ARROW = Pattern.compile("<([^>]*?)(?=<|$)");
+    private static final Pattern P_STRAY_RIGHT_ARROW = Pattern.compile("(^|>)([^<]*?)(?=>)");
+    private static final Pattern P_AMP = Pattern.compile("&");
+    private static final Pattern P_QUOTE = Pattern.compile("\"");
+    private static final Pattern P_LEFT_ARROW = Pattern.compile("<");
+    private static final Pattern P_RIGHT_ARROW = Pattern.compile(">");
+    private static final Pattern P_BOTH_ARROWS = Pattern.compile("<>");
+
+    // @xxx could grow large... maybe use sesat's ReferenceMap
+    private static final ConcurrentMap<String, Pattern> P_REMOVE_PAIR_BLANKS = new ConcurrentHashMap<>();
+    private static final ConcurrentMap<String, Pattern> P_REMOVE_SELF_BLANKS = new ConcurrentHashMap<>();
+
+    /**
+     * set of allowed html elements, along with allowed attributes for each element
+     **/
+    private final Map<String, List<String>> vAllowed;
+    /**
+     * counts of open tags for each (allowable) html element
+     **/
+    private final Map<String, Integer> vTagCounts = new HashMap<>();
+
+    /**
+     * html elements which must always be self-closing (e.g. "<img />")
+     **/
+    private final String[] vSelfClosingTags;
+    /**
+     * html elements which must always have separate opening and closing tags (e.g. "<b></b>")
+     **/
+    private final String[] vNeedClosingTags;
+    /**
+     * set of disallowed html elements
+     **/
+    private final String[] vDisallowed;
+    /**
+     * attributes which should be checked for valid protocols
+     **/
+    private final String[] vProtocolAtts;
+    /**
+     * allowed protocols
+     **/
+    private final String[] vAllowedProtocols;
+    /**
+     * tags which should be removed if they contain no content (e.g. "<b></b>" or "<b />")
+     **/
+    private final String[] vRemoveBlanks;
+    /**
+     * entities allowed within html markup
+     **/
+    private final String[] vAllowedEntities;
+    /**
+     * flag determining whether comments are allowed in input String.
+     */
+    private final boolean stripComment;
+    private final boolean encodeQuotes;
+    /**
+     * flag determining whether to try to make tags when presented with "unbalanced" angle brackets (e.g. "<b text </b>"
+     * becomes "<b> text </b>"). If set to false, unbalanced angle brackets will be html escaped.
+     */
+    private final boolean alwaysMakeTags;
+
+    /**
+     * Default constructor.
+     */
+    public HTMLFilter()
+    {
+        vAllowed = new HashMap<>();
+
+        final ArrayList<String> a_atts = new ArrayList<>();
+        a_atts.add("href");
+        a_atts.add("target");
+        vAllowed.put("a", a_atts);
+
+        final ArrayList<String> img_atts = new ArrayList<>();
+        img_atts.add("src");
+        img_atts.add("width");
+        img_atts.add("height");
+        img_atts.add("alt");
+        vAllowed.put("img", img_atts);
+
+        final ArrayList<String> no_atts = new ArrayList<>();
+        vAllowed.put("b", no_atts);
+        vAllowed.put("strong", no_atts);
+        vAllowed.put("i", no_atts);
+        vAllowed.put("em", no_atts);
+
+        vSelfClosingTags = new String[] { "img" };
+        vNeedClosingTags = new String[] { "a", "b", "strong", "i", "em" };
+        vDisallowed = new String[] {};
+        vAllowedProtocols = new String[] { "http", "mailto", "https" }; // no ftp.
+        vProtocolAtts = new String[] { "src", "href" };
+        vRemoveBlanks = new String[] { "a", "b", "strong", "i", "em" };
+        vAllowedEntities = new String[] { "amp", "gt", "lt", "quot" };
+        stripComment = true;
+        encodeQuotes = true;
+        alwaysMakeTags = false;
+    }
+
+    /**
+     * Map-parameter configurable constructor.
+     *
+     * @param conf map containing configuration. keys match field names.
+     */
+    @SuppressWarnings("unchecked")
+    public HTMLFilter(final Map<String, Object> conf)
+    {
+
+        assert conf.containsKey("vAllowed") : "configuration requires vAllowed";
+        assert conf.containsKey("vSelfClosingTags") : "configuration requires vSelfClosingTags";
+        assert conf.containsKey("vNeedClosingTags") : "configuration requires vNeedClosingTags";
+        assert conf.containsKey("vDisallowed") : "configuration requires vDisallowed";
+        assert conf.containsKey("vAllowedProtocols") : "configuration requires vAllowedProtocols";
+        assert conf.containsKey("vProtocolAtts") : "configuration requires vProtocolAtts";
+        assert conf.containsKey("vRemoveBlanks") : "configuration requires vRemoveBlanks";
+        assert conf.containsKey("vAllowedEntities") : "configuration requires vAllowedEntities";
+
+        vAllowed = Collections.unmodifiableMap((HashMap<String, List<String>>) conf.get("vAllowed"));
+        vSelfClosingTags = (String[]) conf.get("vSelfClosingTags");
+        vNeedClosingTags = (String[]) conf.get("vNeedClosingTags");
+        vDisallowed = (String[]) conf.get("vDisallowed");
+        vAllowedProtocols = (String[]) conf.get("vAllowedProtocols");
+        vProtocolAtts = (String[]) conf.get("vProtocolAtts");
+        vRemoveBlanks = (String[]) conf.get("vRemoveBlanks");
+        vAllowedEntities = (String[]) conf.get("vAllowedEntities");
+        stripComment = conf.containsKey("stripComment") ? (Boolean) conf.get("stripComment") : true;
+        encodeQuotes = conf.containsKey("encodeQuotes") ? (Boolean) conf.get("encodeQuotes") : true;
+        alwaysMakeTags = conf.containsKey("alwaysMakeTags") ? (Boolean) conf.get("alwaysMakeTags") : true;
+    }
+
+    private void reset()
+    {
+        vTagCounts.clear();
+    }
+
+    // ---------------------------------------------------------------
+    // my versions of some PHP library functions
+    public static String chr(final int decimal)
+    {
+        return String.valueOf((char) decimal);
+    }
+
+    public static String htmlSpecialChars(final String s)
+    {
+        String result = s;
+        result = regexReplace(P_AMP, "&amp;", result);
+        result = regexReplace(P_QUOTE, "&quot;", result);
+        result = regexReplace(P_LEFT_ARROW, "&lt;", result);
+        result = regexReplace(P_RIGHT_ARROW, "&gt;", result);
+        return result;
+    }
+
+    // ---------------------------------------------------------------
+
+    /**
+     * given a user submitted input String, filter out any invalid or restricted html.
+     *
+     * @param input text (i.e. submitted by a user) than may contain html
+     * @return "clean" version of input, with only valid, whitelisted html elements allowed
+     */
+    public String filter(final String input)
+    {
+        reset();
+        String s = input;
+
+        s = escapeComments(s);
+
+        s = balanceHTML(s);
+
+        s = checkTags(s);
+
+        s = processRemoveBlanks(s);
+
+        // s = validateEntities(s);
+
+        return s;
+    }
+
+    public boolean isAlwaysMakeTags()
+    {
+        return alwaysMakeTags;
+    }
+
+    public boolean isStripComments()
+    {
+        return stripComment;
+    }
+
+    private String escapeComments(final String s)
+    {
+        final Matcher m = P_COMMENTS.matcher(s);
+        final StringBuffer buf = new StringBuffer();
+        if (m.find())
+        {
+            final String match = m.group(1); // (.*?)
+            m.appendReplacement(buf, Matcher.quoteReplacement("<!--" + htmlSpecialChars(match) + "-->"));
+        }
+        m.appendTail(buf);
+
+        return buf.toString();
+    }
+
+    private String balanceHTML(String s)
+    {
+        if (alwaysMakeTags)
+        {
+            //
+            // try and form html
+            //
+            s = regexReplace(P_END_ARROW, "", s);
+            // 不追加结束标签
+            s = regexReplace(P_BODY_TO_END, "<$1>", s);
+            s = regexReplace(P_XML_CONTENT, "$1<$2", s);
+
+        }
+        else
+        {
+            //
+            // escape stray brackets
+            //
+            s = regexReplace(P_STRAY_LEFT_ARROW, "&lt;$1", s);
+            s = regexReplace(P_STRAY_RIGHT_ARROW, "$1$2&gt;<", s);
+
+            //
+            // the last regexp causes '<>' entities to appear
+            // (we need to do a lookahead assertion so that the last bracket can
+            // be used in the next pass of the regexp)
+            //
+            s = regexReplace(P_BOTH_ARROWS, "", s);
+        }
+
+        return s;
+    }
+
+    private String checkTags(String s)
+    {
+        Matcher m = P_TAGS.matcher(s);
+
+        final StringBuffer buf = new StringBuffer();
+        while (m.find())
+        {
+            String replaceStr = m.group(1);
+            replaceStr = processTag(replaceStr);
+            m.appendReplacement(buf, Matcher.quoteReplacement(replaceStr));
+        }
+        m.appendTail(buf);
+
+        // these get tallied in processTag
+        // (remember to reset before subsequent calls to filter method)
+        final StringBuilder sBuilder = new StringBuilder(buf.toString());
+        for (String key : vTagCounts.keySet())
+        {
+            for (int ii = 0; ii < vTagCounts.get(key); ii++)
+            {
+                sBuilder.append("</").append(key).append(">");
+            }
+        }
+        s = sBuilder.toString();
+
+        return s;
+    }
+
+    private String processRemoveBlanks(final String s)
+    {
+        String result = s;
+        for (String tag : vRemoveBlanks)
+        {
+            if (!P_REMOVE_PAIR_BLANKS.containsKey(tag))
+            {
+                P_REMOVE_PAIR_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?></" + tag + ">"));
+            }
+            result = regexReplace(P_REMOVE_PAIR_BLANKS.get(tag), "", result);
+            if (!P_REMOVE_SELF_BLANKS.containsKey(tag))
+            {
+                P_REMOVE_SELF_BLANKS.putIfAbsent(tag, Pattern.compile("<" + tag + "(\\s[^>]*)?/>"));
+            }
+            result = regexReplace(P_REMOVE_SELF_BLANKS.get(tag), "", result);
+        }
+
+        return result;
+    }
+
+    private static String regexReplace(final Pattern regex_pattern, final String replacement, final String s)
+    {
+        Matcher m = regex_pattern.matcher(s);
+        return m.replaceAll(replacement);
+    }
+
+    private String processTag(final String s)
+    {
+        // ending tags
+        Matcher m = P_END_TAG.matcher(s);
+        if (m.find())
+        {
+            final String name = m.group(1).toLowerCase();
+            if (allowed(name))
+            {
+                if (!inArray(name, vSelfClosingTags))
+                {
+                    if (vTagCounts.containsKey(name))
+                    {
+                        vTagCounts.put(name, vTagCounts.get(name) - 1);
+                        return "</" + name + ">";
+                    }
+                }
+            }
+        }
+
+        // starting tags
+        m = P_START_TAG.matcher(s);
+        if (m.find())
+        {
+            final String name = m.group(1).toLowerCase();
+            final String body = m.group(2);
+            String ending = m.group(3);
+
+            // debug( "in a starting tag, name='" + name + "'; body='" + body + "'; ending='" + ending + "'" );
+            if (allowed(name))
+            {
+                final StringBuilder params = new StringBuilder();
+
+                final Matcher m2 = P_QUOTED_ATTRIBUTES.matcher(body);
+                final Matcher m3 = P_UNQUOTED_ATTRIBUTES.matcher(body);
+                final List<String> paramNames = new ArrayList<>();
+                final List<String> paramValues = new ArrayList<>();
+                while (m2.find())
+                {
+                    paramNames.add(m2.group(1)); // ([a-z0-9]+)
+                    paramValues.add(m2.group(3)); // (.*?)
+                }
+                while (m3.find())
+                {
+                    paramNames.add(m3.group(1)); // ([a-z0-9]+)
+                    paramValues.add(m3.group(3)); // ([^\"\\s']+)
+                }
+
+                String paramName, paramValue;
+                for (int ii = 0; ii < paramNames.size(); ii++)
+                {
+                    paramName = paramNames.get(ii).toLowerCase();
+                    paramValue = paramValues.get(ii);
+
+                    // debug( "paramName='" + paramName + "'" );
+                    // debug( "paramValue='" + paramValue + "'" );
+                    // debug( "allowed? " + vAllowed.get( name ).contains( paramName ) );
+
+                    if (allowedAttribute(name, paramName))
+                    {
+                        if (inArray(paramName, vProtocolAtts))
+                        {
+                            paramValue = processParamProtocol(paramValue);
+                        }
+                        params.append(' ').append(paramName).append("=\\\"").append(paramValue).append("\\\"");
+                    }
+                }
+
+                if (inArray(name, vSelfClosingTags))
+                {
+                    ending = " /";
+                }
+
+                if (inArray(name, vNeedClosingTags))
+                {
+                    ending = "";
+                }
+
+                if (ending == null || ending.length() < 1)
+                {
+                    if (vTagCounts.containsKey(name))
+                    {
+                        vTagCounts.put(name, vTagCounts.get(name) + 1);
+                    }
+                    else
+                    {
+                        vTagCounts.put(name, 1);
+                    }
+                }
+                else
+                {
+                    ending = " /";
+                }
+                return "<" + name + params + ending + ">";
+            }
+            else
+            {
+                return "";
+            }
+        }
+
+        // comments
+        m = P_COMMENT.matcher(s);
+        if (!stripComment && m.find())
+        {
+            return "<" + m.group() + ">";
+        }
+
+        return "";
+    }
+
+    private String processParamProtocol(String s)
+    {
+        s = decodeEntities(s);
+        final Matcher m = P_PROTOCOL.matcher(s);
+        if (m.find())
+        {
+            final String protocol = m.group(1);
+            if (!inArray(protocol, vAllowedProtocols))
+            {
+                // bad protocol, turn into local anchor link instead
+                s = "#" + s.substring(protocol.length() + 1);
+                if (s.startsWith("#//"))
+                {
+                    s = "#" + s.substring(3);
+                }
+            }
+        }
+
+        return s;
+    }
+
+    private String decodeEntities(String s)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        Matcher m = P_ENTITY.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.decode(match).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENTITY_UNICODE.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        buf = new StringBuffer();
+        m = P_ENCODE.matcher(s);
+        while (m.find())
+        {
+            final String match = m.group(1);
+            final int decimal = Integer.valueOf(match, 16).intValue();
+            m.appendReplacement(buf, Matcher.quoteReplacement(chr(decimal)));
+        }
+        m.appendTail(buf);
+        s = buf.toString();
+
+        s = validateEntities(s);
+        return s;
+    }
+
+    private String validateEntities(final String s)
+    {
+        StringBuffer buf = new StringBuffer();
+
+        // validate entities throughout the string
+        Matcher m = P_VALID_ENTITIES.matcher(s);
+        while (m.find())
+        {
+            final String one = m.group(1); // ([^&;]*)
+            final String two = m.group(2); // (?=(;|&|$))
+            m.appendReplacement(buf, Matcher.quoteReplacement(checkEntity(one, two)));
+        }
+        m.appendTail(buf);
+
+        return encodeQuotes(buf.toString());
+    }
+
+    private String encodeQuotes(final String s)
+    {
+        if (encodeQuotes)
+        {
+            StringBuffer buf = new StringBuffer();
+            Matcher m = P_VALID_QUOTES.matcher(s);
+            while (m.find())
+            {
+                final String one = m.group(1); // (>|^)
+                final String two = m.group(2); // ([^<]+?)
+                final String three = m.group(3); // (<|$)
+                // 不替换双引号为&quot;,防止json格式无效 regexReplace(P_QUOTE, "&quot;", two)
+                m.appendReplacement(buf, Matcher.quoteReplacement(one + two + three));
+            }
+            m.appendTail(buf);
+            return buf.toString();
+        }
+        else
+        {
+            return s;
+        }
+    }
+
+    private String checkEntity(final String preamble, final String term)
+    {
+
+        return ";".equals(term) && isValidEntity(preamble) ? '&' + preamble : "&amp;" + preamble;
+    }
+
+    private boolean isValidEntity(final String entity)
+    {
+        return inArray(entity, vAllowedEntities);
+    }
+
+    private static boolean inArray(final String s, final String[] array)
+    {
+        for (String item : array)
+        {
+            if (item != null && item.equals(s))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private boolean allowed(final String name)
+    {
+        return (vAllowed.isEmpty() || vAllowed.containsKey(name)) && !inArray(name, vDisallowed);
+    }
+
+    private boolean allowedAttribute(final String name, final String paramName)
+    {
+        return allowed(name) && (vAllowed.isEmpty() || vAllowed.get(name).contains(paramName));
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpHelper.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpHelper.java
index 8baad384..2b58a0ce 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpHelper.java
@@ -1,55 +1,55 @@
-package com.ruoyi.common.utils.http;
-
-import java.io.BufferedReader;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.nio.charset.StandardCharsets;
-import javax.servlet.ServletRequest;
-import org.apache.commons.lang3.exception.ExceptionUtils;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-
-/**
- * 通用http工具封装
- * 
- * @author ruoyi
- */
-public class HttpHelper
-{
-    private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
-
-    public static String getBodyString(ServletRequest request)
-    {
-        StringBuilder sb = new StringBuilder();
-        BufferedReader reader = null;
-        try (InputStream inputStream = request.getInputStream())
-        {
-            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
-            String line = "";
-            while ((line = reader.readLine()) != null)
-            {
-                sb.append(line);
-            }
-        }
-        catch (IOException e)
-        {
-            LOGGER.warn("getBodyString出现问题!");
-        }
-        finally
-        {
-            if (reader != null)
-            {
-                try
-                {
-                    reader.close();
-                }
-                catch (IOException e)
-                {
-                    LOGGER.error(ExceptionUtils.getMessage(e));
-                }
-            }
-        }
-        return sb.toString();
-    }
-}
+package com.acupuncture.common.utils.http;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.nio.charset.StandardCharsets;
+import javax.servlet.ServletRequest;
+import org.apache.commons.lang3.exception.ExceptionUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 通用http工具封装
+ * 
+ * @author acupuncture
+ */
+public class HttpHelper
+{
+    private static final Logger LOGGER = LoggerFactory.getLogger(HttpHelper.class);
+
+    public static String getBodyString(ServletRequest request)
+    {
+        StringBuilder sb = new StringBuilder();
+        BufferedReader reader = null;
+        try (InputStream inputStream = request.getInputStream())
+        {
+            reader = new BufferedReader(new InputStreamReader(inputStream, StandardCharsets.UTF_8));
+            String line = "";
+            while ((line = reader.readLine()) != null)
+            {
+                sb.append(line);
+            }
+        }
+        catch (IOException e)
+        {
+            LOGGER.warn("getBodyString出现问题!");
+        }
+        finally
+        {
+            if (reader != null)
+            {
+                try
+                {
+                    reader.close();
+                }
+                catch (IOException e)
+                {
+                    LOGGER.error(ExceptionUtils.getMessage(e));
+                }
+            }
+        }
+        return sb.toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpUtils.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpUtils.java
index d3b61cad..e56825dd 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/http/HttpUtils.java
@@ -1,274 +1,274 @@
-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.nio.charset.StandardCharsets;
-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;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 通用http发送方法
- * 
- * @author ruoyi
- */
-public class HttpUtils
-{
-    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
-
-    /**
-     * 向指定 URL 发送GET方法的请求
-     *
-     * @param url 发送请求的 URL
-     * @return 所代表远程资源的响应结果
-     */
-    public static String sendGet(String url)
-    {
-        return sendGet(url, StringUtils.EMPTY);
-    }
-
-    /**
-     * 向指定 URL 发送GET方法的请求
-     *
-     * @param url 发送请求的 URL
-     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
-     * @return 所代表远程资源的响应结果
-     */
-    public static String sendGet(String url, String param)
-    {
-        return sendGet(url, param, Constants.UTF8);
-    }
-
-    /**
-     * 向指定 URL 发送GET方法的请求
-     *
-     * @param url 发送请求的 URL
-     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
-     * @param contentType 编码类型
-     * @return 所代表远程资源的响应结果
-     */
-    public static String sendGet(String url, String param, String contentType)
-    {
-        StringBuilder result = new StringBuilder();
-        BufferedReader in = null;
-        try
-        {
-            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
-            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/5.0 (Windows NT 10.0; Win64; x64)");
-            connection.connect();
-            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
-            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 发送POST方法的请求
-     *
-     * @param url 发送请求的 URL
-     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
-     * @return 所代表远程资源的响应结果
-     */
-    public static String sendPost(String url, String param)
-    {
-        PrintWriter out = null;
-        BufferedReader in = null;
-        StringBuilder result = new StringBuilder();
-        try
-        {
-            log.info("sendPost - {}", url);
-            URL realUrl = new URL(url);
-            URLConnection conn = realUrl.openConnection();
-            conn.setRequestProperty("accept", "*/*");
-            conn.setRequestProperty("connection", "Keep-Alive");
-            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
-            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(), StandardCharsets.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/5.0 (Windows NT 10.0; Win64; x64)");
-            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 && !"".equals(ret.trim()))
-                {
-                    result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.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;
-        }
-    }
+package com.acupuncture.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.nio.charset.StandardCharsets;
+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;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 通用http发送方法
+ * 
+ * @author acupuncture
+ */
+public class HttpUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(HttpUtils.class);
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url)
+    {
+        return sendGet(url, StringUtils.EMPTY);
+    }
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param)
+    {
+        return sendGet(url, param, Constants.UTF8);
+    }
+
+    /**
+     * 向指定 URL 发送GET方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @param contentType 编码类型
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendGet(String url, String param, String contentType)
+    {
+        StringBuilder result = new StringBuilder();
+        BufferedReader in = null;
+        try
+        {
+            String urlNameString = StringUtils.isNotBlank(param) ? url + "?" + param : url;
+            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/5.0 (Windows NT 10.0; Win64; x64)");
+            connection.connect();
+            in = new BufferedReader(new InputStreamReader(connection.getInputStream(), contentType));
+            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 发送POST方法的请求
+     *
+     * @param url 发送请求的 URL
+     * @param param 请求参数,请求参数应该是 name1=value1&name2=value2 的形式。
+     * @return 所代表远程资源的响应结果
+     */
+    public static String sendPost(String url, String param)
+    {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            log.info("sendPost - {}", url);
+            URL realUrl = new URL(url);
+            URLConnection conn = realUrl.openConnection();
+            conn.setRequestProperty("accept", "*/*");
+            conn.setRequestProperty("connection", "Keep-Alive");
+            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+            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(), StandardCharsets.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/5.0 (Windows NT 10.0; Win64; x64)");
+            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 && !"".equals(ret.trim()))
+                {
+                    result.append(new String(ret.getBytes(StandardCharsets.ISO_8859_1), StandardCharsets.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-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/AddressUtils.java
similarity index 83%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/AddressUtils.java
index f95766e4..4e0934e8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/AddressUtils.java
@@ -1,56 +1,56 @@
-package com.ruoyi.common.utils.ip;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-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);
-
-    // IP地址查询
-    public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
-
-    // 未知地址
-    public static final String UNKNOWN = "XX XX";
-
-    public static String getRealAddressByIP(String ip)
-    {
-        // 内网不查询
-        if (IpUtils.internalIp(ip))
-        {
-            return "内网IP";
-        }
-        if (RuoYiConfig.isAddressEnabled())
-        {
-            try
-            {
-                String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
-                if (StringUtils.isEmpty(rspStr))
-                {
-                    log.error("获取地理位置异常 {}", ip);
-                    return UNKNOWN;
-                }
-                JSONObject obj = JSON.parseObject(rspStr);
-                String region = obj.getString("pro");
-                String city = obj.getString("city");
-                return String.format("%s %s", region, city);
-            }
-            catch (Exception e)
-            {
-                log.error("获取地理位置异常 {}", ip);
-            }
-        }
-        return UNKNOWN;
-    }
-}
+package com.acupuncture.common.utils.ip;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.http.HttpUtils;
+
+/**
+ * 获取地址类
+ * 
+ * @author acupuncture
+ */
+public class AddressUtils
+{
+    private static final Logger log = LoggerFactory.getLogger(AddressUtils.class);
+
+    // IP地址查询
+    public static final String IP_URL = "http://whois.pconline.com.cn/ipJson.jsp";
+
+    // 未知地址
+    public static final String UNKNOWN = "XX XX";
+
+    public static String getRealAddressByIP(String ip)
+    {
+        // 内网不查询
+        if (IpUtils.internalIp(ip))
+        {
+            return "内网IP";
+        }
+        if (RuoYiConfig.isAddressEnabled())
+        {
+            try
+            {
+                String rspStr = HttpUtils.sendGet(IP_URL, "ip=" + ip + "&json=true", Constants.GBK);
+                if (StringUtils.isEmpty(rspStr))
+                {
+                    log.error("获取地理位置异常 {}", ip);
+                    return UNKNOWN;
+                }
+                JSONObject obj = JSON.parseObject(rspStr);
+                String region = obj.getString("pro");
+                String city = obj.getString("city");
+                return String.format("%s %s", region, city);
+            }
+            catch (Exception e)
+            {
+                log.error("获取地理位置异常 {}", ip);
+            }
+        }
+        return UNKNOWN;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/IpUtils.java
similarity index 95%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/IpUtils.java
index 33162402..4a044031 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/ip/IpUtils.java
@@ -1,382 +1,382 @@
-package com.ruoyi.common.utils.ip;
-
-import java.net.InetAddress;
-import java.net.UnknownHostException;
-import javax.servlet.http.HttpServletRequest;
-import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 获取IP方法
- * 
- * @author ruoyi
- */
-public class IpUtils
-{
-    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
-    // 匹配 ip
-    public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
-    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
-    // 匹配网段
-    public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
-
-    /**
-     * 获取客户端IP
-     * 
-     * @return IP地址
-     */
-    public static String getIpAddr()
-    {
-        return getIpAddr(ServletUtils.getRequest());
-    }
-
-    /**
-     * 获取客户端IP
-     * 
-     * @param request 请求对象
-     * @return IP地址
-     */
-    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" : getMultistageReverseProxyIp(ip);
-    }
-
-    /**
-     * 检查是否为内部IP地址
-     * 
-     * @param ip IP地址
-     * @return 结果
-     */
-    public static boolean internalIp(String ip)
-    {
-        byte[] addr = textToNumericFormatV4(ip);
-        return internalIp(addr) || "127.0.0.1".equals(ip);
-    }
-
-    /**
-     * 检查是否为内部IP地址
-     * 
-     * @param addr byte地址
-     * @return 结果
-     */
-    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;
-        }
-    }
-
-    /**
-     * 将IPv4地址转换成字节
-     * 
-     * @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;
-    }
-
-    /**
-     * 获取IP地址
-     * 
-     * @return 本地IP地址
-     */
-    public static String getHostIp()
-    {
-        try
-        {
-            return InetAddress.getLocalHost().getHostAddress();
-        }
-        catch (UnknownHostException e)
-        {
-        }
-        return "127.0.0.1";
-    }
-
-    /**
-     * 获取主机名
-     * 
-     * @return 本地主机名
-     */
-    public static String getHostName()
-    {
-        try
-        {
-            return InetAddress.getLocalHost().getHostName();
-        }
-        catch (UnknownHostException e)
-        {
-        }
-        return "未知";
-    }
-
-    /**
-     * 从多级反向代理中获得第一个非unknown IP地址
-     *
-     * @param ip 获得的IP地址
-     * @return 第一个非unknown IP地址
-     */
-    public static String getMultistageReverseProxyIp(String ip)
-    {
-        // 多级反向代理检测
-        if (ip != null && ip.indexOf(",") > 0)
-        {
-            final String[] ips = ip.trim().split(",");
-            for (String subIp : ips)
-            {
-                if (false == isUnknown(subIp))
-                {
-                    ip = subIp;
-                    break;
-                }
-            }
-        }
-        return StringUtils.substring(ip, 0, 255);
-    }
-
-    /**
-     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
-     *
-     * @param checkString 被检测的字符串
-     * @return 是否未知
-     */
-    public static boolean isUnknown(String checkString)
-    {
-        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
-    }
-
-    /**
-     * 是否为IP
-     */
-    public static boolean isIP(String ip)
-    {
-        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
-    }
-
-    /**
-     * 是否为IP,或 *为间隔的通配符地址
-     */
-    public static boolean isIpWildCard(String ip)
-    {
-        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
-    }
-
-    /**
-     * 检测参数是否在ip通配符里
-     */
-    public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
-    {
-        String[] s1 = ipWildCard.split("\\.");
-        String[] s2 = ip.split("\\.");
-        boolean isMatchedSeg = true;
-        for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
-        {
-            if (!s1[i].equals(s2[i]))
-            {
-                isMatchedSeg = false;
-                break;
-            }
-        }
-        return isMatchedSeg;
-    }
-
-    /**
-     * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
-     */
-    public static boolean isIPSegment(String ipSeg)
-    {
-        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
-    }
-
-    /**
-     * 判断ip是否在指定网段中
-     */
-    public static boolean ipIsInNetNoCheck(String iparea, String ip)
-    {
-        int idx = iparea.indexOf('-');
-        String[] sips = iparea.substring(0, idx).split("\\.");
-        String[] sipe = iparea.substring(idx + 1).split("\\.");
-        String[] sipt = ip.split("\\.");
-        long ips = 0L, ipe = 0L, ipt = 0L;
-        for (int i = 0; i < 4; ++i)
-        {
-            ips = ips << 8 | Integer.parseInt(sips[i]);
-            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
-            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
-        }
-        if (ips > ipe)
-        {
-            long t = ips;
-            ips = ipe;
-            ipe = t;
-        }
-        return ips <= ipt && ipt <= ipe;
-    }
-
-    /**
-     * 校验ip是否符合过滤串规则
-     * 
-     * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
-     * @param ip 校验IP地址
-     * @return boolean 结果
-     */
-    public static boolean isMatchedIp(String filter, String ip)
-    {
-        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
-        {
-            return false;
-        }
-        String[] ips = filter.split(";");
-        for (String iStr : ips)
-        {
-            if (isIP(iStr) && iStr.equals(ip))
-            {
-                return true;
-            }
-            else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
-            {
-                return true;
-            }
-            else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
-            {
-                return true;
-            }
-        }
-        return false;
-    }
+package com.acupuncture.common.utils.ip;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import javax.servlet.http.HttpServletRequest;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 获取IP方法
+ * 
+ * @author acupuncture
+ */
+public class IpUtils
+{
+    public final static String REGX_0_255 = "(25[0-5]|2[0-4]\\d|1\\d{2}|[1-9]\\d|\\d)";
+    // 匹配 ip
+    public final static String REGX_IP = "((" + REGX_0_255 + "\\.){3}" + REGX_0_255 + ")";
+    public final static String REGX_IP_WILDCARD = "(((\\*\\.){3}\\*)|(" + REGX_0_255 + "(\\.\\*){3})|(" + REGX_0_255 + "\\." + REGX_0_255 + ")(\\.\\*){2}" + "|((" + REGX_0_255 + "\\.){3}\\*))";
+    // 匹配网段
+    public final static String REGX_IP_SEG = "(" + REGX_IP + "\\-" + REGX_IP + ")";
+
+    /**
+     * 获取客户端IP
+     * 
+     * @return IP地址
+     */
+    public static String getIpAddr()
+    {
+        return getIpAddr(ServletUtils.getRequest());
+    }
+
+    /**
+     * 获取客户端IP
+     * 
+     * @param request 请求对象
+     * @return IP地址
+     */
+    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" : getMultistageReverseProxyIp(ip);
+    }
+
+    /**
+     * 检查是否为内部IP地址
+     * 
+     * @param ip IP地址
+     * @return 结果
+     */
+    public static boolean internalIp(String ip)
+    {
+        byte[] addr = textToNumericFormatV4(ip);
+        return internalIp(addr) || "127.0.0.1".equals(ip);
+    }
+
+    /**
+     * 检查是否为内部IP地址
+     * 
+     * @param addr byte地址
+     * @return 结果
+     */
+    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;
+        }
+    }
+
+    /**
+     * 将IPv4地址转换成字节
+     * 
+     * @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;
+    }
+
+    /**
+     * 获取IP地址
+     * 
+     * @return 本地IP地址
+     */
+    public static String getHostIp()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostAddress();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "127.0.0.1";
+    }
+
+    /**
+     * 获取主机名
+     * 
+     * @return 本地主机名
+     */
+    public static String getHostName()
+    {
+        try
+        {
+            return InetAddress.getLocalHost().getHostName();
+        }
+        catch (UnknownHostException e)
+        {
+        }
+        return "未知";
+    }
+
+    /**
+     * 从多级反向代理中获得第一个非unknown IP地址
+     *
+     * @param ip 获得的IP地址
+     * @return 第一个非unknown IP地址
+     */
+    public static String getMultistageReverseProxyIp(String ip)
+    {
+        // 多级反向代理检测
+        if (ip != null && ip.indexOf(",") > 0)
+        {
+            final String[] ips = ip.trim().split(",");
+            for (String subIp : ips)
+            {
+                if (false == isUnknown(subIp))
+                {
+                    ip = subIp;
+                    break;
+                }
+            }
+        }
+        return StringUtils.substring(ip, 0, 255);
+    }
+
+    /**
+     * 检测给定字符串是否为未知,多用于检测HTTP请求相关
+     *
+     * @param checkString 被检测的字符串
+     * @return 是否未知
+     */
+    public static boolean isUnknown(String checkString)
+    {
+        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
+    }
+
+    /**
+     * 是否为IP
+     */
+    public static boolean isIP(String ip)
+    {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
+    }
+
+    /**
+     * 是否为IP,或 *为间隔的通配符地址
+     */
+    public static boolean isIpWildCard(String ip)
+    {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP_WILDCARD);
+    }
+
+    /**
+     * 检测参数是否在ip通配符里
+     */
+    public static boolean ipIsInWildCardNoCheck(String ipWildCard, String ip)
+    {
+        String[] s1 = ipWildCard.split("\\.");
+        String[] s2 = ip.split("\\.");
+        boolean isMatchedSeg = true;
+        for (int i = 0; i < s1.length && !s1[i].equals("*"); i++)
+        {
+            if (!s1[i].equals(s2[i]))
+            {
+                isMatchedSeg = false;
+                break;
+            }
+        }
+        return isMatchedSeg;
+    }
+
+    /**
+     * 是否为特定格式如:“10.10.10.1-10.10.10.99”的ip段字符串
+     */
+    public static boolean isIPSegment(String ipSeg)
+    {
+        return StringUtils.isNotBlank(ipSeg) && ipSeg.matches(REGX_IP_SEG);
+    }
+
+    /**
+     * 判断ip是否在指定网段中
+     */
+    public static boolean ipIsInNetNoCheck(String iparea, String ip)
+    {
+        int idx = iparea.indexOf('-');
+        String[] sips = iparea.substring(0, idx).split("\\.");
+        String[] sipe = iparea.substring(idx + 1).split("\\.");
+        String[] sipt = ip.split("\\.");
+        long ips = 0L, ipe = 0L, ipt = 0L;
+        for (int i = 0; i < 4; ++i)
+        {
+            ips = ips << 8 | Integer.parseInt(sips[i]);
+            ipe = ipe << 8 | Integer.parseInt(sipe[i]);
+            ipt = ipt << 8 | Integer.parseInt(sipt[i]);
+        }
+        if (ips > ipe)
+        {
+            long t = ips;
+            ips = ipe;
+            ipe = t;
+        }
+        return ips <= ipt && ipt <= ipe;
+    }
+
+    /**
+     * 校验ip是否符合过滤串规则
+     * 
+     * @param filter 过滤IP列表,支持后缀'*'通配,支持网段如:`10.10.10.1-10.10.10.99`
+     * @param ip 校验IP地址
+     * @return boolean 结果
+     */
+    public static boolean isMatchedIp(String filter, String ip)
+    {
+        if (StringUtils.isEmpty(filter) || StringUtils.isEmpty(ip))
+        {
+            return false;
+        }
+        String[] ips = filter.split(";");
+        for (String iStr : ips)
+        {
+            if (isIP(iStr) && iStr.equals(ip))
+            {
+                return true;
+            }
+            else if (isIpWildCard(iStr) && ipIsInWildCardNoCheck(iStr, ip))
+            {
+                return true;
+            }
+            else if (isIPSegment(iStr) && ipIsInNetNoCheck(iStr, ip))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelHandlerAdapter.java
similarity index 86%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelHandlerAdapter.java
index c36c9f1f..e8c672a1 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelHandlerAdapter.java
@@ -1,24 +1,24 @@
-package com.ruoyi.common.utils.poi;
-
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.Workbook;
-
-/**
- * Excel数据格式处理适配器
- * 
- * @author ruoyi
- */
-public interface ExcelHandlerAdapter
-{
-    /**
-     * 格式化
-     * 
-     * @param value 单元格数据值
-     * @param args excel注解args参数组
-     * @param cell 单元格对象
-     * @param wb 工作簿对象
-     *
-     * @return 处理后的值
-     */
-    Object format(Object value, String[] args, Cell cell, Workbook wb);
-}
+package com.acupuncture.common.utils.poi;
+
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.Workbook;
+
+/**
+ * Excel数据格式处理适配器
+ * 
+ * @author acupuncture
+ */
+public interface ExcelHandlerAdapter
+{
+    /**
+     * 格式化
+     * 
+     * @param value 单元格数据值
+     * @param args excel注解args参数组
+     * @param cell 单元格对象
+     * @param wb 工作簿对象
+     *
+     * @return 处理后的值
+     */
+    Object format(Object value, String[] args, Cell cell, Workbook wb);
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelUtil.java
similarity index 96%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelUtil.java
index 7390b518..71311a14 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/poi/ExcelUtil.java
@@ -1,1900 +1,1900 @@
-package com.ruoyi.common.utils.poi;
-
-import java.io.File;
-import java.io.FileOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-import java.io.OutputStream;
-import java.lang.reflect.Field;
-import java.lang.reflect.Method;
-import java.lang.reflect.ParameterizedType;
-import java.math.BigDecimal;
-import java.text.DecimalFormat;
-import java.time.LocalDate;
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Comparator;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.UUID;
-import java.util.stream.Collectors;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import org.apache.commons.lang3.RegExUtils;
-import org.apache.commons.lang3.reflect.FieldUtils;
-import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
-import org.apache.poi.hssf.usermodel.HSSFPicture;
-import org.apache.poi.hssf.usermodel.HSSFPictureData;
-import org.apache.poi.hssf.usermodel.HSSFShape;
-import org.apache.poi.hssf.usermodel.HSSFSheet;
-import org.apache.poi.hssf.usermodel.HSSFWorkbook;
-import org.apache.poi.ooxml.POIXMLDocumentPart;
-import org.apache.poi.ss.usermodel.BorderStyle;
-import org.apache.poi.ss.usermodel.Cell;
-import org.apache.poi.ss.usermodel.CellStyle;
-import org.apache.poi.ss.usermodel.CellType;
-import org.apache.poi.ss.usermodel.ClientAnchor;
-import org.apache.poi.ss.usermodel.DataFormat;
-import org.apache.poi.ss.usermodel.DataValidation;
-import org.apache.poi.ss.usermodel.DataValidationConstraint;
-import org.apache.poi.ss.usermodel.DataValidationHelper;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.apache.poi.ss.usermodel.Drawing;
-import org.apache.poi.ss.usermodel.FillPatternType;
-import org.apache.poi.ss.usermodel.Font;
-import org.apache.poi.ss.usermodel.HorizontalAlignment;
-import org.apache.poi.ss.usermodel.IndexedColors;
-import org.apache.poi.ss.usermodel.Name;
-import org.apache.poi.ss.usermodel.PictureData;
-import org.apache.poi.ss.usermodel.Row;
-import org.apache.poi.ss.usermodel.Sheet;
-import org.apache.poi.ss.usermodel.VerticalAlignment;
-import org.apache.poi.ss.usermodel.Workbook;
-import org.apache.poi.ss.usermodel.WorkbookFactory;
-import org.apache.poi.ss.util.CellRangeAddress;
-import org.apache.poi.ss.util.CellRangeAddressList;
-import org.apache.poi.util.IOUtils;
-import org.apache.poi.xssf.streaming.SXSSFWorkbook;
-import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
-import org.apache.poi.xssf.usermodel.XSSFDataValidation;
-import org.apache.poi.xssf.usermodel.XSSFDrawing;
-import org.apache.poi.xssf.usermodel.XSSFPicture;
-import org.apache.poi.xssf.usermodel.XSSFShape;
-import org.apache.poi.xssf.usermodel.XSSFSheet;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.annotation.Excel.Type;
-import com.ruoyi.common.annotation.Excels;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.exception.UtilException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.DictUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.file.FileTypeUtils;
-import com.ruoyi.common.utils.file.FileUtils;
-import com.ruoyi.common.utils.file.ImageUtils;
-import com.ruoyi.common.utils.reflect.ReflectUtils;
-
-/**
- * Excel相关处理
- * 
- * @author ruoyi
- */
-public class ExcelUtil<T>
-{
-    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
-
-    public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
-
-    public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
-
-    /**
-     * 用于dictType属性数据存储,避免重复查缓存
-     */
-    public Map<String, String> sysDictMap = new HashMap<String, String>();
-
-    /**
-     * Excel sheet最大行数,默认65536
-     */
-    public static final int sheetSize = 65536;
-
-    /**
-     * 工作表名称
-     */
-    private String sheetName;
-
-    /**
-     * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
-     */
-    private Type type;
-
-    /**
-     * 工作薄对象
-     */
-    private Workbook wb;
-
-    /**
-     * 工作表对象
-     */
-    private Sheet sheet;
-
-    /**
-     * 样式列表
-     */
-    private Map<String, CellStyle> styles;
-
-    /**
-     * 导入导出数据列表
-     */
-    private List<T> list;
-
-    /**
-     * 注解列表
-     */
-    private List<Object[]> fields;
-
-    /**
-     * 当前行号
-     */
-    private int rownum;
-
-    /**
-     * 标题
-     */
-    private String title;
-
-    /**
-     * 最大高度
-     */
-    private short maxHeight;
-
-    /**
-     * 合并后最后行数
-     */
-    private int subMergedLastRowNum = 0;
-
-    /**
-     * 合并后开始行数
-     */
-    private int subMergedFirstRowNum = 1;
-
-    /**
-     * 对象的子列表方法
-     */
-    private Method subMethod;
-
-    /**
-     * 对象的子列表属性
-     */
-    private List<Field> subFields;
-
-    /**
-     * 统计列表
-     */
-    private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
-
-    /**
-     * 数字格式
-     */
-    private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
-
-    /**
-     * 实体对象
-     */
-    public Class<T> clazz;
-
-    /**
-     * 需要显示列属性
-     */
-    public String[] includeFields;
-
-    /**
-     * 需要排除列属性
-     */
-    public String[] excludeFields;
-
-    public ExcelUtil(Class<T> clazz)
-    {
-        this.clazz = clazz;
-    }
-
-    /**
-     * 仅在Excel中显示列属性
-     *
-     * @param fields 列属性名 示例[单个"name"/多个"id","name"]
-     */
-    public void showColumn(String... fields)
-    {
-        this.includeFields = fields;
-    }
-
-    /**
-     * 隐藏Excel中列属性
-     *
-     * @param fields 列属性名 示例[单个"name"/多个"id","name"]
-     */
-    public void hideColumn(String... fields)
-    {
-        this.excludeFields = fields;
-    }
-
-    public void init(List<T> list, String sheetName, String title, Type type)
-    {
-        if (list == null)
-        {
-            list = new ArrayList<T>();
-        }
-        this.list = list;
-        this.sheetName = sheetName;
-        this.type = type;
-        this.title = title;
-        createExcelField();
-        createWorkbook();
-        createTitle();
-        createSubHead();
-    }
-
-    /**
-     * 创建excel第一行标题
-     */
-    public void createTitle()
-    {
-        if (StringUtils.isNotEmpty(title))
-        {
-            int titleLastCol = this.fields.size() - 1;
-            if (isSubList())
-            {
-                titleLastCol = titleLastCol + subFields.size() - 1;
-            }
-            Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
-            titleRow.setHeightInPoints(30);
-            Cell titleCell = titleRow.createCell(0);
-            titleCell.setCellStyle(styles.get("title"));
-            titleCell.setCellValue(title);
-            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
-        }
-    }
-
-    /**
-     * 创建对象的子列表名称
-     */
-    public void createSubHead()
-    {
-        if (isSubList())
-        {
-            Row subRow = sheet.createRow(rownum);
-            int column = 0;
-            int subFieldSize = subFields != null ? subFields.size() : 0;
-            for (Object[] objects : fields)
-            {
-                Field field = (Field) objects[0];
-                Excel attr = (Excel) objects[1];
-                if (Collection.class.isAssignableFrom(field.getType()))
-                {
-                    Cell cell = subRow.createCell(column);
-                    cell.setCellValue(attr.name());
-                    cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
-                    if (subFieldSize > 1)
-                    {
-                        CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
-                        sheet.addMergedRegion(cellAddress);
-                    }
-                    column += subFieldSize;
-                }
-                else
-                {
-                    Cell cell = subRow.createCell(column++);
-                    cell.setCellValue(attr.name());
-                    cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
-                }
-            }
-            rownum++;
-        }
-    }
-
-    /**
-     * 对excel表单默认第一个索引名转换成list
-     * 
-     * @param is 输入流
-     * @return 转换后集合
-     */
-    public List<T> importExcel(InputStream is)
-    {
-        return importExcel(is, 0);
-    }
-
-    /**
-     * 对excel表单默认第一个索引名转换成list
-     * 
-     * @param is 输入流
-     * @param titleNum 标题占用行数
-     * @return 转换后集合
-     */
-    public List<T> importExcel(InputStream is, int titleNum)
-    {
-        List<T> list = null;
-        try
-        {
-            list = importExcel(StringUtils.EMPTY, is, titleNum);
-        }
-        catch (Exception e)
-        {
-            log.error("导入Excel异常{}", e.getMessage());
-            throw new UtilException(e.getMessage());
-        }
-        finally
-        {
-            IOUtils.closeQuietly(is);
-        }
-        return list;
-    }
-
-    /**
-     * 对excel表单指定表格索引名转换成list
-     * 
-     * @param sheetName 表格索引名
-     * @param titleNum 标题占用行数
-     * @param is 输入流
-     * @return 转换后集合
-     */
-    public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
-    {
-        this.type = Type.IMPORT;
-        this.wb = WorkbookFactory.create(is);
-        List<T> list = new ArrayList<T>();
-        // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
-        Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
-        if (sheet == null)
-        {
-            throw new IOException("文件sheet不存在");
-        }
-        boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
-        Map<String, PictureData> pictures;
-        if (isXSSFWorkbook)
-        {
-            pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
-        }
-        else
-        {
-            pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);
-        }
-        // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1
-        int rows = sheet.getLastRowNum();
-        if (rows > 0)
-        {
-            // 定义一个map用于存放excel列的序号和field.
-            Map<String, Integer> cellMap = new HashMap<String, Integer>();
-            // 获取表头
-            Row heard = sheet.getRow(titleNum);
-            for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
-            {
-                Cell cell = heard.getCell(i);
-                if (StringUtils.isNotNull(cell))
-                {
-                    String value = this.getCellValue(heard, i).toString();
-                    cellMap.put(value, i);
-                }
-                else
-                {
-                    cellMap.put(null, i);
-                }
-            }
-            // 有数据时才处理 得到类的所有field.
-            List<Object[]> fields = this.getFields();
-            Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
-            for (Object[] objects : fields)
-            {
-                Excel attr = (Excel) objects[1];
-                Integer column = cellMap.get(attr.name());
-                if (column != null)
-                {
-                    fieldsMap.put(column, objects);
-                }
-            }
-            for (int i = titleNum + 1; i <= rows; i++)
-            {
-                // 从第2行开始取数据,默认第一行是表头.
-                Row row = sheet.getRow(i);
-                // 判断当前行是否是空行
-                if (isRowEmpty(row))
-                {
-                    continue;
-                }
-                T entity = null;
-                for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
-                {
-                    Object val = this.getCellValue(row, entry.getKey());
-
-                    // 如果不存在实例则新建.
-                    entity = (entity == null ? clazz.newInstance() : entity);
-                    // 从map中得到对应列的field.
-                    Field field = (Field) entry.getValue()[0];
-                    Excel attr = (Excel) entry.getValue()[1];
-                    // 取得类型,并根据对象类型设置值.
-                    Class<?> fieldType = field.getType();
-                    if (String.class == fieldType)
-                    {
-                        String s = Convert.toStr(val);
-                        if (StringUtils.endsWith(s, ".0"))
-                        {
-                            val = StringUtils.substringBefore(s, ".0");
-                        }
-                        else
-                        {
-                            String dateFormat = field.getAnnotation(Excel.class).dateFormat();
-                            if (StringUtils.isNotEmpty(dateFormat))
-                            {
-                                val = parseDateToStr(dateFormat, val);
-                            }
-                            else
-                            {
-                                val = Convert.toStr(val);
-                            }
-                        }
-                    }
-                    else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
-                    {
-                        val = Convert.toInt(val);
-                    }
-                    else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
-                    {
-                        val = Convert.toLong(val);
-                    }
-                    else if (Double.TYPE == fieldType || Double.class == fieldType)
-                    {
-                        val = Convert.toDouble(val);
-                    }
-                    else if (Float.TYPE == fieldType || Float.class == fieldType)
-                    {
-                        val = Convert.toFloat(val);
-                    }
-                    else if (BigDecimal.class == fieldType)
-                    {
-                        val = Convert.toBigDecimal(val);
-                    }
-                    else if (Date.class == fieldType)
-                    {
-                        if (val instanceof String)
-                        {
-                            val = DateUtils.parseDate(val);
-                        }
-                        else if (val instanceof Double)
-                        {
-                            val = DateUtil.getJavaDate((Double) val);
-                        }
-                    }
-                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
-                    {
-                        val = Convert.toBool(val, false);
-                    }
-                    if (StringUtils.isNotNull(fieldType))
-                    {
-                        String propertyName = field.getName();
-                        if (StringUtils.isNotEmpty(attr.targetAttr()))
-                        {
-                            propertyName = field.getName() + "." + attr.targetAttr();
-                        }
-                        if (StringUtils.isNotEmpty(attr.readConverterExp()))
-                        {
-                            val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
-                        }
-                        else if (StringUtils.isNotEmpty(attr.dictType()))
-                        {
-                            if (!sysDictMap.containsKey(attr.dictType() + val))
-                            {
-                                String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
-                                sysDictMap.put(attr.dictType() + val, dictValue);
-                            }
-                            val = sysDictMap.get(attr.dictType() + val);
-                        }
-                        else if (!attr.handler().equals(ExcelHandlerAdapter.class))
-                        {
-                            val = dataFormatHandlerAdapter(val, attr, null);
-                        }
-                        else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
-                        {
-                            PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
-                            if (image == null)
-                            {
-                                val = "";
-                            }
-                            else
-                            {
-                                byte[] data = image.getData();
-                                val = FileUtils.writeImportBytes(data);
-                            }
-                        }
-                        ReflectUtils.invokeSetter(entity, propertyName, val);
-                    }
-                }
-                list.add(entity);
-            }
-        }
-        return list;
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param list 导出数据集合
-     * @param sheetName 工作表的名称
-     * @return 结果
-     */
-    public AjaxResult exportExcel(List<T> list, String sheetName)
-    {
-        return exportExcel(list, sheetName, StringUtils.EMPTY);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param list 导出数据集合
-     * @param sheetName 工作表的名称
-     * @param title 标题
-     * @return 结果
-     */
-    public AjaxResult exportExcel(List<T> list, String sheetName, String title)
-    {
-        this.init(list, sheetName, title, Type.EXPORT);
-        return exportExcel();
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param response 返回数据
-     * @param list 导出数据集合
-     * @param sheetName 工作表的名称
-     * @return 结果
-     */
-    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
-    {
-        exportExcel(response, list, sheetName, StringUtils.EMPTY);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param response 返回数据
-     * @param list 导出数据集合
-     * @param sheetName 工作表的名称
-     * @param title 标题
-     * @return 结果
-     */
-    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
-    {
-        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-        response.setCharacterEncoding("utf-8");
-        this.init(list, sheetName, title, Type.EXPORT);
-        exportExcel(response);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param sheetName 工作表的名称
-     * @return 结果
-     */
-    public AjaxResult importTemplateExcel(String sheetName)
-    {
-        return importTemplateExcel(sheetName, StringUtils.EMPTY);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param sheetName 工作表的名称
-     * @param title 标题
-     * @return 结果
-     */
-    public AjaxResult importTemplateExcel(String sheetName, String title)
-    {
-        this.init(null, sheetName, title, Type.IMPORT);
-        return exportExcel();
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param sheetName 工作表的名称
-     * @return 结果
-     */
-    public void importTemplateExcel(HttpServletResponse response, String sheetName)
-    {
-        importTemplateExcel(response, sheetName, StringUtils.EMPTY);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @param sheetName 工作表的名称
-     * @param title 标题
-     * @return 结果
-     */
-    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)
-    {
-        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
-        response.setCharacterEncoding("utf-8");
-        this.init(null, sheetName, title, Type.IMPORT);
-        exportExcel(response);
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @return 结果
-     */
-    public void exportExcel(HttpServletResponse response)
-    {
-        try
-        {
-            writeSheet();
-            wb.write(response.getOutputStream());
-        }
-        catch (Exception e)
-        {
-            log.error("导出Excel异常{}", e.getMessage());
-        }
-        finally
-        {
-            IOUtils.closeQuietly(wb);
-        }
-    }
-
-    /**
-     * 对list数据源将其里面的数据导入到excel表单
-     * 
-     * @return 结果
-     */
-    public AjaxResult exportExcel()
-    {
-        OutputStream out = null;
-        try
-        {
-            writeSheet();
-            String filename = encodingFilename(sheetName);
-            out = new FileOutputStream(getAbsoluteFile(filename));
-            wb.write(out);
-            return AjaxResult.success(filename);
-        }
-        catch (Exception e)
-        {
-            log.error("导出Excel异常{}", e.getMessage());
-            throw new UtilException("导出Excel失败,请联系网站管理员!");
-        }
-        finally
-        {
-            IOUtils.closeQuietly(wb);
-            IOUtils.closeQuietly(out);
-        }
-    }
-
-    /**
-     * 创建写入数据到Sheet
-     */
-    public void writeSheet()
-    {
-        // 取出一共有多少个sheet.
-        int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
-        for (int index = 0; index < sheetNo; index++)
-        {
-            createSheet(sheetNo, index);
-
-            // 产生一行
-            Row row = sheet.createRow(rownum);
-            int column = 0;
-            // 写入各个字段的列头名称
-            for (Object[] os : fields)
-            {
-                Field field = (Field) os[0];
-                Excel excel = (Excel) os[1];
-                if (Collection.class.isAssignableFrom(field.getType()))
-                {
-                    for (Field subField : subFields)
-                    {
-                        Excel subExcel = subField.getAnnotation(Excel.class);
-                        this.createHeadCell(subExcel, row, column++);
-                    }
-                }
-                else
-                {
-                    this.createHeadCell(excel, row, column++);
-                }
-            }
-            if (Type.EXPORT.equals(type))
-            {
-                fillExcelData(index, row);
-                addStatisticsRow();
-            }
-        }
-    }
-
-    /**
-     * 填充excel数据
-     * 
-     * @param index 序号
-     * @param row 单元格行
-     */
-    @SuppressWarnings("unchecked")
-    public void fillExcelData(int index, Row row)
-    {
-        int startNo = index * sheetSize;
-        int endNo = Math.min(startNo + sheetSize, list.size());
-        int currentRowNum = rownum + 1; // 从标题行后开始
-
-        for (int i = startNo; i < endNo; i++)
-        {
-            row = sheet.createRow(currentRowNum);
-            T vo = (T) list.get(i);
-            int column = 0;
-            int maxSubListSize = getCurrentMaxSubListSize(vo);
-            for (Object[] os : fields)
-            {
-                Field field = (Field) os[0];
-                Excel excel = (Excel) os[1];
-                if (Collection.class.isAssignableFrom(field.getType()))
-                {
-                    try
-                    {
-                        Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
-                        if (subList != null && !subList.isEmpty())
-                        {
-                            int subIndex = 0;
-                            for (Object subVo : subList)
-                            {
-                                Row subRow = sheet.getRow(currentRowNum + subIndex);
-                                if (subRow == null)
-                                {
-                                    subRow = sheet.createRow(currentRowNum + subIndex);
-                                }
-
-                                int subColumn = column;
-                                for (Field subField : subFields)
-                                {
-                                    Excel subExcel = subField.getAnnotation(Excel.class);
-                                    addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
-                                }
-                                subIndex++;
-                            }
-                            column += subFields.size();
-                        }
-                    }
-                    catch (Exception e)
-                    {
-                        log.error("填充集合数据失败", e);
-                    }
-                }
-                else
-                {
-                    // 创建单元格并设置值
-                    addCell(excel, row, vo, field, column);
-                    if (maxSubListSize > 1 && excel.needMerge())
-                    {
-                        sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
-                    }
-                    column++;
-                }
-            }
-            currentRowNum += maxSubListSize;
-        }
-    }
-
-    /**
-     * 获取子列表最大数
-     */
-    private int getCurrentMaxSubListSize(T vo)
-    {
-        int maxSubListSize = 1;
-        for (Object[] os : fields)
-        {
-            Field field = (Field) os[0];
-            if (Collection.class.isAssignableFrom(field.getType()))
-            {
-                try
-                {
-                    Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
-                    if (subList != null && !subList.isEmpty())
-                    {
-                        maxSubListSize = Math.max(maxSubListSize, subList.size());
-                    }
-                }
-                catch (Exception e)
-                {
-                    log.error("获取集合大小失败", e);
-                }
-            }
-        }
-        return maxSubListSize;
-    }
-
-    /**
-     * 创建表格样式
-     * 
-     * @param wb 工作薄对象
-     * @return 样式列表
-     */
-    private Map<String, CellStyle> createStyles(Workbook wb)
-    {
-        // 写入各条记录,每条记录对应excel表中的一行
-        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
-        CellStyle style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        Font titleFont = wb.createFont();
-        titleFont.setFontName("Arial");
-        titleFont.setFontHeightInPoints((short) 16);
-        titleFont.setBold(true);
-        style.setFont(titleFont);
-        DataFormat dataFormat = wb.createDataFormat();
-        style.setDataFormat(dataFormat.getFormat("@"));
-        styles.put("title", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        style.setBorderRight(BorderStyle.THIN);
-        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderLeft(BorderStyle.THIN);
-        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderTop(BorderStyle.THIN);
-        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        style.setBorderBottom(BorderStyle.THIN);
-        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-        Font dataFont = wb.createFont();
-        dataFont.setFontName("Arial");
-        dataFont.setFontHeightInPoints((short) 10);
-        style.setFont(dataFont);
-        styles.put("data", style);
-
-        style = wb.createCellStyle();
-        style.setAlignment(HorizontalAlignment.CENTER);
-        style.setVerticalAlignment(VerticalAlignment.CENTER);
-        Font totalFont = wb.createFont();
-        totalFont.setFontName("Arial");
-        totalFont.setFontHeightInPoints((short) 10);
-        style.setFont(totalFont);
-        styles.put("total", style);
-
-        styles.putAll(annotationHeaderStyles(wb, styles));
-
-        styles.putAll(annotationDataStyles(wb));
-
-        return styles;
-    }
-
-    /**
-     * 根据Excel注解创建表格头样式
-     * 
-     * @param wb 工作薄对象
-     * @return 自定义样式列表
-     */
-    private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles)
-    {
-        Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>();
-        for (Object[] os : fields)
-        {
-            Excel excel = (Excel) os[1];
-            String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor());
-            if (!headerStyles.containsKey(key))
-            {
-                CellStyle style = wb.createCellStyle();
-                style.cloneStyleFrom(styles.get("data"));
-                style.setAlignment(HorizontalAlignment.CENTER);
-                style.setVerticalAlignment(VerticalAlignment.CENTER);
-                style.setFillForegroundColor(excel.headerBackgroundColor().index);
-                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-                Font headerFont = wb.createFont();
-                headerFont.setFontName("Arial");
-                headerFont.setFontHeightInPoints((short) 10);
-                headerFont.setBold(true);
-                headerFont.setColor(excel.headerColor().index);
-                style.setFont(headerFont);
-                // 设置表格头单元格文本形式
-                DataFormat dataFormat = wb.createDataFormat();
-                style.setDataFormat(dataFormat.getFormat("@"));
-                headerStyles.put(key, style);
-            }
-        }
-        return headerStyles;
-    }
-
-    /**
-     * 根据Excel注解创建表格列样式
-     * 
-     * @param wb 工作薄对象
-     * @return 自定义样式列表
-     */
-    private Map<String, CellStyle> annotationDataStyles(Workbook wb)
-    {
-        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
-        for (Object[] os : fields)
-        {
-            Field field = (Field) os[0];
-            Excel excel = (Excel) os[1];
-            if (Collection.class.isAssignableFrom(field.getType()))
-            {
-                ParameterizedType pt = (ParameterizedType) field.getGenericType();
-                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
-                List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
-                for (Field subField : subFields)
-                {
-                    Excel subExcel = subField.getAnnotation(Excel.class);
-                    annotationDataStyles(styles, subField, subExcel);
-                }
-            }
-            else
-            {
-                annotationDataStyles(styles, field, excel);
-            }
-        }
-        return styles;
-    }
-
-    /**
-     * 根据Excel注解创建表格列样式
-     * 
-     * @param styles 自定义样式列表
-     * @param field  属性列信息
-     * @param excel  注解信息
-     */
-    public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
-    {
-        String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
-        if (!styles.containsKey(key))
-        {
-            CellStyle style = wb.createCellStyle();
-            style.setAlignment(excel.align());
-            style.setVerticalAlignment(VerticalAlignment.CENTER);
-            style.setBorderRight(BorderStyle.THIN);
-            style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-            style.setBorderLeft(BorderStyle.THIN);
-            style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-            style.setBorderTop(BorderStyle.THIN);
-            style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-            style.setBorderBottom(BorderStyle.THIN);
-            style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
-            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
-            style.setFillForegroundColor(excel.backgroundColor().getIndex());
-            style.setWrapText(excel.wrapText());
-            Font dataFont = wb.createFont();
-            dataFont.setFontName("Arial");
-            dataFont.setFontHeightInPoints((short) 10);
-            dataFont.setColor(excel.color().index);
-            style.setFont(dataFont);
-            if (ColumnType.TEXT == excel.cellType())
-            {
-                DataFormat dataFormat = wb.createDataFormat();
-                style.setDataFormat(dataFormat.getFormat("@"));
-            }
-            styles.put(key, style);
-        }
-    }
-
-    /**
-     * 创建单元格
-     */
-    public Cell createHeadCell(Excel attr, Row row, int column)
-    {
-        // 创建列
-        Cell cell = row.createCell(column);
-        // 写入列信息
-        cell.setCellValue(attr.name());
-        setDataValidation(attr, row, column);
-        cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
-        if (isSubList())
-        {
-            // 填充默认样式,防止合并单元格样式失效
-            sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
-            if (attr.needMerge())
-            {
-                sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
-            }
-        }
-        return cell;
-    }
-
-    /**
-     * 设置单元格信息
-     * 
-     * @param value 单元格值
-     * @param attr 注解相关
-     * @param cell 单元格信息
-     */
-    public void setCellVo(Object value, Excel attr, Cell cell)
-    {
-        if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())
-        {
-            String cellValue = Convert.toStr(value);
-            // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。
-            if (StringUtils.startsWithAny(cellValue, FORMULA_STR))
-            {
-                cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
-            }
-            if (value instanceof Collection && StringUtils.equals("[]", cellValue))
-            {
-                cellValue = StringUtils.EMPTY;
-            }
-            cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
-        }
-        else if (ColumnType.NUMERIC == attr.cellType())
-        {
-            if (StringUtils.isNotNull(value))
-            {
-                cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
-            }
-        }
-        else if (ColumnType.IMAGE == attr.cellType())
-        {
-            ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
-            String imagePath = Convert.toStr(value);
-            if (StringUtils.isNotEmpty(imagePath))
-            {
-                byte[] data = ImageUtils.getImage(imagePath);
-                getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
-                        cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
-            }
-        }
-    }
-
-    /**
-     * 获取画布
-     */
-    public static Drawing<?> getDrawingPatriarch(Sheet sheet)
-    {
-        if (sheet.getDrawingPatriarch() == null)
-        {
-            sheet.createDrawingPatriarch();
-        }
-        return sheet.getDrawingPatriarch();
-    }
-
-    /**
-     * 获取图片类型,设置图片插入类型
-     */
-    public int getImageType(byte[] value)
-    {
-        String type = FileTypeUtils.getFileExtendName(value);
-        if ("JPG".equalsIgnoreCase(type))
-        {
-            return Workbook.PICTURE_TYPE_JPEG;
-        }
-        else if ("PNG".equalsIgnoreCase(type))
-        {
-            return Workbook.PICTURE_TYPE_PNG;
-        }
-        return Workbook.PICTURE_TYPE_JPEG;
-    }
-
-    /**
-     * 创建表格样式
-     */
-    public void setDataValidation(Excel attr, Row row, int column)
-    {
-        if (attr.name().indexOf("注:") >= 0)
-        {
-            sheet.setColumnWidth(column, 6000);
-        }
-        else
-        {
-            // 设置列宽
-            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
-        }
-        if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
-        {
-            String[] comboArray = attr.combo();
-            if (attr.comboReadDict())
-            {
-                if (!sysDictMap.containsKey("combo_" + attr.dictType()))
-                {
-                    String labels = DictUtils.getDictLabels(attr.dictType());
-                    sysDictMap.put("combo_" + attr.dictType(), labels);
-                }
-                String val = sysDictMap.get("combo_" + attr.dictType());
-                comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
-            }
-            if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
-            {
-                // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到
-                setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
-            }
-            else
-            {
-                // 提示信息或只能选择不能输入的列内容.
-                setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
-            }
-        }
-    }
-
-    /**
-     * 添加单元格
-     */
-    public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
-    {
-        Cell cell = null;
-        try
-        {
-            // 设置行高
-            row.setHeight(maxHeight);
-            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
-            if (attr.isExport())
-            {
-                // 创建cell
-                cell = row.createCell(column);
-                if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
-                {
-                    if (subMergedLastRowNum >= subMergedFirstRowNum)
-                    {
-                        sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
-                    }
-                }
-                cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
-
-                // 用于读取对象中的属性
-                Object value = getTargetValue(vo, field, attr);
-                String dateFormat = attr.dateFormat();
-                String readConverterExp = attr.readConverterExp();
-                String separator = attr.separator();
-                String dictType = attr.dictType();
-                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
-                {
-                    cell.setCellValue(parseDateToStr(dateFormat, value));
-                }
-                else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
-                {
-                    cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
-                }
-                else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
-                {
-                    if (!sysDictMap.containsKey(dictType + value))
-                    {
-                        String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
-                        sysDictMap.put(dictType + value, lable);
-                    }
-                    cell.setCellValue(sysDictMap.get(dictType + value));
-                }
-                else if (value instanceof BigDecimal && -1 != attr.scale())
-                {
-                    cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
-                }
-                else if (!attr.handler().equals(ExcelHandlerAdapter.class))
-                {
-                    cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
-                }
-                else
-                {
-                    // 设置列类型
-                    setCellVo(value, attr, cell);
-                }
-                addStatisticsData(column, Convert.toStr(value), attr);
-            }
-        }
-        catch (Exception e)
-        {
-            log.error("导出Excel失败{}", e);
-        }
-        return cell;
-    }
-
-    /**
-     * 设置 POI XSSFSheet 单元格提示或选择框
-     * 
-     * @param sheet 表单
-     * @param textlist 下拉框显示的内容
-     * @param promptContent 提示内容
-     * @param firstRow 开始行
-     * @param endRow 结束行
-     * @param firstCol 开始列
-     * @param endCol 结束列
-     */
-    public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,
-            int firstCol, int endCol)
-    {
-        DataValidationHelper helper = sheet.getDataValidationHelper();
-        DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1");
-        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
-        DataValidation dataValidation = helper.createValidation(constraint, regions);
-        if (StringUtils.isNotEmpty(promptContent))
-        {
-            // 如果设置了提示信息则鼠标放上去提示
-            dataValidation.createPromptBox("", promptContent);
-            dataValidation.setShowPromptBox(true);
-        }
-        // 处理Excel兼容性问题
-        if (dataValidation instanceof XSSFDataValidation)
-        {
-            dataValidation.setSuppressDropDownArrow(true);
-            dataValidation.setShowErrorBox(true);
-        }
-        else
-        {
-            dataValidation.setSuppressDropDownArrow(false);
-        }
-        sheet.addValidationData(dataValidation);
-    }
-
-    /**
-     * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框).
-     * 
-     * @param sheet 要设置的sheet.
-     * @param textlist 下拉框显示的内容
-     * @param promptContent 提示内容
-     * @param firstRow 开始行
-     * @param endRow 结束行
-     * @param firstCol 开始列
-     * @param endCol 结束列
-     */
-    public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)
-    {
-        String hideSheetName = "combo_" + firstCol + "_" + endCol;
-        Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
-        for (int i = 0; i < textlist.length; i++)
-        {
-            hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
-        }
-        // 创建名称,可被其他单元格引用
-        Name name = wb.createName();
-        name.setNameName(hideSheetName + "_data");
-        name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
-        DataValidationHelper helper = sheet.getDataValidationHelper();
-        // 加载下拉列表内容
-        DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data");
-        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
-        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
-        // 数据有效性对象
-        DataValidation dataValidation = helper.createValidation(constraint, regions);
-        if (StringUtils.isNotEmpty(promptContent))
-        {
-            // 如果设置了提示信息则鼠标放上去提示
-            dataValidation.createPromptBox("", promptContent);
-            dataValidation.setShowPromptBox(true);
-        }
-        // 处理Excel兼容性问题
-        if (dataValidation instanceof XSSFDataValidation)
-        {
-            dataValidation.setSuppressDropDownArrow(true);
-            dataValidation.setShowErrorBox(true);
-        }
-        else
-        {
-            dataValidation.setSuppressDropDownArrow(false);
-        }
-
-        sheet.addValidationData(dataValidation);
-        // 设置hiddenSheet隐藏
-        wb.setSheetHidden(wb.getSheetIndex(hideSheet), true);
-    }
-
-    /**
-     * 解析导出值 0=男,1=女,2=未知
-     * 
-     * @param propertyValue 参数值
-     * @param converterExp 翻译注解
-     * @param separator 分隔符
-     * @return 解析后值
-     */
-    public static String convertByExp(String propertyValue, String converterExp, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        String[] convertSource = converterExp.split(",");
-        for (String item : convertSource)
-        {
-            String[] itemArray = item.split("=");
-            if (StringUtils.containsAny(propertyValue, separator))
-            {
-                for (String value : propertyValue.split(separator))
-                {
-                    if (itemArray[0].equals(value))
-                    {
-                        propertyString.append(itemArray[1] + separator);
-                        break;
-                    }
-                }
-            }
-            else
-            {
-                if (itemArray[0].equals(propertyValue))
-                {
-                    return itemArray[1];
-                }
-            }
-        }
-        return StringUtils.stripEnd(propertyString.toString(), separator);
-    }
-
-    /**
-     * 反向解析值 男=0,女=1,未知=2
-     * 
-     * @param propertyValue 参数值
-     * @param converterExp 翻译注解
-     * @param separator 分隔符
-     * @return 解析后值
-     */
-    public static String reverseByExp(String propertyValue, String converterExp, String separator)
-    {
-        StringBuilder propertyString = new StringBuilder();
-        String[] convertSource = converterExp.split(",");
-        for (String item : convertSource)
-        {
-            String[] itemArray = item.split("=");
-            if (StringUtils.containsAny(propertyValue, separator))
-            {
-                for (String value : propertyValue.split(separator))
-                {
-                    if (itemArray[1].equals(value))
-                    {
-                        propertyString.append(itemArray[0] + separator);
-                        break;
-                    }
-                }
-            }
-            else
-            {
-                if (itemArray[1].equals(propertyValue))
-                {
-                    return itemArray[0];
-                }
-            }
-        }
-        return StringUtils.stripEnd(propertyString.toString(), separator);
-    }
-
-    /**
-     * 解析字典值
-     * 
-     * @param dictValue 字典值
-     * @param dictType 字典类型
-     * @param separator 分隔符
-     * @return 字典标签
-     */
-    public static String convertDictByExp(String dictValue, String dictType, String separator)
-    {
-        return DictUtils.getDictLabel(dictType, dictValue, separator);
-    }
-
-    /**
-     * 反向解析值字典值
-     * 
-     * @param dictLabel 字典标签
-     * @param dictType 字典类型
-     * @param separator 分隔符
-     * @return 字典值
-     */
-    public static String reverseDictByExp(String dictLabel, String dictType, String separator)
-    {
-        return DictUtils.getDictValue(dictType, dictLabel, separator);
-    }
-
-    /**
-     * 数据处理器
-     * 
-     * @param value 数据值
-     * @param excel 数据注解
-     * @return
-     */
-    public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
-    {
-        try
-        {
-            Object instance = excel.handler().newInstance();
-            Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
-            value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
-        }
-        catch (Exception e)
-        {
-            log.error("不能格式化数据 " + excel.handler(), e.getMessage());
-        }
-        return Convert.toStr(value);
-    }
-
-    /**
-     * 合计统计信息
-     */
-    private void addStatisticsData(Integer index, String text, Excel entity)
-    {
-        if (entity != null && entity.isStatistics())
-        {
-            Double temp = 0D;
-            if (!statistics.containsKey(index))
-            {
-                statistics.put(index, temp);
-            }
-            try
-            {
-                temp = Double.valueOf(text);
-            }
-            catch (NumberFormatException e)
-            {
-            }
-            statistics.put(index, statistics.get(index) + temp);
-        }
-    }
-
-    /**
-     * 创建统计行
-     */
-    public void addStatisticsRow()
-    {
-        if (statistics.size() > 0)
-        {
-            Row row = sheet.createRow(sheet.getLastRowNum() + 1);
-            Set<Integer> keys = statistics.keySet();
-            Cell cell = row.createCell(0);
-            cell.setCellStyle(styles.get("total"));
-            cell.setCellValue("合计");
-
-            for (Integer key : keys)
-            {
-                cell = row.createCell(key);
-                cell.setCellStyle(styles.get("total"));
-                cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));
-            }
-            statistics.clear();
-        }
-    }
-
-    /**
-     * 编码文件名
-     */
-    public String encodingFilename(String filename)
-    {
-        filename = UUID.randomUUID() + "_" + filename + ".xlsx";
-        return filename;
-    }
-
-    /**
-     * 获取下载路径
-     * 
-     * @param filename 文件名称
-     */
-    public String getAbsoluteFile(String filename)
-    {
-        String downloadPath = RuoYiConfig.getDownloadPath() + filename;
-        File desc = new File(downloadPath);
-        if (!desc.getParentFile().exists())
-        {
-            desc.getParentFile().mkdirs();
-        }
-        return downloadPath;
-    }
-
-    /**
-     * 获取bean中的属性值
-     * 
-     * @param vo 实体对象
-     * @param field 字段
-     * @param excel 注解
-     * @return 最终的属性值
-     * @throws Exception
-     */
-    private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
-    {
-        field.setAccessible(true);
-        Object o = field.get(vo);
-        if (StringUtils.isNotEmpty(excel.targetAttr()))
-        {
-            String target = excel.targetAttr();
-            if (target.contains("."))
-            {
-                String[] targets = target.split("[.]");
-                for (String name : targets)
-                {
-                    o = getValue(o, name);
-                }
-            }
-            else
-            {
-                o = getValue(o, target);
-            }
-        }
-        return o;
-    }
-
-    /**
-     * 以类的属性的get方法方法形式获取值
-     * 
-     * @param o
-     * @param name
-     * @return value
-     * @throws Exception
-     */
-    private Object getValue(Object o, String name) throws Exception
-    {
-        if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
-        {
-            Class<?> clazz = o.getClass();
-            Field field = clazz.getDeclaredField(name);
-            field.setAccessible(true);
-            o = field.get(o);
-        }
-        return o;
-    }
-
-    /**
-     * 得到所有定义字段
-     */
-    private void createExcelField()
-    {
-        this.fields = getFields();
-        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
-        this.maxHeight = getRowHeight();
-    }
-
-    /**
-     * 获取字段注解信息
-     */
-    public List<Object[]> getFields()
-    {
-        List<Object[]> fields = new ArrayList<Object[]>();
-        List<Field> tempFields = new ArrayList<>();
-        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
-        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
-        if (StringUtils.isNotEmpty(includeFields))
-        {
-            for (Field field : tempFields)
-            {
-                if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
-                {
-                    addField(fields, field);
-                }
-            }
-        }
-        else if (StringUtils.isNotEmpty(excludeFields))
-        {
-            for (Field field : tempFields)
-            {
-                if (!ArrayUtils.contains(this.excludeFields, field.getName()))
-                {
-                    addField(fields, field);
-                }
-            }
-        }
-        else
-        {
-            for (Field field : tempFields)
-            {
-                addField(fields, field);
-            }
-        }
-        return fields;
-    }
-
-    /**
-     * 添加字段信息
-     */
-    public void addField(List<Object[]> fields, Field field)
-    {
-        // 单注解
-        if (field.isAnnotationPresent(Excel.class))
-        {
-            Excel attr = field.getAnnotation(Excel.class);
-            if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
-            {
-                fields.add(new Object[] { field, attr });
-            }
-            if (Collection.class.isAssignableFrom(field.getType()))
-            {
-                subMethod = getSubMethod(field.getName(), clazz);
-                ParameterizedType pt = (ParameterizedType) field.getGenericType();
-                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
-                this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
-            }
-        }
-
-        // 多注解
-        if (field.isAnnotationPresent(Excels.class))
-        {
-            Excels attrs = field.getAnnotation(Excels.class);
-            Excel[] excels = attrs.value();
-            for (Excel attr : excels)
-            {
-                if (StringUtils.isNotEmpty(includeFields))
-                {
-                    if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
-                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
-                    {
-                        fields.add(new Object[] { field, attr });
-                    }
-                }
-                else
-                {
-                    if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
-                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
-                    {
-                        fields.add(new Object[] { field, attr });
-                    }
-                }
-            }
-        }
-    }
-
-    /**
-     * 根据注解获取最大行高
-     */
-    public short getRowHeight()
-    {
-        double maxHeight = 0;
-        for (Object[] os : this.fields)
-        {
-            Excel excel = (Excel) os[1];
-            maxHeight = Math.max(maxHeight, excel.height());
-        }
-        return (short) (maxHeight * 20);
-    }
-
-    /**
-     * 创建一个工作簿
-     */
-    public void createWorkbook()
-    {
-        this.wb = new SXSSFWorkbook(500);
-        this.sheet = wb.createSheet();
-        wb.setSheetName(0, sheetName);
-        this.styles = createStyles(wb);
-    }
-
-    /**
-     * 创建工作表
-     * 
-     * @param sheetNo sheet数量
-     * @param index 序号
-     */
-    public void createSheet(int sheetNo, int index)
-    {
-        // 设置工作表的名称.
-        if (sheetNo > 1 && index > 0)
-        {
-            this.sheet = wb.createSheet();
-            this.createTitle();
-            wb.setSheetName(index, sheetName + index);
-        }
-    }
-
-    /**
-     * 获取单元格值
-     * 
-     * @param row 获取的行
-     * @param column 获取单元格列号
-     * @return 单元格值
-     */
-    public Object getCellValue(Row row, int column)
-    {
-        if (row == null)
-        {
-            return row;
-        }
-        Object val = "";
-        try
-        {
-            Cell cell = row.getCell(column);
-            if (StringUtils.isNotNull(cell))
-            {
-                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
-                {
-                    val = cell.getNumericCellValue();
-                    if (DateUtil.isCellDateFormatted(cell))
-                    {
-                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
-                    }
-                    else
-                    {
-                        if ((Double) val % 1 != 0)
-                        {
-                            val = new BigDecimal(val.toString());
-                        }
-                        else
-                        {
-                            val = new DecimalFormat("0").format(val);
-                        }
-                    }
-                }
-                else if (cell.getCellType() == CellType.STRING)
-                {
-                    val = cell.getStringCellValue();
-                }
-                else if (cell.getCellType() == CellType.BOOLEAN)
-                {
-                    val = cell.getBooleanCellValue();
-                }
-                else if (cell.getCellType() == CellType.ERROR)
-                {
-                    val = cell.getErrorCellValue();
-                }
-
-            }
-        }
-        catch (Exception e)
-        {
-            return val;
-        }
-        return val;
-    }
-
-    /**
-     * 判断是否是空行
-     * 
-     * @param row 判断的行
-     * @return
-     */
-    private boolean isRowEmpty(Row row)
-    {
-        if (row == null)
-        {
-            return true;
-        }
-        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++)
-        {
-            Cell cell = row.getCell(i);
-            if (cell != null && cell.getCellType() != CellType.BLANK)
-            {
-                return false;
-            }
-        }
-        return true;
-    }
-
-    /**
-     * 获取Excel2003图片
-     *
-     * @param sheet 当前sheet对象
-     * @param workbook 工作簿对象
-     * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData
-     */
-    public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
-    {
-        Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
-        List<HSSFPictureData> pictures = workbook.getAllPictures();
-        if (!pictures.isEmpty())
-        {
-            for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())
-            {
-                HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
-                if (shape instanceof HSSFPicture)
-                {
-                    HSSFPicture pic = (HSSFPicture) shape;
-                    int pictureIndex = pic.getPictureIndex() - 1;
-                    HSSFPictureData picData = pictures.get(pictureIndex);
-                    String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
-                    sheetIndexPicMap.put(picIndex, picData);
-                }
-            }
-            return sheetIndexPicMap;
-        }
-        else
-        {
-            return sheetIndexPicMap;
-        }
-    }
-
-    /**
-     * 获取Excel2007图片
-     *
-     * @param sheet 当前sheet对象
-     * @param workbook 工作簿对象
-     * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData
-     */
-    public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
-    {
-        Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
-        for (POIXMLDocumentPart dr : sheet.getRelations())
-        {
-            if (dr instanceof XSSFDrawing)
-            {
-                XSSFDrawing drawing = (XSSFDrawing) dr;
-                List<XSSFShape> shapes = drawing.getShapes();
-                for (XSSFShape shape : shapes)
-                {
-                    if (shape instanceof XSSFPicture)
-                    {
-                        XSSFPicture pic = (XSSFPicture) shape;
-                        XSSFClientAnchor anchor = pic.getPreferredSize();
-                        CTMarker ctMarker = anchor.getFrom();
-                        String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
-                        sheetIndexPicMap.put(picIndex, pic.getPictureData());
-                    }
-                }
-            }
-        }
-        return sheetIndexPicMap;
-    }
-
-    /**
-     * 格式化不同类型的日期对象
-     * 
-     * @param dateFormat 日期格式
-     * @param val 被格式化的日期对象
-     * @return 格式化后的日期字符
-     */
-    public String parseDateToStr(String dateFormat, Object val)
-    {
-        if (val == null)
-        {
-            return "";
-        }
-        String str;
-        if (val instanceof Date)
-        {
-            str = DateUtils.parseDateToStr(dateFormat, (Date) val);
-        }
-        else if (val instanceof LocalDateTime)
-        {
-            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));
-        }
-        else if (val instanceof LocalDate)
-        {
-            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));
-        }
-        else
-        {
-            str = val.toString();
-        }
-        return str;
-    }
-
-    /**
-     * 是否有对象的子列表
-     */
-    public boolean isSubList()
-    {
-        return StringUtils.isNotNull(subFields) && subFields.size() > 0;
-    }
-
-    /**
-     * 是否有对象的子列表,集合不为空
-     */
-    public boolean isSubListValue(T vo)
-    {
-        return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0;
-    }
-
-    /**
-     * 获取集合的值
-     */
-    public Collection<?> getListCellValue(Object obj)
-    {
-        Object value;
-        try
-        {
-            value = subMethod.invoke(obj, new Object[] {});
-        }
-        catch (Exception e)
-        {
-            return new ArrayList<Object>();
-        }
-        return (Collection<?>) value;
-    }
-
-    /**
-     * 获取对象的子列表方法
-     * 
-     * @param name 名称
-     * @param pojoClass 类对象
-     * @return 子列表方法
-     */
-    public Method getSubMethod(String name, Class<?> pojoClass)
-    {
-        StringBuffer getMethodName = new StringBuffer("get");
-        getMethodName.append(name.substring(0, 1).toUpperCase());
-        getMethodName.append(name.substring(1));
-        Method method = null;
-        try
-        {
-            method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});
-        }
-        catch (Exception e)
-        {
-            log.error("获取对象异常{}", e.getMessage());
-        }
-        return method;
-    }
-}
+package com.acupuncture.common.utils.poi;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.lang.reflect.ParameterizedType;
+import java.math.BigDecimal;
+import java.text.DecimalFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.UUID;
+import java.util.stream.Collectors;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+import org.apache.commons.lang3.RegExUtils;
+import org.apache.commons.lang3.reflect.FieldUtils;
+import org.apache.poi.hssf.usermodel.HSSFClientAnchor;
+import org.apache.poi.hssf.usermodel.HSSFPicture;
+import org.apache.poi.hssf.usermodel.HSSFPictureData;
+import org.apache.poi.hssf.usermodel.HSSFShape;
+import org.apache.poi.hssf.usermodel.HSSFSheet;
+import org.apache.poi.hssf.usermodel.HSSFWorkbook;
+import org.apache.poi.ooxml.POIXMLDocumentPart;
+import org.apache.poi.ss.usermodel.BorderStyle;
+import org.apache.poi.ss.usermodel.Cell;
+import org.apache.poi.ss.usermodel.CellStyle;
+import org.apache.poi.ss.usermodel.CellType;
+import org.apache.poi.ss.usermodel.ClientAnchor;
+import org.apache.poi.ss.usermodel.DataFormat;
+import org.apache.poi.ss.usermodel.DataValidation;
+import org.apache.poi.ss.usermodel.DataValidationConstraint;
+import org.apache.poi.ss.usermodel.DataValidationHelper;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.apache.poi.ss.usermodel.Drawing;
+import org.apache.poi.ss.usermodel.FillPatternType;
+import org.apache.poi.ss.usermodel.Font;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+import org.apache.poi.ss.usermodel.Name;
+import org.apache.poi.ss.usermodel.PictureData;
+import org.apache.poi.ss.usermodel.Row;
+import org.apache.poi.ss.usermodel.Sheet;
+import org.apache.poi.ss.usermodel.VerticalAlignment;
+import org.apache.poi.ss.usermodel.Workbook;
+import org.apache.poi.ss.usermodel.WorkbookFactory;
+import org.apache.poi.ss.util.CellRangeAddress;
+import org.apache.poi.ss.util.CellRangeAddressList;
+import org.apache.poi.util.IOUtils;
+import org.apache.poi.xssf.streaming.SXSSFWorkbook;
+import org.apache.poi.xssf.usermodel.XSSFClientAnchor;
+import org.apache.poi.xssf.usermodel.XSSFDataValidation;
+import org.apache.poi.xssf.usermodel.XSSFDrawing;
+import org.apache.poi.xssf.usermodel.XSSFPicture;
+import org.apache.poi.xssf.usermodel.XSSFShape;
+import org.apache.poi.xssf.usermodel.XSSFSheet;
+import org.apache.poi.xssf.usermodel.XSSFWorkbook;
+import org.openxmlformats.schemas.drawingml.x2006.spreadsheetDrawing.CTMarker;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.annotation.Excel.Type;
+import com.acupuncture.common.annotation.Excels;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.exception.UtilException;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.DictUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.file.FileTypeUtils;
+import com.acupuncture.common.utils.file.FileUtils;
+import com.acupuncture.common.utils.file.ImageUtils;
+import com.acupuncture.common.utils.reflect.ReflectUtils;
+
+/**
+ * Excel相关处理
+ * 
+ * @author acupuncture
+ */
+public class ExcelUtil<T>
+{
+    private static final Logger log = LoggerFactory.getLogger(ExcelUtil.class);
+
+    public static final String FORMULA_REGEX_STR = "=|-|\\+|@";
+
+    public static final String[] FORMULA_STR = { "=", "-", "+", "@" };
+
+    /**
+     * 用于dictType属性数据存储,避免重复查缓存
+     */
+    public Map<String, String> sysDictMap = new HashMap<String, String>();
+
+    /**
+     * Excel sheet最大行数,默认65536
+     */
+    public static final int sheetSize = 65536;
+
+    /**
+     * 工作表名称
+     */
+    private String sheetName;
+
+    /**
+     * 导出类型(EXPORT:导出数据;IMPORT:导入模板)
+     */
+    private Type type;
+
+    /**
+     * 工作薄对象
+     */
+    private Workbook wb;
+
+    /**
+     * 工作表对象
+     */
+    private Sheet sheet;
+
+    /**
+     * 样式列表
+     */
+    private Map<String, CellStyle> styles;
+
+    /**
+     * 导入导出数据列表
+     */
+    private List<T> list;
+
+    /**
+     * 注解列表
+     */
+    private List<Object[]> fields;
+
+    /**
+     * 当前行号
+     */
+    private int rownum;
+
+    /**
+     * 标题
+     */
+    private String title;
+
+    /**
+     * 最大高度
+     */
+    private short maxHeight;
+
+    /**
+     * 合并后最后行数
+     */
+    private int subMergedLastRowNum = 0;
+
+    /**
+     * 合并后开始行数
+     */
+    private int subMergedFirstRowNum = 1;
+
+    /**
+     * 对象的子列表方法
+     */
+    private Method subMethod;
+
+    /**
+     * 对象的子列表属性
+     */
+    private List<Field> subFields;
+
+    /**
+     * 统计列表
+     */
+    private Map<Integer, Double> statistics = new HashMap<Integer, Double>();
+
+    /**
+     * 数字格式
+     */
+    private static final DecimalFormat DOUBLE_FORMAT = new DecimalFormat("######0.00");
+
+    /**
+     * 实体对象
+     */
+    public Class<T> clazz;
+
+    /**
+     * 需要显示列属性
+     */
+    public String[] includeFields;
+
+    /**
+     * 需要排除列属性
+     */
+    public String[] excludeFields;
+
+    public ExcelUtil(Class<T> clazz)
+    {
+        this.clazz = clazz;
+    }
+
+    /**
+     * 仅在Excel中显示列属性
+     *
+     * @param fields 列属性名 示例[单个"name"/多个"id","name"]
+     */
+    public void showColumn(String... fields)
+    {
+        this.includeFields = fields;
+    }
+
+    /**
+     * 隐藏Excel中列属性
+     *
+     * @param fields 列属性名 示例[单个"name"/多个"id","name"]
+     */
+    public void hideColumn(String... fields)
+    {
+        this.excludeFields = fields;
+    }
+
+    public void init(List<T> list, String sheetName, String title, Type type)
+    {
+        if (list == null)
+        {
+            list = new ArrayList<T>();
+        }
+        this.list = list;
+        this.sheetName = sheetName;
+        this.type = type;
+        this.title = title;
+        createExcelField();
+        createWorkbook();
+        createTitle();
+        createSubHead();
+    }
+
+    /**
+     * 创建excel第一行标题
+     */
+    public void createTitle()
+    {
+        if (StringUtils.isNotEmpty(title))
+        {
+            int titleLastCol = this.fields.size() - 1;
+            if (isSubList())
+            {
+                titleLastCol = titleLastCol + subFields.size() - 1;
+            }
+            Row titleRow = sheet.createRow(rownum == 0 ? rownum++ : 0);
+            titleRow.setHeightInPoints(30);
+            Cell titleCell = titleRow.createCell(0);
+            titleCell.setCellStyle(styles.get("title"));
+            titleCell.setCellValue(title);
+            sheet.addMergedRegion(new CellRangeAddress(titleRow.getRowNum(), titleRow.getRowNum(), 0, titleLastCol));
+        }
+    }
+
+    /**
+     * 创建对象的子列表名称
+     */
+    public void createSubHead()
+    {
+        if (isSubList())
+        {
+            Row subRow = sheet.createRow(rownum);
+            int column = 0;
+            int subFieldSize = subFields != null ? subFields.size() : 0;
+            for (Object[] objects : fields)
+            {
+                Field field = (Field) objects[0];
+                Excel attr = (Excel) objects[1];
+                if (Collection.class.isAssignableFrom(field.getType()))
+                {
+                    Cell cell = subRow.createCell(column);
+                    cell.setCellValue(attr.name());
+                    cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
+                    if (subFieldSize > 1)
+                    {
+                        CellRangeAddress cellAddress = new CellRangeAddress(rownum, rownum, column, column + subFieldSize - 1);
+                        sheet.addMergedRegion(cellAddress);
+                    }
+                    column += subFieldSize;
+                }
+                else
+                {
+                    Cell cell = subRow.createCell(column++);
+                    cell.setCellValue(attr.name());
+                    cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
+                }
+            }
+            rownum++;
+        }
+    }
+
+    /**
+     * 对excel表单默认第一个索引名转换成list
+     * 
+     * @param is 输入流
+     * @return 转换后集合
+     */
+    public List<T> importExcel(InputStream is)
+    {
+        return importExcel(is, 0);
+    }
+
+    /**
+     * 对excel表单默认第一个索引名转换成list
+     * 
+     * @param is 输入流
+     * @param titleNum 标题占用行数
+     * @return 转换后集合
+     */
+    public List<T> importExcel(InputStream is, int titleNum)
+    {
+        List<T> list = null;
+        try
+        {
+            list = importExcel(StringUtils.EMPTY, is, titleNum);
+        }
+        catch (Exception e)
+        {
+            log.error("导入Excel异常{}", e.getMessage());
+            throw new UtilException(e.getMessage());
+        }
+        finally
+        {
+            IOUtils.closeQuietly(is);
+        }
+        return list;
+    }
+
+    /**
+     * 对excel表单指定表格索引名转换成list
+     * 
+     * @param sheetName 表格索引名
+     * @param titleNum 标题占用行数
+     * @param is 输入流
+     * @return 转换后集合
+     */
+    public List<T> importExcel(String sheetName, InputStream is, int titleNum) throws Exception
+    {
+        this.type = Type.IMPORT;
+        this.wb = WorkbookFactory.create(is);
+        List<T> list = new ArrayList<T>();
+        // 如果指定sheet名,则取指定sheet中的内容 否则默认指向第1个sheet
+        Sheet sheet = StringUtils.isNotEmpty(sheetName) ? wb.getSheet(sheetName) : wb.getSheetAt(0);
+        if (sheet == null)
+        {
+            throw new IOException("文件sheet不存在");
+        }
+        boolean isXSSFWorkbook = !(wb instanceof HSSFWorkbook);
+        Map<String, PictureData> pictures;
+        if (isXSSFWorkbook)
+        {
+            pictures = getSheetPictures07((XSSFSheet) sheet, (XSSFWorkbook) wb);
+        }
+        else
+        {
+            pictures = getSheetPictures03((HSSFSheet) sheet, (HSSFWorkbook) wb);
+        }
+        // 获取最后一个非空行的行下标,比如总行数为n,则返回的为n-1
+        int rows = sheet.getLastRowNum();
+        if (rows > 0)
+        {
+            // 定义一个map用于存放excel列的序号和field.
+            Map<String, Integer> cellMap = new HashMap<String, Integer>();
+            // 获取表头
+            Row heard = sheet.getRow(titleNum);
+            for (int i = 0; i < heard.getPhysicalNumberOfCells(); i++)
+            {
+                Cell cell = heard.getCell(i);
+                if (StringUtils.isNotNull(cell))
+                {
+                    String value = this.getCellValue(heard, i).toString();
+                    cellMap.put(value, i);
+                }
+                else
+                {
+                    cellMap.put(null, i);
+                }
+            }
+            // 有数据时才处理 得到类的所有field.
+            List<Object[]> fields = this.getFields();
+            Map<Integer, Object[]> fieldsMap = new HashMap<Integer, Object[]>();
+            for (Object[] objects : fields)
+            {
+                Excel attr = (Excel) objects[1];
+                Integer column = cellMap.get(attr.name());
+                if (column != null)
+                {
+                    fieldsMap.put(column, objects);
+                }
+            }
+            for (int i = titleNum + 1; i <= rows; i++)
+            {
+                // 从第2行开始取数据,默认第一行是表头.
+                Row row = sheet.getRow(i);
+                // 判断当前行是否是空行
+                if (isRowEmpty(row))
+                {
+                    continue;
+                }
+                T entity = null;
+                for (Map.Entry<Integer, Object[]> entry : fieldsMap.entrySet())
+                {
+                    Object val = this.getCellValue(row, entry.getKey());
+
+                    // 如果不存在实例则新建.
+                    entity = (entity == null ? clazz.newInstance() : entity);
+                    // 从map中得到对应列的field.
+                    Field field = (Field) entry.getValue()[0];
+                    Excel attr = (Excel) entry.getValue()[1];
+                    // 取得类型,并根据对象类型设置值.
+                    Class<?> fieldType = field.getType();
+                    if (String.class == fieldType)
+                    {
+                        String s = Convert.toStr(val);
+                        if (StringUtils.endsWith(s, ".0"))
+                        {
+                            val = StringUtils.substringBefore(s, ".0");
+                        }
+                        else
+                        {
+                            String dateFormat = field.getAnnotation(Excel.class).dateFormat();
+                            if (StringUtils.isNotEmpty(dateFormat))
+                            {
+                                val = parseDateToStr(dateFormat, val);
+                            }
+                            else
+                            {
+                                val = Convert.toStr(val);
+                            }
+                        }
+                    }
+                    else if ((Integer.TYPE == fieldType || Integer.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
+                    {
+                        val = Convert.toInt(val);
+                    }
+                    else if ((Long.TYPE == fieldType || Long.class == fieldType) && StringUtils.isNumeric(Convert.toStr(val)))
+                    {
+                        val = Convert.toLong(val);
+                    }
+                    else if (Double.TYPE == fieldType || Double.class == fieldType)
+                    {
+                        val = Convert.toDouble(val);
+                    }
+                    else if (Float.TYPE == fieldType || Float.class == fieldType)
+                    {
+                        val = Convert.toFloat(val);
+                    }
+                    else if (BigDecimal.class == fieldType)
+                    {
+                        val = Convert.toBigDecimal(val);
+                    }
+                    else if (Date.class == fieldType)
+                    {
+                        if (val instanceof String)
+                        {
+                            val = DateUtils.parseDate(val);
+                        }
+                        else if (val instanceof Double)
+                        {
+                            val = DateUtil.getJavaDate((Double) val);
+                        }
+                    }
+                    else if (Boolean.TYPE == fieldType || Boolean.class == fieldType)
+                    {
+                        val = Convert.toBool(val, false);
+                    }
+                    if (StringUtils.isNotNull(fieldType))
+                    {
+                        String propertyName = field.getName();
+                        if (StringUtils.isNotEmpty(attr.targetAttr()))
+                        {
+                            propertyName = field.getName() + "." + attr.targetAttr();
+                        }
+                        if (StringUtils.isNotEmpty(attr.readConverterExp()))
+                        {
+                            val = reverseByExp(Convert.toStr(val), attr.readConverterExp(), attr.separator());
+                        }
+                        else if (StringUtils.isNotEmpty(attr.dictType()))
+                        {
+                            if (!sysDictMap.containsKey(attr.dictType() + val))
+                            {
+                                String dictValue = reverseDictByExp(Convert.toStr(val), attr.dictType(), attr.separator());
+                                sysDictMap.put(attr.dictType() + val, dictValue);
+                            }
+                            val = sysDictMap.get(attr.dictType() + val);
+                        }
+                        else if (!attr.handler().equals(ExcelHandlerAdapter.class))
+                        {
+                            val = dataFormatHandlerAdapter(val, attr, null);
+                        }
+                        else if (ColumnType.IMAGE == attr.cellType() && StringUtils.isNotEmpty(pictures))
+                        {
+                            PictureData image = pictures.get(row.getRowNum() + "_" + entry.getKey());
+                            if (image == null)
+                            {
+                                val = "";
+                            }
+                            else
+                            {
+                                byte[] data = image.getData();
+                                val = FileUtils.writeImportBytes(data);
+                            }
+                        }
+                        ReflectUtils.invokeSetter(entity, propertyName, val);
+                    }
+                }
+                list.add(entity);
+            }
+        }
+        return list;
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public AjaxResult exportExcel(List<T> list, String sheetName)
+    {
+        return exportExcel(list, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public AjaxResult exportExcel(List<T> list, String sheetName, String title)
+    {
+        this.init(list, sheetName, title, Type.EXPORT);
+        return exportExcel();
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param response 返回数据
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
+    {
+        exportExcel(response, list, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param response 返回数据
+     * @param list 导出数据集合
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName, String title)
+    {
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        this.init(list, sheetName, title, Type.EXPORT);
+        exportExcel(response);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public AjaxResult importTemplateExcel(String sheetName)
+    {
+        return importTemplateExcel(sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public AjaxResult importTemplateExcel(String sheetName, String title)
+    {
+        this.init(null, sheetName, title, Type.IMPORT);
+        return exportExcel();
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @return 结果
+     */
+    public void importTemplateExcel(HttpServletResponse response, String sheetName)
+    {
+        importTemplateExcel(response, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @param sheetName 工作表的名称
+     * @param title 标题
+     * @return 结果
+     */
+    public void importTemplateExcel(HttpServletResponse response, String sheetName, String title)
+    {
+        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
+        response.setCharacterEncoding("utf-8");
+        this.init(null, sheetName, title, Type.IMPORT);
+        exportExcel(response);
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @return 结果
+     */
+    public void exportExcel(HttpServletResponse response)
+    {
+        try
+        {
+            writeSheet();
+            wb.write(response.getOutputStream());
+        }
+        catch (Exception e)
+        {
+            log.error("导出Excel异常{}", e.getMessage());
+        }
+        finally
+        {
+            IOUtils.closeQuietly(wb);
+        }
+    }
+
+    /**
+     * 对list数据源将其里面的数据导入到excel表单
+     * 
+     * @return 结果
+     */
+    public AjaxResult exportExcel()
+    {
+        OutputStream out = null;
+        try
+        {
+            writeSheet();
+            String filename = encodingFilename(sheetName);
+            out = new FileOutputStream(getAbsoluteFile(filename));
+            wb.write(out);
+            return AjaxResult.success(filename);
+        }
+        catch (Exception e)
+        {
+            log.error("导出Excel异常{}", e.getMessage());
+            throw new UtilException("导出Excel失败,请联系网站管理员!");
+        }
+        finally
+        {
+            IOUtils.closeQuietly(wb);
+            IOUtils.closeQuietly(out);
+        }
+    }
+
+    /**
+     * 创建写入数据到Sheet
+     */
+    public void writeSheet()
+    {
+        // 取出一共有多少个sheet.
+        int sheetNo = Math.max(1, (int) Math.ceil(list.size() * 1.0 / sheetSize));
+        for (int index = 0; index < sheetNo; index++)
+        {
+            createSheet(sheetNo, index);
+
+            // 产生一行
+            Row row = sheet.createRow(rownum);
+            int column = 0;
+            // 写入各个字段的列头名称
+            for (Object[] os : fields)
+            {
+                Field field = (Field) os[0];
+                Excel excel = (Excel) os[1];
+                if (Collection.class.isAssignableFrom(field.getType()))
+                {
+                    for (Field subField : subFields)
+                    {
+                        Excel subExcel = subField.getAnnotation(Excel.class);
+                        this.createHeadCell(subExcel, row, column++);
+                    }
+                }
+                else
+                {
+                    this.createHeadCell(excel, row, column++);
+                }
+            }
+            if (Type.EXPORT.equals(type))
+            {
+                fillExcelData(index, row);
+                addStatisticsRow();
+            }
+        }
+    }
+
+    /**
+     * 填充excel数据
+     * 
+     * @param index 序号
+     * @param row 单元格行
+     */
+    @SuppressWarnings("unchecked")
+    public void fillExcelData(int index, Row row)
+    {
+        int startNo = index * sheetSize;
+        int endNo = Math.min(startNo + sheetSize, list.size());
+        int currentRowNum = rownum + 1; // 从标题行后开始
+
+        for (int i = startNo; i < endNo; i++)
+        {
+            row = sheet.createRow(currentRowNum);
+            T vo = (T) list.get(i);
+            int column = 0;
+            int maxSubListSize = getCurrentMaxSubListSize(vo);
+            for (Object[] os : fields)
+            {
+                Field field = (Field) os[0];
+                Excel excel = (Excel) os[1];
+                if (Collection.class.isAssignableFrom(field.getType()))
+                {
+                    try
+                    {
+                        Collection<?> subList = (Collection<?>) getTargetValue(vo, field, excel);
+                        if (subList != null && !subList.isEmpty())
+                        {
+                            int subIndex = 0;
+                            for (Object subVo : subList)
+                            {
+                                Row subRow = sheet.getRow(currentRowNum + subIndex);
+                                if (subRow == null)
+                                {
+                                    subRow = sheet.createRow(currentRowNum + subIndex);
+                                }
+
+                                int subColumn = column;
+                                for (Field subField : subFields)
+                                {
+                                    Excel subExcel = subField.getAnnotation(Excel.class);
+                                    addCell(subExcel, subRow, (T) subVo, subField, subColumn++);
+                                }
+                                subIndex++;
+                            }
+                            column += subFields.size();
+                        }
+                    }
+                    catch (Exception e)
+                    {
+                        log.error("填充集合数据失败", e);
+                    }
+                }
+                else
+                {
+                    // 创建单元格并设置值
+                    addCell(excel, row, vo, field, column);
+                    if (maxSubListSize > 1 && excel.needMerge())
+                    {
+                        sheet.addMergedRegion(new CellRangeAddress(currentRowNum, currentRowNum + maxSubListSize - 1, column, column));
+                    }
+                    column++;
+                }
+            }
+            currentRowNum += maxSubListSize;
+        }
+    }
+
+    /**
+     * 获取子列表最大数
+     */
+    private int getCurrentMaxSubListSize(T vo)
+    {
+        int maxSubListSize = 1;
+        for (Object[] os : fields)
+        {
+            Field field = (Field) os[0];
+            if (Collection.class.isAssignableFrom(field.getType()))
+            {
+                try
+                {
+                    Collection<?> subList = (Collection<?>) getTargetValue(vo, field, (Excel) os[1]);
+                    if (subList != null && !subList.isEmpty())
+                    {
+                        maxSubListSize = Math.max(maxSubListSize, subList.size());
+                    }
+                }
+                catch (Exception e)
+                {
+                    log.error("获取集合大小失败", e);
+                }
+            }
+        }
+        return maxSubListSize;
+    }
+
+    /**
+     * 创建表格样式
+     * 
+     * @param wb 工作薄对象
+     * @return 样式列表
+     */
+    private Map<String, CellStyle> createStyles(Workbook wb)
+    {
+        // 写入各条记录,每条记录对应excel表中的一行
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+        CellStyle style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        Font titleFont = wb.createFont();
+        titleFont.setFontName("Arial");
+        titleFont.setFontHeightInPoints((short) 16);
+        titleFont.setBold(true);
+        style.setFont(titleFont);
+        DataFormat dataFormat = wb.createDataFormat();
+        style.setDataFormat(dataFormat.getFormat("@"));
+        styles.put("title", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        style.setBorderRight(BorderStyle.THIN);
+        style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderLeft(BorderStyle.THIN);
+        style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderTop(BorderStyle.THIN);
+        style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        style.setBorderBottom(BorderStyle.THIN);
+        style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+        Font dataFont = wb.createFont();
+        dataFont.setFontName("Arial");
+        dataFont.setFontHeightInPoints((short) 10);
+        style.setFont(dataFont);
+        styles.put("data", style);
+
+        style = wb.createCellStyle();
+        style.setAlignment(HorizontalAlignment.CENTER);
+        style.setVerticalAlignment(VerticalAlignment.CENTER);
+        Font totalFont = wb.createFont();
+        totalFont.setFontName("Arial");
+        totalFont.setFontHeightInPoints((short) 10);
+        style.setFont(totalFont);
+        styles.put("total", style);
+
+        styles.putAll(annotationHeaderStyles(wb, styles));
+
+        styles.putAll(annotationDataStyles(wb));
+
+        return styles;
+    }
+
+    /**
+     * 根据Excel注解创建表格头样式
+     * 
+     * @param wb 工作薄对象
+     * @return 自定义样式列表
+     */
+    private Map<String, CellStyle> annotationHeaderStyles(Workbook wb, Map<String, CellStyle> styles)
+    {
+        Map<String, CellStyle> headerStyles = new HashMap<String, CellStyle>();
+        for (Object[] os : fields)
+        {
+            Excel excel = (Excel) os[1];
+            String key = StringUtils.format("header_{}_{}", excel.headerColor(), excel.headerBackgroundColor());
+            if (!headerStyles.containsKey(key))
+            {
+                CellStyle style = wb.createCellStyle();
+                style.cloneStyleFrom(styles.get("data"));
+                style.setAlignment(HorizontalAlignment.CENTER);
+                style.setVerticalAlignment(VerticalAlignment.CENTER);
+                style.setFillForegroundColor(excel.headerBackgroundColor().index);
+                style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+                Font headerFont = wb.createFont();
+                headerFont.setFontName("Arial");
+                headerFont.setFontHeightInPoints((short) 10);
+                headerFont.setBold(true);
+                headerFont.setColor(excel.headerColor().index);
+                style.setFont(headerFont);
+                // 设置表格头单元格文本形式
+                DataFormat dataFormat = wb.createDataFormat();
+                style.setDataFormat(dataFormat.getFormat("@"));
+                headerStyles.put(key, style);
+            }
+        }
+        return headerStyles;
+    }
+
+    /**
+     * 根据Excel注解创建表格列样式
+     * 
+     * @param wb 工作薄对象
+     * @return 自定义样式列表
+     */
+    private Map<String, CellStyle> annotationDataStyles(Workbook wb)
+    {
+        Map<String, CellStyle> styles = new HashMap<String, CellStyle>();
+        for (Object[] os : fields)
+        {
+            Field field = (Field) os[0];
+            Excel excel = (Excel) os[1];
+            if (Collection.class.isAssignableFrom(field.getType()))
+            {
+                ParameterizedType pt = (ParameterizedType) field.getGenericType();
+                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
+                List<Field> subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
+                for (Field subField : subFields)
+                {
+                    Excel subExcel = subField.getAnnotation(Excel.class);
+                    annotationDataStyles(styles, subField, subExcel);
+                }
+            }
+            else
+            {
+                annotationDataStyles(styles, field, excel);
+            }
+        }
+        return styles;
+    }
+
+    /**
+     * 根据Excel注解创建表格列样式
+     * 
+     * @param styles 自定义样式列表
+     * @param field  属性列信息
+     * @param excel  注解信息
+     */
+    public void annotationDataStyles(Map<String, CellStyle> styles, Field field, Excel excel)
+    {
+        String key = StringUtils.format("data_{}_{}_{}_{}_{}", excel.align(), excel.color(), excel.backgroundColor(), excel.cellType(), excel.wrapText());
+        if (!styles.containsKey(key))
+        {
+            CellStyle style = wb.createCellStyle();
+            style.setAlignment(excel.align());
+            style.setVerticalAlignment(VerticalAlignment.CENTER);
+            style.setBorderRight(BorderStyle.THIN);
+            style.setRightBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+            style.setBorderLeft(BorderStyle.THIN);
+            style.setLeftBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+            style.setBorderTop(BorderStyle.THIN);
+            style.setTopBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+            style.setBorderBottom(BorderStyle.THIN);
+            style.setBottomBorderColor(IndexedColors.GREY_50_PERCENT.getIndex());
+            style.setFillPattern(FillPatternType.SOLID_FOREGROUND);
+            style.setFillForegroundColor(excel.backgroundColor().getIndex());
+            style.setWrapText(excel.wrapText());
+            Font dataFont = wb.createFont();
+            dataFont.setFontName("Arial");
+            dataFont.setFontHeightInPoints((short) 10);
+            dataFont.setColor(excel.color().index);
+            style.setFont(dataFont);
+            if (ColumnType.TEXT == excel.cellType())
+            {
+                DataFormat dataFormat = wb.createDataFormat();
+                style.setDataFormat(dataFormat.getFormat("@"));
+            }
+            styles.put(key, style);
+        }
+    }
+
+    /**
+     * 创建单元格
+     */
+    public Cell createHeadCell(Excel attr, Row row, int column)
+    {
+        // 创建列
+        Cell cell = row.createCell(column);
+        // 写入列信息
+        cell.setCellValue(attr.name());
+        setDataValidation(attr, row, column);
+        cell.setCellStyle(styles.get(StringUtils.format("header_{}_{}", attr.headerColor(), attr.headerBackgroundColor())));
+        if (isSubList())
+        {
+            // 填充默认样式,防止合并单元格样式失效
+            sheet.setDefaultColumnStyle(column, styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
+            if (attr.needMerge())
+            {
+                sheet.addMergedRegion(new CellRangeAddress(rownum - 1, rownum, column, column));
+            }
+        }
+        return cell;
+    }
+
+    /**
+     * 设置单元格信息
+     * 
+     * @param value 单元格值
+     * @param attr 注解相关
+     * @param cell 单元格信息
+     */
+    public void setCellVo(Object value, Excel attr, Cell cell)
+    {
+        if (ColumnType.STRING == attr.cellType() || ColumnType.TEXT == attr.cellType())
+        {
+            String cellValue = Convert.toStr(value);
+            // 对于任何以表达式触发字符 =-+@开头的单元格,直接使用tab字符作为前缀,防止CSV注入。
+            if (StringUtils.startsWithAny(cellValue, FORMULA_STR))
+            {
+                cellValue = RegExUtils.replaceFirst(cellValue, FORMULA_REGEX_STR, "\t$0");
+            }
+            if (value instanceof Collection && StringUtils.equals("[]", cellValue))
+            {
+                cellValue = StringUtils.EMPTY;
+            }
+            cell.setCellValue(StringUtils.isNull(cellValue) ? attr.defaultValue() : cellValue + attr.suffix());
+        }
+        else if (ColumnType.NUMERIC == attr.cellType())
+        {
+            if (StringUtils.isNotNull(value))
+            {
+                cell.setCellValue(StringUtils.contains(Convert.toStr(value), ".") ? Convert.toDouble(value) : Convert.toInt(value));
+            }
+        }
+        else if (ColumnType.IMAGE == attr.cellType())
+        {
+            ClientAnchor anchor = new XSSFClientAnchor(0, 0, 0, 0, (short) cell.getColumnIndex(), cell.getRow().getRowNum(), (short) (cell.getColumnIndex() + 1), cell.getRow().getRowNum() + 1);
+            String imagePath = Convert.toStr(value);
+            if (StringUtils.isNotEmpty(imagePath))
+            {
+                byte[] data = ImageUtils.getImage(imagePath);
+                getDrawingPatriarch(cell.getSheet()).createPicture(anchor,
+                        cell.getSheet().getWorkbook().addPicture(data, getImageType(data)));
+            }
+        }
+    }
+
+    /**
+     * 获取画布
+     */
+    public static Drawing<?> getDrawingPatriarch(Sheet sheet)
+    {
+        if (sheet.getDrawingPatriarch() == null)
+        {
+            sheet.createDrawingPatriarch();
+        }
+        return sheet.getDrawingPatriarch();
+    }
+
+    /**
+     * 获取图片类型,设置图片插入类型
+     */
+    public int getImageType(byte[] value)
+    {
+        String type = FileTypeUtils.getFileExtendName(value);
+        if ("JPG".equalsIgnoreCase(type))
+        {
+            return Workbook.PICTURE_TYPE_JPEG;
+        }
+        else if ("PNG".equalsIgnoreCase(type))
+        {
+            return Workbook.PICTURE_TYPE_PNG;
+        }
+        return Workbook.PICTURE_TYPE_JPEG;
+    }
+
+    /**
+     * 创建表格样式
+     */
+    public void setDataValidation(Excel attr, Row row, int column)
+    {
+        if (attr.name().indexOf("注:") >= 0)
+        {
+            sheet.setColumnWidth(column, 6000);
+        }
+        else
+        {
+            // 设置列宽
+            sheet.setColumnWidth(column, (int) ((attr.width() + 0.72) * 256));
+        }
+        if (StringUtils.isNotEmpty(attr.prompt()) || attr.combo().length > 0 || attr.comboReadDict())
+        {
+            String[] comboArray = attr.combo();
+            if (attr.comboReadDict())
+            {
+                if (!sysDictMap.containsKey("combo_" + attr.dictType()))
+                {
+                    String labels = DictUtils.getDictLabels(attr.dictType());
+                    sysDictMap.put("combo_" + attr.dictType(), labels);
+                }
+                String val = sysDictMap.get("combo_" + attr.dictType());
+                comboArray = StringUtils.split(val, DictUtils.SEPARATOR);
+            }
+            if (comboArray.length > 15 || StringUtils.join(comboArray).length() > 255)
+            {
+                // 如果下拉数大于15或字符串长度大于255,则使用一个新sheet存储,避免生成的模板下拉值获取不到
+                setXSSFValidationWithHidden(sheet, comboArray, attr.prompt(), 1, 100, column, column);
+            }
+            else
+            {
+                // 提示信息或只能选择不能输入的列内容.
+                setPromptOrValidation(sheet, comboArray, attr.prompt(), 1, 100, column, column);
+            }
+        }
+    }
+
+    /**
+     * 添加单元格
+     */
+    public Cell addCell(Excel attr, Row row, T vo, Field field, int column)
+    {
+        Cell cell = null;
+        try
+        {
+            // 设置行高
+            row.setHeight(maxHeight);
+            // 根据Excel中设置情况决定是否导出,有些情况需要保持为空,希望用户填写这一列.
+            if (attr.isExport())
+            {
+                // 创建cell
+                cell = row.createCell(column);
+                if (isSubListValue(vo) && getListCellValue(vo).size() > 1 && attr.needMerge())
+                {
+                    if (subMergedLastRowNum >= subMergedFirstRowNum)
+                    {
+                        sheet.addMergedRegion(new CellRangeAddress(subMergedFirstRowNum, subMergedLastRowNum, column, column));
+                    }
+                }
+                cell.setCellStyle(styles.get(StringUtils.format("data_{}_{}_{}_{}_{}", attr.align(), attr.color(), attr.backgroundColor(), attr.cellType(), attr.wrapText())));
+
+                // 用于读取对象中的属性
+                Object value = getTargetValue(vo, field, attr);
+                String dateFormat = attr.dateFormat();
+                String readConverterExp = attr.readConverterExp();
+                String separator = attr.separator();
+                String dictType = attr.dictType();
+                if (StringUtils.isNotEmpty(dateFormat) && StringUtils.isNotNull(value))
+                {
+                    cell.setCellValue(parseDateToStr(dateFormat, value));
+                }
+                else if (StringUtils.isNotEmpty(readConverterExp) && StringUtils.isNotNull(value))
+                {
+                    cell.setCellValue(convertByExp(Convert.toStr(value), readConverterExp, separator));
+                }
+                else if (StringUtils.isNotEmpty(dictType) && StringUtils.isNotNull(value))
+                {
+                    if (!sysDictMap.containsKey(dictType + value))
+                    {
+                        String lable = convertDictByExp(Convert.toStr(value), dictType, separator);
+                        sysDictMap.put(dictType + value, lable);
+                    }
+                    cell.setCellValue(sysDictMap.get(dictType + value));
+                }
+                else if (value instanceof BigDecimal && -1 != attr.scale())
+                {
+                    cell.setCellValue((((BigDecimal) value).setScale(attr.scale(), attr.roundingMode())).doubleValue());
+                }
+                else if (!attr.handler().equals(ExcelHandlerAdapter.class))
+                {
+                    cell.setCellValue(dataFormatHandlerAdapter(value, attr, cell));
+                }
+                else
+                {
+                    // 设置列类型
+                    setCellVo(value, attr, cell);
+                }
+                addStatisticsData(column, Convert.toStr(value), attr);
+            }
+        }
+        catch (Exception e)
+        {
+            log.error("导出Excel失败{}", e);
+        }
+        return cell;
+    }
+
+    /**
+     * 设置 POI XSSFSheet 单元格提示或选择框
+     * 
+     * @param sheet 表单
+     * @param textlist 下拉框显示的内容
+     * @param promptContent 提示内容
+     * @param firstRow 开始行
+     * @param endRow 结束行
+     * @param firstCol 开始列
+     * @param endCol 结束列
+     */
+    public void setPromptOrValidation(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow,
+            int firstCol, int endCol)
+    {
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        DataValidationConstraint constraint = textlist.length > 0 ? helper.createExplicitListConstraint(textlist) : helper.createCustomConstraint("DD1");
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        if (StringUtils.isNotEmpty(promptContent))
+        {
+            // 如果设置了提示信息则鼠标放上去提示
+            dataValidation.createPromptBox("", promptContent);
+            dataValidation.setShowPromptBox(true);
+        }
+        // 处理Excel兼容性问题
+        if (dataValidation instanceof XSSFDataValidation)
+        {
+            dataValidation.setSuppressDropDownArrow(true);
+            dataValidation.setShowErrorBox(true);
+        }
+        else
+        {
+            dataValidation.setSuppressDropDownArrow(false);
+        }
+        sheet.addValidationData(dataValidation);
+    }
+
+    /**
+     * 设置某些列的值只能输入预制的数据,显示下拉框(兼容超出一定数量的下拉框).
+     * 
+     * @param sheet 要设置的sheet.
+     * @param textlist 下拉框显示的内容
+     * @param promptContent 提示内容
+     * @param firstRow 开始行
+     * @param endRow 结束行
+     * @param firstCol 开始列
+     * @param endCol 结束列
+     */
+    public void setXSSFValidationWithHidden(Sheet sheet, String[] textlist, String promptContent, int firstRow, int endRow, int firstCol, int endCol)
+    {
+        String hideSheetName = "combo_" + firstCol + "_" + endCol;
+        Sheet hideSheet = wb.createSheet(hideSheetName); // 用于存储 下拉菜单数据
+        for (int i = 0; i < textlist.length; i++)
+        {
+            hideSheet.createRow(i).createCell(0).setCellValue(textlist[i]);
+        }
+        // 创建名称,可被其他单元格引用
+        Name name = wb.createName();
+        name.setNameName(hideSheetName + "_data");
+        name.setRefersToFormula(hideSheetName + "!$A$1:$A$" + textlist.length);
+        DataValidationHelper helper = sheet.getDataValidationHelper();
+        // 加载下拉列表内容
+        DataValidationConstraint constraint = helper.createFormulaListConstraint(hideSheetName + "_data");
+        // 设置数据有效性加载在哪个单元格上,四个参数分别是:起始行、终止行、起始列、终止列
+        CellRangeAddressList regions = new CellRangeAddressList(firstRow, endRow, firstCol, endCol);
+        // 数据有效性对象
+        DataValidation dataValidation = helper.createValidation(constraint, regions);
+        if (StringUtils.isNotEmpty(promptContent))
+        {
+            // 如果设置了提示信息则鼠标放上去提示
+            dataValidation.createPromptBox("", promptContent);
+            dataValidation.setShowPromptBox(true);
+        }
+        // 处理Excel兼容性问题
+        if (dataValidation instanceof XSSFDataValidation)
+        {
+            dataValidation.setSuppressDropDownArrow(true);
+            dataValidation.setShowErrorBox(true);
+        }
+        else
+        {
+            dataValidation.setSuppressDropDownArrow(false);
+        }
+
+        sheet.addValidationData(dataValidation);
+        // 设置hiddenSheet隐藏
+        wb.setSheetHidden(wb.getSheetIndex(hideSheet), true);
+    }
+
+    /**
+     * 解析导出值 0=男,1=女,2=未知
+     * 
+     * @param propertyValue 参数值
+     * @param converterExp 翻译注解
+     * @param separator 分隔符
+     * @return 解析后值
+     */
+    public static String convertByExp(String propertyValue, String converterExp, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        String[] convertSource = converterExp.split(",");
+        for (String item : convertSource)
+        {
+            String[] itemArray = item.split("=");
+            if (StringUtils.containsAny(propertyValue, separator))
+            {
+                for (String value : propertyValue.split(separator))
+                {
+                    if (itemArray[0].equals(value))
+                    {
+                        propertyString.append(itemArray[1] + separator);
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                if (itemArray[0].equals(propertyValue))
+                {
+                    return itemArray[1];
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 反向解析值 男=0,女=1,未知=2
+     * 
+     * @param propertyValue 参数值
+     * @param converterExp 翻译注解
+     * @param separator 分隔符
+     * @return 解析后值
+     */
+    public static String reverseByExp(String propertyValue, String converterExp, String separator)
+    {
+        StringBuilder propertyString = new StringBuilder();
+        String[] convertSource = converterExp.split(",");
+        for (String item : convertSource)
+        {
+            String[] itemArray = item.split("=");
+            if (StringUtils.containsAny(propertyValue, separator))
+            {
+                for (String value : propertyValue.split(separator))
+                {
+                    if (itemArray[1].equals(value))
+                    {
+                        propertyString.append(itemArray[0] + separator);
+                        break;
+                    }
+                }
+            }
+            else
+            {
+                if (itemArray[1].equals(propertyValue))
+                {
+                    return itemArray[0];
+                }
+            }
+        }
+        return StringUtils.stripEnd(propertyString.toString(), separator);
+    }
+
+    /**
+     * 解析字典值
+     * 
+     * @param dictValue 字典值
+     * @param dictType 字典类型
+     * @param separator 分隔符
+     * @return 字典标签
+     */
+    public static String convertDictByExp(String dictValue, String dictType, String separator)
+    {
+        return DictUtils.getDictLabel(dictType, dictValue, separator);
+    }
+
+    /**
+     * 反向解析值字典值
+     * 
+     * @param dictLabel 字典标签
+     * @param dictType 字典类型
+     * @param separator 分隔符
+     * @return 字典值
+     */
+    public static String reverseDictByExp(String dictLabel, String dictType, String separator)
+    {
+        return DictUtils.getDictValue(dictType, dictLabel, separator);
+    }
+
+    /**
+     * 数据处理器
+     * 
+     * @param value 数据值
+     * @param excel 数据注解
+     * @return
+     */
+    public String dataFormatHandlerAdapter(Object value, Excel excel, Cell cell)
+    {
+        try
+        {
+            Object instance = excel.handler().newInstance();
+            Method formatMethod = excel.handler().getMethod("format", new Class[] { Object.class, String[].class, Cell.class, Workbook.class });
+            value = formatMethod.invoke(instance, value, excel.args(), cell, this.wb);
+        }
+        catch (Exception e)
+        {
+            log.error("不能格式化数据 " + excel.handler(), e.getMessage());
+        }
+        return Convert.toStr(value);
+    }
+
+    /**
+     * 合计统计信息
+     */
+    private void addStatisticsData(Integer index, String text, Excel entity)
+    {
+        if (entity != null && entity.isStatistics())
+        {
+            Double temp = 0D;
+            if (!statistics.containsKey(index))
+            {
+                statistics.put(index, temp);
+            }
+            try
+            {
+                temp = Double.valueOf(text);
+            }
+            catch (NumberFormatException e)
+            {
+            }
+            statistics.put(index, statistics.get(index) + temp);
+        }
+    }
+
+    /**
+     * 创建统计行
+     */
+    public void addStatisticsRow()
+    {
+        if (statistics.size() > 0)
+        {
+            Row row = sheet.createRow(sheet.getLastRowNum() + 1);
+            Set<Integer> keys = statistics.keySet();
+            Cell cell = row.createCell(0);
+            cell.setCellStyle(styles.get("total"));
+            cell.setCellValue("合计");
+
+            for (Integer key : keys)
+            {
+                cell = row.createCell(key);
+                cell.setCellStyle(styles.get("total"));
+                cell.setCellValue(DOUBLE_FORMAT.format(statistics.get(key)));
+            }
+            statistics.clear();
+        }
+    }
+
+    /**
+     * 编码文件名
+     */
+    public String encodingFilename(String filename)
+    {
+        filename = UUID.randomUUID() + "_" + filename + ".xlsx";
+        return filename;
+    }
+
+    /**
+     * 获取下载路径
+     * 
+     * @param filename 文件名称
+     */
+    public String getAbsoluteFile(String filename)
+    {
+        String downloadPath = RuoYiConfig.getDownloadPath() + filename;
+        File desc = new File(downloadPath);
+        if (!desc.getParentFile().exists())
+        {
+            desc.getParentFile().mkdirs();
+        }
+        return downloadPath;
+    }
+
+    /**
+     * 获取bean中的属性值
+     * 
+     * @param vo 实体对象
+     * @param field 字段
+     * @param excel 注解
+     * @return 最终的属性值
+     * @throws Exception
+     */
+    private Object getTargetValue(T vo, Field field, Excel excel) throws Exception
+    {
+        field.setAccessible(true);
+        Object o = field.get(vo);
+        if (StringUtils.isNotEmpty(excel.targetAttr()))
+        {
+            String target = excel.targetAttr();
+            if (target.contains("."))
+            {
+                String[] targets = target.split("[.]");
+                for (String name : targets)
+                {
+                    o = getValue(o, name);
+                }
+            }
+            else
+            {
+                o = getValue(o, target);
+            }
+        }
+        return o;
+    }
+
+    /**
+     * 以类的属性的get方法方法形式获取值
+     * 
+     * @param o
+     * @param name
+     * @return value
+     * @throws Exception
+     */
+    private Object getValue(Object o, String name) throws Exception
+    {
+        if (StringUtils.isNotNull(o) && StringUtils.isNotEmpty(name))
+        {
+            Class<?> clazz = o.getClass();
+            Field field = clazz.getDeclaredField(name);
+            field.setAccessible(true);
+            o = field.get(o);
+        }
+        return o;
+    }
+
+    /**
+     * 得到所有定义字段
+     */
+    private void createExcelField()
+    {
+        this.fields = getFields();
+        this.fields = this.fields.stream().sorted(Comparator.comparing(objects -> ((Excel) objects[1]).sort())).collect(Collectors.toList());
+        this.maxHeight = getRowHeight();
+    }
+
+    /**
+     * 获取字段注解信息
+     */
+    public List<Object[]> getFields()
+    {
+        List<Object[]> fields = new ArrayList<Object[]>();
+        List<Field> tempFields = new ArrayList<>();
+        tempFields.addAll(Arrays.asList(clazz.getSuperclass().getDeclaredFields()));
+        tempFields.addAll(Arrays.asList(clazz.getDeclaredFields()));
+        if (StringUtils.isNotEmpty(includeFields))
+        {
+            for (Field field : tempFields)
+            {
+                if (ArrayUtils.contains(this.includeFields, field.getName()) || field.isAnnotationPresent(Excels.class))
+                {
+                    addField(fields, field);
+                }
+            }
+        }
+        else if (StringUtils.isNotEmpty(excludeFields))
+        {
+            for (Field field : tempFields)
+            {
+                if (!ArrayUtils.contains(this.excludeFields, field.getName()))
+                {
+                    addField(fields, field);
+                }
+            }
+        }
+        else
+        {
+            for (Field field : tempFields)
+            {
+                addField(fields, field);
+            }
+        }
+        return fields;
+    }
+
+    /**
+     * 添加字段信息
+     */
+    public void addField(List<Object[]> fields, Field field)
+    {
+        // 单注解
+        if (field.isAnnotationPresent(Excel.class))
+        {
+            Excel attr = field.getAnnotation(Excel.class);
+            if (attr != null && (attr.type() == Type.ALL || attr.type() == type))
+            {
+                fields.add(new Object[] { field, attr });
+            }
+            if (Collection.class.isAssignableFrom(field.getType()))
+            {
+                subMethod = getSubMethod(field.getName(), clazz);
+                ParameterizedType pt = (ParameterizedType) field.getGenericType();
+                Class<?> subClass = (Class<?>) pt.getActualTypeArguments()[0];
+                this.subFields = FieldUtils.getFieldsListWithAnnotation(subClass, Excel.class);
+            }
+        }
+
+        // 多注解
+        if (field.isAnnotationPresent(Excels.class))
+        {
+            Excels attrs = field.getAnnotation(Excels.class);
+            Excel[] excels = attrs.value();
+            for (Excel attr : excels)
+            {
+                if (StringUtils.isNotEmpty(includeFields))
+                {
+                    if (ArrayUtils.contains(this.includeFields, field.getName() + "." + attr.targetAttr())
+                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
+                    {
+                        fields.add(new Object[] { field, attr });
+                    }
+                }
+                else
+                {
+                    if (!ArrayUtils.contains(this.excludeFields, field.getName() + "." + attr.targetAttr())
+                            && (attr != null && (attr.type() == Type.ALL || attr.type() == type)))
+                    {
+                        fields.add(new Object[] { field, attr });
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * 根据注解获取最大行高
+     */
+    public short getRowHeight()
+    {
+        double maxHeight = 0;
+        for (Object[] os : this.fields)
+        {
+            Excel excel = (Excel) os[1];
+            maxHeight = Math.max(maxHeight, excel.height());
+        }
+        return (short) (maxHeight * 20);
+    }
+
+    /**
+     * 创建一个工作簿
+     */
+    public void createWorkbook()
+    {
+        this.wb = new SXSSFWorkbook(500);
+        this.sheet = wb.createSheet();
+        wb.setSheetName(0, sheetName);
+        this.styles = createStyles(wb);
+    }
+
+    /**
+     * 创建工作表
+     * 
+     * @param sheetNo sheet数量
+     * @param index 序号
+     */
+    public void createSheet(int sheetNo, int index)
+    {
+        // 设置工作表的名称.
+        if (sheetNo > 1 && index > 0)
+        {
+            this.sheet = wb.createSheet();
+            this.createTitle();
+            wb.setSheetName(index, sheetName + index);
+        }
+    }
+
+    /**
+     * 获取单元格值
+     * 
+     * @param row 获取的行
+     * @param column 获取单元格列号
+     * @return 单元格值
+     */
+    public Object getCellValue(Row row, int column)
+    {
+        if (row == null)
+        {
+            return row;
+        }
+        Object val = "";
+        try
+        {
+            Cell cell = row.getCell(column);
+            if (StringUtils.isNotNull(cell))
+            {
+                if (cell.getCellType() == CellType.NUMERIC || cell.getCellType() == CellType.FORMULA)
+                {
+                    val = cell.getNumericCellValue();
+                    if (DateUtil.isCellDateFormatted(cell))
+                    {
+                        val = DateUtil.getJavaDate((Double) val); // POI Excel 日期格式转换
+                    }
+                    else
+                    {
+                        if ((Double) val % 1 != 0)
+                        {
+                            val = new BigDecimal(val.toString());
+                        }
+                        else
+                        {
+                            val = new DecimalFormat("0").format(val);
+                        }
+                    }
+                }
+                else if (cell.getCellType() == CellType.STRING)
+                {
+                    val = cell.getStringCellValue();
+                }
+                else if (cell.getCellType() == CellType.BOOLEAN)
+                {
+                    val = cell.getBooleanCellValue();
+                }
+                else if (cell.getCellType() == CellType.ERROR)
+                {
+                    val = cell.getErrorCellValue();
+                }
+
+            }
+        }
+        catch (Exception e)
+        {
+            return val;
+        }
+        return val;
+    }
+
+    /**
+     * 判断是否是空行
+     * 
+     * @param row 判断的行
+     * @return
+     */
+    private boolean isRowEmpty(Row row)
+    {
+        if (row == null)
+        {
+            return true;
+        }
+        for (int i = row.getFirstCellNum(); i < row.getLastCellNum(); i++)
+        {
+            Cell cell = row.getCell(i);
+            if (cell != null && cell.getCellType() != CellType.BLANK)
+            {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 获取Excel2003图片
+     *
+     * @param sheet 当前sheet对象
+     * @param workbook 工作簿对象
+     * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData
+     */
+    public static Map<String, PictureData> getSheetPictures03(HSSFSheet sheet, HSSFWorkbook workbook)
+    {
+        Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
+        List<HSSFPictureData> pictures = workbook.getAllPictures();
+        if (!pictures.isEmpty())
+        {
+            for (HSSFShape shape : sheet.getDrawingPatriarch().getChildren())
+            {
+                HSSFClientAnchor anchor = (HSSFClientAnchor) shape.getAnchor();
+                if (shape instanceof HSSFPicture)
+                {
+                    HSSFPicture pic = (HSSFPicture) shape;
+                    int pictureIndex = pic.getPictureIndex() - 1;
+                    HSSFPictureData picData = pictures.get(pictureIndex);
+                    String picIndex = anchor.getRow1() + "_" + anchor.getCol1();
+                    sheetIndexPicMap.put(picIndex, picData);
+                }
+            }
+            return sheetIndexPicMap;
+        }
+        else
+        {
+            return sheetIndexPicMap;
+        }
+    }
+
+    /**
+     * 获取Excel2007图片
+     *
+     * @param sheet 当前sheet对象
+     * @param workbook 工作簿对象
+     * @return Map key:图片单元格索引(1_1)String,value:图片流PictureData
+     */
+    public static Map<String, PictureData> getSheetPictures07(XSSFSheet sheet, XSSFWorkbook workbook)
+    {
+        Map<String, PictureData> sheetIndexPicMap = new HashMap<String, PictureData>();
+        for (POIXMLDocumentPart dr : sheet.getRelations())
+        {
+            if (dr instanceof XSSFDrawing)
+            {
+                XSSFDrawing drawing = (XSSFDrawing) dr;
+                List<XSSFShape> shapes = drawing.getShapes();
+                for (XSSFShape shape : shapes)
+                {
+                    if (shape instanceof XSSFPicture)
+                    {
+                        XSSFPicture pic = (XSSFPicture) shape;
+                        XSSFClientAnchor anchor = pic.getPreferredSize();
+                        CTMarker ctMarker = anchor.getFrom();
+                        String picIndex = ctMarker.getRow() + "_" + ctMarker.getCol();
+                        sheetIndexPicMap.put(picIndex, pic.getPictureData());
+                    }
+                }
+            }
+        }
+        return sheetIndexPicMap;
+    }
+
+    /**
+     * 格式化不同类型的日期对象
+     * 
+     * @param dateFormat 日期格式
+     * @param val 被格式化的日期对象
+     * @return 格式化后的日期字符
+     */
+    public String parseDateToStr(String dateFormat, Object val)
+    {
+        if (val == null)
+        {
+            return "";
+        }
+        String str;
+        if (val instanceof Date)
+        {
+            str = DateUtils.parseDateToStr(dateFormat, (Date) val);
+        }
+        else if (val instanceof LocalDateTime)
+        {
+            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDateTime) val));
+        }
+        else if (val instanceof LocalDate)
+        {
+            str = DateUtils.parseDateToStr(dateFormat, DateUtils.toDate((LocalDate) val));
+        }
+        else
+        {
+            str = val.toString();
+        }
+        return str;
+    }
+
+    /**
+     * 是否有对象的子列表
+     */
+    public boolean isSubList()
+    {
+        return StringUtils.isNotNull(subFields) && subFields.size() > 0;
+    }
+
+    /**
+     * 是否有对象的子列表,集合不为空
+     */
+    public boolean isSubListValue(T vo)
+    {
+        return StringUtils.isNotNull(subFields) && subFields.size() > 0 && StringUtils.isNotNull(getListCellValue(vo)) && getListCellValue(vo).size() > 0;
+    }
+
+    /**
+     * 获取集合的值
+     */
+    public Collection<?> getListCellValue(Object obj)
+    {
+        Object value;
+        try
+        {
+            value = subMethod.invoke(obj, new Object[] {});
+        }
+        catch (Exception e)
+        {
+            return new ArrayList<Object>();
+        }
+        return (Collection<?>) value;
+    }
+
+    /**
+     * 获取对象的子列表方法
+     * 
+     * @param name 名称
+     * @param pojoClass 类对象
+     * @return 子列表方法
+     */
+    public Method getSubMethod(String name, Class<?> pojoClass)
+    {
+        StringBuffer getMethodName = new StringBuffer("get");
+        getMethodName.append(name.substring(0, 1).toUpperCase());
+        getMethodName.append(name.substring(1));
+        Method method = null;
+        try
+        {
+            method = pojoClass.getMethod(getMethodName.toString(), new Class[] {});
+        }
+        catch (Exception e)
+        {
+            log.error("获取对象异常{}", e.getMessage());
+        }
+        return method;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/reflect/ReflectUtils.java
similarity index 96%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/reflect/ReflectUtils.java
index 9befe41a..339fe456 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/reflect/ReflectUtils.java
@@ -1,410 +1,410 @@
-package com.ruoyi.common.utils.reflect;
-
-import java.lang.reflect.Field;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.lang.reflect.ParameterizedType;
-import java.lang.reflect.Type;
-import java.util.Date;
-import org.apache.commons.lang3.StringUtils;
-import org.apache.commons.lang3.Validate;
-import org.apache.poi.ss.usermodel.DateUtil;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.utils.DateUtils;
-
-/**
- * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
- * 
- * @author ruoyi
- */
-@SuppressWarnings("rawtypes")
-public class ReflectUtils
-{
-    private static final String SETTER_PREFIX = "set";
-
-    private static final String GETTER_PREFIX = "get";
-
-    private static final String CGLIB_CLASS_SEPARATOR = "$$";
-
-    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
-
-    /**
-     * 调用Getter方法.
-     * 支持多级,如:对象名.对象名.方法
-     */
-    @SuppressWarnings("unchecked")
-    public static <E> E invokeGetter(Object obj, String propertyName)
-    {
-        Object object = obj;
-        for (String name : StringUtils.split(propertyName, "."))
-        {
-            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
-            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
-        }
-        return (E) object;
-    }
-
-    /**
-     * 调用Setter方法, 仅匹配方法名。
-     * 支持多级,如:对象名.对象名.方法
-     */
-    public static <E> void invokeSetter(Object obj, String propertyName, E value)
-    {
-        Object object = obj;
-        String[] names = StringUtils.split(propertyName, ".");
-        for (int i = 0; i < names.length; i++)
-        {
-            if (i < names.length - 1)
-            {
-                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
-                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
-            }
-            else
-            {
-                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
-                invokeMethodByName(object, setterMethodName, new Object[] { value });
-            }
-        }
-    }
-
-    /**
-     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
-     */
-    @SuppressWarnings("unchecked")
-    public static <E> E getFieldValue(final Object obj, final String fieldName)
-    {
-        Field field = getAccessibleField(obj, fieldName);
-        if (field == null)
-        {
-            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
-            return null;
-        }
-        E result = null;
-        try
-        {
-            result = (E) field.get(obj);
-        }
-        catch (IllegalAccessException e)
-        {
-            logger.error("不可能抛出的异常{}", e.getMessage());
-        }
-        return result;
-    }
-
-    /**
-     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
-     */
-    public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
-    {
-        Field field = getAccessibleField(obj, fieldName);
-        if (field == null)
-        {
-            // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
-            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
-            return;
-        }
-        try
-        {
-            field.set(obj, value);
-        }
-        catch (IllegalAccessException e)
-        {
-            logger.error("不可能抛出的异常: {}", e.getMessage());
-        }
-    }
-
-    /**
-     * 直接调用对象方法, 无视private/protected修饰符.
-     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
-     * 同时匹配方法名+参数类型,
-     */
-    @SuppressWarnings("unchecked")
-    public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
-            final Object[] args)
-    {
-        if (obj == null || methodName == null)
-        {
-            return null;
-        }
-        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
-        if (method == null)
-        {
-            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
-            return null;
-        }
-        try
-        {
-            return (E) method.invoke(obj, args);
-        }
-        catch (Exception e)
-        {
-            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
-            throw convertReflectionExceptionToUnchecked(msg, e);
-        }
-    }
-
-    /**
-     * 直接调用对象方法, 无视private/protected修饰符,
-     * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
-     * 只匹配函数名,如果有多个同名函数调用第一个。
-     */
-    @SuppressWarnings("unchecked")
-    public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
-    {
-        Method method = getAccessibleMethodByName(obj, methodName, args.length);
-        if (method == null)
-        {
-            // 如果为空不报错,直接返回空。
-            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
-            return null;
-        }
-        try
-        {
-            // 类型转换(将参数数据类型转换为目标方法参数类型)
-            Class<?>[] cs = method.getParameterTypes();
-            for (int i = 0; i < cs.length; i++)
-            {
-                if (args[i] != null && !args[i].getClass().equals(cs[i]))
-                {
-                    if (cs[i] == String.class)
-                    {
-                        args[i] = Convert.toStr(args[i]);
-                        if (StringUtils.endsWith((String) args[i], ".0"))
-                        {
-                            args[i] = StringUtils.substringBefore((String) args[i], ".0");
-                        }
-                    }
-                    else if (cs[i] == Integer.class)
-                    {
-                        args[i] = Convert.toInt(args[i]);
-                    }
-                    else if (cs[i] == Long.class)
-                    {
-                        args[i] = Convert.toLong(args[i]);
-                    }
-                    else if (cs[i] == Double.class)
-                    {
-                        args[i] = Convert.toDouble(args[i]);
-                    }
-                    else if (cs[i] == Float.class)
-                    {
-                        args[i] = Convert.toFloat(args[i]);
-                    }
-                    else if (cs[i] == Date.class)
-                    {
-                        if (args[i] instanceof String)
-                        {
-                            args[i] = DateUtils.parseDate(args[i]);
-                        }
-                        else
-                        {
-                            args[i] = DateUtil.getJavaDate((Double) args[i]);
-                        }
-                    }
-                    else if (cs[i] == boolean.class || cs[i] == Boolean.class)
-                    {
-                        args[i] = Convert.toBool(args[i]);
-                    }
-                }
-            }
-            return (E) method.invoke(obj, args);
-        }
-        catch (Exception e)
-        {
-            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
-            throw convertReflectionExceptionToUnchecked(msg, e);
-        }
-    }
-
-    /**
-     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
-     * 如向上转型到Object仍无法找到, 返回null.
-     */
-    public static Field getAccessibleField(final Object obj, final String fieldName)
-    {
-        // 为空不报错。直接返回 null
-        if (obj == null)
-        {
-            return null;
-        }
-        Validate.notBlank(fieldName, "fieldName can't be blank");
-        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
-        {
-            try
-            {
-                Field field = superClass.getDeclaredField(fieldName);
-                makeAccessible(field);
-                return field;
-            }
-            catch (NoSuchFieldException e)
-            {
-                continue;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
-     * 如向上转型到Object仍无法找到, 返回null.
-     * 匹配函数名+参数类型。
-     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
-     */
-    public static Method getAccessibleMethod(final Object obj, final String methodName,
-            final Class<?>... parameterTypes)
-    {
-        // 为空不报错。直接返回 null
-        if (obj == null)
-        {
-            return null;
-        }
-        Validate.notBlank(methodName, "methodName can't be blank");
-        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
-        {
-            try
-            {
-                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
-                makeAccessible(method);
-                return method;
-            }
-            catch (NoSuchMethodException e)
-            {
-                continue;
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
-     * 如向上转型到Object仍无法找到, 返回null.
-     * 只匹配函数名。
-     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
-     */
-    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
-    {
-        // 为空不报错。直接返回 null
-        if (obj == null)
-        {
-            return null;
-        }
-        Validate.notBlank(methodName, "methodName can't be blank");
-        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
-        {
-            Method[] methods = searchType.getDeclaredMethods();
-            for (Method method : methods)
-            {
-                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
-                {
-                    makeAccessible(method);
-                    return method;
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
-     */
-    public static void makeAccessible(Method method)
-    {
-        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
-                && !method.isAccessible())
-        {
-            method.setAccessible(true);
-        }
-    }
-
-    /**
-     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
-     */
-    public static void makeAccessible(Field field)
-    {
-        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
-                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
-        {
-            field.setAccessible(true);
-        }
-    }
-
-    /**
-     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
-     * 如无法找到, 返回Object.class.
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> Class<T> getClassGenricType(final Class clazz)
-    {
-        return getClassGenricType(clazz, 0);
-    }
-
-    /**
-     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
-     * 如无法找到, 返回Object.class.
-     */
-    public static Class getClassGenricType(final Class clazz, final int index)
-    {
-        Type genType = clazz.getGenericSuperclass();
-
-        if (!(genType instanceof ParameterizedType))
-        {
-            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
-            return Object.class;
-        }
-
-        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
-
-        if (index >= params.length || index < 0)
-        {
-            logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
-                    + params.length);
-            return Object.class;
-        }
-        if (!(params[index] instanceof Class))
-        {
-            logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
-            return Object.class;
-        }
-
-        return (Class) params[index];
-    }
-
-    public static Class<?> getUserClass(Object instance)
-    {
-        if (instance == null)
-        {
-            throw new RuntimeException("Instance must not be null");
-        }
-        Class clazz = instance.getClass();
-        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
-        {
-            Class<?> superClass = clazz.getSuperclass();
-            if (superClass != null && !Object.class.equals(superClass))
-            {
-                return superClass;
-            }
-        }
-        return clazz;
-
-    }
-
-    /**
-     * 将反射时的checked exception转换为unchecked exception.
-     */
-    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
-    {
-        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
-                || e instanceof NoSuchMethodException)
-        {
-            return new IllegalArgumentException(msg, e);
-        }
-        else if (e instanceof InvocationTargetException)
-        {
-            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
-        }
-        return new RuntimeException(msg, e);
-    }
-}
+package com.acupuncture.common.utils.reflect;
+
+import java.lang.reflect.Field;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.lang.reflect.ParameterizedType;
+import java.lang.reflect.Type;
+import java.util.Date;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.Validate;
+import org.apache.poi.ss.usermodel.DateUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.utils.DateUtils;
+
+/**
+ * 反射工具类. 提供调用getter/setter方法, 访问私有变量, 调用私有方法, 获取泛型类型Class, 被AOP过的真实类等工具函数.
+ * 
+ * @author acupuncture
+ */
+@SuppressWarnings("rawtypes")
+public class ReflectUtils
+{
+    private static final String SETTER_PREFIX = "set";
+
+    private static final String GETTER_PREFIX = "get";
+
+    private static final String CGLIB_CLASS_SEPARATOR = "$$";
+
+    private static Logger logger = LoggerFactory.getLogger(ReflectUtils.class);
+
+    /**
+     * 调用Getter方法.
+     * 支持多级,如:对象名.对象名.方法
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeGetter(Object obj, String propertyName)
+    {
+        Object object = obj;
+        for (String name : StringUtils.split(propertyName, "."))
+        {
+            String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(name);
+            object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+        }
+        return (E) object;
+    }
+
+    /**
+     * 调用Setter方法, 仅匹配方法名。
+     * 支持多级,如:对象名.对象名.方法
+     */
+    public static <E> void invokeSetter(Object obj, String propertyName, E value)
+    {
+        Object object = obj;
+        String[] names = StringUtils.split(propertyName, ".");
+        for (int i = 0; i < names.length; i++)
+        {
+            if (i < names.length - 1)
+            {
+                String getterMethodName = GETTER_PREFIX + StringUtils.capitalize(names[i]);
+                object = invokeMethod(object, getterMethodName, new Class[] {}, new Object[] {});
+            }
+            else
+            {
+                String setterMethodName = SETTER_PREFIX + StringUtils.capitalize(names[i]);
+                invokeMethodByName(object, setterMethodName, new Object[] { value });
+            }
+        }
+    }
+
+    /**
+     * 直接读取对象属性值, 无视private/protected修饰符, 不经过getter函数.
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E getFieldValue(final Object obj, final String fieldName)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return null;
+        }
+        E result = null;
+        try
+        {
+            result = (E) field.get(obj);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常{}", e.getMessage());
+        }
+        return result;
+    }
+
+    /**
+     * 直接设置对象属性值, 无视private/protected修饰符, 不经过setter函数.
+     */
+    public static <E> void setFieldValue(final Object obj, final String fieldName, final E value)
+    {
+        Field field = getAccessibleField(obj, fieldName);
+        if (field == null)
+        {
+            // throw new IllegalArgumentException("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + fieldName + "] 字段 ");
+            return;
+        }
+        try
+        {
+            field.set(obj, value);
+        }
+        catch (IllegalAccessException e)
+        {
+            logger.error("不可能抛出的异常: {}", e.getMessage());
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符.
+     * 用于一次性调用的情况,否则应使用getAccessibleMethod()函数获得Method后反复调用.
+     * 同时匹配方法名+参数类型,
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethod(final Object obj, final String methodName, final Class<?>[] parameterTypes,
+            final Object[] args)
+    {
+        if (obj == null || methodName == null)
+        {
+            return null;
+        }
+        Method method = getAccessibleMethod(obj, methodName, parameterTypes);
+        if (method == null)
+        {
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 直接调用对象方法, 无视private/protected修饰符,
+     * 用于一次性调用的情况,否则应使用getAccessibleMethodByName()函数获得Method后反复调用.
+     * 只匹配函数名,如果有多个同名函数调用第一个。
+     */
+    @SuppressWarnings("unchecked")
+    public static <E> E invokeMethodByName(final Object obj, final String methodName, final Object[] args)
+    {
+        Method method = getAccessibleMethodByName(obj, methodName, args.length);
+        if (method == null)
+        {
+            // 如果为空不报错,直接返回空。
+            logger.debug("在 [" + obj.getClass() + "] 中,没有找到 [" + methodName + "] 方法 ");
+            return null;
+        }
+        try
+        {
+            // 类型转换(将参数数据类型转换为目标方法参数类型)
+            Class<?>[] cs = method.getParameterTypes();
+            for (int i = 0; i < cs.length; i++)
+            {
+                if (args[i] != null && !args[i].getClass().equals(cs[i]))
+                {
+                    if (cs[i] == String.class)
+                    {
+                        args[i] = Convert.toStr(args[i]);
+                        if (StringUtils.endsWith((String) args[i], ".0"))
+                        {
+                            args[i] = StringUtils.substringBefore((String) args[i], ".0");
+                        }
+                    }
+                    else if (cs[i] == Integer.class)
+                    {
+                        args[i] = Convert.toInt(args[i]);
+                    }
+                    else if (cs[i] == Long.class)
+                    {
+                        args[i] = Convert.toLong(args[i]);
+                    }
+                    else if (cs[i] == Double.class)
+                    {
+                        args[i] = Convert.toDouble(args[i]);
+                    }
+                    else if (cs[i] == Float.class)
+                    {
+                        args[i] = Convert.toFloat(args[i]);
+                    }
+                    else if (cs[i] == Date.class)
+                    {
+                        if (args[i] instanceof String)
+                        {
+                            args[i] = DateUtils.parseDate(args[i]);
+                        }
+                        else
+                        {
+                            args[i] = DateUtil.getJavaDate((Double) args[i]);
+                        }
+                    }
+                    else if (cs[i] == boolean.class || cs[i] == Boolean.class)
+                    {
+                        args[i] = Convert.toBool(args[i]);
+                    }
+                }
+            }
+            return (E) method.invoke(obj, args);
+        }
+        catch (Exception e)
+        {
+            String msg = "method: " + method + ", obj: " + obj + ", args: " + args + "";
+            throw convertReflectionExceptionToUnchecked(msg, e);
+        }
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredField, 并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     */
+    public static Field getAccessibleField(final Object obj, final String fieldName)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(fieldName, "fieldName can't be blank");
+        for (Class<?> superClass = obj.getClass(); superClass != Object.class; superClass = superClass.getSuperclass())
+        {
+            try
+            {
+                Field field = superClass.getDeclaredField(fieldName);
+                makeAccessible(field);
+                return field;
+            }
+            catch (NoSuchFieldException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 匹配函数名+参数类型。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethod(final Object obj, final String methodName,
+            final Class<?>... parameterTypes)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            try
+            {
+                Method method = searchType.getDeclaredMethod(methodName, parameterTypes);
+                makeAccessible(method);
+                return method;
+            }
+            catch (NoSuchMethodException e)
+            {
+                continue;
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 循环向上转型, 获取对象的DeclaredMethod,并强制设置为可访问.
+     * 如向上转型到Object仍无法找到, 返回null.
+     * 只匹配函数名。
+     * 用于方法需要被多次调用的情况. 先使用本函数先取得Method,然后调用Method.invoke(Object obj, Object... args)
+     */
+    public static Method getAccessibleMethodByName(final Object obj, final String methodName, int argsNum)
+    {
+        // 为空不报错。直接返回 null
+        if (obj == null)
+        {
+            return null;
+        }
+        Validate.notBlank(methodName, "methodName can't be blank");
+        for (Class<?> searchType = obj.getClass(); searchType != Object.class; searchType = searchType.getSuperclass())
+        {
+            Method[] methods = searchType.getDeclaredMethods();
+            for (Method method : methods)
+            {
+                if (method.getName().equals(methodName) && method.getParameterTypes().length == argsNum)
+                {
+                    makeAccessible(method);
+                    return method;
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 改变private/protected的方法为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Method method)
+    {
+        if ((!Modifier.isPublic(method.getModifiers()) || !Modifier.isPublic(method.getDeclaringClass().getModifiers()))
+                && !method.isAccessible())
+        {
+            method.setAccessible(true);
+        }
+    }
+
+    /**
+     * 改变private/protected的成员变量为public,尽量不调用实际改动的语句,避免JDK的SecurityManager抱怨。
+     */
+    public static void makeAccessible(Field field)
+    {
+        if ((!Modifier.isPublic(field.getModifiers()) || !Modifier.isPublic(field.getDeclaringClass().getModifiers())
+                || Modifier.isFinal(field.getModifiers())) && !field.isAccessible())
+        {
+            field.setAccessible(true);
+        }
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的泛型参数的类型, 注意泛型必须定义在父类处
+     * 如无法找到, 返回Object.class.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> getClassGenricType(final Class clazz)
+    {
+        return getClassGenricType(clazz, 0);
+    }
+
+    /**
+     * 通过反射, 获得Class定义中声明的父类的泛型参数的类型.
+     * 如无法找到, 返回Object.class.
+     */
+    public static Class getClassGenricType(final Class clazz, final int index)
+    {
+        Type genType = clazz.getGenericSuperclass();
+
+        if (!(genType instanceof ParameterizedType))
+        {
+            logger.debug(clazz.getSimpleName() + "'s superclass not ParameterizedType");
+            return Object.class;
+        }
+
+        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
+
+        if (index >= params.length || index < 0)
+        {
+            logger.debug("Index: " + index + ", Size of " + clazz.getSimpleName() + "'s Parameterized Type: "
+                    + params.length);
+            return Object.class;
+        }
+        if (!(params[index] instanceof Class))
+        {
+            logger.debug(clazz.getSimpleName() + " not set the actual class on superclass generic parameter");
+            return Object.class;
+        }
+
+        return (Class) params[index];
+    }
+
+    public static Class<?> getUserClass(Object instance)
+    {
+        if (instance == null)
+        {
+            throw new RuntimeException("Instance must not be null");
+        }
+        Class clazz = instance.getClass();
+        if (clazz != null && clazz.getName().contains(CGLIB_CLASS_SEPARATOR))
+        {
+            Class<?> superClass = clazz.getSuperclass();
+            if (superClass != null && !Object.class.equals(superClass))
+            {
+                return superClass;
+            }
+        }
+        return clazz;
+
+    }
+
+    /**
+     * 将反射时的checked exception转换为unchecked exception.
+     */
+    public static RuntimeException convertReflectionExceptionToUnchecked(String msg, Exception e)
+    {
+        if (e instanceof IllegalAccessException || e instanceof IllegalArgumentException
+                || e instanceof NoSuchMethodException)
+        {
+            return new IllegalArgumentException(msg, e);
+        }
+        else if (e instanceof InvocationTargetException)
+        {
+            return new RuntimeException(msg, ((InvocationTargetException) e).getTargetException());
+        }
+        return new RuntimeException(msg, e);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Base64.java
similarity index 96%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Base64.java
index f2c1bfe0..f4e7a5a8 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Base64.java
@@ -1,291 +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;
-    }
-}
+package com.acupuncture.common.utils.sign;
+
+/**
+ * Base64工具类
+ * 
+ * @author acupuncture
+ */
+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-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Md5Utils.java
similarity index 92%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Md5Utils.java
index 8fb0fc5e..06b741f7 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sign/Md5Utils.java
@@ -1,67 +1,67 @@
-package com.ruoyi.common.utils.sign;
-
-import java.nio.charset.StandardCharsets;
-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(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
-        }
-        catch (Exception e)
-        {
-            log.error("not supported charset...{}", e);
-            return s;
-        }
-    }
-}
+package com.acupuncture.common.utils.sign;
+
+import java.nio.charset.StandardCharsets;
+import java.security.MessageDigest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Md5加密方法
+ * 
+ * @author acupuncture
+ */
+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(StandardCharsets.UTF_8), StandardCharsets.UTF_8);
+        }
+        catch (Exception e)
+        {
+            log.error("not supported charset...{}", e);
+            return s;
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/spring/SpringUtils.java
similarity index 94%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/spring/SpringUtils.java
index 2c251a91..5fdbd89f 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/spring/SpringUtils.java
@@ -1,158 +1,158 @@
-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.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * spring工具类 方便在非spring管理环境中获取bean
- * 
- * @author ruoyi
- */
-@Component
-public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware 
-{
-    /** Spring应用上下文环境 */
-    private static ConfigurableListableBeanFactory beanFactory;
-
-    private static ApplicationContext applicationContext;
-
-    @Override
-    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException 
-    {
-        SpringUtils.beanFactory = beanFactory;
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
-    {
-        SpringUtils.applicationContext = applicationContext;
-    }
-
-    /**
-     * 获取对象
-     *
-     * @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);
-    }
-
-    /**
-     * 获取类型为requiredType的对象
-     *
-     * @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定义是一个singleton还是一个prototype。 如果与给定名字相应的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);
-    }
-
-    /**
-     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
-     *
-     * @param name
-     * @return
-     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
-     *
-     */
-    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
-    {
-        return beanFactory.getAliases(name);
-    }
-
-    /**
-     * 获取aop代理对象
-     * 
-     * @param invoker
-     * @return
-     */
-    @SuppressWarnings("unchecked")
-    public static <T> T getAopProxy(T invoker)
-    {
-        return (T) AopContext.currentProxy();
-    }
-
-    /**
-     * 获取当前的环境配置,无配置返回null
-     *
-     * @return 当前的环境配置
-     */
-    public static String[] getActiveProfiles()
-    {
-        return applicationContext.getEnvironment().getActiveProfiles();
-    }
-
-    /**
-     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
-     *
-     * @return 当前的环境配置
-     */
-    public static String getActiveProfile()
-    {
-        final String[] activeProfiles = getActiveProfiles();
-        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
-    }
-
-    /**
-     * 获取配置文件中的值
-     *
-     * @param key 配置文件的key
-     * @return 当前的配置文件的值
-     *
-     */
-    public static String getRequiredProperty(String key)
-    {
-        return applicationContext.getEnvironment().getRequiredProperty(key);
-    }
-}
+package com.acupuncture.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.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * spring工具类 方便在非spring管理环境中获取bean
+ * 
+ * @author acupuncture
+ */
+@Component
+public final class SpringUtils implements BeanFactoryPostProcessor, ApplicationContextAware 
+{
+    /** Spring应用上下文环境 */
+    private static ConfigurableListableBeanFactory beanFactory;
+
+    private static ApplicationContext applicationContext;
+
+    @Override
+    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException 
+    {
+        SpringUtils.beanFactory = beanFactory;
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
+    {
+        SpringUtils.applicationContext = applicationContext;
+    }
+
+    /**
+     * 获取对象
+     *
+     * @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);
+    }
+
+    /**
+     * 获取类型为requiredType的对象
+     *
+     * @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定义是一个singleton还是一个prototype。 如果与给定名字相应的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);
+    }
+
+    /**
+     * 如果给定的bean名字在bean定义中有别名,则返回这些别名
+     *
+     * @param name
+     * @return
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 获取aop代理对象
+     * 
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker)
+    {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 获取当前的环境配置,无配置返回null
+     *
+     * @return 当前的环境配置
+     */
+    public static String[] getActiveProfiles()
+    {
+        return applicationContext.getEnvironment().getActiveProfiles();
+    }
+
+    /**
+     * 获取当前的环境配置,当有多个环境配置时,只获取第一个
+     *
+     * @return 当前的环境配置
+     */
+    public static String getActiveProfile()
+    {
+        final String[] activeProfiles = getActiveProfiles();
+        return StringUtils.isNotEmpty(activeProfiles) ? activeProfiles[0] : null;
+    }
+
+    /**
+     * 获取配置文件中的值
+     *
+     * @param key 配置文件的key
+     * @return 当前的配置文件的值
+     *
+     */
+    public static String getRequiredProperty(String key)
+    {
+        return applicationContext.getEnvironment().getRequiredProperty(key);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sql/SqlUtil.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/sql/SqlUtil.java
index 2c4ed876..80a49be0 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/sql/SqlUtil.java
@@ -1,70 +1,70 @@
-package com.ruoyi.common.utils.sql;
-
-import com.ruoyi.common.exception.UtilException;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * sql操作工具类
- * 
- * @author ruoyi
- */
-public class SqlUtil
-{
-    /**
-     * 定义常用的 sql关键字
-     */
-    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
-
-    /**
-     * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
-     */
-    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
-
-    /**
-     * 限制orderBy最大长度
-     */
-    private static final int ORDER_BY_MAX_LENGTH = 500;
-
-    /**
-     * 检查字符,防止注入绕过
-     */
-    public static String escapeOrderBySql(String value)
-    {
-        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
-        {
-            throw new UtilException("参数不符合规范,不能进行查询");
-        }
-        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
-        {
-            throw new UtilException("参数已超过最大限制,不能进行查询");
-        }
-        return value;
-    }
-
-    /**
-     * 验证 order by 语法是否符合规范
-     */
-    public static boolean isValidOrderBySql(String value)
-    {
-        return value.matches(SQL_PATTERN);
-    }
-
-    /**
-     * SQL关键字检查
-     */
-    public static void filterKeyword(String value)
-    {
-        if (StringUtils.isEmpty(value))
-        {
-            return;
-        }
-        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
-        for (String sqlKeyword : sqlKeywords)
-        {
-            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
-            {
-                throw new UtilException("参数存在SQL注入风险");
-            }
-        }
-    }
-}
+package com.acupuncture.common.utils.sql;
+
+import com.acupuncture.common.exception.UtilException;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * sql操作工具类
+ * 
+ * @author acupuncture
+ */
+public class SqlUtil
+{
+    /**
+     * 定义常用的 sql关键字
+     */
+    public static String SQL_REGEX = "\u000B|and |extractvalue|updatexml|sleep|exec |insert |select |delete |update |drop |count |chr |mid |master |truncate |char |declare |or |union |like |+|/*|user()";
+
+    /**
+     * 仅支持字母、数字、下划线、空格、逗号、小数点(支持多个字段排序)
+     */
+    public static String SQL_PATTERN = "[a-zA-Z0-9_\\ \\,\\.]+";
+
+    /**
+     * 限制orderBy最大长度
+     */
+    private static final int ORDER_BY_MAX_LENGTH = 500;
+
+    /**
+     * 检查字符,防止注入绕过
+     */
+    public static String escapeOrderBySql(String value)
+    {
+        if (StringUtils.isNotEmpty(value) && !isValidOrderBySql(value))
+        {
+            throw new UtilException("参数不符合规范,不能进行查询");
+        }
+        if (StringUtils.length(value) > ORDER_BY_MAX_LENGTH)
+        {
+            throw new UtilException("参数已超过最大限制,不能进行查询");
+        }
+        return value;
+    }
+
+    /**
+     * 验证 order by 语法是否符合规范
+     */
+    public static boolean isValidOrderBySql(String value)
+    {
+        return value.matches(SQL_PATTERN);
+    }
+
+    /**
+     * SQL关键字检查
+     */
+    public static void filterKeyword(String value)
+    {
+        if (StringUtils.isEmpty(value))
+        {
+            return;
+        }
+        String[] sqlKeywords = StringUtils.split(SQL_REGEX, "\\|");
+        for (String sqlKeyword : sqlKeywords)
+        {
+            if (StringUtils.indexOfIgnoreCase(value, sqlKeyword) > -1)
+            {
+                throw new UtilException("参数存在SQL注入风险");
+            }
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/IdUtils.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/IdUtils.java
index 0256511f..04d7ec1d 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/IdUtils.java
@@ -1,49 +1,49 @@
-package com.ruoyi.common.utils.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,使用性能更好的ThreadLocalRandom生成UUID
-     * 
-     * @return 随机UUID
-     */
-    public static String fastUUID()
-    {
-        return UUID.fastUUID().toString();
-    }
-
-    /**
-     * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
-     * 
-     * @return 简化的UUID,去掉了横线
-     */
-    public static String fastSimpleUUID()
-    {
-        return UUID.fastUUID().toString(true);
-    }
-}
+package com.acupuncture.common.utils.uuid;
+
+/**
+ * ID生成器工具类
+ * 
+ * @author acupuncture
+ */
+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,使用性能更好的ThreadLocalRandom生成UUID
+     * 
+     * @return 随机UUID
+     */
+    public static String fastUUID()
+    {
+        return UUID.fastUUID().toString();
+    }
+
+    /**
+     * 简化的UUID,去掉了横线,使用性能更好的ThreadLocalRandom生成UUID
+     * 
+     * @return 简化的UUID,去掉了横线
+     */
+    public static String fastSimpleUUID()
+    {
+        return UUID.fastUUID().toString(true);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/Seq.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/Seq.java
index 3f621d5d..03bff086 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/Seq.java
@@ -1,86 +1,86 @@
-package com.ruoyi.common.utils.uuid;
-
-import java.util.concurrent.atomic.AtomicInteger;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * @author ruoyi 序列生成类
- */
-public class Seq
-{
-    // 通用序列类型
-    public static final String commSeqType = "COMMON";
-
-    // 上传序列类型
-    public static final String uploadSeqType = "UPLOAD";
-
-    // 通用接口序列数
-    private static AtomicInteger commSeq = new AtomicInteger(1);
-
-    // 上传接口序列数
-    private static AtomicInteger uploadSeq = new AtomicInteger(1);
-
-    // 机器标识
-    private static final String machineCode = "A";
-
-    /**
-     * 获取通用序列号
-     * 
-     * @return 序列值
-     */
-    public static String getId()
-    {
-        return getId(commSeqType);
-    }
-    
-    /**
-     * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
-     * 
-     * @return 序列值
-     */
-    public static String getId(String type)
-    {
-        AtomicInteger atomicInt = commSeq;
-        if (uploadSeqType.equals(type))
-        {
-            atomicInt = uploadSeq;
-        }
-        return getId(atomicInt, 3);
-    }
-
-    /**
-     * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
-     * 
-     * @param atomicInt 序列数
-     * @param length 数值长度
-     * @return 序列值
-     */
-    public static String getId(AtomicInteger atomicInt, int length)
-    {
-        String result = DateUtils.dateTimeNow();
-        result += machineCode;
-        result += getSeq(atomicInt, length);
-        return result;
-    }
-
-    /**
-     * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
-     * 
-     * @return 序列值
-     */
-    private synchronized static String getSeq(AtomicInteger atomicInt, int length)
-    {
-        // 先取值再+1
-        int value = atomicInt.getAndIncrement();
-
-        // 如果更新后值>=10 的 (length)幂次方则重置为1
-        int maxSeq = (int) Math.pow(10, length);
-        if (atomicInt.get() >= maxSeq)
-        {
-            atomicInt.set(1);
-        }
-        // 转字符串,用0左补齐
-        return StringUtils.padl(value, length);
-    }
-}
+package com.acupuncture.common.utils.uuid;
+
+import java.util.concurrent.atomic.AtomicInteger;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * @author acupuncture 序列生成类
+ */
+public class Seq
+{
+    // 通用序列类型
+    public static final String commSeqType = "COMMON";
+
+    // 上传序列类型
+    public static final String uploadSeqType = "UPLOAD";
+
+    // 通用接口序列数
+    private static AtomicInteger commSeq = new AtomicInteger(1);
+
+    // 上传接口序列数
+    private static AtomicInteger uploadSeq = new AtomicInteger(1);
+
+    // 机器标识
+    private static final String machineCode = "A";
+
+    /**
+     * 获取通用序列号
+     * 
+     * @return 序列值
+     */
+    public static String getId()
+    {
+        return getId(commSeqType);
+    }
+    
+    /**
+     * 默认16位序列号 yyMMddHHmmss + 一位机器标识 + 3长度循环递增字符串
+     * 
+     * @return 序列值
+     */
+    public static String getId(String type)
+    {
+        AtomicInteger atomicInt = commSeq;
+        if (uploadSeqType.equals(type))
+        {
+            atomicInt = uploadSeq;
+        }
+        return getId(atomicInt, 3);
+    }
+
+    /**
+     * 通用接口序列号 yyMMddHHmmss + 一位机器标识 + length长度循环递增字符串
+     * 
+     * @param atomicInt 序列数
+     * @param length 数值长度
+     * @return 序列值
+     */
+    public static String getId(AtomicInteger atomicInt, int length)
+    {
+        String result = DateUtils.dateTimeNow();
+        result += machineCode;
+        result += getSeq(atomicInt, length);
+        return result;
+    }
+
+    /**
+     * 序列循环递增字符串[1, 10 的 (length)幂次方), 用0左补齐length位数
+     * 
+     * @return 序列值
+     */
+    private synchronized static String getSeq(AtomicInteger atomicInt, int length)
+    {
+        // 先取值再+1
+        int value = atomicInt.getAndIncrement();
+
+        // 如果更新后值>=10 的 (length)幂次方则重置为1
+        int maxSeq = (int) Math.pow(10, length);
+        if (atomicInt.get() >= maxSeq)
+        {
+            atomicInt.set(1);
+        }
+        // 转字符串,用0左补齐
+        return StringUtils.padl(value, length);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/UUID.java
similarity index 96%
rename from ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/UUID.java
index 97497f28..6c05bb36 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/utils/uuid/UUID.java
@@ -1,484 +1,484 @@
-package com.ruoyi.common.utils.uuid;
-
-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();
-    }
-
-    /** 此UUID的最高64有效位 */
-    private final long mostSigBits;
-
-    /** 此UUID的最低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 的静态工厂。
-     * 
-     * @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(基于名称的)UUID 的静态工厂。
-     *
-     * @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、time_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 字段构造。clock_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 是否简单模式,简单模式为不带'-'的UUID字符串
-     * @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 (!isSimple)
-        {
-            builder.append('-');
-        }
-        // time_mid
-        builder.append(digits(mostSigBits >> 16, 4));
-        if (!isSimple)
-        {
-            builder.append('-');
-        }
-        // time_high_and_version
-        builder.append(digits(mostSigBits, 4));
-        if (!isSimple)
-        {
-            builder.append('-');
-        }
-        // variant_and_sequence
-        builder.append(digits(leastSigBits >> 48, 4));
-        if (!isSimple)
-        {
-            builder.append('-');
-        }
-        // node
-        builder.append(digits(leastSigBits, 12));
-
-        return builder.toString();
-    }
-
-    /**
-     * 返回此 UUID 的哈希码。
-     *
-     * @return UUID 的哈希码值。
-     */
-    @Override
-    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}
-     */
-    @Override
-    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。
-     *
-     */
-    @Override
-    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
-    /**
-     * 返回指定数字对应的hex值
-     * 
-     * @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是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
-     * 
-     * @return {@link ThreadLocalRandom}
-     */
-    public static ThreadLocalRandom getRandom()
-    {
-        return ThreadLocalRandom.current();
-    }
-}
+package com.acupuncture.common.utils.uuid;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.Random;
+import java.util.concurrent.ThreadLocalRandom;
+import com.acupuncture.common.exception.UtilException;
+
+/**
+ * 提供通用唯一识别码(universally unique identifier)(UUID)实现
+ *
+ * @author acupuncture
+ */
+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();
+    }
+
+    /** 此UUID的最高64有效位 */
+    private final long mostSigBits;
+
+    /** 此UUID的最低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 的静态工厂。
+     * 
+     * @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(基于名称的)UUID 的静态工厂。
+     *
+     * @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、time_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 字段构造。clock_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 是否简单模式,简单模式为不带'-'的UUID字符串
+     * @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 (!isSimple)
+        {
+            builder.append('-');
+        }
+        // time_mid
+        builder.append(digits(mostSigBits >> 16, 4));
+        if (!isSimple)
+        {
+            builder.append('-');
+        }
+        // time_high_and_version
+        builder.append(digits(mostSigBits, 4));
+        if (!isSimple)
+        {
+            builder.append('-');
+        }
+        // variant_and_sequence
+        builder.append(digits(leastSigBits >> 48, 4));
+        if (!isSimple)
+        {
+            builder.append('-');
+        }
+        // node
+        builder.append(digits(leastSigBits, 12));
+
+        return builder.toString();
+    }
+
+    /**
+     * 返回此 UUID 的哈希码。
+     *
+     * @return UUID 的哈希码值。
+     */
+    @Override
+    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}
+     */
+    @Override
+    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。
+     *
+     */
+    @Override
+    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
+    /**
+     * 返回指定数字对应的hex值
+     * 
+     * @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是JDK 7之后提供并发产生随机数,能够解决多个线程发生的竞争争夺。
+     * 
+     * @return {@link ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom getRandom()
+    {
+        return ThreadLocalRandom.current();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java b/acupuncture-common/src/main/java/com/acupuncture/common/xss/Xss.java
similarity index 89%
rename from ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/xss/Xss.java
index 14e43dc5..dbd4c6c5 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/xss/Xss.java
@@ -1,27 +1,27 @@
-package com.ruoyi.common.xss;
-
-import javax.validation.Constraint;
-import javax.validation.Payload;
-import java.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-/**
- * 自定义xss校验注解
- * 
- * @author ruoyi
- */
-@Retention(RetentionPolicy.RUNTIME)
-@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
-@Constraint(validatedBy = { XssValidator.class })
-public @interface Xss
-{
-    String message()
-
-    default "不允许任何脚本运行";
-
-    Class<?>[] groups() default {};
-
-    Class<? extends Payload>[] payload() default {};
-}
+package com.acupuncture.common.xss;
+
+import javax.validation.Constraint;
+import javax.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 自定义xss校验注解
+ * 
+ * @author acupuncture
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(value = { ElementType.METHOD, ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
+@Constraint(validatedBy = { XssValidator.class })
+public @interface Xss
+{
+    String message()
+
+    default "不允许任何脚本运行";
+
+    Class<?>[] groups() default {};
+
+    Class<? extends Payload>[] payload() default {};
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java b/acupuncture-common/src/main/java/com/acupuncture/common/xss/XssValidator.java
similarity index 88%
rename from ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
rename to acupuncture-common/src/main/java/com/acupuncture/common/xss/XssValidator.java
index b859428e..a4e02374 100644
--- a/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
+++ b/acupuncture-common/src/main/java/com/acupuncture/common/xss/XssValidator.java
@@ -1,39 +1,39 @@
-package com.ruoyi.common.xss;
-
-import com.ruoyi.common.utils.StringUtils;
-import javax.validation.ConstraintValidator;
-import javax.validation.ConstraintValidatorContext;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
-
-/**
- * 自定义xss校验注解实现
- * 
- * @author ruoyi
- */
-public class XssValidator implements ConstraintValidator<Xss, String>
-{
-    private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
-
-    @Override
-    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
-    {
-        if (StringUtils.isBlank(value))
-        {
-            return true;
-        }
-        return !containsHtml(value);
-    }
-
-    public static boolean containsHtml(String value)
-    {
-        StringBuilder sHtml = new StringBuilder();
-        Pattern pattern = Pattern.compile(HTML_PATTERN);
-        Matcher matcher = pattern.matcher(value);
-        while (matcher.find())
-        {
-            sHtml.append(matcher.group());
-        }
-        return pattern.matcher(sHtml).matches();
-    }
+package com.acupuncture.common.xss;
+
+import com.acupuncture.common.utils.StringUtils;
+import javax.validation.ConstraintValidator;
+import javax.validation.ConstraintValidatorContext;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 自定义xss校验注解实现
+ * 
+ * @author acupuncture
+ */
+public class XssValidator implements ConstraintValidator<Xss, String>
+{
+    private static final String HTML_PATTERN = "<(\\S*?)[^>]*>.*?|<.*? />";
+
+    @Override
+    public boolean isValid(String value, ConstraintValidatorContext constraintValidatorContext)
+    {
+        if (StringUtils.isBlank(value))
+        {
+            return true;
+        }
+        return !containsHtml(value);
+    }
+
+    public static boolean containsHtml(String value)
+    {
+        StringBuilder sHtml = new StringBuilder();
+        Pattern pattern = Pattern.compile(HTML_PATTERN);
+        Matcher matcher = pattern.matcher(value);
+        while (matcher.find())
+        {
+            sHtml.append(matcher.group());
+        }
+        return pattern.matcher(sHtml).matches();
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-framework/pom.xml b/acupuncture-framework/pom.xml
similarity index 86%
rename from ruoyi-framework/pom.xml
rename to acupuncture-framework/pom.xml
index d8d6d88d..1295e36d 100644
--- a/ruoyi-framework/pom.xml
+++ b/acupuncture-framework/pom.xml
@@ -1,64 +1,64 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ruoyi-framework</artifactId>
-
-    <description>
-        framework框架核心
-    </description>
-
-    <dependencies>
-
-        <!-- SpringBoot Web容器 -->
-         <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-        </dependency>
-
-        <!-- SpringBoot 拦截器 -->
-        <dependency>
-            <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-aop</artifactId>
-        </dependency>
-
-        <!-- 阿里数据库连接池 -->
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid-spring-boot-starter</artifactId>
-        </dependency>
-
-        <!-- 验证码 -->
-        <dependency>
-            <groupId>pro.fessional</groupId>
-            <artifactId>kaptcha</artifactId>
-            <exclusions>
-                <exclusion>
-                    <artifactId>servlet-api</artifactId>
-                    <groupId>javax.servlet</groupId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <!-- 获取系统信息 -->
-        <dependency>
-            <groupId>com.github.oshi</groupId>
-            <artifactId>oshi-core</artifactId>
-        </dependency>
-
-        <!-- 系统模块-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-system</artifactId>
-        </dependency>
-
-    </dependencies>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>acupuncture-framework</artifactId>
+
+    <description>
+        framework框架核心
+    </description>
+
+    <dependencies>
+
+        <!-- SpringBoot Web容器 -->
+         <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- SpringBoot 拦截器 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <!-- 阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 验证码 -->
+        <dependency>
+            <groupId>pro.fessional</groupId>
+            <artifactId>kaptcha</artifactId>
+            <exclusions>
+                <exclusion>
+                    <artifactId>servlet-api</artifactId>
+                    <groupId>javax.servlet</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 获取系统信息 -->
+        <dependency>
+            <groupId>com.github.oshi</groupId>
+            <artifactId>oshi-core</artifactId>
+        </dependency>
+
+        <!-- 系统模块-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-system</artifactId>
+        </dependency>
+
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataScopeAspect.java
similarity index 89%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataScopeAspect.java
index 719c3711..e7396b17 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataScopeAspect.java
@@ -1,184 +1,184 @@
-package com.ruoyi.framework.aspectj;
-
-import java.util.ArrayList;
-import java.util.List;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.annotation.DataScope;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.context.PermissionContextHolder;
-
-/**
- * 数据过滤处理
- *
- * @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";
-
-    /**
-     * 数据权限过滤关键字
-     */
-    public static final String DATA_SCOPE = "dataScope";
-
-    @Before("@annotation(controllerDataScope)")
-    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
-    {
-        clearDataScope(point);
-        handleDataScope(point, controllerDataScope);
-    }
-
-    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
-    {
-        // 获取当前的用户
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNotNull(loginUser))
-        {
-            SysUser currentUser = loginUser.getUser();
-            // 如果是超级管理员,则不过滤数据
-            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
-            {
-                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
-                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
-            }
-        }
-    }
-
-    /**
-     * 数据范围过滤
-     *
-     * @param joinPoint 切点
-     * @param user 用户
-     * @param deptAlias 部门别名
-     * @param userAlias 用户别名
-     * @param permission 权限字符
-     */
-    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
-    {
-        StringBuilder sqlString = new StringBuilder();
-        List<String> conditions = new ArrayList<String>();
-        List<String> scopeCustomIds = new ArrayList<String>();
-        user.getRoles().forEach(role -> {
-            if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
-            {
-                scopeCustomIds.add(Convert.toStr(role.getRoleId()));
-            }
-        });
-
-        for (SysRole role : user.getRoles())
-        {
-            String dataScope = role.getDataScope();
-            if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
-            {
-                continue;
-            }
-            if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
-            {
-                continue;
-            }
-            if (DATA_SCOPE_ALL.equals(dataScope))
-            {
-                sqlString = new StringBuilder();
-                conditions.add(dataScope);
-                break;
-            }
-            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
-            {
-                if (scopeCustomIds.size() > 1)
-                {
-                    // 多个自定数据权限使用in查询,避免多次拼接。
-                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
-                }
-                else
-                {
-                    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
-                {
-                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
-                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
-                }
-            }
-            conditions.add(dataScope);
-        }
-
-        // 角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据
-        if (StringUtils.isEmpty(conditions))
-        {
-            sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
-        }
-
-        if (StringUtils.isNotBlank(sqlString.toString()))
-        {
-            Object params = joinPoint.getArgs()[0];
-            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
-            {
-                BaseEntity baseEntity = (BaseEntity) params;
-                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
-            }
-        }
-    }
-
-    /**
-     * 拼接权限sql前先清空params.dataScope参数防止注入
-     */
-    private void clearDataScope(final JoinPoint joinPoint)
-    {
-        Object params = joinPoint.getArgs()[0];
-        if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
-        {
-            BaseEntity baseEntity = (BaseEntity) params;
-            baseEntity.getParams().put(DATA_SCOPE, "");
-        }
-    }
-}
+package com.acupuncture.framework.aspectj;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.annotation.DataScope;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.security.context.PermissionContextHolder;
+
+/**
+ * 数据过滤处理
+ *
+ * @author acupuncture
+ */
+@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";
+
+    /**
+     * 数据权限过滤关键字
+     */
+    public static final String DATA_SCOPE = "dataScope";
+
+    @Before("@annotation(controllerDataScope)")
+    public void doBefore(JoinPoint point, DataScope controllerDataScope) throws Throwable
+    {
+        clearDataScope(point);
+        handleDataScope(point, controllerDataScope);
+    }
+
+    protected void handleDataScope(final JoinPoint joinPoint, DataScope controllerDataScope)
+    {
+        // 获取当前的用户
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        if (StringUtils.isNotNull(loginUser))
+        {
+            SysUser currentUser = loginUser.getUser();
+            // 如果是超级管理员,则不过滤数据
+            if (StringUtils.isNotNull(currentUser) && !currentUser.isAdmin())
+            {
+                String permission = StringUtils.defaultIfEmpty(controllerDataScope.permission(), PermissionContextHolder.getContext());
+                dataScopeFilter(joinPoint, currentUser, controllerDataScope.deptAlias(), controllerDataScope.userAlias(), permission);
+            }
+        }
+    }
+
+    /**
+     * 数据范围过滤
+     *
+     * @param joinPoint 切点
+     * @param user 用户
+     * @param deptAlias 部门别名
+     * @param userAlias 用户别名
+     * @param permission 权限字符
+     */
+    public static void dataScopeFilter(JoinPoint joinPoint, SysUser user, String deptAlias, String userAlias, String permission)
+    {
+        StringBuilder sqlString = new StringBuilder();
+        List<String> conditions = new ArrayList<String>();
+        List<String> scopeCustomIds = new ArrayList<String>();
+        user.getRoles().forEach(role -> {
+            if (DATA_SCOPE_CUSTOM.equals(role.getDataScope()) && StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL) && StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
+            {
+                scopeCustomIds.add(Convert.toStr(role.getRoleId()));
+            }
+        });
+
+        for (SysRole role : user.getRoles())
+        {
+            String dataScope = role.getDataScope();
+            if (conditions.contains(dataScope) || StringUtils.equals(role.getStatus(), UserConstants.ROLE_DISABLE))
+            {
+                continue;
+            }
+            if (!StringUtils.containsAny(role.getPermissions(), Convert.toStrArray(permission)))
+            {
+                continue;
+            }
+            if (DATA_SCOPE_ALL.equals(dataScope))
+            {
+                sqlString = new StringBuilder();
+                conditions.add(dataScope);
+                break;
+            }
+            else if (DATA_SCOPE_CUSTOM.equals(dataScope))
+            {
+                if (scopeCustomIds.size() > 1)
+                {
+                    // 多个自定数据权限使用in查询,避免多次拼接。
+                    sqlString.append(StringUtils.format(" OR {}.dept_id IN ( SELECT dept_id FROM sys_role_dept WHERE role_id in ({}) ) ", deptAlias, String.join(",", scopeCustomIds)));
+                }
+                else
+                {
+                    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
+                {
+                    // 数据权限为仅本人且没有userAlias别名不查询任何数据
+                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+                }
+            }
+            conditions.add(dataScope);
+        }
+
+        // 角色都不包含传递过来的权限字符,这个时候sqlString也会为空,所以要限制一下,不查询任何数据
+        if (StringUtils.isEmpty(conditions))
+        {
+            sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+        }
+
+        if (StringUtils.isNotBlank(sqlString.toString()))
+        {
+            Object params = joinPoint.getArgs()[0];
+            if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
+            {
+                BaseEntity baseEntity = (BaseEntity) params;
+                baseEntity.getParams().put(DATA_SCOPE, " AND (" + sqlString.substring(4) + ")");
+            }
+        }
+    }
+
+    /**
+     * 拼接权限sql前先清空params.dataScope参数防止注入
+     */
+    private void clearDataScope(final JoinPoint joinPoint)
+    {
+        Object params = joinPoint.getArgs()[0];
+        if (StringUtils.isNotNull(params) && params instanceof BaseEntity)
+        {
+            BaseEntity baseEntity = (BaseEntity) params;
+            baseEntity.getParams().put(DATA_SCOPE, "");
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataSourceAspect.java
similarity index 80%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataSourceAspect.java
index 4648fcd3..1ef9e3fd 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/DataSourceAspect.java
@@ -1,72 +1,72 @@
-package com.ruoyi.framework.aspectj;
-
-import java.util.Objects;
-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.AnnotationUtils;
-import org.springframework.core.annotation.Order;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.annotation.DataSource;
-import com.ruoyi.common.utils.StringUtils;
-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.common.annotation.DataSource)"
-            + "|| @within(com.ruoyi.common.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();
-        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
-        if (Objects.nonNull(dataSource))
-        {
-            return dataSource;
-        }
-
-        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
-    }
-}
+package com.acupuncture.framework.aspectj;
+
+import java.util.Objects;
+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.AnnotationUtils;
+import org.springframework.core.annotation.Order;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.annotation.DataSource;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.datasource.DynamicDataSourceContextHolder;
+
+/**
+ * 多数据源处理
+ * 
+ * @author acupuncture
+ */
+@Aspect
+@Order(1)
+@Component
+public class DataSourceAspect
+{
+    protected Logger logger = LoggerFactory.getLogger(getClass());
+
+    @Pointcut("@annotation(com.acupuncture.common.annotation.DataSource)"
+            + "|| @within(com.acupuncture.common.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();
+        DataSource dataSource = AnnotationUtils.findAnnotation(signature.getMethod(), DataSource.class);
+        if (Objects.nonNull(dataSource))
+        {
+            return dataSource;
+        }
+
+        return AnnotationUtils.findAnnotation(signature.getDeclaringType(), DataSource.class);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/LogAspect.java
similarity index 90%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/LogAspect.java
index ca9a10f7..1222695b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/LogAspect.java
@@ -1,254 +1,254 @@
-package com.ruoyi.framework.aspectj;
-
-import java.util.Collection;
-import java.util.Map;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.lang3.ArrayUtils;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.AfterReturning;
-import org.aspectj.lang.annotation.AfterThrowing;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.core.NamedThreadLocal;
-import org.springframework.stereotype.Component;
-import org.springframework.validation.BindingResult;
-import org.springframework.web.multipart.MultipartFile;
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.enums.BusinessStatus;
-import com.ruoyi.common.enums.HttpMethod;
-import com.ruoyi.common.filter.PropertyPreExcludeFilter;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.ip.IpUtils;
-import com.ruoyi.framework.manager.AsyncManager;
-import com.ruoyi.framework.manager.factory.AsyncFactory;
-import com.ruoyi.system.domain.SysOperLog;
-
-/**
- * 操作日志记录处理
- * 
- * @author ruoyi
- */
-@Aspect
-@Component
-public class LogAspect
-{
-    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
-
-    /** 排除敏感属性字段 */
-    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
-
-    /** 计算操作消耗时间 */
-    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
-
-    /**
-     * 处理请求前执行
-     */
-    @Before(value = "@annotation(controllerLog)")
-    public void boBefore(JoinPoint joinPoint, Log controllerLog)
-    {
-        TIME_THREADLOCAL.set(System.currentTimeMillis());
-    }
-
-    /**
-     * 处理完请求后执行
-     *
-     * @param joinPoint 切点
-     */
-    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
-    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
-    {
-        handleLog(joinPoint, controllerLog, null, jsonResult);
-    }
-
-    /**
-     * 拦截异常操作
-     * 
-     * @param joinPoint 切点
-     * @param e 异常
-     */
-    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
-    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
-    {
-        handleLog(joinPoint, controllerLog, e, null);
-    }
-
-    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
-    {
-        try
-        {
-            // 获取当前的用户
-            LoginUser loginUser = SecurityUtils.getLoginUser();
-
-            // *========数据库日志=========*//
-            SysOperLog operLog = new SysOperLog();
-            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
-            // 请求的地址
-            String ip = IpUtils.getIpAddr();
-            operLog.setOperIp(ip);
-            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
-            if (loginUser != null)
-            {
-                operLog.setOperName(loginUser.getUsername());
-                SysUser currentUser = loginUser.getUser();
-                if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
-                {
-                    operLog.setDeptName(currentUser.getDept().getDeptName());
-                }
-            }
-
-            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, jsonResult);
-            // 设置消耗时间
-            operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
-            // 保存数据库
-            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
-        }
-        catch (Exception exp)
-        {
-            // 记录本地异常日志
-            log.error("异常信息:{}", exp.getMessage());
-            exp.printStackTrace();
-        }
-        finally
-        {
-            TIME_THREADLOCAL.remove();
-        }
-    }
-
-    /**
-     * 获取注解中对方法的描述信息 用于Controller层注解
-     * 
-     * @param log 日志
-     * @param operLog 操作日志
-     * @throws Exception
-     */
-    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
-    {
-        // 设置action动作
-        operLog.setBusinessType(log.businessType().ordinal());
-        // 设置标题
-        operLog.setTitle(log.title());
-        // 设置操作人类别
-        operLog.setOperatorType(log.operatorType().ordinal());
-        // 是否需要保存request,参数和值
-        if (log.isSaveRequestData())
-        {
-            // 获取参数的信息,传入到数据库中。
-            setRequestValue(joinPoint, operLog, log.excludeParamNames());
-        }
-        // 是否需要保存response,参数和值
-        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
-        {
-            operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
-        }
-    }
-
-    /**
-     * 获取请求的参数,放到log中
-     * 
-     * @param operLog 操作日志
-     * @throws Exception 异常
-     */
-    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
-    {
-        Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
-        String requestMethod = operLog.getRequestMethod();
-        if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
-        {
-            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
-            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
-        }
-        else
-        {
-            operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
-        }
-    }
-
-    /**
-     * 参数拼装
-     */
-    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
-    {
-        String params = "";
-        if (paramsArray != null && paramsArray.length > 0)
-        {
-            for (Object o : paramsArray)
-            {
-                if (StringUtils.isNotNull(o) && !isFilterObject(o))
-                {
-                    try
-                    {
-                        String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
-                        params += jsonObj.toString() + " ";
-                    }
-                    catch (Exception e)
-                    {
-                    }
-                }
-            }
-        }
-        return params.trim();
-    }
-
-    /**
-     * 忽略敏感属性
-     */
-    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
-    {
-        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
-    }
-
-    /**
-     * 判断是否需要过滤的对象。
-     * 
-     * @param o 对象信息。
-     * @return 如果是需要过滤的对象,则返回true;否则返回false。
-     */
-    @SuppressWarnings("rawtypes")
-    public boolean isFilterObject(final Object o)
-    {
-        Class<?> clazz = o.getClass();
-        if (clazz.isArray())
-        {
-            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
-        }
-        else if (Collection.class.isAssignableFrom(clazz))
-        {
-            Collection collection = (Collection) o;
-            for (Object value : collection)
-            {
-                return value instanceof MultipartFile;
-            }
-        }
-        else if (Map.class.isAssignableFrom(clazz))
-        {
-            Map map = (Map) o;
-            for (Object value : map.entrySet())
-            {
-                Map.Entry entry = (Map.Entry) value;
-                return entry.getValue() instanceof MultipartFile;
-            }
-        }
-        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
-                || o instanceof BindingResult;
-    }
-}
+package com.acupuncture.framework.aspectj;
+
+import java.util.Collection;
+import java.util.Map;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.lang3.ArrayUtils;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.AfterReturning;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.core.NamedThreadLocal;
+import org.springframework.stereotype.Component;
+import org.springframework.validation.BindingResult;
+import org.springframework.web.multipart.MultipartFile;
+import com.alibaba.fastjson2.JSON;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.enums.BusinessStatus;
+import com.acupuncture.common.enums.HttpMethod;
+import com.acupuncture.common.filter.PropertyPreExcludeFilter;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.ip.IpUtils;
+import com.acupuncture.framework.manager.AsyncManager;
+import com.acupuncture.framework.manager.factory.AsyncFactory;
+import com.acupuncture.system.domain.SysOperLog;
+
+/**
+ * 操作日志记录处理
+ * 
+ * @author acupuncture
+ */
+@Aspect
+@Component
+public class LogAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(LogAspect.class);
+
+    /** 排除敏感属性字段 */
+    public static final String[] EXCLUDE_PROPERTIES = { "password", "oldPassword", "newPassword", "confirmPassword" };
+
+    /** 计算操作消耗时间 */
+    private static final ThreadLocal<Long> TIME_THREADLOCAL = new NamedThreadLocal<Long>("Cost Time");
+
+    /**
+     * 处理请求前执行
+     */
+    @Before(value = "@annotation(controllerLog)")
+    public void boBefore(JoinPoint joinPoint, Log controllerLog)
+    {
+        TIME_THREADLOCAL.set(System.currentTimeMillis());
+    }
+
+    /**
+     * 处理完请求后执行
+     *
+     * @param joinPoint 切点
+     */
+    @AfterReturning(pointcut = "@annotation(controllerLog)", returning = "jsonResult")
+    public void doAfterReturning(JoinPoint joinPoint, Log controllerLog, Object jsonResult)
+    {
+        handleLog(joinPoint, controllerLog, null, jsonResult);
+    }
+
+    /**
+     * 拦截异常操作
+     * 
+     * @param joinPoint 切点
+     * @param e 异常
+     */
+    @AfterThrowing(value = "@annotation(controllerLog)", throwing = "e")
+    public void doAfterThrowing(JoinPoint joinPoint, Log controllerLog, Exception e)
+    {
+        handleLog(joinPoint, controllerLog, e, null);
+    }
+
+    protected void handleLog(final JoinPoint joinPoint, Log controllerLog, final Exception e, Object jsonResult)
+    {
+        try
+        {
+            // 获取当前的用户
+            LoginUser loginUser = SecurityUtils.getLoginUser();
+
+            // *========数据库日志=========*//
+            SysOperLog operLog = new SysOperLog();
+            operLog.setStatus(BusinessStatus.SUCCESS.ordinal());
+            // 请求的地址
+            String ip = IpUtils.getIpAddr();
+            operLog.setOperIp(ip);
+            operLog.setOperUrl(StringUtils.substring(ServletUtils.getRequest().getRequestURI(), 0, 255));
+            if (loginUser != null)
+            {
+                operLog.setOperName(loginUser.getUsername());
+                SysUser currentUser = loginUser.getUser();
+                if (StringUtils.isNotNull(currentUser) && StringUtils.isNotNull(currentUser.getDept()))
+                {
+                    operLog.setDeptName(currentUser.getDept().getDeptName());
+                }
+            }
+
+            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, jsonResult);
+            // 设置消耗时间
+            operLog.setCostTime(System.currentTimeMillis() - TIME_THREADLOCAL.get());
+            // 保存数据库
+            AsyncManager.me().execute(AsyncFactory.recordOper(operLog));
+        }
+        catch (Exception exp)
+        {
+            // 记录本地异常日志
+            log.error("异常信息:{}", exp.getMessage());
+            exp.printStackTrace();
+        }
+        finally
+        {
+            TIME_THREADLOCAL.remove();
+        }
+    }
+
+    /**
+     * 获取注解中对方法的描述信息 用于Controller层注解
+     * 
+     * @param log 日志
+     * @param operLog 操作日志
+     * @throws Exception
+     */
+    public void getControllerMethodDescription(JoinPoint joinPoint, Log log, SysOperLog operLog, Object jsonResult) throws Exception
+    {
+        // 设置action动作
+        operLog.setBusinessType(log.businessType().ordinal());
+        // 设置标题
+        operLog.setTitle(log.title());
+        // 设置操作人类别
+        operLog.setOperatorType(log.operatorType().ordinal());
+        // 是否需要保存request,参数和值
+        if (log.isSaveRequestData())
+        {
+            // 获取参数的信息,传入到数据库中。
+            setRequestValue(joinPoint, operLog, log.excludeParamNames());
+        }
+        // 是否需要保存response,参数和值
+        if (log.isSaveResponseData() && StringUtils.isNotNull(jsonResult))
+        {
+            operLog.setJsonResult(StringUtils.substring(JSON.toJSONString(jsonResult), 0, 2000));
+        }
+    }
+
+    /**
+     * 获取请求的参数,放到log中
+     * 
+     * @param operLog 操作日志
+     * @throws Exception 异常
+     */
+    private void setRequestValue(JoinPoint joinPoint, SysOperLog operLog, String[] excludeParamNames) throws Exception
+    {
+        Map<?, ?> paramsMap = ServletUtils.getParamMap(ServletUtils.getRequest());
+        String requestMethod = operLog.getRequestMethod();
+        if (StringUtils.isEmpty(paramsMap) && StringUtils.equalsAny(requestMethod, HttpMethod.PUT.name(), HttpMethod.POST.name(), HttpMethod.DELETE.name()))
+        {
+            String params = argsArrayToString(joinPoint.getArgs(), excludeParamNames);
+            operLog.setOperParam(StringUtils.substring(params, 0, 2000));
+        }
+        else
+        {
+            operLog.setOperParam(StringUtils.substring(JSON.toJSONString(paramsMap, excludePropertyPreFilter(excludeParamNames)), 0, 2000));
+        }
+    }
+
+    /**
+     * 参数拼装
+     */
+    private String argsArrayToString(Object[] paramsArray, String[] excludeParamNames)
+    {
+        String params = "";
+        if (paramsArray != null && paramsArray.length > 0)
+        {
+            for (Object o : paramsArray)
+            {
+                if (StringUtils.isNotNull(o) && !isFilterObject(o))
+                {
+                    try
+                    {
+                        String jsonObj = JSON.toJSONString(o, excludePropertyPreFilter(excludeParamNames));
+                        params += jsonObj.toString() + " ";
+                    }
+                    catch (Exception e)
+                    {
+                    }
+                }
+            }
+        }
+        return params.trim();
+    }
+
+    /**
+     * 忽略敏感属性
+     */
+    public PropertyPreExcludeFilter excludePropertyPreFilter(String[] excludeParamNames)
+    {
+        return new PropertyPreExcludeFilter().addExcludes(ArrayUtils.addAll(EXCLUDE_PROPERTIES, excludeParamNames));
+    }
+
+    /**
+     * 判断是否需要过滤的对象。
+     * 
+     * @param o 对象信息。
+     * @return 如果是需要过滤的对象,则返回true;否则返回false。
+     */
+    @SuppressWarnings("rawtypes")
+    public boolean isFilterObject(final Object o)
+    {
+        Class<?> clazz = o.getClass();
+        if (clazz.isArray())
+        {
+            return clazz.getComponentType().isAssignableFrom(MultipartFile.class);
+        }
+        else if (Collection.class.isAssignableFrom(clazz))
+        {
+            Collection collection = (Collection) o;
+            for (Object value : collection)
+            {
+                return value instanceof MultipartFile;
+            }
+        }
+        else if (Map.class.isAssignableFrom(clazz))
+        {
+            Map map = (Map) o;
+            for (Object value : map.entrySet())
+            {
+                Map.Entry entry = (Map.Entry) value;
+                return entry.getValue() instanceof MultipartFile;
+            }
+        }
+        return o instanceof MultipartFile || o instanceof HttpServletRequest || o instanceof HttpServletResponse
+                || o instanceof BindingResult;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/RateLimiterAspect.java
similarity index 87%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/RateLimiterAspect.java
index a2015d70..ae02ed5c 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/aspectj/RateLimiterAspect.java
@@ -1,89 +1,89 @@
-package com.ruoyi.framework.aspectj;
-
-import java.lang.reflect.Method;
-import java.util.Collections;
-import java.util.List;
-import org.aspectj.lang.JoinPoint;
-import org.aspectj.lang.annotation.Aspect;
-import org.aspectj.lang.annotation.Before;
-import org.aspectj.lang.reflect.MethodSignature;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.data.redis.core.RedisTemplate;
-import org.springframework.data.redis.core.script.RedisScript;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.annotation.RateLimiter;
-import com.ruoyi.common.enums.LimitType;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.ip.IpUtils;
-
-/**
- * 限流处理
- *
- * @author ruoyi
- */
-@Aspect
-@Component
-public class RateLimiterAspect
-{
-    private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
-
-    private RedisTemplate<Object, Object> redisTemplate;
-
-    private RedisScript<Long> limitScript;
-
-    @Autowired
-    public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
-    {
-        this.redisTemplate = redisTemplate;
-    }
-
-    @Autowired
-    public void setLimitScript(RedisScript<Long> limitScript)
-    {
-        this.limitScript = limitScript;
-    }
-
-    @Before("@annotation(rateLimiter)")
-    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
-    {
-        int time = rateLimiter.time();
-        int count = rateLimiter.count();
-
-        String combineKey = getCombineKey(rateLimiter, point);
-        List<Object> keys = Collections.singletonList(combineKey);
-        try
-        {
-            Long number = redisTemplate.execute(limitScript, keys, count, time);
-            if (StringUtils.isNull(number) || number.intValue() > count)
-            {
-                throw new ServiceException("访问过于频繁,请稍候再试");
-            }
-            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
-        }
-        catch (ServiceException e)
-        {
-            throw e;
-        }
-        catch (Exception e)
-        {
-            throw new RuntimeException("服务器限流异常,请稍候再试");
-        }
-    }
-
-    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
-    {
-        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
-        if (rateLimiter.limitType() == LimitType.IP)
-        {
-            stringBuffer.append(IpUtils.getIpAddr()).append("-");
-        }
-        MethodSignature signature = (MethodSignature) point.getSignature();
-        Method method = signature.getMethod();
-        Class<?> targetClass = method.getDeclaringClass();
-        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
-        return stringBuffer.toString();
-    }
-}
+package com.acupuncture.framework.aspectj;
+
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.List;
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Before;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.core.script.RedisScript;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.annotation.RateLimiter;
+import com.acupuncture.common.enums.LimitType;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.ip.IpUtils;
+
+/**
+ * 限流处理
+ *
+ * @author acupuncture
+ */
+@Aspect
+@Component
+public class RateLimiterAspect
+{
+    private static final Logger log = LoggerFactory.getLogger(RateLimiterAspect.class);
+
+    private RedisTemplate<Object, Object> redisTemplate;
+
+    private RedisScript<Long> limitScript;
+
+    @Autowired
+    public void setRedisTemplate1(RedisTemplate<Object, Object> redisTemplate)
+    {
+        this.redisTemplate = redisTemplate;
+    }
+
+    @Autowired
+    public void setLimitScript(RedisScript<Long> limitScript)
+    {
+        this.limitScript = limitScript;
+    }
+
+    @Before("@annotation(rateLimiter)")
+    public void doBefore(JoinPoint point, RateLimiter rateLimiter) throws Throwable
+    {
+        int time = rateLimiter.time();
+        int count = rateLimiter.count();
+
+        String combineKey = getCombineKey(rateLimiter, point);
+        List<Object> keys = Collections.singletonList(combineKey);
+        try
+        {
+            Long number = redisTemplate.execute(limitScript, keys, count, time);
+            if (StringUtils.isNull(number) || number.intValue() > count)
+            {
+                throw new ServiceException("访问过于频繁,请稍候再试");
+            }
+            log.info("限制请求'{}',当前请求'{}',缓存key'{}'", count, number.intValue(), combineKey);
+        }
+        catch (ServiceException e)
+        {
+            throw e;
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException("服务器限流异常,请稍候再试");
+        }
+    }
+
+    public String getCombineKey(RateLimiter rateLimiter, JoinPoint point)
+    {
+        StringBuffer stringBuffer = new StringBuffer(rateLimiter.key());
+        if (rateLimiter.limitType() == LimitType.IP)
+        {
+            stringBuffer.append(IpUtils.getIpAddr()).append("-");
+        }
+        MethodSignature signature = (MethodSignature) point.getSignature();
+        Method method = signature.getMethod();
+        Class<?> targetClass = method.getDeclaringClass();
+        stringBuffer.append(targetClass.getName()).append("-").append(method.getName());
+        return stringBuffer.toString();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ApplicationConfig.java
similarity index 87%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/ApplicationConfig.java
index 66a00e7c..6b0ecbcc 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ApplicationConfig.java
@@ -1,30 +1,30 @@
-package com.ruoyi.framework.config;
-
-import java.util.TimeZone;
-import org.mybatis.spring.annotation.MapperScan;
-import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.context.annotation.EnableAspectJAutoProxy;
-
-/**
- * 程序注解配置
- *
- * @author ruoyi
- */
-@Configuration
-// 表示通过aop框架暴露该代理对象,AopContext能够访问
-@EnableAspectJAutoProxy(exposeProxy = true)
-// 指定要扫描的Mapper类的包的路径
-@MapperScan("com.ruoyi.**.mapper")
-public class ApplicationConfig
-{
-    /**
-     * 时区配置
-     */
-    @Bean
-    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
-    {
-        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
-    }
-}
+package com.acupuncture.framework.config;
+
+import java.util.TimeZone;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.EnableAspectJAutoProxy;
+
+/**
+ * 程序注解配置
+ *
+ * @author acupuncture
+ */
+@Configuration
+// 表示通过aop框架暴露该代理对象,AopContext能够访问
+@EnableAspectJAutoProxy(exposeProxy = true)
+// 指定要扫描的Mapper类的包的路径
+@MapperScan("com.acupuncture.**.mapper")
+public class ApplicationConfig
+{
+    /**
+     * 时区配置
+     */
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jacksonObjectMapperCustomization()
+    {
+        return jacksonObjectMapperBuilder -> jacksonObjectMapperBuilder.timeZone(TimeZone.getDefault());
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/CaptchaConfig.java
similarity index 95%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/CaptchaConfig.java
index 43e78aeb..98c69f7c 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/CaptchaConfig.java
@@ -1,4 +1,4 @@
-package com.ruoyi.framework.config;
+package com.acupuncture.framework.config;
 
 import java.util.Properties;
 import org.springframework.context.annotation.Bean;
@@ -10,7 +10,7 @@ import static com.google.code.kaptcha.Constants.*;
 /**
  * 验证码配置
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 @Configuration
 public class CaptchaConfig
@@ -63,7 +63,7 @@ public class CaptchaConfig
         // KAPTCHA_SESSION_KEY
         properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
         // 验证码文本生成器
-        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator");
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.acupuncture.framework.config.KaptchaTextCreator");
         // 验证码文本字符间距 默认为2
         properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
         // 验证码文本字符长度 默认为5
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/DruidConfig.java
similarity index 92%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/DruidConfig.java
index f671b3a3..8471fbc8 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/DruidConfig.java
@@ -1,126 +1,126 @@
-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.common.enums.DataSourceType;
-import com.ruoyi.common.utils.spring.SpringUtils;
-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)
-    {
-        Map<Object, Object> targetDataSources = new HashMap<>();
-        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
-        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
-        return new DynamicDataSource(masterDataSource, targetDataSources);
-    }
-    
-    /**
-     * 设置数据源
-     * 
-     * @param targetDataSources 备选数据源集合
-     * @param sourceName 数据源名称
-     * @param beanName bean名称
-     */
-    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
-    {
-        try
-        {
-            DataSource dataSource = SpringUtils.getBean(beanName);
-            targetDataSources.put(sourceName, dataSource);
-        }
-        catch (Exception e)
-        {
-        }
-    }
-
-    /**
-     * 去除监控页面底部的广告
-     */
-    @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);
-                // 正则替换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;
-    }
-}
+package com.acupuncture.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.acupuncture.common.enums.DataSourceType;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.framework.config.properties.DruidProperties;
+import com.acupuncture.framework.datasource.DynamicDataSource;
+
+/**
+ * druid 配置多数据源
+ * 
+ * @author acupuncture
+ */
+@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)
+    {
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.MASTER.name(), masterDataSource);
+        setDataSource(targetDataSources, DataSourceType.SLAVE.name(), "slaveDataSource");
+        return new DynamicDataSource(masterDataSource, targetDataSources);
+    }
+    
+    /**
+     * 设置数据源
+     * 
+     * @param targetDataSources 备选数据源集合
+     * @param sourceName 数据源名称
+     * @param beanName bean名称
+     */
+    public void setDataSource(Map<Object, Object> targetDataSources, String sourceName, String beanName)
+    {
+        try
+        {
+            DataSource dataSource = SpringUtils.getBean(beanName);
+            targetDataSources.put(sourceName, dataSource);
+        }
+        catch (Exception e)
+        {
+        }
+    }
+
+    /**
+     * 去除监控页面底部的广告
+     */
+    @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);
+                // 正则替换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-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/FastJson2JsonRedisSerializer.java
similarity index 90%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/FastJson2JsonRedisSerializer.java
index bd369b4c..97b74692 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/FastJson2JsonRedisSerializer.java
@@ -1,52 +1,52 @@
-package com.ruoyi.framework.config;
-
-import java.nio.charset.Charset;
-import org.springframework.data.redis.serializer.RedisSerializer;
-import org.springframework.data.redis.serializer.SerializationException;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONReader;
-import com.alibaba.fastjson2.JSONWriter;
-import com.alibaba.fastjson2.filter.Filter;
-import com.ruoyi.common.constant.Constants;
-
-/**
- * Redis使用FastJson序列化
- * 
- * @author ruoyi
- */
-public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
-{
-    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
-
-    static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
-
-    private Class<T> clazz;
-
-    public FastJson2JsonRedisSerializer(Class<T> clazz)
-    {
-        super();
-        this.clazz = clazz;
-    }
-
-    @Override
-    public byte[] serialize(T t) throws SerializationException
-    {
-        if (t == null)
-        {
-            return new byte[0];
-        }
-        return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
-    }
-
-    @Override
-    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, AUTO_TYPE_FILTER);
-    }
-}
+package com.acupuncture.framework.config;
+
+import java.nio.charset.Charset;
+import org.springframework.data.redis.serializer.RedisSerializer;
+import org.springframework.data.redis.serializer.SerializationException;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONReader;
+import com.alibaba.fastjson2.JSONWriter;
+import com.alibaba.fastjson2.filter.Filter;
+import com.acupuncture.common.constant.Constants;
+
+/**
+ * Redis使用FastJson序列化
+ * 
+ * @author acupuncture
+ */
+public class FastJson2JsonRedisSerializer<T> implements RedisSerializer<T>
+{
+    public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
+
+    static final Filter AUTO_TYPE_FILTER = JSONReader.autoTypeFilter(Constants.JSON_WHITELIST_STR);
+
+    private Class<T> clazz;
+
+    public FastJson2JsonRedisSerializer(Class<T> clazz)
+    {
+        super();
+        this.clazz = clazz;
+    }
+
+    @Override
+    public byte[] serialize(T t) throws SerializationException
+    {
+        if (t == null)
+        {
+            return new byte[0];
+        }
+        return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(DEFAULT_CHARSET);
+    }
+
+    @Override
+    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, AUTO_TYPE_FILTER);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/FilterConfig.java
similarity index 88%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/FilterConfig.java
index 610807a8..ff3ba171 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/FilterConfig.java
@@ -1,58 +1,58 @@
-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.autoconfigure.condition.ConditionalOnProperty;
-import org.springframework.boot.web.servlet.FilterRegistrationBean;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import com.ruoyi.common.filter.RepeatableFilter;
-import com.ruoyi.common.filter.XssFilter;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * Filter配置
- *
- * @author ruoyi
- */
-@Configuration
-public class FilterConfig
-{
-    @Value("${xss.excludes}")
-    private String excludes;
-
-    @Value("${xss.urlPatterns}")
-    private String urlPatterns;
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Bean
-    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
-    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(FilterRegistrationBean.HIGHEST_PRECEDENCE);
-        Map<String, String> initParameters = new HashMap<String, String>();
-        initParameters.put("excludes", excludes);
-        registration.setInitParameters(initParameters);
-        return registration;
-    }
-
-    @SuppressWarnings({ "rawtypes", "unchecked" })
-    @Bean
-    public FilterRegistrationBean someFilterRegistration()
-    {
-        FilterRegistrationBean registration = new FilterRegistrationBean();
-        registration.setFilter(new RepeatableFilter());
-        registration.addUrlPatterns("/*");
-        registration.setName("repeatableFilter");
-        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
-        return registration;
-    }
-
-}
+package com.acupuncture.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.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.acupuncture.common.filter.RepeatableFilter;
+import com.acupuncture.common.filter.XssFilter;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * Filter配置
+ *
+ * @author acupuncture
+ */
+@Configuration
+public class FilterConfig
+{
+    @Value("${xss.excludes}")
+    private String excludes;
+
+    @Value("${xss.urlPatterns}")
+    private String urlPatterns;
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    @ConditionalOnProperty(value = "xss.enabled", havingValue = "true")
+    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(FilterRegistrationBean.HIGHEST_PRECEDENCE);
+        Map<String, String> initParameters = new HashMap<String, String>();
+        initParameters.put("excludes", excludes);
+        registration.setInitParameters(initParameters);
+        return registration;
+    }
+
+    @SuppressWarnings({ "rawtypes", "unchecked" })
+    @Bean
+    public FilterRegistrationBean someFilterRegistration()
+    {
+        FilterRegistrationBean registration = new FilterRegistrationBean();
+        registration.setFilter(new RepeatableFilter());
+        registration.addUrlPatterns("/*");
+        registration.setName("repeatableFilter");
+        registration.setOrder(FilterRegistrationBean.LOWEST_PRECEDENCE);
+        return registration;
+    }
+
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/I18nConfig.java
similarity index 91%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/I18nConfig.java
index 163fd01c..5e2a4707 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/I18nConfig.java
@@ -1,4 +1,4 @@
-package com.ruoyi.framework.config;
+package com.acupuncture.framework.config;
 
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
@@ -7,12 +7,12 @@ import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
 import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
 import org.springframework.web.servlet.i18n.SessionLocaleResolver;
-import com.ruoyi.common.constant.Constants;
+import com.acupuncture.common.constant.Constants;
 
 /**
  * 资源文件配置加载
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 @Configuration
 public class I18nConfig implements WebMvcConfigurer
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/KaptchaTextCreator.java
similarity index 96%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/KaptchaTextCreator.java
index 7f8e1d50..77f6e42d 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/KaptchaTextCreator.java
@@ -1,4 +1,4 @@
-package com.ruoyi.framework.config;
+package com.acupuncture.framework.config;
 
 import java.util.Random;
 import com.google.code.kaptcha.text.impl.DefaultTextCreator;
@@ -6,7 +6,7 @@ import com.google.code.kaptcha.text.impl.DefaultTextCreator;
 /**
  * 验证码文本生成器
  *
- * @author ruoyi
+ * @author acupuncture
  */
 public class KaptchaTextCreator extends DefaultTextCreator
 {
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/MyBatisConfig.java
similarity index 95%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/MyBatisConfig.java
index e30fe74f..981a9a2e 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MyBatisConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/MyBatisConfig.java
@@ -1,132 +1,132 @@
-package com.ruoyi.framework.config;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.Arrays;
-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.DefaultResourceLoader;
-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;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 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;
-    }
-
-    public Resource[] resolveMapperLocations(String[] mapperLocations)
-    {
-        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
-        List<Resource> resources = new ArrayList<Resource>();
-        if (mapperLocations != null)
-        {
-            for (String mapperLocation : mapperLocations)
-            {
-                try
-                {
-                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
-                    resources.addAll(Arrays.asList(mappers));
-                }
-                catch (IOException e)
-                {
-                    // ignore
-                }
-            }
-        }
-        return resources.toArray(new Resource[resources.size()]);
-    }
-
-    @Bean
-    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
-    {
-        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
-        String mapperLocations = env.getProperty("mybatis.mapperLocations");
-        String configLocation = env.getProperty("mybatis.configLocation");
-        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
-        VFS.addImplClass(SpringBootVFS.class);
-
-        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
-        sessionFactory.setDataSource(dataSource);
-        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
-        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
-        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
-        return sessionFactory.getObject();
-    }
+package com.acupuncture.framework.config;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+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.DefaultResourceLoader;
+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;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * Mybatis支持*匹配扫描包
+ * 
+ * @author acupuncture
+ */
+@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;
+    }
+
+    public Resource[] resolveMapperLocations(String[] mapperLocations)
+    {
+        ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
+        List<Resource> resources = new ArrayList<Resource>();
+        if (mapperLocations != null)
+        {
+            for (String mapperLocation : mapperLocations)
+            {
+                try
+                {
+                    Resource[] mappers = resourceResolver.getResources(mapperLocation);
+                    resources.addAll(Arrays.asList(mappers));
+                }
+                catch (IOException e)
+                {
+                    // ignore
+                }
+            }
+        }
+        return resources.toArray(new Resource[resources.size()]);
+    }
+
+    @Bean
+    public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception
+    {
+        String typeAliasesPackage = env.getProperty("mybatis.typeAliasesPackage");
+        String mapperLocations = env.getProperty("mybatis.mapperLocations");
+        String configLocation = env.getProperty("mybatis.configLocation");
+        typeAliasesPackage = setTypeAliasesPackage(typeAliasesPackage);
+        VFS.addImplClass(SpringBootVFS.class);
+
+        final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
+        sessionFactory.setDataSource(dataSource);
+        sessionFactory.setTypeAliasesPackage(typeAliasesPackage);
+        sessionFactory.setMapperLocations(resolveMapperLocations(StringUtils.split(mapperLocations, ",")));
+        sessionFactory.setConfigLocation(new DefaultResourceLoader().getResource(configLocation));
+        return sessionFactory.getObject();
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/RedisConfig.java
similarity index 95%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/RedisConfig.java
index b188ac29..deea1464 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/RedisConfig.java
@@ -1,69 +1,69 @@
-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.core.script.DefaultRedisScript;
-import org.springframework.data.redis.serializer.StringRedisSerializer;
-
-/**
- * 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);
-
-        // 使用StringRedisSerializer来序列化和反序列化redis的key值
-        template.setKeySerializer(new StringRedisSerializer());
-        template.setValueSerializer(serializer);
-
-        // Hash的key也采用StringRedisSerializer的序列化方式
-        template.setHashKeySerializer(new StringRedisSerializer());
-        template.setHashValueSerializer(serializer);
-
-        template.afterPropertiesSet();
-        return template;
-    }
-
-    @Bean
-    public DefaultRedisScript<Long> limitScript()
-    {
-        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
-        redisScript.setScriptText(limitScriptText());
-        redisScript.setResultType(Long.class);
-        return redisScript;
-    }
-
-    /**
-     * 限流脚本
-     */
-    private String limitScriptText()
-    {
-        return "local key = KEYS[1]\n" +
-                "local count = tonumber(ARGV[1])\n" +
-                "local time = tonumber(ARGV[2])\n" +
-                "local current = redis.call('get', key);\n" +
-                "if current and tonumber(current) > count then\n" +
-                "    return tonumber(current);\n" +
-                "end\n" +
-                "current = redis.call('incr', key)\n" +
-                "if tonumber(current) == 1 then\n" +
-                "    redis.call('expire', key, time)\n" +
-                "end\n" +
-                "return tonumber(current);";
-    }
-}
+package com.acupuncture.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.core.script.DefaultRedisScript;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+/**
+ * redis配置
+ * 
+ * @author acupuncture
+ */
+@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);
+
+        // 使用StringRedisSerializer来序列化和反序列化redis的key值
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(serializer);
+
+        // Hash的key也采用StringRedisSerializer的序列化方式
+        template.setHashKeySerializer(new StringRedisSerializer());
+        template.setHashValueSerializer(serializer);
+
+        template.afterPropertiesSet();
+        return template;
+    }
+
+    @Bean
+    public DefaultRedisScript<Long> limitScript()
+    {
+        DefaultRedisScript<Long> redisScript = new DefaultRedisScript<>();
+        redisScript.setScriptText(limitScriptText());
+        redisScript.setResultType(Long.class);
+        return redisScript;
+    }
+
+    /**
+     * 限流脚本
+     */
+    private String limitScriptText()
+    {
+        return "local key = KEYS[1]\n" +
+                "local count = tonumber(ARGV[1])\n" +
+                "local time = tonumber(ARGV[2])\n" +
+                "local current = redis.call('get', key);\n" +
+                "if current and tonumber(current) > count then\n" +
+                "    return tonumber(current);\n" +
+                "end\n" +
+                "current = redis.call('incr', key)\n" +
+                "if tonumber(current) == 1 then\n" +
+                "    redis.call('expire', key, time)\n" +
+                "end\n" +
+                "return tonumber(current);";
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ResourcesConfig.java
similarity index 89%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/ResourcesConfig.java
index b6afb5db..d267da24 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ResourcesConfig.java
@@ -1,73 +1,73 @@
-package com.ruoyi.framework.config;
-
-import java.util.concurrent.TimeUnit;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.http.CacheControl;
-import org.springframework.web.cors.CorsConfiguration;
-import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
-import org.springframework.web.filter.CorsFilter;
-import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
-import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
-import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
-import com.ruoyi.common.config.RuoYiConfig;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
-
-/**
- * 通用配置
- * 
- * @author ruoyi
- */
-@Configuration
-public class ResourcesConfig implements WebMvcConfigurer
-{
-    @Autowired
-    private RepeatSubmitInterceptor repeatSubmitInterceptor;
-
-    @Override
-    public void addResourceHandlers(ResourceHandlerRegistry registry)
-    {
-        /** 本地文件上传路径 */
-        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
-                .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
-
-        /** swagger配置 */
-        registry.addResourceHandler("/swagger-ui/**")
-                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
-                .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());
-    }
-
-    /**
-     * 自定义拦截规则
-     */
-    @Override
-    public void addInterceptors(InterceptorRegistry registry)
-    {
-        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
-    }
-
-    /**
-     * 跨域配置
-     */
-    @Bean
-    public CorsFilter corsFilter()
-    {
-        CorsConfiguration config = new CorsConfiguration();
-        config.setAllowCredentials(true);
-        // 设置访问源地址
-        config.addAllowedOriginPattern("*");
-        // 设置访问源请求头
-        config.addAllowedHeader("*");
-        // 设置访问源请求方法
-        config.addAllowedMethod("*");
-        // 有效期 1800秒
-        config.setMaxAge(1800L);
-        // 添加映射路径,拦截一切请求
-        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
-        source.registerCorsConfiguration("/**", config);
-        // 返回新的CorsFilter
-        return new CorsFilter(source);
-    }
+package com.acupuncture.framework.config;
+
+import java.util.concurrent.TimeUnit;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.CacheControl;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+import com.acupuncture.common.config.RuoYiConfig;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.framework.interceptor.RepeatSubmitInterceptor;
+
+/**
+ * 通用配置
+ * 
+ * @author acupuncture
+ */
+@Configuration
+public class ResourcesConfig implements WebMvcConfigurer
+{
+    @Autowired
+    private RepeatSubmitInterceptor repeatSubmitInterceptor;
+
+    @Override
+    public void addResourceHandlers(ResourceHandlerRegistry registry)
+    {
+        /** 本地文件上传路径 */
+        registry.addResourceHandler(Constants.RESOURCE_PREFIX + "/**")
+                .addResourceLocations("file:" + RuoYiConfig.getProfile() + "/");
+
+        /** swagger配置 */
+        registry.addResourceHandler("/swagger-ui/**")
+                .addResourceLocations("classpath:/META-INF/resources/webjars/springfox-swagger-ui/")
+                .setCacheControl(CacheControl.maxAge(5, TimeUnit.HOURS).cachePublic());
+    }
+
+    /**
+     * 自定义拦截规则
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry)
+    {
+        registry.addInterceptor(repeatSubmitInterceptor).addPathPatterns("/**");
+    }
+
+    /**
+     * 跨域配置
+     */
+    @Bean
+    public CorsFilter corsFilter()
+    {
+        CorsConfiguration config = new CorsConfiguration();
+        config.setAllowCredentials(true);
+        // 设置访问源地址
+        config.addAllowedOriginPattern("*");
+        // 设置访问源请求头
+        config.addAllowedHeader("*");
+        // 设置访问源请求方法
+        config.addAllowedMethod("*");
+        // 有效期 1800秒
+        config.setMaxAge(1800L);
+        // 添加映射路径,拦截一切请求
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
+        source.registerCorsConfiguration("/**", config);
+        // 返回新的CorsFilter
+        return new CorsFilter(source);
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java
similarity index 92%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java
index b04beffb..6f45c4b0 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/SecurityConfig.java
@@ -1,139 +1,139 @@
-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 org.springframework.http.HttpMethod;
-import org.springframework.security.authentication.AuthenticationManager;
-import org.springframework.security.authentication.ProviderManager;
-import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
-import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
-import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-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.SecurityFilterChain;
-import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
-import org.springframework.security.web.authentication.logout.LogoutFilter;
-import org.springframework.web.filter.CorsFilter;
-import com.ruoyi.framework.config.properties.PermitAllUrlProperties;
-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
- */
-@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
-@Configuration
-public class SecurityConfig
-{
-    /**
-     * 自定义用户认证逻辑
-     */
-    @Autowired
-    private UserDetailsService userDetailsService;
-    
-    /**
-     * 认证失败处理类
-     */
-    @Autowired
-    private AuthenticationEntryPointImpl unauthorizedHandler;
-
-    /**
-     * 退出处理类
-     */
-    @Autowired
-    private LogoutSuccessHandlerImpl logoutSuccessHandler;
-
-    /**
-     * token认证过滤器
-     */
-    @Autowired
-    private JwtAuthenticationTokenFilter authenticationTokenFilter;
-    
-    /**
-     * 跨域过滤器
-     */
-    @Autowired
-    private CorsFilter corsFilter;
-
-    /**
-     * 允许匿名访问的地址
-     */
-    @Autowired
-    private PermitAllUrlProperties permitAllUrl;
-
-    /**
-     * 身份验证实现
-     */
-    @Bean
-    public AuthenticationManager authenticationManager()
-    {
-        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
-        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
-        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
-        return new ProviderManager(daoAuthenticationProvider);
-    }
-
-    /**
-     * anyRequest          |   匹配所有请求路径
-     * access              |   SpringEl表达式结果为true时可以访问
-     * anonymous           |   匿名可以访问
-     * denyAll             |   用户不能访问
-     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
-     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
-     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
-     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
-     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
-     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
-     * permitAll           |   用户可以任意访问
-     * rememberMe          |   允许通过remember-me登录的用户访问
-     * authenticated       |   用户登录后可访问
-     */
-    @Bean
-    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
-    {
-        return httpSecurity
-            // CSRF禁用,因为不使用session
-            .csrf(csrf -> csrf.disable())
-            // 禁用HTTP响应标头
-            .headers((headersCustomizer) -> {
-                headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
-            })
-            // 认证失败处理类
-            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
-            // 基于token,所以不需要session
-            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
-            // 注解标记允许匿名访问的url
-            .authorizeHttpRequests((requests) -> {
-                permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
-                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
-                requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
-                    // 静态资源,可匿名访问
-                    .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
-                    .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
-                    // 除上面外的所有请求全部需要鉴权认证
-                    .anyRequest().authenticated();
-            })
-            // 添加Logout filter
-            .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
-            // 添加JWT filter
-            .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
-            // 添加CORS filter
-            .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
-            .addFilterBefore(corsFilter, LogoutFilter.class)
-            .build();
-    }
-
-    /**
-     * 强散列哈希加密实现
-     */
-    @Bean
-    public BCryptPasswordEncoder bCryptPasswordEncoder()
-    {
-        return new BCryptPasswordEncoder();
-    }
-}
+package com.acupuncture.framework.config;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.authentication.AuthenticationManager;
+import org.springframework.security.authentication.ProviderManager;
+import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
+import org.springframework.security.config.annotation.method.configuration.EnableMethodSecurity;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+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.SecurityFilterChain;
+import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
+import org.springframework.security.web.authentication.logout.LogoutFilter;
+import org.springframework.web.filter.CorsFilter;
+import com.acupuncture.framework.config.properties.PermitAllUrlProperties;
+import com.acupuncture.framework.security.filter.JwtAuthenticationTokenFilter;
+import com.acupuncture.framework.security.handle.AuthenticationEntryPointImpl;
+import com.acupuncture.framework.security.handle.LogoutSuccessHandlerImpl;
+
+/**
+ * spring security配置
+ * 
+ * @author acupuncture
+ */
+@EnableMethodSecurity(prePostEnabled = true, securedEnabled = true)
+@Configuration
+public class SecurityConfig
+{
+    /**
+     * 自定义用户认证逻辑
+     */
+    @Autowired
+    private UserDetailsService userDetailsService;
+    
+    /**
+     * 认证失败处理类
+     */
+    @Autowired
+    private AuthenticationEntryPointImpl unauthorizedHandler;
+
+    /**
+     * 退出处理类
+     */
+    @Autowired
+    private LogoutSuccessHandlerImpl logoutSuccessHandler;
+
+    /**
+     * token认证过滤器
+     */
+    @Autowired
+    private JwtAuthenticationTokenFilter authenticationTokenFilter;
+    
+    /**
+     * 跨域过滤器
+     */
+    @Autowired
+    private CorsFilter corsFilter;
+
+    /**
+     * 允许匿名访问的地址
+     */
+    @Autowired
+    private PermitAllUrlProperties permitAllUrl;
+
+    /**
+     * 身份验证实现
+     */
+    @Bean
+    public AuthenticationManager authenticationManager()
+    {
+        DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider();
+        daoAuthenticationProvider.setUserDetailsService(userDetailsService);
+        daoAuthenticationProvider.setPasswordEncoder(bCryptPasswordEncoder());
+        return new ProviderManager(daoAuthenticationProvider);
+    }
+
+    /**
+     * anyRequest          |   匹配所有请求路径
+     * access              |   SpringEl表达式结果为true时可以访问
+     * anonymous           |   匿名可以访问
+     * denyAll             |   用户不能访问
+     * fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)
+     * hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问
+     * hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问
+     * hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问
+     * hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问
+     * hasRole             |   如果有参数,参数表示角色,则其角色可以访问
+     * permitAll           |   用户可以任意访问
+     * rememberMe          |   允许通过remember-me登录的用户访问
+     * authenticated       |   用户登录后可访问
+     */
+    @Bean
+    protected SecurityFilterChain filterChain(HttpSecurity httpSecurity) throws Exception
+    {
+        return httpSecurity
+            // CSRF禁用,因为不使用session
+            .csrf(csrf -> csrf.disable())
+            // 禁用HTTP响应标头
+            .headers((headersCustomizer) -> {
+                headersCustomizer.cacheControl(cache -> cache.disable()).frameOptions(options -> options.sameOrigin());
+            })
+            // 认证失败处理类
+            .exceptionHandling(exception -> exception.authenticationEntryPoint(unauthorizedHandler))
+            // 基于token,所以不需要session
+            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+            // 注解标记允许匿名访问的url
+            .authorizeHttpRequests((requests) -> {
+                permitAllUrl.getUrls().forEach(url -> requests.antMatchers(url).permitAll());
+                // 对于登录login 注册register 验证码captchaImage 允许匿名访问
+                requests.antMatchers("/login", "/register", "/captchaImage").permitAll()
+                    // 静态资源,可匿名访问
+                    .antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll()
+                    .antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()
+                    // 除上面外的所有请求全部需要鉴权认证
+                    .anyRequest().authenticated();
+            })
+            // 添加Logout filter
+            .logout(logout -> logout.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler))
+            // 添加JWT filter
+            .addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class)
+            // 添加CORS filter
+            .addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class)
+            .addFilterBefore(corsFilter, LogoutFilter.class)
+            .build();
+    }
+
+    /**
+     * 强散列哈希加密实现
+     */
+    @Bean
+    public BCryptPasswordEncoder bCryptPasswordEncoder()
+    {
+        return new BCryptPasswordEncoder();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ServerConfig.java
similarity index 85%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/ServerConfig.java
index 157e9f46..189c0237 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ServerConfig.java
@@ -1,32 +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();
-    }
-}
+package com.acupuncture.framework.config;
+
+import javax.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.utils.ServletUtils;
+
+/**
+ * 服务相关配置
+ * 
+ * @author acupuncture
+ */
+@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-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ThreadPoolConfig.java
similarity index 92%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/ThreadPoolConfig.java
index 63739f9c..d2194956 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/ThreadPoolConfig.java
@@ -1,63 +1,63 @@
-package com.ruoyi.framework.config;
-
-import com.ruoyi.common.utils.Threads;
-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 java.util.concurrent.ScheduledExecutorService;
-import java.util.concurrent.ScheduledThreadPoolExecutor;
-import java.util.concurrent.ThreadPoolExecutor;
-
-/**
- * 线程池配置
- *
- * @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(),
-                new ThreadPoolExecutor.CallerRunsPolicy())
-        {
-            @Override
-            protected void afterExecute(Runnable r, Throwable t)
-            {
-                super.afterExecute(r, t);
-                Threads.printException(r, t);
-            }
-        };
-    }
-}
+package com.acupuncture.framework.config;
+
+import com.acupuncture.common.utils.Threads;
+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 java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.ScheduledThreadPoolExecutor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 线程池配置
+ *
+ * @author acupuncture
+ **/
+@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(),
+                new ThreadPoolExecutor.CallerRunsPolicy())
+        {
+            @Override
+            protected void afterExecute(Runnable r, Throwable t)
+            {
+                super.afterExecute(r, t);
+                Threads.printException(r, t);
+            }
+        };
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/DruidProperties.java
similarity index 95%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/DruidProperties.java
index 2dd49ab9..9d5f43e3 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/DruidProperties.java
@@ -1,89 +1,89 @@
-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.connectTimeout}")
-    private int connectTimeout;
-
-    @Value("${spring.datasource.druid.socketTimeout}")
-    private int socketTimeout;
-
-    @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.setConnectTimeout(connectTimeout);
-        
-        /** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */
-        datasource.setSocketTimeout(socketTimeout);
-
-        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
-        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
-
-        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
-        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
-        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
-
-        /**
-         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
-         */
-        datasource.setValidationQuery(validationQuery);
-        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
-        datasource.setTestWhileIdle(testWhileIdle);
-        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
-        datasource.setTestOnBorrow(testOnBorrow);
-        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
-        datasource.setTestOnReturn(testOnReturn);
-        return datasource;
-    }
-}
+package com.acupuncture.framework.config.properties;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Configuration;
+import com.alibaba.druid.pool.DruidDataSource;
+
+/**
+ * druid 配置属性
+ * 
+ * @author acupuncture
+ */
+@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.connectTimeout}")
+    private int connectTimeout;
+
+    @Value("${spring.datasource.druid.socketTimeout}")
+    private int socketTimeout;
+
+    @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.setConnectTimeout(connectTimeout);
+        
+        /** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */
+        datasource.setSocketTimeout(socketTimeout);
+
+        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
+        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
+
+        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
+        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
+        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);
+
+        /**
+         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
+         */
+        datasource.setValidationQuery(validationQuery);
+        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
+        datasource.setTestWhileIdle(testWhileIdle);
+        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
+        datasource.setTestOnBorrow(testOnBorrow);
+        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
+        datasource.setTestOnReturn(testOnReturn);
+        return datasource;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/PermitAllUrlProperties.java
similarity index 93%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/PermitAllUrlProperties.java
index f1dcbfcb..a0e0445d 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/config/properties/PermitAllUrlProperties.java
@@ -1,73 +1,73 @@
-package com.ruoyi.framework.config.properties;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.Optional;
-import java.util.regex.Pattern;
-import org.apache.commons.lang3.RegExUtils;
-import org.springframework.beans.BeansException;
-import org.springframework.beans.factory.InitializingBean;
-import org.springframework.context.ApplicationContext;
-import org.springframework.context.ApplicationContextAware;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.core.annotation.AnnotationUtils;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
-import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
-import com.ruoyi.common.annotation.Anonymous;
-
-/**
- * 设置Anonymous注解允许匿名访问的url
- * 
- * @author ruoyi
- */
-@Configuration
-public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
-{
-    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
-
-    private ApplicationContext applicationContext;
-
-    private List<String> urls = new ArrayList<>();
-
-    public String ASTERISK = "*";
-
-    @Override
-    public void afterPropertiesSet()
-    {
-        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
-        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
-
-        map.keySet().forEach(info -> {
-            HandlerMethod handlerMethod = map.get(info);
-
-            // 获取方法上边的注解 替代path variable 为 *
-            Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
-            Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
-                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
-
-            // 获取类上边的注解, 替代path variable 为 *
-            Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
-            Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
-                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
-        });
-    }
-
-    @Override
-    public void setApplicationContext(ApplicationContext context) throws BeansException
-    {
-        this.applicationContext = context;
-    }
-
-    public List<String> getUrls()
-    {
-        return urls;
-    }
-
-    public void setUrls(List<String> urls)
-    {
-        this.urls = urls;
-    }
-}
+package com.acupuncture.framework.config.properties;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.Optional;
+import java.util.regex.Pattern;
+import org.apache.commons.lang3.RegExUtils;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.InitializingBean;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.annotation.AnnotationUtils;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.mvc.method.RequestMappingInfo;
+import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
+import com.acupuncture.common.annotation.Anonymous;
+
+/**
+ * 设置Anonymous注解允许匿名访问的url
+ * 
+ * @author acupuncture
+ */
+@Configuration
+public class PermitAllUrlProperties implements InitializingBean, ApplicationContextAware
+{
+    private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
+
+    private ApplicationContext applicationContext;
+
+    private List<String> urls = new ArrayList<>();
+
+    public String ASTERISK = "*";
+
+    @Override
+    public void afterPropertiesSet()
+    {
+        RequestMappingHandlerMapping mapping = applicationContext.getBean(RequestMappingHandlerMapping.class);
+        Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
+
+        map.keySet().forEach(info -> {
+            HandlerMethod handlerMethod = map.get(info);
+
+            // 获取方法上边的注解 替代path variable 为 *
+            Anonymous method = AnnotationUtils.findAnnotation(handlerMethod.getMethod(), Anonymous.class);
+            Optional.ofNullable(method).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
+                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
+
+            // 获取类上边的注解, 替代path variable 为 *
+            Anonymous controller = AnnotationUtils.findAnnotation(handlerMethod.getBeanType(), Anonymous.class);
+            Optional.ofNullable(controller).ifPresent(anonymous -> Objects.requireNonNull(info.getPatternsCondition().getPatterns())
+                    .forEach(url -> urls.add(RegExUtils.replaceAll(url, PATTERN, ASTERISK))));
+        });
+    }
+
+    @Override
+    public void setApplicationContext(ApplicationContext context) throws BeansException
+    {
+        this.applicationContext = context;
+    }
+
+    public List<String> getUrls()
+    {
+        return urls;
+    }
+
+    public void setUrls(List<String> urls)
+    {
+        this.urls = urls;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSource.java
similarity index 88%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSource.java
index 014ae380..3d248f08 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSource.java
@@ -1,26 +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();
-    }
+package com.acupuncture.framework.datasource;
+
+import java.util.Map;
+import javax.sql.DataSource;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/**
+ * 动态数据源
+ * 
+ * @author acupuncture
+ */
+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-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSourceContextHolder.java
similarity index 91%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSourceContextHolder.java
index 859a7824..e92463a9 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/datasource/DynamicDataSourceContextHolder.java
@@ -1,45 +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维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
-     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
-     */
-    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();
-    }
-}
+package com.acupuncture.framework.datasource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 数据源切换处理
+ * 
+ * @author acupuncture
+ */
+public class DynamicDataSourceContextHolder
+{
+    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
+
+    /**
+     * 使用ThreadLocal维护变量,ThreadLocal为每个使用该变量的线程提供独立的变量副本,
+     * 所以每一个线程都可以独立地改变自己的副本,而不会影响其它线程所对应的副本。
+     */
+    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-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/RepeatSubmitInterceptor.java
similarity index 86%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/RepeatSubmitInterceptor.java
index e41968a5..651fc2fb 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/RepeatSubmitInterceptor.java
@@ -1,56 +1,56 @@
-package com.ruoyi.framework.interceptor;
-
-import java.lang.reflect.Method;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import org.springframework.stereotype.Component;
-import org.springframework.web.method.HandlerMethod;
-import org.springframework.web.servlet.HandlerInterceptor;
-import com.alibaba.fastjson2.JSON;
-import com.ruoyi.common.annotation.RepeatSubmit;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.utils.ServletUtils;
-
-/**
- * 防止重复提交拦截器
- *
- * @author ruoyi
- */
-@Component
-public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
-{
-    @Override
-    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
-    {
-        if (handler instanceof HandlerMethod)
-        {
-            HandlerMethod handlerMethod = (HandlerMethod) handler;
-            Method method = handlerMethod.getMethod();
-            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
-            if (annotation != null)
-            {
-                if (this.isRepeatSubmit(request, annotation))
-                {
-                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());
-                    ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
-                    return false;
-                }
-            }
-            return true;
-        }
-        else
-        {
-            return true;
-        }
-    }
-
-    /**
-     * 验证是否重复提交由子类实现具体的防重复提交的规则
-     *
-     * @param request 请求信息
-     * @param annotation 防重复注解参数
-     * @return 结果
-     * @throws Exception
-     */
-    public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
-}
+package com.acupuncture.framework.interceptor;
+
+import java.lang.reflect.Method;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import org.springframework.stereotype.Component;
+import org.springframework.web.method.HandlerMethod;
+import org.springframework.web.servlet.HandlerInterceptor;
+import com.alibaba.fastjson2.JSON;
+import com.acupuncture.common.annotation.RepeatSubmit;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.utils.ServletUtils;
+
+/**
+ * 防止重复提交拦截器
+ *
+ * @author acupuncture
+ */
+@Component
+public abstract class RepeatSubmitInterceptor implements HandlerInterceptor
+{
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception
+    {
+        if (handler instanceof HandlerMethod)
+        {
+            HandlerMethod handlerMethod = (HandlerMethod) handler;
+            Method method = handlerMethod.getMethod();
+            RepeatSubmit annotation = method.getAnnotation(RepeatSubmit.class);
+            if (annotation != null)
+            {
+                if (this.isRepeatSubmit(request, annotation))
+                {
+                    AjaxResult ajaxResult = AjaxResult.error(annotation.message());
+                    ServletUtils.renderString(response, JSON.toJSONString(ajaxResult));
+                    return false;
+                }
+            }
+            return true;
+        }
+        else
+        {
+            return true;
+        }
+    }
+
+    /**
+     * 验证是否重复提交由子类实现具体的防重复提交的规则
+     *
+     * @param request 请求信息
+     * @param annotation 防重复注解参数
+     * @return 结果
+     * @throws Exception
+     */
+    public abstract boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation);
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/impl/SameUrlDataInterceptor.java
similarity index 86%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/impl/SameUrlDataInterceptor.java
index 316a370c..3a562e6d 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/interceptor/impl/SameUrlDataInterceptor.java
@@ -1,110 +1,110 @@
-package com.ruoyi.framework.interceptor.impl;
-
-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.alibaba.fastjson2.JSON;
-import com.ruoyi.common.annotation.RepeatSubmit;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.filter.RepeatedlyRequestWrapper;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.http.HttpHelper;
-import com.ruoyi.framework.interceptor.RepeatSubmitInterceptor;
-
-/**
- * 判断请求url和数据是否和上一次相同,
- * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
- * 
- * @author ruoyi
- */
-@Component
-public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
-{
-    public final String REPEAT_PARAMS = "repeatParams";
-
-    public final String REPEAT_TIME = "repeatTime";
-
-    // 令牌自定义标识
-    @Value("${token.header}")
-    private String header;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    @SuppressWarnings("unchecked")
-    @Override
-    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
-    {
-        String nowParams = "";
-        if (request instanceof RepeatedlyRequestWrapper)
-        {
-            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
-            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
-        }
-
-        // body参数为空,获取Parameter的数据
-        if (StringUtils.isEmpty(nowParams))
-        {
-            nowParams = JSON.toJSONString(request.getParameterMap());
-        }
-        Map<String, Object> nowDataMap = new HashMap<String, Object>();
-        nowDataMap.put(REPEAT_PARAMS, nowParams);
-        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
-
-        // 请求地址(作为存放cache的key值)
-        String url = request.getRequestURI();
-
-        // 唯一值(没有消息头则使用请求地址)
-        String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
-
-        // 唯一标识(指定key + url + 消息头)
-        String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
-
-        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
-        if (sessionObj != null)
-        {
-            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
-            if (sessionMap.containsKey(url))
-            {
-                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
-                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
-                {
-                    return true;
-                }
-            }
-        }
-        Map<String, Object> cacheMap = new HashMap<String, Object>();
-        cacheMap.put(url, nowDataMap);
-        redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
-        return false;
-    }
-
-    /**
-     * 判断参数是否相同
-     */
-    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
-    {
-        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
-        String preParams = (String) preMap.get(REPEAT_PARAMS);
-        return nowParams.equals(preParams);
-    }
-
-    /**
-     * 判断两次间隔时间
-     */
-    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)
-    {
-        long time1 = (Long) nowMap.get(REPEAT_TIME);
-        long time2 = (Long) preMap.get(REPEAT_TIME);
-        if ((time1 - time2) < interval)
-        {
-            return true;
-        }
-        return false;
-    }
-}
+package com.acupuncture.framework.interceptor.impl;
+
+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.alibaba.fastjson2.JSON;
+import com.acupuncture.common.annotation.RepeatSubmit;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.filter.RepeatedlyRequestWrapper;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.http.HttpHelper;
+import com.acupuncture.framework.interceptor.RepeatSubmitInterceptor;
+
+/**
+ * 判断请求url和数据是否和上一次相同,
+ * 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
+ * 
+ * @author acupuncture
+ */
+@Component
+public class SameUrlDataInterceptor extends RepeatSubmitInterceptor
+{
+    public final String REPEAT_PARAMS = "repeatParams";
+
+    public final String REPEAT_TIME = "repeatTime";
+
+    // 令牌自定义标识
+    @Value("${token.header}")
+    private String header;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public boolean isRepeatSubmit(HttpServletRequest request, RepeatSubmit annotation)
+    {
+        String nowParams = "";
+        if (request instanceof RepeatedlyRequestWrapper)
+        {
+            RepeatedlyRequestWrapper repeatedlyRequest = (RepeatedlyRequestWrapper) request;
+            nowParams = HttpHelper.getBodyString(repeatedlyRequest);
+        }
+
+        // body参数为空,获取Parameter的数据
+        if (StringUtils.isEmpty(nowParams))
+        {
+            nowParams = JSON.toJSONString(request.getParameterMap());
+        }
+        Map<String, Object> nowDataMap = new HashMap<String, Object>();
+        nowDataMap.put(REPEAT_PARAMS, nowParams);
+        nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
+
+        // 请求地址(作为存放cache的key值)
+        String url = request.getRequestURI();
+
+        // 唯一值(没有消息头则使用请求地址)
+        String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
+
+        // 唯一标识(指定key + url + 消息头)
+        String cacheRepeatKey = CacheConstants.REPEAT_SUBMIT_KEY + url + submitKey;
+
+        Object sessionObj = redisCache.getCacheObject(cacheRepeatKey);
+        if (sessionObj != null)
+        {
+            Map<String, Object> sessionMap = (Map<String, Object>) sessionObj;
+            if (sessionMap.containsKey(url))
+            {
+                Map<String, Object> preDataMap = (Map<String, Object>) sessionMap.get(url);
+                if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, annotation.interval()))
+                {
+                    return true;
+                }
+            }
+        }
+        Map<String, Object> cacheMap = new HashMap<String, Object>();
+        cacheMap.put(url, nowDataMap);
+        redisCache.setCacheObject(cacheRepeatKey, cacheMap, annotation.interval(), TimeUnit.MILLISECONDS);
+        return false;
+    }
+
+    /**
+     * 判断参数是否相同
+     */
+    private boolean compareParams(Map<String, Object> nowMap, Map<String, Object> preMap)
+    {
+        String nowParams = (String) nowMap.get(REPEAT_PARAMS);
+        String preParams = (String) preMap.get(REPEAT_PARAMS);
+        return nowParams.equals(preParams);
+    }
+
+    /**
+     * 判断两次间隔时间
+     */
+    private boolean compareTime(Map<String, Object> nowMap, Map<String, Object> preMap, int interval)
+    {
+        long time1 = (Long) nowMap.get(REPEAT_TIME);
+        long time2 = (Long) preMap.get(REPEAT_TIME);
+        if ((time1 - time2) < interval)
+        {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/AsyncManager.java
similarity index 82%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/manager/AsyncManager.java
index 6ed6d5b7..ce8cd927 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/AsyncManager.java
@@ -1,55 +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);
-    }
-}
+package com.acupuncture.framework.manager;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import com.acupuncture.common.utils.Threads;
+import com.acupuncture.common.utils.spring.SpringUtils;
+
+/**
+ * 异步任务管理器
+ * 
+ * @author acupuncture
+ */
+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-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/ShutdownManager.java
similarity index 88%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/manager/ShutdownManager.java
index 8d8fb5a3..ecef25bc 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/ShutdownManager.java
@@ -1,39 +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);
-        }
-    }
-}
+package com.acupuncture.framework.manager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import javax.annotation.PreDestroy;
+
+/**
+ * 确保应用退出时能关闭后台线程
+ *
+ * @author acupuncture
+ */
+@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-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/factory/AsyncFactory.java
similarity index 82%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/manager/factory/AsyncFactory.java
index 98517b78..3a0a4abf 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/manager/factory/AsyncFactory.java
@@ -1,102 +1,102 @@
-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.StringUtils;
-import com.ruoyi.common.utils.ip.AddressUtils;
-import com.ruoyi.common.utils.ip.IpUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.system.domain.SysLogininfor;
-import com.ruoyi.system.domain.SysOperLog;
-import com.ruoyi.system.service.ISysLogininforService;
-import com.ruoyi.system.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();
-        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 (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
-                {
-                    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);
-            }
-        };
-    }
-}
+package com.acupuncture.framework.manager.factory;
+
+import java.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.utils.LogUtils;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.ip.AddressUtils;
+import com.acupuncture.common.utils.ip.IpUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.system.domain.SysLogininfor;
+import com.acupuncture.system.domain.SysOperLog;
+import com.acupuncture.system.service.ISysLogininforService;
+import com.acupuncture.system.service.ISysOperLogService;
+import eu.bitwalker.useragentutils.UserAgent;
+
+/**
+ * 异步工厂(产生任务用)
+ * 
+ * @author acupuncture
+ */
+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();
+        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 (StringUtils.equalsAny(status, Constants.LOGIN_SUCCESS, Constants.LOGOUT, Constants.REGISTER))
+                {
+                    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-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/AuthenticationContextHolder.java
similarity index 84%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/AuthenticationContextHolder.java
index 5ee5bbdd..d5ef8d2a 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/AuthenticationContextHolder.java
@@ -1,28 +1,28 @@
-package com.ruoyi.framework.security.context;
-
-import org.springframework.security.core.Authentication;
-
-/**
- * 身份验证信息
- * 
- * @author ruoyi
- */
-public class AuthenticationContextHolder
-{
-    private static final ThreadLocal<Authentication> contextHolder = new ThreadLocal<>();
-
-    public static Authentication getContext()
-    {
-        return contextHolder.get();
-    }
-
-    public static void setContext(Authentication context)
-    {
-        contextHolder.set(context);
-    }
-
-    public static void clearContext()
-    {
-        contextHolder.remove();
-    }
-}
+package com.acupuncture.framework.security.context;
+
+import org.springframework.security.core.Authentication;
+
+/**
+ * 身份验证信息
+ * 
+ * @author acupuncture
+ */
+public class AuthenticationContextHolder
+{
+    private static final ThreadLocal<Authentication> contextHolder = new ThreadLocal<>();
+
+    public static Authentication getContext()
+    {
+        return contextHolder.get();
+    }
+
+    public static void setContext(Authentication context)
+    {
+        contextHolder.set(context);
+    }
+
+    public static void clearContext()
+    {
+        contextHolder.remove();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/PermissionContextHolder.java
similarity index 84%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/PermissionContextHolder.java
index 2fcd65b4..e1a62eec 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/context/PermissionContextHolder.java
@@ -1,27 +1,27 @@
-package com.ruoyi.framework.security.context;
-
-import org.springframework.web.context.request.RequestAttributes;
-import org.springframework.web.context.request.RequestContextHolder;
-import com.ruoyi.common.core.text.Convert;
-
-/**
- * 权限信息
- * 
- * @author ruoyi
- */
-public class PermissionContextHolder
-{
-    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
-
-    public static void setContext(String permission)
-    {
-        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
-                RequestAttributes.SCOPE_REQUEST);
-    }
-
-    public static String getContext()
-    {
-        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
-                RequestAttributes.SCOPE_REQUEST));
-    }
-}
+package com.acupuncture.framework.security.context;
+
+import org.springframework.web.context.request.RequestAttributes;
+import org.springframework.web.context.request.RequestContextHolder;
+import com.acupuncture.common.core.text.Convert;
+
+/**
+ * 权限信息
+ * 
+ * @author acupuncture
+ */
+public class PermissionContextHolder
+{
+    private static final String PERMISSION_CONTEXT_ATTRIBUTES = "PERMISSION_CONTEXT";
+
+    public static void setContext(String permission)
+    {
+        RequestContextHolder.currentRequestAttributes().setAttribute(PERMISSION_CONTEXT_ATTRIBUTES, permission,
+                RequestAttributes.SCOPE_REQUEST);
+    }
+
+    public static String getContext()
+    {
+        return Convert.toStr(RequestContextHolder.currentRequestAttributes().getAttribute(PERMISSION_CONTEXT_ATTRIBUTES,
+                RequestAttributes.SCOPE_REQUEST));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/filter/JwtAuthenticationTokenFilter.java
similarity index 84%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/security/filter/JwtAuthenticationTokenFilter.java
index 75fd00d1..b2e29167 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/filter/JwtAuthenticationTokenFilter.java
@@ -1,44 +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.core.domain.model.LoginUser;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.web.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);
-    }
-}
+package com.acupuncture.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.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.web.service.TokenService;
+
+/**
+ * token过滤器 验证token有效性
+ * 
+ * @author acupuncture
+ */
+@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-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/AuthenticationEntryPointImpl.java
similarity index 78%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/AuthenticationEntryPointImpl.java
index 9d86feab..f2498526 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/AuthenticationEntryPointImpl.java
@@ -1,34 +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.fastjson2.JSON;
-import com.ruoyi.common.constant.HttpStatus;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 认证失败处理类 返回未授权
- * 
- * @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)));
-    }
-}
+package com.acupuncture.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.fastjson2.JSON;
+import com.acupuncture.common.constant.HttpStatus;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 认证失败处理类 返回未授权
+ * 
+ * @author acupuncture
+ */
+@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-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/LogoutSuccessHandlerImpl.java
similarity index 72%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/LogoutSuccessHandlerImpl.java
index d9b7d529..5e58de88 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/security/handle/LogoutSuccessHandlerImpl.java
@@ -1,53 +1,53 @@
-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.fastjson2.JSON;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.utils.MessageUtils;
-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.web.service.TokenService;
-
-/**
- * 自定义退出处理类 返回成功
- * 
- * @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();
-            // 删除用户缓存记录
-            tokenService.delLoginUser(loginUser.getToken());
-            // 记录用户退出日志
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
-        }
-        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
-    }
-}
+package com.acupuncture.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.fastjson2.JSON;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.utils.MessageUtils;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.manager.AsyncManager;
+import com.acupuncture.framework.manager.factory.AsyncFactory;
+import com.acupuncture.framework.web.service.TokenService;
+
+/**
+ * 自定义退出处理类 返回成功
+ * 
+ * @author acupuncture
+ */
+@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();
+            // 删除用户缓存记录
+            tokenService.delLoginUser(loginUser.getToken());
+            // 记录用户退出日志
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(userName, Constants.LOGOUT, MessageUtils.message("user.logout.success")));
+        }
+        ServletUtils.renderString(response, JSON.toJSONString(AjaxResult.success(MessageUtils.message("user.logout.success"))));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/Server.java
similarity index 90%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/Server.java
index 30a1957e..ffc547dc 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/Server.java
@@ -1,240 +1,240 @@
-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();
-        List<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);
-        }
-    }
-}
+package com.acupuncture.framework.web.domain;
+
+import java.net.UnknownHostException;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Properties;
+import com.acupuncture.common.utils.Arith;
+import com.acupuncture.common.utils.ip.IpUtils;
+import com.acupuncture.framework.web.domain.server.Cpu;
+import com.acupuncture.framework.web.domain.server.Jvm;
+import com.acupuncture.framework.web.domain.server.Mem;
+import com.acupuncture.framework.web.domain.server.Sys;
+import com.acupuncture.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 acupuncture
+ */
+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();
+        List<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-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Cpu.java
similarity index 87%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Cpu.java
index cf7b46e1..20c64a90 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Cpu.java
@@ -1,101 +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;
-    }
-}
+package com.acupuncture.framework.web.domain.server;
+
+import com.acupuncture.common.utils.Arith;
+
+/**
+ * CPU相关信息
+ * 
+ * @author acupuncture
+ */
+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-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Jvm.java
similarity index 88%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Jvm.java
index 8e142ac5..80de5da8 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Jvm.java
@@ -1,130 +1,130 @@
-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.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());
-    }
-
-    /**
-     * 运行参数
-     */
-    public String getInputArgs()
-    {
-        return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
-    }
-}
+package com.acupuncture.framework.web.domain.server;
+
+import java.lang.management.ManagementFactory;
+import com.acupuncture.common.utils.Arith;
+import com.acupuncture.common.utils.DateUtils;
+
+/**
+ * JVM相关信息
+ * 
+ * @author acupuncture
+ */
+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.timeDistance(DateUtils.getNowDate(), DateUtils.getServerStartDate());
+    }
+
+    /**
+     * 运行参数
+     */
+    public String getInputArgs()
+    {
+        return ManagementFactory.getRuntimeMXBean().getInputArguments().toString();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Mem.java
similarity index 84%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Mem.java
index ac715049..fd462abf 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Mem.java
@@ -1,61 +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);
-    }
-}
+package com.acupuncture.framework.web.domain.server;
+
+import com.acupuncture.common.utils.Arith;
+
+/**
+ * 內存相关信息
+ * 
+ * @author acupuncture
+ */
+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-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Sys.java
similarity index 89%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Sys.java
index a5f65e46..12718dd0 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/Sys.java
@@ -1,84 +1,84 @@
-package com.ruoyi.framework.web.domain.server;
-
-/**
- * 系统相关信息
- * 
- * @author ruoyi
- */
-public class Sys
-{
-    /**
-     * 服务器名称
-     */
-    private String computerName;
-
-    /**
-     * 服务器Ip
-     */
-    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;
-    }
-}
+package com.acupuncture.framework.web.domain.server;
+
+/**
+ * 系统相关信息
+ * 
+ * @author acupuncture
+ */
+public class Sys
+{
+    /**
+     * 服务器名称
+     */
+    private String computerName;
+
+    /**
+     * 服务器Ip
+     */
+    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-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/SysFile.java
similarity index 89%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/SysFile.java
index 47ecf3f3..bf9a91ff 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/domain/server/SysFile.java
@@ -1,114 +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;
-    }
-}
+package com.acupuncture.framework.web.domain.server;
+
+/**
+ * 系统文件相关信息
+ * 
+ * @author acupuncture
+ */
+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-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/exception/GlobalExceptionHandler.java
similarity index 90%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/exception/GlobalExceptionHandler.java
index e118fb53..002f9ef1 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/exception/GlobalExceptionHandler.java
@@ -1,145 +1,145 @@
-package com.ruoyi.framework.web.exception;
-
-import javax.servlet.http.HttpServletRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.security.access.AccessDeniedException;
-import org.springframework.validation.BindException;
-import org.springframework.web.HttpRequestMethodNotSupportedException;
-import org.springframework.web.bind.MethodArgumentNotValidException;
-import org.springframework.web.bind.MissingPathVariableException;
-import org.springframework.web.bind.annotation.ExceptionHandler;
-import org.springframework.web.bind.annotation.RestControllerAdvice;
-import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
-import com.ruoyi.common.constant.HttpStatus;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.exception.DemoModeException;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.html.EscapeUtil;
-
-/**
- * 全局异常处理器
- * 
- * @author ruoyi
- */
-@RestControllerAdvice
-public class GlobalExceptionHandler
-{
-    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
-
-    /**
-     * 权限校验异常
-     */
-    @ExceptionHandler(AccessDeniedException.class)
-    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
-        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
-    }
-
-    /**
-     * 请求方式不支持
-     */
-    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
-    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
-            HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
-        return AjaxResult.error(e.getMessage());
-    }
-
-    /**
-     * 业务异常
-     */
-    @ExceptionHandler(ServiceException.class)
-    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
-    {
-        log.error(e.getMessage(), e);
-        Integer code = e.getCode();
-        return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
-    }
-
-    /**
-     * 请求路径中缺少必需的路径变量
-     */
-    @ExceptionHandler(MissingPathVariableException.class)
-    public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
-        return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
-    }
-
-    /**
-     * 请求参数类型不匹配
-     */
-    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
-    public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        String value = Convert.toStr(e.getValue());
-        if (StringUtils.isNotEmpty(value))
-        {
-            value = EscapeUtil.clean(value);
-        }
-        log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
-        return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value));
-    }
-
-    /**
-     * 拦截未知的运行时异常
-     */
-    @ExceptionHandler(RuntimeException.class)
-    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',发生未知异常.", requestURI, e);
-        return AjaxResult.error(e.getMessage());
-    }
-
-    /**
-     * 系统异常
-     */
-    @ExceptionHandler(Exception.class)
-    public AjaxResult handleException(Exception e, HttpServletRequest request)
-    {
-        String requestURI = request.getRequestURI();
-        log.error("请求地址'{}',发生系统异常.", requestURI, e);
-        return AjaxResult.error(e.getMessage());
-    }
-
-    /**
-     * 自定义验证异常
-     */
-    @ExceptionHandler(BindException.class)
-    public AjaxResult handleBindException(BindException e)
-    {
-        log.error(e.getMessage(), e);
-        String message = e.getAllErrors().get(0).getDefaultMessage();
-        return AjaxResult.error(message);
-    }
-
-    /**
-     * 自定义验证异常
-     */
-    @ExceptionHandler(MethodArgumentNotValidException.class)
-    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
-    {
-        log.error(e.getMessage(), e);
-        String message = e.getBindingResult().getFieldError().getDefaultMessage();
-        return AjaxResult.error(message);
-    }
-
-    /**
-     * 演示模式异常
-     */
-    @ExceptionHandler(DemoModeException.class)
-    public AjaxResult handleDemoModeException(DemoModeException e)
-    {
-        return AjaxResult.error("演示模式,不允许操作");
-    }
-}
+package com.acupuncture.framework.web.exception;
+
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.validation.BindException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MethodArgumentNotValidException;
+import org.springframework.web.bind.MissingPathVariableException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+import com.acupuncture.common.constant.HttpStatus;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.exception.DemoModeException;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.html.EscapeUtil;
+
+/**
+ * 全局异常处理器
+ * 
+ * @author acupuncture
+ */
+@RestControllerAdvice
+public class GlobalExceptionHandler
+{
+    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);
+
+    /**
+     * 权限校验异常
+     */
+    @ExceptionHandler(AccessDeniedException.class)
+    public AjaxResult handleAccessDeniedException(AccessDeniedException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',权限校验失败'{}'", requestURI, e.getMessage());
+        return AjaxResult.error(HttpStatus.FORBIDDEN, "没有权限,请联系管理员授权");
+    }
+
+    /**
+     * 请求方式不支持
+     */
+    @ExceptionHandler(HttpRequestMethodNotSupportedException.class)
+    public AjaxResult handleHttpRequestMethodNotSupported(HttpRequestMethodNotSupportedException e,
+            HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',不支持'{}'请求", requestURI, e.getMethod());
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 业务异常
+     */
+    @ExceptionHandler(ServiceException.class)
+    public AjaxResult handleServiceException(ServiceException e, HttpServletRequest request)
+    {
+        log.error(e.getMessage(), e);
+        Integer code = e.getCode();
+        return StringUtils.isNotNull(code) ? AjaxResult.error(code, e.getMessage()) : AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 请求路径中缺少必需的路径变量
+     */
+    @ExceptionHandler(MissingPathVariableException.class)
+    public AjaxResult handleMissingPathVariableException(MissingPathVariableException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求路径中缺少必需的路径变量'{}',发生系统异常.", requestURI, e);
+        return AjaxResult.error(String.format("请求路径中缺少必需的路径变量[%s]", e.getVariableName()));
+    }
+
+    /**
+     * 请求参数类型不匹配
+     */
+    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
+    public AjaxResult handleMethodArgumentTypeMismatchException(MethodArgumentTypeMismatchException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        String value = Convert.toStr(e.getValue());
+        if (StringUtils.isNotEmpty(value))
+        {
+            value = EscapeUtil.clean(value);
+        }
+        log.error("请求参数类型不匹配'{}',发生系统异常.", requestURI, e);
+        return AjaxResult.error(String.format("请求参数类型不匹配,参数[%s]要求类型为:'%s',但输入值为:'%s'", e.getName(), e.getRequiredType().getName(), value));
+    }
+
+    /**
+     * 拦截未知的运行时异常
+     */
+    @ExceptionHandler(RuntimeException.class)
+    public AjaxResult handleRuntimeException(RuntimeException e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生未知异常.", requestURI, e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 系统异常
+     */
+    @ExceptionHandler(Exception.class)
+    public AjaxResult handleException(Exception e, HttpServletRequest request)
+    {
+        String requestURI = request.getRequestURI();
+        log.error("请求地址'{}',发生系统异常.", requestURI, e);
+        return AjaxResult.error(e.getMessage());
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(BindException.class)
+    public AjaxResult handleBindException(BindException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getAllErrors().get(0).getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 自定义验证异常
+     */
+    @ExceptionHandler(MethodArgumentNotValidException.class)
+    public Object handleMethodArgumentNotValidException(MethodArgumentNotValidException e)
+    {
+        log.error(e.getMessage(), e);
+        String message = e.getBindingResult().getFieldError().getDefaultMessage();
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 演示模式异常
+     */
+    @ExceptionHandler(DemoModeException.class)
+    public AjaxResult handleDemoModeException(DemoModeException e)
+    {
+        return AjaxResult.error("演示模式,不允许操作");
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/PermissionService.java
similarity index 87%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/PermissionService.java
index 6892467d..d3add08a 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/PermissionService.java
@@ -1,159 +1,159 @@
-package com.ruoyi.framework.web.service;
-
-import java.util.Set;
-import org.springframework.stereotype.Service;
-import org.springframework.util.CollectionUtils;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.security.context.PermissionContextHolder;
-
-/**
- * RuoYi首创 自定义权限实现,ss取自SpringSecurity首字母
- * 
- * @author ruoyi
- */
-@Service("ss")
-public class PermissionService
-{
-    /**
-     * 验证用户是否具备某权限
-     * 
-     * @param permission 权限字符串
-     * @return 用户是否具备某权限
-     */
-    public boolean hasPermi(String permission)
-    {
-        if (StringUtils.isEmpty(permission))
-        {
-            return false;
-        }
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
-        {
-            return false;
-        }
-        PermissionContextHolder.setContext(permission);
-        return hasPermissions(loginUser.getPermissions(), permission);
-    }
-
-    /**
-     * 验证用户是否不具备某权限,与 hasPermi逻辑相反
-     *
-     * @param permission 权限字符串
-     * @return 用户是否不具备某权限
-     */
-    public boolean lacksPermi(String permission)
-    {
-        return hasPermi(permission) != true;
-    }
-
-    /**
-     * 验证用户是否具有以下任意一个权限
-     *
-     * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
-     * @return 用户是否具有以下任意一个权限
-     */
-    public boolean hasAnyPermi(String permissions)
-    {
-        if (StringUtils.isEmpty(permissions))
-        {
-            return false;
-        }
-        LoginUser loginUser = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
-        {
-            return false;
-        }
-        PermissionContextHolder.setContext(permissions);
-        Set<String> authorities = loginUser.getPermissions();
-        for (String permission : permissions.split(Constants.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 = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
-        {
-            return false;
-        }
-        for (SysRole sysRole : loginUser.getUser().getRoles())
-        {
-            String roleKey = sysRole.getRoleKey();
-            if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(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 = SecurityUtils.getLoginUser();
-        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
-        {
-            return false;
-        }
-        for (String role : roles.split(Constants.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(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
-    }
-}
+package com.acupuncture.framework.web.service;
+
+import java.util.Set;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.security.context.PermissionContextHolder;
+
+/**
+ * acupuncture首创 自定义权限实现,ss取自SpringSecurity首字母
+ * 
+ * @author acupuncture
+ */
+@Service("ss")
+public class PermissionService
+{
+    /**
+     * 验证用户是否具备某权限
+     * 
+     * @param permission 权限字符串
+     * @return 用户是否具备某权限
+     */
+    public boolean hasPermi(String permission)
+    {
+        if (StringUtils.isEmpty(permission))
+        {
+            return false;
+        }
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        PermissionContextHolder.setContext(permission);
+        return hasPermissions(loginUser.getPermissions(), permission);
+    }
+
+    /**
+     * 验证用户是否不具备某权限,与 hasPermi逻辑相反
+     *
+     * @param permission 权限字符串
+     * @return 用户是否不具备某权限
+     */
+    public boolean lacksPermi(String permission)
+    {
+        return hasPermi(permission) != true;
+    }
+
+    /**
+     * 验证用户是否具有以下任意一个权限
+     *
+     * @param permissions 以 PERMISSION_DELIMETER 为分隔符的权限列表
+     * @return 用户是否具有以下任意一个权限
+     */
+    public boolean hasAnyPermi(String permissions)
+    {
+        if (StringUtils.isEmpty(permissions))
+        {
+            return false;
+        }
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getPermissions()))
+        {
+            return false;
+        }
+        PermissionContextHolder.setContext(permissions);
+        Set<String> authorities = loginUser.getPermissions();
+        for (String permission : permissions.split(Constants.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 = SecurityUtils.getLoginUser();
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (SysRole sysRole : loginUser.getUser().getRoles())
+        {
+            String roleKey = sysRole.getRoleKey();
+            if (Constants.SUPER_ADMIN.equals(roleKey) || roleKey.equals(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 = SecurityUtils.getLoginUser();
+        if (StringUtils.isNull(loginUser) || CollectionUtils.isEmpty(loginUser.getUser().getRoles()))
+        {
+            return false;
+        }
+        for (String role : roles.split(Constants.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(Constants.ALL_PERMISSION) || permissions.contains(StringUtils.trim(permission));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java
similarity index 81%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java
index 97abcead..9cb4d385 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysLoginService.java
@@ -1,181 +1,181 @@
-package com.ruoyi.framework.web.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.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.exception.user.BlackListException;
-import com.ruoyi.common.exception.user.CaptchaException;
-import com.ruoyi.common.exception.user.CaptchaExpireException;
-import com.ruoyi.common.exception.user.UserNotExistsException;
-import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.MessageUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.ip.IpUtils;
-import com.ruoyi.framework.manager.AsyncManager;
-import com.ruoyi.framework.manager.factory.AsyncFactory;
-import com.ruoyi.framework.security.context.AuthenticationContextHolder;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 登录校验方法
- * 
- * @author ruoyi
- */
-@Component
-public class SysLoginService
-{
-    @Autowired
-    private TokenService tokenService;
-
-    @Resource
-    private AuthenticationManager authenticationManager;
-
-    @Autowired
-    private RedisCache redisCache;
-    
-    @Autowired
-    private ISysUserService userService;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    /**
-     * 登录验证
-     * 
-     * @param username 用户名
-     * @param password 密码
-     * @param code 验证码
-     * @param uuid 唯一标识
-     * @return 结果
-     */
-    public String login(String username, String password, String code, String uuid)
-    {
-        // 验证码校验
-        validateCaptcha(username, code, uuid);
-        // 登录前置校验
-        loginPreCheck(username, password);
-        // 用户验证
-        Authentication authentication = null;
-        try
-        {
-            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
-            AuthenticationContextHolder.setContext(authenticationToken);
-            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
-            authentication = authenticationManager.authenticate(authenticationToken);
-        }
-        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 ServiceException(e.getMessage());
-            }
-        }
-        finally
-        {
-            AuthenticationContextHolder.clearContext();
-        }
-        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
-        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
-        recordLoginInfo(loginUser.getUserId());
-        // 生成token
-        return tokenService.createToken(loginUser);
-    }
-
-    /**
-     * 校验验证码
-     * 
-     * @param username 用户名
-     * @param code 验证码
-     * @param uuid 唯一标识
-     * @return 结果
-     */
-    public void validateCaptcha(String username, String code, String uuid)
-    {
-        boolean captchaEnabled = configService.selectCaptchaEnabled();
-        if (captchaEnabled)
-        {
-            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
-            String captcha = redisCache.getCacheObject(verifyKey);
-            if (captcha == null)
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
-                throw new CaptchaExpireException();
-            }
-            redisCache.deleteObject(verifyKey);
-            if (!code.equalsIgnoreCase(captcha))
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
-                throw new CaptchaException();
-            }
-        }
-    }
-
-    /**
-     * 登录前置校验
-     * @param username 用户名
-     * @param password 用户密码
-     */
-    public void loginPreCheck(String username, String password)
-    {
-        // 用户名或密码为空 错误
-        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
-        {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
-            throw new UserNotExistsException();
-        }
-        // 密码如果不在指定范围内 错误
-        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
-                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
-        {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
-            throw new UserPasswordNotMatchException();
-        }
-        // 用户名不在指定范围内 错误
-        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
-                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
-        {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
-            throw new UserPasswordNotMatchException();
-        }
-        // IP黑名单校验
-        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
-        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
-        {
-            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
-            throw new BlackListException();
-        }
-    }
-
-    /**
-     * 记录登录信息
-     *
-     * @param userId 用户ID
-     */
-    public void recordLoginInfo(Long userId)
-    {
-        SysUser sysUser = new SysUser();
-        sysUser.setUserId(userId);
-        sysUser.setLoginIp(IpUtils.getIpAddr());
-        sysUser.setLoginDate(DateUtils.getNowDate());
-        userService.updateUserProfile(sysUser);
-    }
-}
+package com.acupuncture.framework.web.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.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.exception.user.BlackListException;
+import com.acupuncture.common.exception.user.CaptchaException;
+import com.acupuncture.common.exception.user.CaptchaExpireException;
+import com.acupuncture.common.exception.user.UserNotExistsException;
+import com.acupuncture.common.exception.user.UserPasswordNotMatchException;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.MessageUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.ip.IpUtils;
+import com.acupuncture.framework.manager.AsyncManager;
+import com.acupuncture.framework.manager.factory.AsyncFactory;
+import com.acupuncture.framework.security.context.AuthenticationContextHolder;
+import com.acupuncture.system.service.ISysConfigService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 登录校验方法
+ * 
+ * @author acupuncture
+ */
+@Component
+public class SysLoginService
+{
+    @Autowired
+    private TokenService tokenService;
+
+    @Resource
+    private AuthenticationManager authenticationManager;
+
+    @Autowired
+    private RedisCache redisCache;
+    
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 登录验证
+     * 
+     * @param username 用户名
+     * @param password 密码
+     * @param code 验证码
+     * @param uuid 唯一标识
+     * @return 结果
+     */
+    public String login(String username, String password, String code, String uuid)
+    {
+        // 验证码校验
+        validateCaptcha(username, code, uuid);
+        // 登录前置校验
+        loginPreCheck(username, password);
+        // 用户验证
+        Authentication authentication = null;
+        try
+        {
+            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
+            AuthenticationContextHolder.setContext(authenticationToken);
+            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
+            authentication = authenticationManager.authenticate(authenticationToken);
+        }
+        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 ServiceException(e.getMessage());
+            }
+        }
+        finally
+        {
+            AuthenticationContextHolder.clearContext();
+        }
+        AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_SUCCESS, MessageUtils.message("user.login.success")));
+        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
+        recordLoginInfo(loginUser.getUserId());
+        // 生成token
+        return tokenService.createToken(loginUser);
+    }
+
+    /**
+     * 校验验证码
+     * 
+     * @param username 用户名
+     * @param code 验证码
+     * @param uuid 唯一标识
+     * @return 结果
+     */
+    public void validateCaptcha(String username, String code, String uuid)
+    {
+        boolean captchaEnabled = configService.selectCaptchaEnabled();
+        if (captchaEnabled)
+        {
+            String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
+            String captcha = redisCache.getCacheObject(verifyKey);
+            if (captcha == null)
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire")));
+                throw new CaptchaExpireException();
+            }
+            redisCache.deleteObject(verifyKey);
+            if (!code.equalsIgnoreCase(captcha))
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error")));
+                throw new CaptchaException();
+            }
+        }
+    }
+
+    /**
+     * 登录前置校验
+     * @param username 用户名
+     * @param password 用户密码
+     */
+    public void loginPreCheck(String username, String password)
+    {
+        // 用户名或密码为空 错误
+        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("not.null")));
+            throw new UserNotExistsException();
+        }
+        // 密码如果不在指定范围内 错误
+        if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+            throw new UserPasswordNotMatchException();
+        }
+        // 用户名不在指定范围内 错误
+        if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.password.not.match")));
+            throw new UserPasswordNotMatchException();
+        }
+        // IP黑名单校验
+        String blackStr = configService.selectConfigByKey("sys.login.blackIPList");
+        if (IpUtils.isMatchedIp(blackStr, IpUtils.getIpAddr()))
+        {
+            AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("login.blocked")));
+            throw new BlackListException();
+        }
+    }
+
+    /**
+     * 记录登录信息
+     *
+     * @param userId 用户ID
+     */
+    public void recordLoginInfo(Long userId)
+    {
+        SysUser sysUser = new SysUser();
+        sysUser.setUserId(userId);
+        sysUser.setLoginIp(IpUtils.getIpAddr());
+        sysUser.setLoginDate(DateUtils.getNowDate());
+        userService.updateUserProfile(sysUser);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPasswordService.java
similarity index 79%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPasswordService.java
index 7a1f93d4..120fa2c7 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPasswordService.java
@@ -1,86 +1,86 @@
-package com.ruoyi.framework.web.service;
-
-import java.util.concurrent.TimeUnit;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.security.core.Authentication;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.exception.user.UserPasswordNotMatchException;
-import com.ruoyi.common.exception.user.UserPasswordRetryLimitExceedException;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.framework.security.context.AuthenticationContextHolder;
-
-/**
- * 登录密码方法
- * 
- * @author ruoyi
- */
-@Component
-public class SysPasswordService
-{
-    @Autowired
-    private RedisCache redisCache;
-
-    @Value(value = "${user.password.maxRetryCount}")
-    private int maxRetryCount;
-
-    @Value(value = "${user.password.lockTime}")
-    private int lockTime;
-
-    /**
-     * 登录账户密码错误次数缓存键名
-     * 
-     * @param username 用户名
-     * @return 缓存键key
-     */
-    private String getCacheKey(String username)
-    {
-        return CacheConstants.PWD_ERR_CNT_KEY + username;
-    }
-
-    public void validate(SysUser user)
-    {
-        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
-        String username = usernamePasswordAuthenticationToken.getName();
-        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
-
-        Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
-
-        if (retryCount == null)
-        {
-            retryCount = 0;
-        }
-
-        if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
-        {
-            throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
-        }
-
-        if (!matches(user, password))
-        {
-            retryCount = retryCount + 1;
-            redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
-            throw new UserPasswordNotMatchException();
-        }
-        else
-        {
-            clearLoginRecordCache(username);
-        }
-    }
-
-    public boolean matches(SysUser user, String rawPassword)
-    {
-        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
-    }
-
-    public void clearLoginRecordCache(String loginName)
-    {
-        if (redisCache.hasKey(getCacheKey(loginName)))
-        {
-            redisCache.deleteObject(getCacheKey(loginName));
-        }
-    }
-}
+package com.acupuncture.framework.web.service;
+
+import java.util.concurrent.TimeUnit;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.security.core.Authentication;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.exception.user.UserPasswordNotMatchException;
+import com.acupuncture.common.exception.user.UserPasswordRetryLimitExceedException;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.framework.security.context.AuthenticationContextHolder;
+
+/**
+ * 登录密码方法
+ * 
+ * @author acupuncture
+ */
+@Component
+public class SysPasswordService
+{
+    @Autowired
+    private RedisCache redisCache;
+
+    @Value(value = "${user.password.maxRetryCount}")
+    private int maxRetryCount;
+
+    @Value(value = "${user.password.lockTime}")
+    private int lockTime;
+
+    /**
+     * 登录账户密码错误次数缓存键名
+     * 
+     * @param username 用户名
+     * @return 缓存键key
+     */
+    private String getCacheKey(String username)
+    {
+        return CacheConstants.PWD_ERR_CNT_KEY + username;
+    }
+
+    public void validate(SysUser user)
+    {
+        Authentication usernamePasswordAuthenticationToken = AuthenticationContextHolder.getContext();
+        String username = usernamePasswordAuthenticationToken.getName();
+        String password = usernamePasswordAuthenticationToken.getCredentials().toString();
+
+        Integer retryCount = redisCache.getCacheObject(getCacheKey(username));
+
+        if (retryCount == null)
+        {
+            retryCount = 0;
+        }
+
+        if (retryCount >= Integer.valueOf(maxRetryCount).intValue())
+        {
+            throw new UserPasswordRetryLimitExceedException(maxRetryCount, lockTime);
+        }
+
+        if (!matches(user, password))
+        {
+            retryCount = retryCount + 1;
+            redisCache.setCacheObject(getCacheKey(username), retryCount, lockTime, TimeUnit.MINUTES);
+            throw new UserPasswordNotMatchException();
+        }
+        else
+        {
+            clearLoginRecordCache(username);
+        }
+    }
+
+    public boolean matches(SysUser user, String rawPassword)
+    {
+        return SecurityUtils.matchesPassword(rawPassword, user.getPassword());
+    }
+
+    public void clearLoginRecordCache(String loginName)
+    {
+        if (redisCache.hasKey(getCacheKey(loginName)))
+        {
+            redisCache.deleteObject(getCacheKey(loginName));
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPermissionService.java
similarity index 82%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPermissionService.java
index dbfccde2..190ff6bc 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysPermissionService.java
@@ -1,88 +1,88 @@
-package com.ruoyi.framework.web.service;
-
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import org.springframework.util.CollectionUtils;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.service.ISysMenuService;
-import com.ruoyi.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> perms = new HashSet<String>();
-        // 管理员拥有所有权限
-        if (user.isAdmin())
-        {
-            perms.add("*:*:*");
-        }
-        else
-        {
-            List<SysRole> roles = user.getRoles();
-            if (!CollectionUtils.isEmpty(roles))
-            {
-                // 多角色设置permissions属性,以便数据权限匹配权限
-                for (SysRole role : roles)
-                {
-                    if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL))
-                    {
-                        Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
-                        role.setPermissions(rolePerms);
-                        perms.addAll(rolePerms);
-                    }
-                }
-            }
-            else
-            {
-                perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
-            }
-        }
-        return perms;
-    }
-}
+package com.acupuncture.framework.web.service;
+
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.service.ISysMenuService;
+import com.acupuncture.system.service.ISysRoleService;
+
+/**
+ * 用户权限处理
+ * 
+ * @author acupuncture
+ */
+@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> perms = new HashSet<String>();
+        // 管理员拥有所有权限
+        if (user.isAdmin())
+        {
+            perms.add("*:*:*");
+        }
+        else
+        {
+            List<SysRole> roles = user.getRoles();
+            if (!CollectionUtils.isEmpty(roles))
+            {
+                // 多角色设置permissions属性,以便数据权限匹配权限
+                for (SysRole role : roles)
+                {
+                    if (StringUtils.equals(role.getStatus(), UserConstants.ROLE_NORMAL))
+                    {
+                        Set<String> rolePerms = menuService.selectMenuPermsByRoleId(role.getRoleId());
+                        role.setPermissions(rolePerms);
+                        perms.addAll(rolePerms);
+                    }
+                }
+            }
+            else
+            {
+                perms.addAll(menuService.selectMenuPermsByUserId(user.getUserId()));
+            }
+        }
+        return perms;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysRegisterService.java
similarity index 75%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysRegisterService.java
index 6093515a..57358303 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/SysRegisterService.java
@@ -1,115 +1,115 @@
-package com.ruoyi.framework.web.service;
-
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.RegisterBody;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.exception.user.CaptchaException;
-import com.ruoyi.common.exception.user.CaptchaExpireException;
-import com.ruoyi.common.utils.MessageUtils;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.framework.manager.AsyncManager;
-import com.ruoyi.framework.manager.factory.AsyncFactory;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 注册校验方法
- * 
- * @author ruoyi
- */
-@Component
-public class SysRegisterService
-{
-    @Autowired
-    private ISysUserService userService;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    /**
-     * 注册
-     */
-    public String register(RegisterBody registerBody)
-    {
-        String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
-        SysUser sysUser = new SysUser();
-        sysUser.setUserName(username);
-
-        // 验证码开关
-        boolean captchaEnabled = configService.selectCaptchaEnabled();
-        if (captchaEnabled)
-        {
-            validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
-        }
-
-        if (StringUtils.isEmpty(username))
-        {
-            msg = "用户名不能为空";
-        }
-        else if (StringUtils.isEmpty(password))
-        {
-            msg = "用户密码不能为空";
-        }
-        else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
-                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
-        {
-            msg = "账户长度必须在2到20个字符之间";
-        }
-        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
-                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
-        {
-            msg = "密码长度必须在5到20个字符之间";
-        }
-        else if (!userService.checkUserNameUnique(sysUser))
-        {
-            msg = "保存用户'" + username + "'失败,注册账号已存在";
-        }
-        else
-        {
-            sysUser.setNickName(username);
-            sysUser.setPassword(SecurityUtils.encryptPassword(password));
-            boolean regFlag = userService.registerUser(sysUser);
-            if (!regFlag)
-            {
-                msg = "注册失败,请联系系统管理人员";
-            }
-            else
-            {
-                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")));
-            }
-        }
-        return msg;
-    }
-
-    /**
-     * 校验验证码
-     * 
-     * @param username 用户名
-     * @param code 验证码
-     * @param uuid 唯一标识
-     * @return 结果
-     */
-    public void validateCaptcha(String username, String code, String uuid)
-    {
-        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
-        String captcha = redisCache.getCacheObject(verifyKey);
-        redisCache.deleteObject(verifyKey);
-        if (captcha == null)
-        {
-            throw new CaptchaExpireException();
-        }
-        if (!code.equalsIgnoreCase(captcha))
-        {
-            throw new CaptchaException();
-        }
-    }
-}
+package com.acupuncture.framework.web.service;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.RegisterBody;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.exception.user.CaptchaException;
+import com.acupuncture.common.exception.user.CaptchaExpireException;
+import com.acupuncture.common.utils.MessageUtils;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.framework.manager.AsyncManager;
+import com.acupuncture.framework.manager.factory.AsyncFactory;
+import com.acupuncture.system.service.ISysConfigService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 注册校验方法
+ * 
+ * @author acupuncture
+ */
+@Component
+public class SysRegisterService
+{
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 注册
+     */
+    public String register(RegisterBody registerBody)
+    {
+        String msg = "", username = registerBody.getUsername(), password = registerBody.getPassword();
+        SysUser sysUser = new SysUser();
+        sysUser.setUserName(username);
+
+        // 验证码开关
+        boolean captchaEnabled = configService.selectCaptchaEnabled();
+        if (captchaEnabled)
+        {
+            validateCaptcha(username, registerBody.getCode(), registerBody.getUuid());
+        }
+
+        if (StringUtils.isEmpty(username))
+        {
+            msg = "用户名不能为空";
+        }
+        else if (StringUtils.isEmpty(password))
+        {
+            msg = "用户密码不能为空";
+        }
+        else if (username.length() < UserConstants.USERNAME_MIN_LENGTH
+                || username.length() > UserConstants.USERNAME_MAX_LENGTH)
+        {
+            msg = "账户长度必须在2到20个字符之间";
+        }
+        else if (password.length() < UserConstants.PASSWORD_MIN_LENGTH
+                || password.length() > UserConstants.PASSWORD_MAX_LENGTH)
+        {
+            msg = "密码长度必须在5到20个字符之间";
+        }
+        else if (!userService.checkUserNameUnique(sysUser))
+        {
+            msg = "保存用户'" + username + "'失败,注册账号已存在";
+        }
+        else
+        {
+            sysUser.setNickName(username);
+            sysUser.setPassword(SecurityUtils.encryptPassword(password));
+            boolean regFlag = userService.registerUser(sysUser);
+            if (!regFlag)
+            {
+                msg = "注册失败,请联系系统管理人员";
+            }
+            else
+            {
+                AsyncManager.me().execute(AsyncFactory.recordLogininfor(username, Constants.REGISTER, MessageUtils.message("user.register.success")));
+            }
+        }
+        return msg;
+    }
+
+    /**
+     * 校验验证码
+     * 
+     * @param username 用户名
+     * @param code 验证码
+     * @param uuid 唯一标识
+     * @return 结果
+     */
+    public void validateCaptcha(String username, String code, String uuid)
+    {
+        String verifyKey = CacheConstants.CAPTCHA_CODE_KEY + StringUtils.nvl(uuid, "");
+        String captcha = redisCache.getCacheObject(verifyKey);
+        redisCache.deleteObject(verifyKey);
+        if (captcha == null)
+        {
+            throw new CaptchaExpireException();
+        }
+        if (!code.equalsIgnoreCase(captcha))
+        {
+            throw new CaptchaException();
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/TokenService.java
similarity index 89%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/TokenService.java
index e062fafb..26fc566b 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/TokenService.java
@@ -1,231 +1,231 @@
-package com.ruoyi.framework.web.service;
-
-import java.util.HashMap;
-import java.util.Map;
-import java.util.concurrent.TimeUnit;
-import javax.servlet.http.HttpServletRequest;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.utils.ServletUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.ip.AddressUtils;
-import com.ruoyi.common.utils.ip.IpUtils;
-import com.ruoyi.common.utils.uuid.IdUtils;
-import eu.bitwalker.useragentutils.UserAgent;
-import io.jsonwebtoken.Claims;
-import io.jsonwebtoken.Jwts;
-import io.jsonwebtoken.SignatureAlgorithm;
-
-/**
- * token验证处理
- *
- * @author ruoyi
- */
-@Component
-public class TokenService
-{
-    private static final Logger log = LoggerFactory.getLogger(TokenService.class);
-
-    // 令牌自定义标识
-    @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))
-        {
-            try
-            {
-                Claims claims = parseToken(token);
-                // 解析对应的权限以及用户信息
-                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
-                String userKey = getTokenKey(uuid);
-                LoginUser user = redisCache.getCacheObject(userKey);
-                return user;
-            }
-            catch (Exception e)
-            {
-                log.error("获取用户信息异常'{}'", e.getMessage());
-            }
-        }
-        return null;
-    }
-
-    /**
-     * 设置用户身份信息
-     */
-    public void setLoginUser(LoginUser loginUser)
-    {
-        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
-        {
-            refreshToken(loginUser);
-        }
-    }
-
-    /**
-     * 删除用户身份信息
-     */
-    public void delLoginUser(String token)
-    {
-        if (StringUtils.isNotEmpty(token))
-        {
-            String userKey = getTokenKey(token);
-            redisCache.deleteObject(userKey);
-        }
-    }
-
-    /**
-     * 创建令牌
-     *
-     * @param loginUser 用户信息
-     * @return 令牌
-     */
-    public String createToken(LoginUser loginUser)
-    {
-        String token = IdUtils.fastUUID();
-        loginUser.setToken(token);
-        setUserAgent(loginUser);
-        refreshToken(loginUser);
-
-        Map<String, Object> claims = new HashMap<>();
-        claims.put(Constants.LOGIN_USER_KEY, token);
-        return createToken(claims);
-    }
-
-    /**
-     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
-     *
-     * @param loginUser
-     * @return 令牌
-     */
-    public void verifyToken(LoginUser loginUser)
-    {
-        long expireTime = loginUser.getExpireTime();
-        long currentTime = System.currentTimeMillis();
-        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
-        {
-            refreshToken(loginUser);
-        }
-    }
-
-    /**
-     * 刷新令牌有效期
-     *
-     * @param loginUser 登录信息
-     */
-    public void refreshToken(LoginUser loginUser)
-    {
-        loginUser.setLoginTime(System.currentTimeMillis());
-        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
-        // 根据uuid将loginUser缓存
-        String userKey = getTokenKey(loginUser.getToken());
-        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
-    }
-
-    /**
-     * 设置用户代理信息
-     *
-     * @param loginUser 登录信息
-     */
-    public void setUserAgent(LoginUser loginUser)
-    {
-        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
-        String ip = IpUtils.getIpAddr();
-        loginUser.setIpaddr(ip);
-        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
-        loginUser.setBrowser(userAgent.getBrowser().getName());
-        loginUser.setOs(userAgent.getOperatingSystem().getName());
-    }
-
-    /**
-     * 从数据声明生成令牌
-     *
-     * @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 CacheConstants.LOGIN_TOKEN_KEY + uuid;
-    }
-}
+package com.acupuncture.framework.web.service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import javax.servlet.http.HttpServletRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.utils.ServletUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.ip.AddressUtils;
+import com.acupuncture.common.utils.ip.IpUtils;
+import com.acupuncture.common.utils.uuid.IdUtils;
+import eu.bitwalker.useragentutils.UserAgent;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jwts;
+import io.jsonwebtoken.SignatureAlgorithm;
+
+/**
+ * token验证处理
+ *
+ * @author acupuncture
+ */
+@Component
+public class TokenService
+{
+    private static final Logger log = LoggerFactory.getLogger(TokenService.class);
+
+    // 令牌自定义标识
+    @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))
+        {
+            try
+            {
+                Claims claims = parseToken(token);
+                // 解析对应的权限以及用户信息
+                String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
+                String userKey = getTokenKey(uuid);
+                LoginUser user = redisCache.getCacheObject(userKey);
+                return user;
+            }
+            catch (Exception e)
+            {
+                log.error("获取用户信息异常'{}'", e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * 设置用户身份信息
+     */
+    public void setLoginUser(LoginUser loginUser)
+    {
+        if (StringUtils.isNotNull(loginUser) && StringUtils.isNotEmpty(loginUser.getToken()))
+        {
+            refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 删除用户身份信息
+     */
+    public void delLoginUser(String token)
+    {
+        if (StringUtils.isNotEmpty(token))
+        {
+            String userKey = getTokenKey(token);
+            redisCache.deleteObject(userKey);
+        }
+    }
+
+    /**
+     * 创建令牌
+     *
+     * @param loginUser 用户信息
+     * @return 令牌
+     */
+    public String createToken(LoginUser loginUser)
+    {
+        String token = IdUtils.fastUUID();
+        loginUser.setToken(token);
+        setUserAgent(loginUser);
+        refreshToken(loginUser);
+
+        Map<String, Object> claims = new HashMap<>();
+        claims.put(Constants.LOGIN_USER_KEY, token);
+        return createToken(claims);
+    }
+
+    /**
+     * 验证令牌有效期,相差不足20分钟,自动刷新缓存
+     *
+     * @param loginUser
+     * @return 令牌
+     */
+    public void verifyToken(LoginUser loginUser)
+    {
+        long expireTime = loginUser.getExpireTime();
+        long currentTime = System.currentTimeMillis();
+        if (expireTime - currentTime <= MILLIS_MINUTE_TEN)
+        {
+            refreshToken(loginUser);
+        }
+    }
+
+    /**
+     * 刷新令牌有效期
+     *
+     * @param loginUser 登录信息
+     */
+    public void refreshToken(LoginUser loginUser)
+    {
+        loginUser.setLoginTime(System.currentTimeMillis());
+        loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
+        // 根据uuid将loginUser缓存
+        String userKey = getTokenKey(loginUser.getToken());
+        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+    }
+
+    /**
+     * 设置用户代理信息
+     *
+     * @param loginUser 登录信息
+     */
+    public void setUserAgent(LoginUser loginUser)
+    {
+        UserAgent userAgent = UserAgent.parseUserAgentString(ServletUtils.getRequest().getHeader("User-Agent"));
+        String ip = IpUtils.getIpAddr();
+        loginUser.setIpaddr(ip);
+        loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
+        loginUser.setBrowser(userAgent.getBrowser().getName());
+        loginUser.setOs(userAgent.getOperatingSystem().getName());
+    }
+
+    /**
+     * 从数据声明生成令牌
+     *
+     * @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 CacheConstants.LOGIN_TOKEN_KEY + uuid;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java
similarity index 80%
rename from ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
rename to acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java
index e294fbd2..6d1ab302 100644
--- a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
+++ b/acupuncture-framework/src/main/java/com/acupuncture/framework/web/service/UserDetailsServiceImpl.java
@@ -1,66 +1,66 @@
-package com.ruoyi.framework.web.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.core.domain.entity.SysUser;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.enums.UserStatus;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.MessageUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.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 SysPasswordService passwordService;
-
-    @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 ServiceException(MessageUtils.message("user.not.exists"));
-        }
-        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
-        {
-            log.info("登录用户:{} 已被删除.", username);
-            throw new ServiceException(MessageUtils.message("user.password.delete"));
-        }
-        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
-        {
-            log.info("登录用户:{} 已被停用.", username);
-            throw new ServiceException(MessageUtils.message("user.blocked"));
-        }
-
-        passwordService.validate(user);
-
-        return createLoginUser(user);
-    }
-
-    public UserDetails createLoginUser(SysUser user)
-    {
-        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
-    }
-}
+package com.acupuncture.framework.web.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.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.enums.UserStatus;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.MessageUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 用户验证处理
+ *
+ * @author acupuncture
+ */
+@Service
+public class UserDetailsServiceImpl implements UserDetailsService
+{
+    private static final Logger log = LoggerFactory.getLogger(UserDetailsServiceImpl.class);
+
+    @Autowired
+    private ISysUserService userService;
+    
+    @Autowired
+    private SysPasswordService passwordService;
+
+    @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 ServiceException(MessageUtils.message("user.not.exists"));
+        }
+        else if (UserStatus.DELETED.getCode().equals(user.getDelFlag()))
+        {
+            log.info("登录用户:{} 已被删除.", username);
+            throw new ServiceException(MessageUtils.message("user.password.delete"));
+        }
+        else if (UserStatus.DISABLE.getCode().equals(user.getStatus()))
+        {
+            log.info("登录用户:{} 已被停用.", username);
+            throw new ServiceException(MessageUtils.message("user.blocked"));
+        }
+
+        passwordService.validate(user);
+
+        return createLoginUser(user);
+    }
+
+    public UserDetails createLoginUser(SysUser user)
+    {
+        return new LoginUser(user.getUserId(), user.getDeptId(), user, permissionService.getMenuPermission(user));
+    }
+}
diff --git a/ruoyi-generator/pom.xml b/acupuncture-generator/pom.xml
similarity index 79%
rename from ruoyi-generator/pom.xml
rename to acupuncture-generator/pom.xml
index 9dd41f99..4861ad7e 100644
--- a/ruoyi-generator/pom.xml
+++ b/acupuncture-generator/pom.xml
@@ -1,40 +1,40 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ruoyi-generator</artifactId>
-
-    <description>
-        generator代码生成
-    </description>
-
-    <dependencies>
-
-        <!-- velocity代码生成使用模板 -->
-        <dependency>
-            <groupId>org.apache.velocity</groupId>
-            <artifactId>velocity-engine-core</artifactId>
-        </dependency>
-
-        <!-- 通用工具-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-common</artifactId>
-        </dependency>
-
-        <!-- 阿里数据库连接池 -->
-        <dependency>
-            <groupId>com.alibaba</groupId>
-            <artifactId>druid-spring-boot-starter</artifactId>
-        </dependency>
-
-    </dependencies>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>acupuncture-generator</artifactId>
+
+    <description>
+        generator代码生成
+    </description>
+
+    <dependencies>
+
+        <!-- velocity代码生成使用模板 -->
+        <dependency>
+            <groupId>org.apache.velocity</groupId>
+            <artifactId>velocity-engine-core</artifactId>
+        </dependency>
+
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-common</artifactId>
+        </dependency>
+
+        <!-- 阿里数据库连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+        </dependency>
+
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/config/GenConfig.java
similarity index 93%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/config/GenConfig.java
index 43320f5e..575e5efa 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/config/GenConfig.java
@@ -1,87 +1,87 @@
-package com.ruoyi.generator.config;
-
-import org.springframework.beans.factory.annotation.Value;
-import org.springframework.boot.context.properties.ConfigurationProperties;
-import org.springframework.context.annotation.PropertySource;
-import org.springframework.stereotype.Component;
-
-/**
- * 读取代码生成相关配置
- * 
- * @author ruoyi
- */
-@Component
-@ConfigurationProperties(prefix = "gen")
-@PropertySource(value = { "classpath:generator.yml" })
-public class GenConfig
-{
-    /** 作者 */
-    public static String author;
-
-    /** 生成包路径 */
-    public static String packageName;
-
-    /** 自动去除表前缀 */
-    public static boolean autoRemovePre;
-
-    /** 表前缀 */
-    public static String tablePrefix;
-
-    /** 是否允许生成文件覆盖到本地(自定义路径) */
-    public static boolean allowOverwrite;
-
-    public static String getAuthor()
-    {
-        return author;
-    }
-
-    @Value("${author}")
-    public void setAuthor(String author)
-    {
-        GenConfig.author = author;
-    }
-
-    public static String getPackageName()
-    {
-        return packageName;
-    }
-
-    @Value("${packageName}")
-    public void setPackageName(String packageName)
-    {
-        GenConfig.packageName = packageName;
-    }
-
-    public static boolean getAutoRemovePre()
-    {
-        return autoRemovePre;
-    }
-
-    @Value("${autoRemovePre}")
-    public void setAutoRemovePre(boolean autoRemovePre)
-    {
-        GenConfig.autoRemovePre = autoRemovePre;
-    }
-
-    public static String getTablePrefix()
-    {
-        return tablePrefix;
-    }
-
-    @Value("${tablePrefix}")
-    public void setTablePrefix(String tablePrefix)
-    {
-        GenConfig.tablePrefix = tablePrefix;
-    }
-
-    public static boolean isAllowOverwrite()
-    {
-        return allowOverwrite;
-    }
-
-    @Value("${allowOverwrite}")
-    public void setAllowOverwrite(boolean allowOverwrite)
-    {
-        GenConfig.allowOverwrite = allowOverwrite;
-    }
-}
+package com.acupuncture.generator.config;
+
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.PropertySource;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取代码生成相关配置
+ * 
+ * @author acupuncture
+ */
+@Component
+@ConfigurationProperties(prefix = "gen")
+@PropertySource(value = { "classpath:generator.yml" })
+public class GenConfig
+{
+    /** 作者 */
+    public static String author;
+
+    /** 生成包路径 */
+    public static String packageName;
+
+    /** 自动去除表前缀 */
+    public static boolean autoRemovePre;
+
+    /** 表前缀 */
+    public static String tablePrefix;
+
+    /** 是否允许生成文件覆盖到本地(自定义路径) */
+    public static boolean allowOverwrite;
+
+    public static String getAuthor()
+    {
+        return author;
+    }
+
+    @Value("${author}")
+    public void setAuthor(String author)
+    {
+        GenConfig.author = author;
+    }
+
+    public static String getPackageName()
+    {
+        return packageName;
+    }
+
+    @Value("${packageName}")
+    public void setPackageName(String packageName)
+    {
+        GenConfig.packageName = packageName;
+    }
+
+    public static boolean getAutoRemovePre()
+    {
+        return autoRemovePre;
+    }
+
+    @Value("${autoRemovePre}")
+    public void setAutoRemovePre(boolean autoRemovePre)
+    {
+        GenConfig.autoRemovePre = autoRemovePre;
+    }
+
+    public static String getTablePrefix()
+    {
+        return tablePrefix;
+    }
+
+    @Value("${tablePrefix}")
+    public void setTablePrefix(String tablePrefix)
+    {
+        GenConfig.tablePrefix = tablePrefix;
+    }
+
+    public static boolean isAllowOverwrite()
+    {
+        return allowOverwrite;
+    }
+
+    @Value("${allowOverwrite}")
+    public void setAllowOverwrite(boolean allowOverwrite)
+    {
+        GenConfig.allowOverwrite = allowOverwrite;
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/controller/GenController.java
similarity index 89%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/controller/GenController.java
index ed6e0b29..51f40da6 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/controller/GenController.java
@@ -1,263 +1,263 @@
-package com.ruoyi.generator.controller;
-
-import java.io.IOException;
-import java.util.ArrayList;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import javax.servlet.http.HttpServletResponse;
-import org.apache.commons.io.IOUtils;
-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.RestController;
-import com.alibaba.druid.DbType;
-import com.alibaba.druid.sql.SQLUtils;
-import com.alibaba.druid.sql.ast.SQLStatement;
-import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.sql.SqlUtil;
-import com.ruoyi.generator.config.GenConfig;
-import com.ruoyi.generator.domain.GenTable;
-import com.ruoyi.generator.domain.GenTableColumn;
-import com.ruoyi.generator.service.IGenTableColumnService;
-import com.ruoyi.generator.service.IGenTableService;
-
-/**
- * 代码生成 操作处理
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/tool/gen")
-public class GenController extends BaseController
-{
-    @Autowired
-    private IGenTableService genTableService;
-
-    @Autowired
-    private IGenTableColumnService genTableColumnService;
-
-    /**
-     * 查询代码生成列表
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping("/list")
-    public TableDataInfo genList(GenTable genTable)
-    {
-        startPage();
-        List<GenTable> list = genTableService.selectGenTableList(genTable);
-        return getDataTable(list);
-    }
-
-    /**
-     * 修改代码生成业务
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
-    @GetMapping(value = "/{tableId}")
-    public AjaxResult getInfo(@PathVariable Long tableId)
-    {
-        GenTable table = genTableService.selectGenTableById(tableId);
-        List<GenTable> tables = genTableService.selectGenTableAll();
-        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
-        Map<String, Object> map = new HashMap<String, Object>();
-        map.put("info", table);
-        map.put("rows", list);
-        map.put("tables", tables);
-        return success(map);
-    }
-
-    /**
-     * 查询数据库列表
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping("/db/list")
-    public TableDataInfo dataList(GenTable genTable)
-    {
-        startPage();
-        List<GenTable> list = genTableService.selectDbTableList(genTable);
-        return getDataTable(list);
-    }
-
-    /**
-     * 查询数据表字段列表
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
-    @GetMapping(value = "/column/{tableId}")
-    public TableDataInfo columnList(Long tableId)
-    {
-        TableDataInfo dataInfo = new TableDataInfo();
-        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
-        dataInfo.setRows(list);
-        dataInfo.setTotal(list.size());
-        return dataInfo;
-    }
-
-    /**
-     * 导入表结构(保存)
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
-    @Log(title = "代码生成", businessType = BusinessType.IMPORT)
-    @PostMapping("/importTable")
-    public AjaxResult importTableSave(String tables)
-    {
-        String[] tableNames = Convert.toStrArray(tables);
-        // 查询表信息
-        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
-        genTableService.importGenTable(tableList, SecurityUtils.getUsername());
-        return success();
-    }
-
-    /**
-     * 创建表结构(保存)
-     */
-    @PreAuthorize("@ss.hasRole('admin')")
-    @Log(title = "创建表", businessType = BusinessType.OTHER)
-    @PostMapping("/createTable")
-    public AjaxResult createTableSave(String sql)
-    {
-        try
-        {
-            SqlUtil.filterKeyword(sql);
-            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
-            List<String> tableNames = new ArrayList<>();
-            for (SQLStatement sqlStatement : sqlStatements)
-            {
-                if (sqlStatement instanceof MySqlCreateTableStatement)
-                {
-                    MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
-                    if (genTableService.createTable(createTableStatement.toString()))
-                    {
-                        String tableName = createTableStatement.getTableName().replaceAll("`", "");
-                        tableNames.add(tableName);
-                    }
-                }
-            }
-            List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
-            String operName = SecurityUtils.getUsername();
-            genTableService.importGenTable(tableList, operName);
-            return AjaxResult.success();
-        }
-        catch (Exception e)
-        {
-            logger.error(e.getMessage(), e);
-            return AjaxResult.error("创建表结构异常");
-        }
-    }
-
-    /**
-     * 修改保存代码生成业务
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
-    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
-    {
-        genTableService.validateEdit(genTable);
-        genTableService.updateGenTable(genTable);
-        return success();
-    }
-
-    /**
-     * 删除代码生成
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
-    @Log(title = "代码生成", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{tableIds}")
-    public AjaxResult remove(@PathVariable Long[] tableIds)
-    {
-        genTableService.deleteGenTableByIds(tableIds);
-        return success();
-    }
-
-    /**
-     * 预览代码
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
-    @GetMapping("/preview/{tableId}")
-    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
-    {
-        Map<String, String> dataMap = genTableService.previewCode(tableId);
-        return success(dataMap);
-    }
-
-    /**
-     * 生成代码(下载方式)
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
-    @GetMapping("/download/{tableName}")
-    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
-    {
-        byte[] data = genTableService.downloadCode(tableName);
-        genCode(response, data);
-    }
-
-    /**
-     * 生成代码(自定义路径)
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
-    @GetMapping("/genCode/{tableName}")
-    public AjaxResult genCode(@PathVariable("tableName") String tableName)
-    {
-        if (!GenConfig.isAllowOverwrite())
-        {
-            return AjaxResult.error("【系统预设】不允许生成文件覆盖到本地");
-        }
-        genTableService.generatorCode(tableName);
-        return success();
-    }
-
-    /**
-     * 同步数据库
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
-    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
-    @GetMapping("/synchDb/{tableName}")
-    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
-    {
-        genTableService.synchDb(tableName);
-        return success();
-    }
-
-    /**
-     * 批量生成代码
-     */
-    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
-    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
-    @GetMapping("/batchGenCode")
-    public void batchGenCode(HttpServletResponse response, String tables) throws IOException
-    {
-        String[] tableNames = Convert.toStrArray(tables);
-        byte[] data = genTableService.downloadCode(tableNames);
-        genCode(response, data);
-    }
-
-    /**
-     * 生成zip文件
-     */
-    private void genCode(HttpServletResponse response, byte[] data) throws IOException
-    {
-        response.reset();
-        response.addHeader("Access-Control-Allow-Origin", "*");
-        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
-        response.setHeader("Content-Disposition", "attachment; filename=\"ruoyi.zip\"");
-        response.addHeader("Content-Length", "" + data.length);
-        response.setContentType("application/octet-stream; charset=UTF-8");
-        IOUtils.write(data, response.getOutputStream());
-    }
+package com.acupuncture.generator.controller;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.commons.io.IOUtils;
+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.RestController;
+import com.alibaba.druid.DbType;
+import com.alibaba.druid.sql.SQLUtils;
+import com.alibaba.druid.sql.ast.SQLStatement;
+import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlCreateTableStatement;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.sql.SqlUtil;
+import com.acupuncture.generator.config.GenConfig;
+import com.acupuncture.generator.domain.GenTable;
+import com.acupuncture.generator.domain.GenTableColumn;
+import com.acupuncture.generator.service.IGenTableColumnService;
+import com.acupuncture.generator.service.IGenTableService;
+
+/**
+ * 代码生成 操作处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/tool/gen")
+public class GenController extends BaseController
+{
+    @Autowired
+    private IGenTableService genTableService;
+
+    @Autowired
+    private IGenTableColumnService genTableColumnService;
+
+    /**
+     * 查询代码生成列表
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/list")
+    public TableDataInfo genList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectGenTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 修改代码生成业务
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:query')")
+    @GetMapping(value = "/{tableId}")
+    public AjaxResult getInfo(@PathVariable Long tableId)
+    {
+        GenTable table = genTableService.selectGenTableById(tableId);
+        List<GenTable> tables = genTableService.selectGenTableAll();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
+        Map<String, Object> map = new HashMap<String, Object>();
+        map.put("info", table);
+        map.put("rows", list);
+        map.put("tables", tables);
+        return success(map);
+    }
+
+    /**
+     * 查询数据库列表
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/db/list")
+    public TableDataInfo dataList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectDbTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询数据表字段列表
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping(value = "/column/{tableId}")
+    public TableDataInfo columnList(Long tableId)
+    {
+        TableDataInfo dataInfo = new TableDataInfo();
+        List<GenTableColumn> list = genTableColumnService.selectGenTableColumnListByTableId(tableId);
+        dataInfo.setRows(list);
+        dataInfo.setTotal(list.size());
+        return dataInfo;
+    }
+
+    /**
+     * 导入表结构(保存)
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:import')")
+    @Log(title = "代码生成", businessType = BusinessType.IMPORT)
+    @PostMapping("/importTable")
+    public AjaxResult importTableSave(String tables)
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        // 查询表信息
+        List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames);
+        genTableService.importGenTable(tableList, SecurityUtils.getUsername());
+        return success();
+    }
+
+    /**
+     * 创建表结构(保存)
+     */
+    @PreAuthorize("@ss.hasRole('admin')")
+    @Log(title = "创建表", businessType = BusinessType.OTHER)
+    @PostMapping("/createTable")
+    public AjaxResult createTableSave(String sql)
+    {
+        try
+        {
+            SqlUtil.filterKeyword(sql);
+            List<SQLStatement> sqlStatements = SQLUtils.parseStatements(sql, DbType.mysql);
+            List<String> tableNames = new ArrayList<>();
+            for (SQLStatement sqlStatement : sqlStatements)
+            {
+                if (sqlStatement instanceof MySqlCreateTableStatement)
+                {
+                    MySqlCreateTableStatement createTableStatement = (MySqlCreateTableStatement) sqlStatement;
+                    if (genTableService.createTable(createTableStatement.toString()))
+                    {
+                        String tableName = createTableStatement.getTableName().replaceAll("`", "");
+                        tableNames.add(tableName);
+                    }
+                }
+            }
+            List<GenTable> tableList = genTableService.selectDbTableListByNames(tableNames.toArray(new String[tableNames.size()]));
+            String operName = SecurityUtils.getUsername();
+            genTableService.importGenTable(tableList, operName);
+            return AjaxResult.success();
+        }
+        catch (Exception e)
+        {
+            logger.error(e.getMessage(), e);
+            return AjaxResult.error("创建表结构异常");
+        }
+    }
+
+    /**
+     * 修改保存代码生成业务
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
+    {
+        genTableService.validateEdit(genTable);
+        genTableService.updateGenTable(genTable);
+        return success();
+    }
+
+    /**
+     * 删除代码生成
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
+    @Log(title = "代码生成", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tableIds}")
+    public AjaxResult remove(@PathVariable Long[] tableIds)
+    {
+        genTableService.deleteGenTableByIds(tableIds);
+        return success();
+    }
+
+    /**
+     * 预览代码
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:preview')")
+    @GetMapping("/preview/{tableId}")
+    public AjaxResult preview(@PathVariable("tableId") Long tableId) throws IOException
+    {
+        Map<String, String> dataMap = genTableService.previewCode(tableId);
+        return success(dataMap);
+    }
+
+    /**
+     * 生成代码(下载方式)
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+    @GetMapping("/download/{tableName}")
+    public void download(HttpServletResponse response, @PathVariable("tableName") String tableName) throws IOException
+    {
+        byte[] data = genTableService.downloadCode(tableName);
+        genCode(response, data);
+    }
+
+    /**
+     * 生成代码(自定义路径)
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+    @GetMapping("/genCode/{tableName}")
+    public AjaxResult genCode(@PathVariable("tableName") String tableName)
+    {
+        if (!GenConfig.isAllowOverwrite())
+        {
+            return AjaxResult.error("【系统预设】不允许生成文件覆盖到本地");
+        }
+        genTableService.generatorCode(tableName);
+        return success();
+    }
+
+    /**
+     * 同步数据库
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "代码生成", businessType = BusinessType.UPDATE)
+    @GetMapping("/synchDb/{tableName}")
+    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
+    {
+        genTableService.synchDb(tableName);
+        return success();
+    }
+
+    /**
+     * 批量生成代码
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "代码生成", businessType = BusinessType.GENCODE)
+    @GetMapping("/batchGenCode")
+    public void batchGenCode(HttpServletResponse response, String tables) throws IOException
+    {
+        String[] tableNames = Convert.toStrArray(tables);
+        byte[] data = genTableService.downloadCode(tableNames);
+        genCode(response, data);
+    }
+
+    /**
+     * 生成zip文件
+     */
+    private void genCode(HttpServletResponse response, byte[] data) throws IOException
+    {
+        response.reset();
+        response.addHeader("Access-Control-Allow-Origin", "*");
+        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
+        response.setHeader("Content-Disposition", "attachment; filename=\"acupuncture.zip\"");
+        response.addHeader("Content-Length", "" + data.length);
+        response.setContentType("application/octet-stream; charset=UTF-8");
+        IOUtils.write(data, response.getOutputStream());
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTable.java
similarity index 93%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTable.java
index 2777d419..accf4eff 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTable.java
@@ -1,385 +1,385 @@
-package com.ruoyi.generator.domain;
-
-import java.util.List;
-import javax.validation.Valid;
-import javax.validation.constraints.NotBlank;
-import org.apache.commons.lang3.ArrayUtils;
-import com.ruoyi.common.constant.GenConstants;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 业务表 gen_table
- * 
- * @author ruoyi
- */
-public class GenTable extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 编号 */
-    private Long tableId;
-
-    /** 表名称 */
-    @NotBlank(message = "表名称不能为空")
-    private String tableName;
-
-    /** 表描述 */
-    @NotBlank(message = "表描述不能为空")
-    private String tableComment;
-
-    /** 关联父表的表名 */
-    private String subTableName;
-
-    /** 本表关联父表的外键名 */
-    private String subTableFkName;
-
-    /** 实体类名称(首字母大写) */
-    @NotBlank(message = "实体类名称不能为空")
-    private String className;
-
-    /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */
-    private String tplCategory;
-
-    /** 前端类型(element-ui模版 element-plus模版) */
-    private String tplWebType;
-
-    /** 生成包路径 */
-    @NotBlank(message = "生成包路径不能为空")
-    private String packageName;
-
-    /** 生成模块名 */
-    @NotBlank(message = "生成模块名不能为空")
-    private String moduleName;
-
-    /** 生成业务名 */
-    @NotBlank(message = "生成业务名不能为空")
-    private String businessName;
-
-    /** 生成功能名 */
-    @NotBlank(message = "生成功能名不能为空")
-    private String functionName;
-
-    /** 生成作者 */
-    @NotBlank(message = "作者不能为空")
-    private String functionAuthor;
-
-    /** 生成代码方式(0zip压缩包 1自定义路径) */
-    private String genType;
-
-    /** 生成路径(不填默认项目路径) */
-    private String genPath;
-
-    /** 主键信息 */
-    private GenTableColumn pkColumn;
-
-    /** 子表信息 */
-    private GenTable subTable;
-
-    /** 表列信息 */
-    @Valid
-    private List<GenTableColumn> columns;
-
-    /** 其它生成选项 */
-    private String options;
-
-    /** 树编码字段 */
-    private String treeCode;
-
-    /** 树父编码字段 */
-    private String treeParentCode;
-
-    /** 树名称字段 */
-    private String treeName;
-
-    /** 上级菜单ID字段 */
-    private Long parentMenuId;
-
-    /** 上级菜单名称字段 */
-    private String parentMenuName;
-
-    public Long getTableId()
-    {
-        return tableId;
-    }
-
-    public void setTableId(Long tableId)
-    {
-        this.tableId = tableId;
-    }
-
-    public String getTableName()
-    {
-        return tableName;
-    }
-
-    public void setTableName(String tableName)
-    {
-        this.tableName = tableName;
-    }
-
-    public String getTableComment()
-    {
-        return tableComment;
-    }
-
-    public void setTableComment(String tableComment)
-    {
-        this.tableComment = tableComment;
-    }
-
-    public String getSubTableName()
-    {
-        return subTableName;
-    }
-
-    public void setSubTableName(String subTableName)
-    {
-        this.subTableName = subTableName;
-    }
-
-    public String getSubTableFkName()
-    {
-        return subTableFkName;
-    }
-
-    public void setSubTableFkName(String subTableFkName)
-    {
-        this.subTableFkName = subTableFkName;
-    }
-
-    public String getClassName()
-    {
-        return className;
-    }
-
-    public void setClassName(String className)
-    {
-        this.className = className;
-    }
-
-    public String getTplCategory()
-    {
-        return tplCategory;
-    }
-
-    public void setTplCategory(String tplCategory)
-    {
-        this.tplCategory = tplCategory;
-    }
-
-    public String getTplWebType()
-    {
-        return tplWebType;
-    }
-
-    public void setTplWebType(String tplWebType)
-    {
-        this.tplWebType = tplWebType;
-    }
-
-    public String getPackageName()
-    {
-        return packageName;
-    }
-
-    public void setPackageName(String packageName)
-    {
-        this.packageName = packageName;
-    }
-
-    public String getModuleName()
-    {
-        return moduleName;
-    }
-
-    public void setModuleName(String moduleName)
-    {
-        this.moduleName = moduleName;
-    }
-
-    public String getBusinessName()
-    {
-        return businessName;
-    }
-
-    public void setBusinessName(String businessName)
-    {
-        this.businessName = businessName;
-    }
-
-    public String getFunctionName()
-    {
-        return functionName;
-    }
-
-    public void setFunctionName(String functionName)
-    {
-        this.functionName = functionName;
-    }
-
-    public String getFunctionAuthor()
-    {
-        return functionAuthor;
-    }
-
-    public void setFunctionAuthor(String functionAuthor)
-    {
-        this.functionAuthor = functionAuthor;
-    }
-
-    public String getGenType()
-    {
-        return genType;
-    }
-
-    public void setGenType(String genType)
-    {
-        this.genType = genType;
-    }
-
-    public String getGenPath()
-    {
-        return genPath;
-    }
-
-    public void setGenPath(String genPath)
-    {
-        this.genPath = genPath;
-    }
-
-    public GenTableColumn getPkColumn()
-    {
-        return pkColumn;
-    }
-
-    public void setPkColumn(GenTableColumn pkColumn)
-    {
-        this.pkColumn = pkColumn;
-    }
-
-    public GenTable getSubTable()
-    {
-        return subTable;
-    }
-
-    public void setSubTable(GenTable subTable)
-    {
-        this.subTable = subTable;
-    }
-
-    public List<GenTableColumn> getColumns()
-    {
-        return columns;
-    }
-
-    public void setColumns(List<GenTableColumn> columns)
-    {
-        this.columns = columns;
-    }
-
-    public String getOptions()
-    {
-        return options;
-    }
-
-    public void setOptions(String options)
-    {
-        this.options = options;
-    }
-
-    public String getTreeCode()
-    {
-        return treeCode;
-    }
-
-    public void setTreeCode(String treeCode)
-    {
-        this.treeCode = treeCode;
-    }
-
-    public String getTreeParentCode()
-    {
-        return treeParentCode;
-    }
-
-    public void setTreeParentCode(String treeParentCode)
-    {
-        this.treeParentCode = treeParentCode;
-    }
-
-    public String getTreeName()
-    {
-        return treeName;
-    }
-
-    public void setTreeName(String treeName)
-    {
-        this.treeName = treeName;
-    }
-
-    public Long getParentMenuId()
-    {
-        return parentMenuId;
-    }
-
-    public void setParentMenuId(Long parentMenuId)
-    {
-        this.parentMenuId = parentMenuId;
-    }
-
-    public String getParentMenuName()
-    {
-        return parentMenuName;
-    }
-
-    public void setParentMenuName(String parentMenuName)
-    {
-        this.parentMenuName = parentMenuName;
-    }
-
-    public boolean isSub()
-    {
-        return isSub(this.tplCategory);
-    }
-
-    public static boolean isSub(String tplCategory)
-    {
-        return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
-    }
-
-    public boolean isTree()
-    {
-        return isTree(this.tplCategory);
-    }
-
-    public static boolean isTree(String tplCategory)
-    {
-        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
-    }
-
-    public boolean isCrud()
-    {
-        return isCrud(this.tplCategory);
-    }
-
-    public static boolean isCrud(String tplCategory)
-    {
-        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
-    }
-
-    public boolean isSuperColumn(String javaField)
-    {
-        return isSuperColumn(this.tplCategory, javaField);
-    }
-
-    public static boolean isSuperColumn(String tplCategory, String javaField)
-    {
-        if (isTree(tplCategory))
-        {
-            return StringUtils.equalsAnyIgnoreCase(javaField,
-                    ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
-        }
-        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
-    }
+package com.acupuncture.generator.domain;
+
+import java.util.List;
+import javax.validation.Valid;
+import javax.validation.constraints.NotBlank;
+import org.apache.commons.lang3.ArrayUtils;
+import com.acupuncture.common.constant.GenConstants;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 业务表 gen_table
+ * 
+ * @author acupuncture
+ */
+public class GenTable extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 编号 */
+    private Long tableId;
+
+    /** 表名称 */
+    @NotBlank(message = "表名称不能为空")
+    private String tableName;
+
+    /** 表描述 */
+    @NotBlank(message = "表描述不能为空")
+    private String tableComment;
+
+    /** 关联父表的表名 */
+    private String subTableName;
+
+    /** 本表关联父表的外键名 */
+    private String subTableFkName;
+
+    /** 实体类名称(首字母大写) */
+    @NotBlank(message = "实体类名称不能为空")
+    private String className;
+
+    /** 使用的模板(crud单表操作 tree树表操作 sub主子表操作) */
+    private String tplCategory;
+
+    /** 前端类型(element-ui模版 element-plus模版) */
+    private String tplWebType;
+
+    /** 生成包路径 */
+    @NotBlank(message = "生成包路径不能为空")
+    private String packageName;
+
+    /** 生成模块名 */
+    @NotBlank(message = "生成模块名不能为空")
+    private String moduleName;
+
+    /** 生成业务名 */
+    @NotBlank(message = "生成业务名不能为空")
+    private String businessName;
+
+    /** 生成功能名 */
+    @NotBlank(message = "生成功能名不能为空")
+    private String functionName;
+
+    /** 生成作者 */
+    @NotBlank(message = "作者不能为空")
+    private String functionAuthor;
+
+    /** 生成代码方式(0zip压缩包 1自定义路径) */
+    private String genType;
+
+    /** 生成路径(不填默认项目路径) */
+    private String genPath;
+
+    /** 主键信息 */
+    private GenTableColumn pkColumn;
+
+    /** 子表信息 */
+    private GenTable subTable;
+
+    /** 表列信息 */
+    @Valid
+    private List<GenTableColumn> columns;
+
+    /** 其它生成选项 */
+    private String options;
+
+    /** 树编码字段 */
+    private String treeCode;
+
+    /** 树父编码字段 */
+    private String treeParentCode;
+
+    /** 树名称字段 */
+    private String treeName;
+
+    /** 上级菜单ID字段 */
+    private Long parentMenuId;
+
+    /** 上级菜单名称字段 */
+    private String parentMenuName;
+
+    public Long getTableId()
+    {
+        return tableId;
+    }
+
+    public void setTableId(Long tableId)
+    {
+        this.tableId = tableId;
+    }
+
+    public String getTableName()
+    {
+        return tableName;
+    }
+
+    public void setTableName(String tableName)
+    {
+        this.tableName = tableName;
+    }
+
+    public String getTableComment()
+    {
+        return tableComment;
+    }
+
+    public void setTableComment(String tableComment)
+    {
+        this.tableComment = tableComment;
+    }
+
+    public String getSubTableName()
+    {
+        return subTableName;
+    }
+
+    public void setSubTableName(String subTableName)
+    {
+        this.subTableName = subTableName;
+    }
+
+    public String getSubTableFkName()
+    {
+        return subTableFkName;
+    }
+
+    public void setSubTableFkName(String subTableFkName)
+    {
+        this.subTableFkName = subTableFkName;
+    }
+
+    public String getClassName()
+    {
+        return className;
+    }
+
+    public void setClassName(String className)
+    {
+        this.className = className;
+    }
+
+    public String getTplCategory()
+    {
+        return tplCategory;
+    }
+
+    public void setTplCategory(String tplCategory)
+    {
+        this.tplCategory = tplCategory;
+    }
+
+    public String getTplWebType()
+    {
+        return tplWebType;
+    }
+
+    public void setTplWebType(String tplWebType)
+    {
+        this.tplWebType = tplWebType;
+    }
+
+    public String getPackageName()
+    {
+        return packageName;
+    }
+
+    public void setPackageName(String packageName)
+    {
+        this.packageName = packageName;
+    }
+
+    public String getModuleName()
+    {
+        return moduleName;
+    }
+
+    public void setModuleName(String moduleName)
+    {
+        this.moduleName = moduleName;
+    }
+
+    public String getBusinessName()
+    {
+        return businessName;
+    }
+
+    public void setBusinessName(String businessName)
+    {
+        this.businessName = businessName;
+    }
+
+    public String getFunctionName()
+    {
+        return functionName;
+    }
+
+    public void setFunctionName(String functionName)
+    {
+        this.functionName = functionName;
+    }
+
+    public String getFunctionAuthor()
+    {
+        return functionAuthor;
+    }
+
+    public void setFunctionAuthor(String functionAuthor)
+    {
+        this.functionAuthor = functionAuthor;
+    }
+
+    public String getGenType()
+    {
+        return genType;
+    }
+
+    public void setGenType(String genType)
+    {
+        this.genType = genType;
+    }
+
+    public String getGenPath()
+    {
+        return genPath;
+    }
+
+    public void setGenPath(String genPath)
+    {
+        this.genPath = genPath;
+    }
+
+    public GenTableColumn getPkColumn()
+    {
+        return pkColumn;
+    }
+
+    public void setPkColumn(GenTableColumn pkColumn)
+    {
+        this.pkColumn = pkColumn;
+    }
+
+    public GenTable getSubTable()
+    {
+        return subTable;
+    }
+
+    public void setSubTable(GenTable subTable)
+    {
+        this.subTable = subTable;
+    }
+
+    public List<GenTableColumn> getColumns()
+    {
+        return columns;
+    }
+
+    public void setColumns(List<GenTableColumn> columns)
+    {
+        this.columns = columns;
+    }
+
+    public String getOptions()
+    {
+        return options;
+    }
+
+    public void setOptions(String options)
+    {
+        this.options = options;
+    }
+
+    public String getTreeCode()
+    {
+        return treeCode;
+    }
+
+    public void setTreeCode(String treeCode)
+    {
+        this.treeCode = treeCode;
+    }
+
+    public String getTreeParentCode()
+    {
+        return treeParentCode;
+    }
+
+    public void setTreeParentCode(String treeParentCode)
+    {
+        this.treeParentCode = treeParentCode;
+    }
+
+    public String getTreeName()
+    {
+        return treeName;
+    }
+
+    public void setTreeName(String treeName)
+    {
+        this.treeName = treeName;
+    }
+
+    public Long getParentMenuId()
+    {
+        return parentMenuId;
+    }
+
+    public void setParentMenuId(Long parentMenuId)
+    {
+        this.parentMenuId = parentMenuId;
+    }
+
+    public String getParentMenuName()
+    {
+        return parentMenuName;
+    }
+
+    public void setParentMenuName(String parentMenuName)
+    {
+        this.parentMenuName = parentMenuName;
+    }
+
+    public boolean isSub()
+    {
+        return isSub(this.tplCategory);
+    }
+
+    public static boolean isSub(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_SUB, tplCategory);
+    }
+
+    public boolean isTree()
+    {
+        return isTree(this.tplCategory);
+    }
+
+    public static boolean isTree(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_TREE, tplCategory);
+    }
+
+    public boolean isCrud()
+    {
+        return isCrud(this.tplCategory);
+    }
+
+    public static boolean isCrud(String tplCategory)
+    {
+        return tplCategory != null && StringUtils.equals(GenConstants.TPL_CRUD, tplCategory);
+    }
+
+    public boolean isSuperColumn(String javaField)
+    {
+        return isSuperColumn(this.tplCategory, javaField);
+    }
+
+    public static boolean isSuperColumn(String tplCategory, String javaField)
+    {
+        if (isTree(tplCategory))
+        {
+            return StringUtils.equalsAnyIgnoreCase(javaField,
+                    ArrayUtils.addAll(GenConstants.TREE_ENTITY, GenConstants.BASE_ENTITY));
+        }
+        return StringUtils.equalsAnyIgnoreCase(javaField, GenConstants.BASE_ENTITY);
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTableColumn.java
similarity index 93%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTableColumn.java
index 9140d4da..8d0e1648 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/domain/GenTableColumn.java
@@ -1,373 +1,373 @@
-package com.ruoyi.generator.domain;
-
-import javax.validation.constraints.NotBlank;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 代码生成业务字段表 gen_table_column
- * 
- * @author ruoyi
- */
-public class GenTableColumn extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 编号 */
-    private Long columnId;
-
-    /** 归属表编号 */
-    private Long tableId;
-
-    /** 列名称 */
-    private String columnName;
-
-    /** 列描述 */
-    private String columnComment;
-
-    /** 列类型 */
-    private String columnType;
-
-    /** JAVA类型 */
-    private String javaType;
-
-    /** JAVA字段名 */
-    @NotBlank(message = "Java属性不能为空")
-    private String javaField;
-
-    /** 是否主键(1是) */
-    private String isPk;
-
-    /** 是否自增(1是) */
-    private String isIncrement;
-
-    /** 是否必填(1是) */
-    private String isRequired;
-
-    /** 是否为插入字段(1是) */
-    private String isInsert;
-
-    /** 是否编辑字段(1是) */
-    private String isEdit;
-
-    /** 是否列表字段(1是) */
-    private String isList;
-
-    /** 是否查询字段(1是) */
-    private String isQuery;
-
-    /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */
-    private String queryType;
-
-    /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) */
-    private String htmlType;
-
-    /** 字典类型 */
-    private String dictType;
-
-    /** 排序 */
-    private Integer sort;
-
-    public void setColumnId(Long columnId)
-    {
-        this.columnId = columnId;
-    }
-
-    public Long getColumnId()
-    {
-        return columnId;
-    }
-
-    public void setTableId(Long tableId)
-    {
-        this.tableId = tableId;
-    }
-
-    public Long getTableId()
-    {
-        return tableId;
-    }
-
-    public void setColumnName(String columnName)
-    {
-        this.columnName = columnName;
-    }
-
-    public String getColumnName()
-    {
-        return columnName;
-    }
-
-    public void setColumnComment(String columnComment)
-    {
-        this.columnComment = columnComment;
-    }
-
-    public String getColumnComment()
-    {
-        return columnComment;
-    }
-
-    public void setColumnType(String columnType)
-    {
-        this.columnType = columnType;
-    }
-
-    public String getColumnType()
-    {
-        return columnType;
-    }
-
-    public void setJavaType(String javaType)
-    {
-        this.javaType = javaType;
-    }
-
-    public String getJavaType()
-    {
-        return javaType;
-    }
-
-    public void setJavaField(String javaField)
-    {
-        this.javaField = javaField;
-    }
-
-    public String getJavaField()
-    {
-        return javaField;
-    }
-
-    public String getCapJavaField()
-    {
-        return StringUtils.capitalize(javaField);
-    }
-
-    public void setIsPk(String isPk)
-    {
-        this.isPk = isPk;
-    }
-
-    public String getIsPk()
-    {
-        return isPk;
-    }
-
-    public boolean isPk()
-    {
-        return isPk(this.isPk);
-    }
-
-    public boolean isPk(String isPk)
-    {
-        return isPk != null && StringUtils.equals("1", isPk);
-    }
-
-    public String getIsIncrement()
-    {
-        return isIncrement;
-    }
-
-    public void setIsIncrement(String isIncrement)
-    {
-        this.isIncrement = isIncrement;
-    }
-
-    public boolean isIncrement()
-    {
-        return isIncrement(this.isIncrement);
-    }
-
-    public boolean isIncrement(String isIncrement)
-    {
-        return isIncrement != null && StringUtils.equals("1", isIncrement);
-    }
-
-    public void setIsRequired(String isRequired)
-    {
-        this.isRequired = isRequired;
-    }
-
-    public String getIsRequired()
-    {
-        return isRequired;
-    }
-
-    public boolean isRequired()
-    {
-        return isRequired(this.isRequired);
-    }
-
-    public boolean isRequired(String isRequired)
-    {
-        return isRequired != null && StringUtils.equals("1", isRequired);
-    }
-
-    public void setIsInsert(String isInsert)
-    {
-        this.isInsert = isInsert;
-    }
-
-    public String getIsInsert()
-    {
-        return isInsert;
-    }
-
-    public boolean isInsert()
-    {
-        return isInsert(this.isInsert);
-    }
-
-    public boolean isInsert(String isInsert)
-    {
-        return isInsert != null && StringUtils.equals("1", isInsert);
-    }
-
-    public void setIsEdit(String isEdit)
-    {
-        this.isEdit = isEdit;
-    }
-
-    public String getIsEdit()
-    {
-        return isEdit;
-    }
-
-    public boolean isEdit()
-    {
-        return isInsert(this.isEdit);
-    }
-
-    public boolean isEdit(String isEdit)
-    {
-        return isEdit != null && StringUtils.equals("1", isEdit);
-    }
-
-    public void setIsList(String isList)
-    {
-        this.isList = isList;
-    }
-
-    public String getIsList()
-    {
-        return isList;
-    }
-
-    public boolean isList()
-    {
-        return isList(this.isList);
-    }
-
-    public boolean isList(String isList)
-    {
-        return isList != null && StringUtils.equals("1", isList);
-    }
-
-    public void setIsQuery(String isQuery)
-    {
-        this.isQuery = isQuery;
-    }
-
-    public String getIsQuery()
-    {
-        return isQuery;
-    }
-
-    public boolean isQuery()
-    {
-        return isQuery(this.isQuery);
-    }
-
-    public boolean isQuery(String isQuery)
-    {
-        return isQuery != null && StringUtils.equals("1", isQuery);
-    }
-
-    public void setQueryType(String queryType)
-    {
-        this.queryType = queryType;
-    }
-
-    public String getQueryType()
-    {
-        return queryType;
-    }
-
-    public String getHtmlType()
-    {
-        return htmlType;
-    }
-
-    public void setHtmlType(String htmlType)
-    {
-        this.htmlType = htmlType;
-    }
-
-    public void setDictType(String dictType)
-    {
-        this.dictType = dictType;
-    }
-
-    public String getDictType()
-    {
-        return dictType;
-    }
-
-    public void setSort(Integer sort)
-    {
-        this.sort = sort;
-    }
-
-    public Integer getSort()
-    {
-        return sort;
-    }
-
-    public boolean isSuperColumn()
-    {
-        return isSuperColumn(this.javaField);
-    }
-
-    public static boolean isSuperColumn(String javaField)
-    {
-        return StringUtils.equalsAnyIgnoreCase(javaField,
-                // BaseEntity
-                "createBy", "createTime", "updateBy", "updateTime", "remark",
-                // TreeEntity
-                "parentName", "parentId", "orderNum", "ancestors");
-    }
-
-    public boolean isUsableColumn()
-    {
-        return isUsableColumn(javaField);
-    }
-
-    public static boolean isUsableColumn(String javaField)
-    {
-        // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
-        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
-    }
-
-    public String readConverterExp()
-    {
-        String remarks = StringUtils.substringBetween(this.columnComment, "(", ")");
-        StringBuffer sb = new StringBuffer();
-        if (StringUtils.isNotEmpty(remarks))
-        {
-            for (String value : remarks.split(" "))
-            {
-                if (StringUtils.isNotEmpty(value))
-                {
-                    Object startStr = value.subSequence(0, 1);
-                    String endStr = value.substring(1);
-                    sb.append("").append(startStr).append("=").append(endStr).append(",");
-                }
-            }
-            return sb.deleteCharAt(sb.length() - 1).toString();
-        }
-        else
-        {
-            return this.columnComment;
-        }
-    }
-}
+package com.acupuncture.generator.domain;
+
+import javax.validation.constraints.NotBlank;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 代码生成业务字段表 gen_table_column
+ * 
+ * @author acupuncture
+ */
+public class GenTableColumn extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 编号 */
+    private Long columnId;
+
+    /** 归属表编号 */
+    private Long tableId;
+
+    /** 列名称 */
+    private String columnName;
+
+    /** 列描述 */
+    private String columnComment;
+
+    /** 列类型 */
+    private String columnType;
+
+    /** JAVA类型 */
+    private String javaType;
+
+    /** JAVA字段名 */
+    @NotBlank(message = "Java属性不能为空")
+    private String javaField;
+
+    /** 是否主键(1是) */
+    private String isPk;
+
+    /** 是否自增(1是) */
+    private String isIncrement;
+
+    /** 是否必填(1是) */
+    private String isRequired;
+
+    /** 是否为插入字段(1是) */
+    private String isInsert;
+
+    /** 是否编辑字段(1是) */
+    private String isEdit;
+
+    /** 是否列表字段(1是) */
+    private String isList;
+
+    /** 是否查询字段(1是) */
+    private String isQuery;
+
+    /** 查询方式(EQ等于、NE不等于、GT大于、LT小于、LIKE模糊、BETWEEN范围) */
+    private String queryType;
+
+    /** 显示类型(input文本框、textarea文本域、select下拉框、checkbox复选框、radio单选框、datetime日期控件、image图片上传控件、upload文件上传控件、editor富文本控件) */
+    private String htmlType;
+
+    /** 字典类型 */
+    private String dictType;
+
+    /** 排序 */
+    private Integer sort;
+
+    public void setColumnId(Long columnId)
+    {
+        this.columnId = columnId;
+    }
+
+    public Long getColumnId()
+    {
+        return columnId;
+    }
+
+    public void setTableId(Long tableId)
+    {
+        this.tableId = tableId;
+    }
+
+    public Long getTableId()
+    {
+        return tableId;
+    }
+
+    public void setColumnName(String columnName)
+    {
+        this.columnName = columnName;
+    }
+
+    public String getColumnName()
+    {
+        return columnName;
+    }
+
+    public void setColumnComment(String columnComment)
+    {
+        this.columnComment = columnComment;
+    }
+
+    public String getColumnComment()
+    {
+        return columnComment;
+    }
+
+    public void setColumnType(String columnType)
+    {
+        this.columnType = columnType;
+    }
+
+    public String getColumnType()
+    {
+        return columnType;
+    }
+
+    public void setJavaType(String javaType)
+    {
+        this.javaType = javaType;
+    }
+
+    public String getJavaType()
+    {
+        return javaType;
+    }
+
+    public void setJavaField(String javaField)
+    {
+        this.javaField = javaField;
+    }
+
+    public String getJavaField()
+    {
+        return javaField;
+    }
+
+    public String getCapJavaField()
+    {
+        return StringUtils.capitalize(javaField);
+    }
+
+    public void setIsPk(String isPk)
+    {
+        this.isPk = isPk;
+    }
+
+    public String getIsPk()
+    {
+        return isPk;
+    }
+
+    public boolean isPk()
+    {
+        return isPk(this.isPk);
+    }
+
+    public boolean isPk(String isPk)
+    {
+        return isPk != null && StringUtils.equals("1", isPk);
+    }
+
+    public String getIsIncrement()
+    {
+        return isIncrement;
+    }
+
+    public void setIsIncrement(String isIncrement)
+    {
+        this.isIncrement = isIncrement;
+    }
+
+    public boolean isIncrement()
+    {
+        return isIncrement(this.isIncrement);
+    }
+
+    public boolean isIncrement(String isIncrement)
+    {
+        return isIncrement != null && StringUtils.equals("1", isIncrement);
+    }
+
+    public void setIsRequired(String isRequired)
+    {
+        this.isRequired = isRequired;
+    }
+
+    public String getIsRequired()
+    {
+        return isRequired;
+    }
+
+    public boolean isRequired()
+    {
+        return isRequired(this.isRequired);
+    }
+
+    public boolean isRequired(String isRequired)
+    {
+        return isRequired != null && StringUtils.equals("1", isRequired);
+    }
+
+    public void setIsInsert(String isInsert)
+    {
+        this.isInsert = isInsert;
+    }
+
+    public String getIsInsert()
+    {
+        return isInsert;
+    }
+
+    public boolean isInsert()
+    {
+        return isInsert(this.isInsert);
+    }
+
+    public boolean isInsert(String isInsert)
+    {
+        return isInsert != null && StringUtils.equals("1", isInsert);
+    }
+
+    public void setIsEdit(String isEdit)
+    {
+        this.isEdit = isEdit;
+    }
+
+    public String getIsEdit()
+    {
+        return isEdit;
+    }
+
+    public boolean isEdit()
+    {
+        return isInsert(this.isEdit);
+    }
+
+    public boolean isEdit(String isEdit)
+    {
+        return isEdit != null && StringUtils.equals("1", isEdit);
+    }
+
+    public void setIsList(String isList)
+    {
+        this.isList = isList;
+    }
+
+    public String getIsList()
+    {
+        return isList;
+    }
+
+    public boolean isList()
+    {
+        return isList(this.isList);
+    }
+
+    public boolean isList(String isList)
+    {
+        return isList != null && StringUtils.equals("1", isList);
+    }
+
+    public void setIsQuery(String isQuery)
+    {
+        this.isQuery = isQuery;
+    }
+
+    public String getIsQuery()
+    {
+        return isQuery;
+    }
+
+    public boolean isQuery()
+    {
+        return isQuery(this.isQuery);
+    }
+
+    public boolean isQuery(String isQuery)
+    {
+        return isQuery != null && StringUtils.equals("1", isQuery);
+    }
+
+    public void setQueryType(String queryType)
+    {
+        this.queryType = queryType;
+    }
+
+    public String getQueryType()
+    {
+        return queryType;
+    }
+
+    public String getHtmlType()
+    {
+        return htmlType;
+    }
+
+    public void setHtmlType(String htmlType)
+    {
+        this.htmlType = htmlType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setSort(Integer sort)
+    {
+        this.sort = sort;
+    }
+
+    public Integer getSort()
+    {
+        return sort;
+    }
+
+    public boolean isSuperColumn()
+    {
+        return isSuperColumn(this.javaField);
+    }
+
+    public static boolean isSuperColumn(String javaField)
+    {
+        return StringUtils.equalsAnyIgnoreCase(javaField,
+                // BaseEntity
+                "createBy", "createTime", "updateBy", "updateTime", "remark",
+                // TreeEntity
+                "parentName", "parentId", "orderNum", "ancestors");
+    }
+
+    public boolean isUsableColumn()
+    {
+        return isUsableColumn(javaField);
+    }
+
+    public static boolean isUsableColumn(String javaField)
+    {
+        // isSuperColumn()中的名单用于避免生成多余Domain属性,若某些属性在生成页面时需要用到不能忽略,则放在此处白名单
+        return StringUtils.equalsAnyIgnoreCase(javaField, "parentId", "orderNum", "remark");
+    }
+
+    public String readConverterExp()
+    {
+        String remarks = StringUtils.substringBetween(this.columnComment, "(", ")");
+        StringBuffer sb = new StringBuffer();
+        if (StringUtils.isNotEmpty(remarks))
+        {
+            for (String value : remarks.split(" "))
+            {
+                if (StringUtils.isNotEmpty(value))
+                {
+                    Object startStr = value.subSequence(0, 1);
+                    String endStr = value.substring(1);
+                    sb.append("").append(startStr).append("=").append(endStr).append(",");
+                }
+            }
+            return sb.deleteCharAt(sb.length() - 1).toString();
+        }
+        else
+        {
+            return this.columnComment;
+        }
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableColumnMapper.java
similarity index 88%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableColumnMapper.java
index 0dc34289..62a8b0e6 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableColumnMapper.java
@@ -1,60 +1,60 @@
-package com.ruoyi.generator.mapper;
-
-import java.util.List;
-import com.ruoyi.generator.domain.GenTableColumn;
-
-/**
- * 业务字段 数据层
- * 
- * @author ruoyi
- */
-public interface GenTableColumnMapper
-{
-    /**
-     * 根据表名称查询列信息
-     * 
-     * @param tableName 表名称
-     * @return 列信息
-     */
-    public List<GenTableColumn> selectDbTableColumnsByName(String tableName);
-
-    /**
-     * 查询业务字段列表
-     * 
-     * @param tableId 业务字段编号
-     * @return 业务字段集合
-     */
-    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
-
-    /**
-     * 新增业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-    public int insertGenTableColumn(GenTableColumn genTableColumn);
-
-    /**
-     * 修改业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-    public int updateGenTableColumn(GenTableColumn genTableColumn);
-
-    /**
-     * 删除业务字段
-     * 
-     * @param genTableColumns 列数据
-     * @return 结果
-     */
-    public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);
-
-    /**
-     * 批量删除业务字段
-     * 
-     * @param ids 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteGenTableColumnByIds(Long[] ids);
-}
+package com.acupuncture.generator.mapper;
+
+import java.util.List;
+import com.acupuncture.generator.domain.GenTableColumn;
+
+/**
+ * 业务字段 数据层
+ * 
+ * @author acupuncture
+ */
+public interface GenTableColumnMapper
+{
+    /**
+     * 根据表名称查询列信息
+     * 
+     * @param tableName 表名称
+     * @return 列信息
+     */
+    public List<GenTableColumn> selectDbTableColumnsByName(String tableName);
+
+    /**
+     * 查询业务字段列表
+     * 
+     * @param tableId 业务字段编号
+     * @return 业务字段集合
+     */
+    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+    /**
+     * 新增业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+    public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 修改业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+    public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 删除业务字段
+     * 
+     * @param genTableColumns 列数据
+     * @return 结果
+     */
+    public int deleteGenTableColumns(List<GenTableColumn> genTableColumns);
+
+    /**
+     * 批量删除业务字段
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteGenTableColumnByIds(Long[] ids);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableMapper.java
similarity index 90%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableMapper.java
index a5ce3c60..d09c3b1f 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/mapper/GenTableMapper.java
@@ -1,91 +1,91 @@
-package com.ruoyi.generator.mapper;
-
-import java.util.List;
-import com.ruoyi.generator.domain.GenTable;
-
-/**
- * 业务 数据层
- * 
- * @author ruoyi
- */
-public interface GenTableMapper
-{
-    /**
-     * 查询业务列表
-     * 
-     * @param genTable 业务信息
-     * @return 业务集合
-     */
-    public List<GenTable> selectGenTableList(GenTable genTable);
-
-    /**
-     * 查询据库列表
-     * 
-     * @param genTable 业务信息
-     * @return 数据库表集合
-     */
-    public List<GenTable> selectDbTableList(GenTable genTable);
-
-    /**
-     * 查询据库列表
-     * 
-     * @param tableNames 表名称组
-     * @return 数据库表集合
-     */
-    public List<GenTable> selectDbTableListByNames(String[] tableNames);
-
-    /**
-     * 查询所有表信息
-     * 
-     * @return 表信息集合
-     */
-    public List<GenTable> selectGenTableAll();
-
-    /**
-     * 查询表ID业务信息
-     * 
-     * @param id 业务ID
-     * @return 业务信息
-     */
-    public GenTable selectGenTableById(Long id);
-
-    /**
-     * 查询表名称业务信息
-     * 
-     * @param tableName 表名称
-     * @return 业务信息
-     */
-    public GenTable selectGenTableByName(String tableName);
-
-    /**
-     * 新增业务
-     * 
-     * @param genTable 业务信息
-     * @return 结果
-     */
-    public int insertGenTable(GenTable genTable);
-
-    /**
-     * 修改业务
-     * 
-     * @param genTable 业务信息
-     * @return 结果
-     */
-    public int updateGenTable(GenTable genTable);
-
-    /**
-     * 批量删除业务
-     * 
-     * @param ids 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteGenTableByIds(Long[] ids);
-
-    /**
-     * 创建表
-     *
-     * @param sql 表结构
-     * @return 结果
-     */
-    public int createTable(String sql);
-}
+package com.acupuncture.generator.mapper;
+
+import java.util.List;
+import com.acupuncture.generator.domain.GenTable;
+
+/**
+ * 业务 数据层
+ * 
+ * @author acupuncture
+ */
+public interface GenTableMapper
+{
+    /**
+     * 查询业务列表
+     * 
+     * @param genTable 业务信息
+     * @return 业务集合
+     */
+    public List<GenTable> selectGenTableList(GenTable genTable);
+
+    /**
+     * 查询据库列表
+     * 
+     * @param genTable 业务信息
+     * @return 数据库表集合
+     */
+    public List<GenTable> selectDbTableList(GenTable genTable);
+
+    /**
+     * 查询据库列表
+     * 
+     * @param tableNames 表名称组
+     * @return 数据库表集合
+     */
+    public List<GenTable> selectDbTableListByNames(String[] tableNames);
+
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    public List<GenTable> selectGenTableAll();
+
+    /**
+     * 查询表ID业务信息
+     * 
+     * @param id 业务ID
+     * @return 业务信息
+     */
+    public GenTable selectGenTableById(Long id);
+
+    /**
+     * 查询表名称业务信息
+     * 
+     * @param tableName 表名称
+     * @return 业务信息
+     */
+    public GenTable selectGenTableByName(String tableName);
+
+    /**
+     * 新增业务
+     * 
+     * @param genTable 业务信息
+     * @return 结果
+     */
+    public int insertGenTable(GenTable genTable);
+
+    /**
+     * 修改业务
+     * 
+     * @param genTable 业务信息
+     * @return 结果
+     */
+    public int updateGenTable(GenTable genTable);
+
+    /**
+     * 批量删除业务
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteGenTableByIds(Long[] ids);
+
+    /**
+     * 创建表
+     *
+     * @param sql 表结构
+     * @return 结果
+     */
+    public int createTable(String sql);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableColumnServiceImpl.java
similarity index 84%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableColumnServiceImpl.java
index 3a2d66a5..a40a36bd 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableColumnServiceImpl.java
@@ -1,68 +1,68 @@
-package com.ruoyi.generator.service;
-
-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.generator.domain.GenTableColumn;
-import com.ruoyi.generator.mapper.GenTableColumnMapper;
-
-/**
- * 业务字段 服务层实现
- * 
- * @author ruoyi
- */
-@Service
-public class GenTableColumnServiceImpl implements IGenTableColumnService 
-{
-	@Autowired
-	private GenTableColumnMapper genTableColumnMapper;
-
-	/**
-     * 查询业务字段列表
-     * 
-     * @param tableId 业务字段编号
-     * @return 业务字段集合
-     */
-	@Override
-	public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId)
-	{
-	    return genTableColumnMapper.selectGenTableColumnListByTableId(tableId);
-	}
-	
-    /**
-     * 新增业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-	@Override
-	public int insertGenTableColumn(GenTableColumn genTableColumn)
-	{
-	    return genTableColumnMapper.insertGenTableColumn(genTableColumn);
-	}
-	
-	/**
-     * 修改业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-	@Override
-	public int updateGenTableColumn(GenTableColumn genTableColumn)
-	{
-	    return genTableColumnMapper.updateGenTableColumn(genTableColumn);
-	}
-
-	/**
-     * 删除业务字段对象
-     * 
-     * @param ids 需要删除的数据ID
-     * @return 结果
-     */
-	@Override
-	public int deleteGenTableColumnByIds(String ids)
-	{
-		return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
-	}
-}
+package com.acupuncture.generator.service;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.generator.domain.GenTableColumn;
+import com.acupuncture.generator.mapper.GenTableColumnMapper;
+
+/**
+ * 业务字段 服务层实现
+ * 
+ * @author acupuncture
+ */
+@Service
+public class GenTableColumnServiceImpl implements IGenTableColumnService 
+{
+	@Autowired
+	private GenTableColumnMapper genTableColumnMapper;
+
+	/**
+     * 查询业务字段列表
+     * 
+     * @param tableId 业务字段编号
+     * @return 业务字段集合
+     */
+	@Override
+	public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId)
+	{
+	    return genTableColumnMapper.selectGenTableColumnListByTableId(tableId);
+	}
+	
+    /**
+     * 新增业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+	@Override
+	public int insertGenTableColumn(GenTableColumn genTableColumn)
+	{
+	    return genTableColumnMapper.insertGenTableColumn(genTableColumn);
+	}
+	
+	/**
+     * 修改业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+	@Override
+	public int updateGenTableColumn(GenTableColumn genTableColumn)
+	{
+	    return genTableColumnMapper.updateGenTableColumn(genTableColumn);
+	}
+
+	/**
+     * 删除业务字段对象
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+	@Override
+	public int deleteGenTableColumnByIds(String ids)
+	{
+		return genTableColumnMapper.deleteGenTableColumnByIds(Convert.toLongArray(ids));
+	}
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableServiceImpl.java
similarity index 93%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableServiceImpl.java
index 99a837aa..d90aa4b5 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/GenTableServiceImpl.java
@@ -1,531 +1,531 @@
-package com.ruoyi.generator.service;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.IOException;
-import java.io.StringWriter;
-import java.util.LinkedHashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.function.Function;
-import java.util.stream.Collectors;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
-import org.apache.commons.io.FileUtils;
-import org.apache.commons.io.IOUtils;
-import org.apache.velocity.Template;
-import org.apache.velocity.VelocityContext;
-import org.apache.velocity.app.Velocity;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.GenConstants;
-import com.ruoyi.common.core.text.CharsetKit;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.generator.domain.GenTable;
-import com.ruoyi.generator.domain.GenTableColumn;
-import com.ruoyi.generator.mapper.GenTableColumnMapper;
-import com.ruoyi.generator.mapper.GenTableMapper;
-import com.ruoyi.generator.util.GenUtils;
-import com.ruoyi.generator.util.VelocityInitializer;
-import com.ruoyi.generator.util.VelocityUtils;
-
-/**
- * 业务 服务层实现
- * 
- * @author ruoyi
- */
-@Service
-public class GenTableServiceImpl implements IGenTableService
-{
-    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
-
-    @Autowired
-    private GenTableMapper genTableMapper;
-
-    @Autowired
-    private GenTableColumnMapper genTableColumnMapper;
-
-    /**
-     * 查询业务信息
-     * 
-     * @param id 业务ID
-     * @return 业务信息
-     */
-    @Override
-    public GenTable selectGenTableById(Long id)
-    {
-        GenTable genTable = genTableMapper.selectGenTableById(id);
-        setTableFromOptions(genTable);
-        return genTable;
-    }
-
-    /**
-     * 查询业务列表
-     * 
-     * @param genTable 业务信息
-     * @return 业务集合
-     */
-    @Override
-    public List<GenTable> selectGenTableList(GenTable genTable)
-    {
-        return genTableMapper.selectGenTableList(genTable);
-    }
-
-    /**
-     * 查询据库列表
-     * 
-     * @param genTable 业务信息
-     * @return 数据库表集合
-     */
-    @Override
-    public List<GenTable> selectDbTableList(GenTable genTable)
-    {
-        return genTableMapper.selectDbTableList(genTable);
-    }
-
-    /**
-     * 查询据库列表
-     * 
-     * @param tableNames 表名称组
-     * @return 数据库表集合
-     */
-    @Override
-    public List<GenTable> selectDbTableListByNames(String[] tableNames)
-    {
-        return genTableMapper.selectDbTableListByNames(tableNames);
-    }
-
-    /**
-     * 查询所有表信息
-     * 
-     * @return 表信息集合
-     */
-    @Override
-    public List<GenTable> selectGenTableAll()
-    {
-        return genTableMapper.selectGenTableAll();
-    }
-
-    /**
-     * 修改业务
-     * 
-     * @param genTable 业务信息
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public void updateGenTable(GenTable genTable)
-    {
-        String options = JSON.toJSONString(genTable.getParams());
-        genTable.setOptions(options);
-        int row = genTableMapper.updateGenTable(genTable);
-        if (row > 0)
-        {
-            for (GenTableColumn cenTableColumn : genTable.getColumns())
-            {
-                genTableColumnMapper.updateGenTableColumn(cenTableColumn);
-            }
-        }
-    }
-
-    /**
-     * 删除业务对象
-     * 
-     * @param tableIds 需要删除的数据ID
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public void deleteGenTableByIds(Long[] tableIds)
-    {
-        genTableMapper.deleteGenTableByIds(tableIds);
-        genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
-    }
-
-    /**
-     * 创建表
-     *
-     * @param sql 创建表语句
-     * @return 结果
-     */
-    @Override
-    public boolean createTable(String sql)
-    {
-        return genTableMapper.createTable(sql) == 0;
-    }
-
-    /**
-     * 导入表结构
-     * 
-     * @param tableList 导入表列表
-     */
-    @Override
-    @Transactional
-    public void importGenTable(List<GenTable> tableList, String operName)
-    {
-        try
-        {
-            for (GenTable table : tableList)
-            {
-                String tableName = table.getTableName();
-                GenUtils.initTable(table, operName);
-                int row = genTableMapper.insertGenTable(table);
-                if (row > 0)
-                {
-                    // 保存列信息
-                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
-                    for (GenTableColumn column : genTableColumns)
-                    {
-                        GenUtils.initColumnField(column, table);
-                        genTableColumnMapper.insertGenTableColumn(column);
-                    }
-                }
-            }
-        }
-        catch (Exception e)
-        {
-            throw new ServiceException("导入失败:" + e.getMessage());
-        }
-    }
-
-    /**
-     * 预览代码
-     * 
-     * @param tableId 表编号
-     * @return 预览数据列表
-     */
-    @Override
-    public Map<String, String> previewCode(Long tableId)
-    {
-        Map<String, String> dataMap = new LinkedHashMap<>();
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableById(tableId);
-        // 设置主子表信息
-        setSubTable(table);
-        // 设置主键列信息
-        setPkColumn(table);
-        VelocityInitializer.initVelocity();
-
-        VelocityContext context = VelocityUtils.prepareContext(table);
-
-        // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
-        for (String template : templates)
-        {
-            // 渲染模板
-            StringWriter sw = new StringWriter();
-            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
-            tpl.merge(context, sw);
-            dataMap.put(template, sw.toString());
-        }
-        return dataMap;
-    }
-
-    /**
-     * 生成代码(下载方式)
-     * 
-     * @param tableName 表名称
-     * @return 数据
-     */
-    @Override
-    public byte[] downloadCode(String tableName)
-    {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        ZipOutputStream zip = new ZipOutputStream(outputStream);
-        generatorCode(tableName, zip);
-        IOUtils.closeQuietly(zip);
-        return outputStream.toByteArray();
-    }
-
-    /**
-     * 生成代码(自定义路径)
-     * 
-     * @param tableName 表名称
-     */
-    @Override
-    public void generatorCode(String tableName)
-    {
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableByName(tableName);
-        // 设置主子表信息
-        setSubTable(table);
-        // 设置主键列信息
-        setPkColumn(table);
-
-        VelocityInitializer.initVelocity();
-
-        VelocityContext context = VelocityUtils.prepareContext(table);
-
-        // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
-        for (String template : templates)
-        {
-            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
-            {
-                // 渲染模板
-                StringWriter sw = new StringWriter();
-                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
-                tpl.merge(context, sw);
-                try
-                {
-                    String path = getGenPath(table, template);
-                    FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
-                }
-                catch (IOException e)
-                {
-                    throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
-                }
-            }
-        }
-    }
-
-    /**
-     * 同步数据库
-     * 
-     * @param tableName 表名称
-     */
-    @Override
-    @Transactional
-    public void synchDb(String tableName)
-    {
-        GenTable table = genTableMapper.selectGenTableByName(tableName);
-        List<GenTableColumn> tableColumns = table.getColumns();
-        Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
-
-        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
-        if (StringUtils.isEmpty(dbTableColumns))
-        {
-            throw new ServiceException("同步数据失败,原表结构不存在");
-        }
-        List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
-
-        dbTableColumns.forEach(column -> {
-            GenUtils.initColumnField(column, table);
-            if (tableColumnMap.containsKey(column.getColumnName()))
-            {
-                GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
-                column.setColumnId(prevColumn.getColumnId());
-                if (column.isList())
-                {
-                    // 如果是列表,继续保留查询方式/字典类型选项
-                    column.setDictType(prevColumn.getDictType());
-                    column.setQueryType(prevColumn.getQueryType());
-                }
-                if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
-                        && (column.isInsert() || column.isEdit())
-                        && ((column.isUsableColumn()) || (!column.isSuperColumn())))
-                {
-                    // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
-                    column.setIsRequired(prevColumn.getIsRequired());
-                    column.setHtmlType(prevColumn.getHtmlType());
-                }
-                genTableColumnMapper.updateGenTableColumn(column);
-            }
-            else
-            {
-                genTableColumnMapper.insertGenTableColumn(column);
-            }
-        });
-
-        List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
-        if (StringUtils.isNotEmpty(delColumns))
-        {
-            genTableColumnMapper.deleteGenTableColumns(delColumns);
-        }
-    }
-
-    /**
-     * 批量生成代码(下载方式)
-     * 
-     * @param tableNames 表数组
-     * @return 数据
-     */
-    @Override
-    public byte[] downloadCode(String[] tableNames)
-    {
-        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
-        ZipOutputStream zip = new ZipOutputStream(outputStream);
-        for (String tableName : tableNames)
-        {
-            generatorCode(tableName, zip);
-        }
-        IOUtils.closeQuietly(zip);
-        return outputStream.toByteArray();
-    }
-
-    /**
-     * 查询表信息并生成代码
-     */
-    private void generatorCode(String tableName, ZipOutputStream zip)
-    {
-        // 查询表信息
-        GenTable table = genTableMapper.selectGenTableByName(tableName);
-        // 设置主子表信息
-        setSubTable(table);
-        // 设置主键列信息
-        setPkColumn(table);
-
-        VelocityInitializer.initVelocity();
-
-        VelocityContext context = VelocityUtils.prepareContext(table);
-
-        // 获取模板列表
-        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
-        for (String template : templates)
-        {
-            // 渲染模板
-            StringWriter sw = new StringWriter();
-            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
-            tpl.merge(context, sw);
-            try
-            {
-                // 添加到zip
-                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
-                IOUtils.write(sw.toString(), zip, Constants.UTF8);
-                IOUtils.closeQuietly(sw);
-                zip.flush();
-                zip.closeEntry();
-            }
-            catch (IOException e)
-            {
-                log.error("渲染模板失败,表名:" + table.getTableName(), e);
-            }
-        }
-    }
-
-    /**
-     * 修改保存参数校验
-     * 
-     * @param genTable 业务信息
-     */
-    @Override
-    public void validateEdit(GenTable genTable)
-    {
-        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
-        {
-            String options = JSON.toJSONString(genTable.getParams());
-            JSONObject paramsObj = JSON.parseObject(options);
-            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
-            {
-                throw new ServiceException("树编码字段不能为空");
-            }
-            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
-            {
-                throw new ServiceException("树父编码字段不能为空");
-            }
-            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
-            {
-                throw new ServiceException("树名称字段不能为空");
-            }
-            else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
-            {
-                if (StringUtils.isEmpty(genTable.getSubTableName()))
-                {
-                    throw new ServiceException("关联子表的表名不能为空");
-                }
-                else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
-                {
-                    throw new ServiceException("子表关联的外键名不能为空");
-                }
-            }
-        }
-    }
-
-    /**
-     * 设置主键列信息
-     * 
-     * @param table 业务表信息
-     */
-    public void setPkColumn(GenTable table)
-    {
-        for (GenTableColumn column : table.getColumns())
-        {
-            if (column.isPk())
-            {
-                table.setPkColumn(column);
-                break;
-            }
-        }
-        if (StringUtils.isNull(table.getPkColumn()))
-        {
-            table.setPkColumn(table.getColumns().get(0));
-        }
-        if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
-        {
-            for (GenTableColumn column : table.getSubTable().getColumns())
-            {
-                if (column.isPk())
-                {
-                    table.getSubTable().setPkColumn(column);
-                    break;
-                }
-            }
-            if (StringUtils.isNull(table.getSubTable().getPkColumn()))
-            {
-                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
-            }
-        }
-    }
-
-    /**
-     * 设置主子表信息
-     * 
-     * @param table 业务表信息
-     */
-    public void setSubTable(GenTable table)
-    {
-        String subTableName = table.getSubTableName();
-        if (StringUtils.isNotEmpty(subTableName))
-        {
-            table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
-        }
-    }
-
-    /**
-     * 设置代码生成其他选项值
-     * 
-     * @param genTable 设置后的生成对象
-     */
-    public void setTableFromOptions(GenTable genTable)
-    {
-        JSONObject paramsObj = JSON.parseObject(genTable.getOptions());
-        if (StringUtils.isNotNull(paramsObj))
-        {
-            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
-            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
-            String treeName = paramsObj.getString(GenConstants.TREE_NAME);
-            Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID);
-            String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
-
-            genTable.setTreeCode(treeCode);
-            genTable.setTreeParentCode(treeParentCode);
-            genTable.setTreeName(treeName);
-            genTable.setParentMenuId(parentMenuId);
-            genTable.setParentMenuName(parentMenuName);
-        }
-    }
-
-    /**
-     * 获取代码生成地址
-     * 
-     * @param table 业务表信息
-     * @param template 模板文件路径
-     * @return 生成地址
-     */
-    public static String getGenPath(GenTable table, String template)
-    {
-        String genPath = table.getGenPath();
-        if (StringUtils.equals(genPath, "/"))
-        {
-            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
-        }
-        return genPath + File.separator + VelocityUtils.getFileName(template, table);
-    }
+package com.acupuncture.generator.service;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.IOUtils;
+import org.apache.velocity.Template;
+import org.apache.velocity.VelocityContext;
+import org.apache.velocity.app.Velocity;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.GenConstants;
+import com.acupuncture.common.core.text.CharsetKit;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.generator.domain.GenTable;
+import com.acupuncture.generator.domain.GenTableColumn;
+import com.acupuncture.generator.mapper.GenTableColumnMapper;
+import com.acupuncture.generator.mapper.GenTableMapper;
+import com.acupuncture.generator.util.GenUtils;
+import com.acupuncture.generator.util.VelocityInitializer;
+import com.acupuncture.generator.util.VelocityUtils;
+
+/**
+ * 业务 服务层实现
+ * 
+ * @author acupuncture
+ */
+@Service
+public class GenTableServiceImpl implements IGenTableService
+{
+    private static final Logger log = LoggerFactory.getLogger(GenTableServiceImpl.class);
+
+    @Autowired
+    private GenTableMapper genTableMapper;
+
+    @Autowired
+    private GenTableColumnMapper genTableColumnMapper;
+
+    /**
+     * 查询业务信息
+     * 
+     * @param id 业务ID
+     * @return 业务信息
+     */
+    @Override
+    public GenTable selectGenTableById(Long id)
+    {
+        GenTable genTable = genTableMapper.selectGenTableById(id);
+        setTableFromOptions(genTable);
+        return genTable;
+    }
+
+    /**
+     * 查询业务列表
+     * 
+     * @param genTable 业务信息
+     * @return 业务集合
+     */
+    @Override
+    public List<GenTable> selectGenTableList(GenTable genTable)
+    {
+        return genTableMapper.selectGenTableList(genTable);
+    }
+
+    /**
+     * 查询据库列表
+     * 
+     * @param genTable 业务信息
+     * @return 数据库表集合
+     */
+    @Override
+    public List<GenTable> selectDbTableList(GenTable genTable)
+    {
+        return genTableMapper.selectDbTableList(genTable);
+    }
+
+    /**
+     * 查询据库列表
+     * 
+     * @param tableNames 表名称组
+     * @return 数据库表集合
+     */
+    @Override
+    public List<GenTable> selectDbTableListByNames(String[] tableNames)
+    {
+        return genTableMapper.selectDbTableListByNames(tableNames);
+    }
+
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    @Override
+    public List<GenTable> selectGenTableAll()
+    {
+        return genTableMapper.selectGenTableAll();
+    }
+
+    /**
+     * 修改业务
+     * 
+     * @param genTable 业务信息
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public void updateGenTable(GenTable genTable)
+    {
+        String options = JSON.toJSONString(genTable.getParams());
+        genTable.setOptions(options);
+        int row = genTableMapper.updateGenTable(genTable);
+        if (row > 0)
+        {
+            for (GenTableColumn cenTableColumn : genTable.getColumns())
+            {
+                genTableColumnMapper.updateGenTableColumn(cenTableColumn);
+            }
+        }
+    }
+
+    /**
+     * 删除业务对象
+     * 
+     * @param tableIds 需要删除的数据ID
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public void deleteGenTableByIds(Long[] tableIds)
+    {
+        genTableMapper.deleteGenTableByIds(tableIds);
+        genTableColumnMapper.deleteGenTableColumnByIds(tableIds);
+    }
+
+    /**
+     * 创建表
+     *
+     * @param sql 创建表语句
+     * @return 结果
+     */
+    @Override
+    public boolean createTable(String sql)
+    {
+        return genTableMapper.createTable(sql) == 0;
+    }
+
+    /**
+     * 导入表结构
+     * 
+     * @param tableList 导入表列表
+     */
+    @Override
+    @Transactional
+    public void importGenTable(List<GenTable> tableList, String operName)
+    {
+        try
+        {
+            for (GenTable table : tableList)
+            {
+                String tableName = table.getTableName();
+                GenUtils.initTable(table, operName);
+                int row = genTableMapper.insertGenTable(table);
+                if (row > 0)
+                {
+                    // 保存列信息
+                    List<GenTableColumn> genTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+                    for (GenTableColumn column : genTableColumns)
+                    {
+                        GenUtils.initColumnField(column, table);
+                        genTableColumnMapper.insertGenTableColumn(column);
+                    }
+                }
+            }
+        }
+        catch (Exception e)
+        {
+            throw new ServiceException("导入失败:" + e.getMessage());
+        }
+    }
+
+    /**
+     * 预览代码
+     * 
+     * @param tableId 表编号
+     * @return 预览数据列表
+     */
+    @Override
+    public Map<String, String> previewCode(Long tableId)
+    {
+        Map<String, String> dataMap = new LinkedHashMap<>();
+        // 查询表信息
+        GenTable table = genTableMapper.selectGenTableById(tableId);
+        // 设置主子表信息
+        setSubTable(table);
+        // 设置主键列信息
+        setPkColumn(table);
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 获取模板列表
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        for (String template : templates)
+        {
+            // 渲染模板
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            dataMap.put(template, sw.toString());
+        }
+        return dataMap;
+    }
+
+    /**
+     * 生成代码(下载方式)
+     * 
+     * @param tableName 表名称
+     * @return 数据
+     */
+    @Override
+    public byte[] downloadCode(String tableName)
+    {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        generatorCode(tableName, zip);
+        IOUtils.closeQuietly(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 生成代码(自定义路径)
+     * 
+     * @param tableName 表名称
+     */
+    @Override
+    public void generatorCode(String tableName)
+    {
+        // 查询表信息
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        // 设置主子表信息
+        setSubTable(table);
+        // 设置主键列信息
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 获取模板列表
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        for (String template : templates)
+        {
+            if (!StringUtils.containsAny(template, "sql.vm", "api.js.vm", "index.vue.vm", "index-tree.vue.vm"))
+            {
+                // 渲染模板
+                StringWriter sw = new StringWriter();
+                Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+                tpl.merge(context, sw);
+                try
+                {
+                    String path = getGenPath(table, template);
+                    FileUtils.writeStringToFile(new File(path), sw.toString(), CharsetKit.UTF_8);
+                }
+                catch (IOException e)
+                {
+                    throw new ServiceException("渲染模板失败,表名:" + table.getTableName());
+                }
+            }
+        }
+    }
+
+    /**
+     * 同步数据库
+     * 
+     * @param tableName 表名称
+     */
+    @Override
+    @Transactional
+    public void synchDb(String tableName)
+    {
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        List<GenTableColumn> tableColumns = table.getColumns();
+        Map<String, GenTableColumn> tableColumnMap = tableColumns.stream().collect(Collectors.toMap(GenTableColumn::getColumnName, Function.identity()));
+
+        List<GenTableColumn> dbTableColumns = genTableColumnMapper.selectDbTableColumnsByName(tableName);
+        if (StringUtils.isEmpty(dbTableColumns))
+        {
+            throw new ServiceException("同步数据失败,原表结构不存在");
+        }
+        List<String> dbTableColumnNames = dbTableColumns.stream().map(GenTableColumn::getColumnName).collect(Collectors.toList());
+
+        dbTableColumns.forEach(column -> {
+            GenUtils.initColumnField(column, table);
+            if (tableColumnMap.containsKey(column.getColumnName()))
+            {
+                GenTableColumn prevColumn = tableColumnMap.get(column.getColumnName());
+                column.setColumnId(prevColumn.getColumnId());
+                if (column.isList())
+                {
+                    // 如果是列表,继续保留查询方式/字典类型选项
+                    column.setDictType(prevColumn.getDictType());
+                    column.setQueryType(prevColumn.getQueryType());
+                }
+                if (StringUtils.isNotEmpty(prevColumn.getIsRequired()) && !column.isPk()
+                        && (column.isInsert() || column.isEdit())
+                        && ((column.isUsableColumn()) || (!column.isSuperColumn())))
+                {
+                    // 如果是(新增/修改&非主键/非忽略及父属性),继续保留必填/显示类型选项
+                    column.setIsRequired(prevColumn.getIsRequired());
+                    column.setHtmlType(prevColumn.getHtmlType());
+                }
+                genTableColumnMapper.updateGenTableColumn(column);
+            }
+            else
+            {
+                genTableColumnMapper.insertGenTableColumn(column);
+            }
+        });
+
+        List<GenTableColumn> delColumns = tableColumns.stream().filter(column -> !dbTableColumnNames.contains(column.getColumnName())).collect(Collectors.toList());
+        if (StringUtils.isNotEmpty(delColumns))
+        {
+            genTableColumnMapper.deleteGenTableColumns(delColumns);
+        }
+    }
+
+    /**
+     * 批量生成代码(下载方式)
+     * 
+     * @param tableNames 表数组
+     * @return 数据
+     */
+    @Override
+    public byte[] downloadCode(String[] tableNames)
+    {
+        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+        ZipOutputStream zip = new ZipOutputStream(outputStream);
+        for (String tableName : tableNames)
+        {
+            generatorCode(tableName, zip);
+        }
+        IOUtils.closeQuietly(zip);
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 查询表信息并生成代码
+     */
+    private void generatorCode(String tableName, ZipOutputStream zip)
+    {
+        // 查询表信息
+        GenTable table = genTableMapper.selectGenTableByName(tableName);
+        // 设置主子表信息
+        setSubTable(table);
+        // 设置主键列信息
+        setPkColumn(table);
+
+        VelocityInitializer.initVelocity();
+
+        VelocityContext context = VelocityUtils.prepareContext(table);
+
+        // 获取模板列表
+        List<String> templates = VelocityUtils.getTemplateList(table.getTplCategory(), table.getTplWebType());
+        for (String template : templates)
+        {
+            // 渲染模板
+            StringWriter sw = new StringWriter();
+            Template tpl = Velocity.getTemplate(template, Constants.UTF8);
+            tpl.merge(context, sw);
+            try
+            {
+                // 添加到zip
+                zip.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, table)));
+                IOUtils.write(sw.toString(), zip, Constants.UTF8);
+                IOUtils.closeQuietly(sw);
+                zip.flush();
+                zip.closeEntry();
+            }
+            catch (IOException e)
+            {
+                log.error("渲染模板失败,表名:" + table.getTableName(), e);
+            }
+        }
+    }
+
+    /**
+     * 修改保存参数校验
+     * 
+     * @param genTable 业务信息
+     */
+    @Override
+    public void validateEdit(GenTable genTable)
+    {
+        if (GenConstants.TPL_TREE.equals(genTable.getTplCategory()))
+        {
+            String options = JSON.toJSONString(genTable.getParams());
+            JSONObject paramsObj = JSON.parseObject(options);
+            if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_CODE)))
+            {
+                throw new ServiceException("树编码字段不能为空");
+            }
+            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_PARENT_CODE)))
+            {
+                throw new ServiceException("树父编码字段不能为空");
+            }
+            else if (StringUtils.isEmpty(paramsObj.getString(GenConstants.TREE_NAME)))
+            {
+                throw new ServiceException("树名称字段不能为空");
+            }
+            else if (GenConstants.TPL_SUB.equals(genTable.getTplCategory()))
+            {
+                if (StringUtils.isEmpty(genTable.getSubTableName()))
+                {
+                    throw new ServiceException("关联子表的表名不能为空");
+                }
+                else if (StringUtils.isEmpty(genTable.getSubTableFkName()))
+                {
+                    throw new ServiceException("子表关联的外键名不能为空");
+                }
+            }
+        }
+    }
+
+    /**
+     * 设置主键列信息
+     * 
+     * @param table 业务表信息
+     */
+    public void setPkColumn(GenTable table)
+    {
+        for (GenTableColumn column : table.getColumns())
+        {
+            if (column.isPk())
+            {
+                table.setPkColumn(column);
+                break;
+            }
+        }
+        if (StringUtils.isNull(table.getPkColumn()))
+        {
+            table.setPkColumn(table.getColumns().get(0));
+        }
+        if (GenConstants.TPL_SUB.equals(table.getTplCategory()))
+        {
+            for (GenTableColumn column : table.getSubTable().getColumns())
+            {
+                if (column.isPk())
+                {
+                    table.getSubTable().setPkColumn(column);
+                    break;
+                }
+            }
+            if (StringUtils.isNull(table.getSubTable().getPkColumn()))
+            {
+                table.getSubTable().setPkColumn(table.getSubTable().getColumns().get(0));
+            }
+        }
+    }
+
+    /**
+     * 设置主子表信息
+     * 
+     * @param table 业务表信息
+     */
+    public void setSubTable(GenTable table)
+    {
+        String subTableName = table.getSubTableName();
+        if (StringUtils.isNotEmpty(subTableName))
+        {
+            table.setSubTable(genTableMapper.selectGenTableByName(subTableName));
+        }
+    }
+
+    /**
+     * 设置代码生成其他选项值
+     * 
+     * @param genTable 设置后的生成对象
+     */
+    public void setTableFromOptions(GenTable genTable)
+    {
+        JSONObject paramsObj = JSON.parseObject(genTable.getOptions());
+        if (StringUtils.isNotNull(paramsObj))
+        {
+            String treeCode = paramsObj.getString(GenConstants.TREE_CODE);
+            String treeParentCode = paramsObj.getString(GenConstants.TREE_PARENT_CODE);
+            String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+            Long parentMenuId = paramsObj.getLongValue(GenConstants.PARENT_MENU_ID);
+            String parentMenuName = paramsObj.getString(GenConstants.PARENT_MENU_NAME);
+
+            genTable.setTreeCode(treeCode);
+            genTable.setTreeParentCode(treeParentCode);
+            genTable.setTreeName(treeName);
+            genTable.setParentMenuId(parentMenuId);
+            genTable.setParentMenuName(parentMenuName);
+        }
+    }
+
+    /**
+     * 获取代码生成地址
+     * 
+     * @param table 业务表信息
+     * @param template 模板文件路径
+     * @return 生成地址
+     */
+    public static String getGenPath(GenTable table, String template)
+    {
+        String genPath = table.getGenPath();
+        if (StringUtils.equals(genPath, "/"))
+        {
+            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+        }
+        return genPath + File.separator + VelocityUtils.getFileName(template, table);
+    }
 }
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableColumnService.java
similarity index 85%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableColumnService.java
index 2130d043..857f6c5f 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableColumnService.java
@@ -1,44 +1,44 @@
-package com.ruoyi.generator.service;
-
-import java.util.List;
-import com.ruoyi.generator.domain.GenTableColumn;
-
-/**
- * 业务字段 服务层
- * 
- * @author ruoyi
- */
-public interface IGenTableColumnService
-{
-    /**
-     * 查询业务字段列表
-     * 
-     * @param tableId 业务字段编号
-     * @return 业务字段集合
-     */
-    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
-
-    /**
-     * 新增业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-    public int insertGenTableColumn(GenTableColumn genTableColumn);
-
-    /**
-     * 修改业务字段
-     * 
-     * @param genTableColumn 业务字段信息
-     * @return 结果
-     */
-    public int updateGenTableColumn(GenTableColumn genTableColumn);
-
-    /**
-     * 删除业务字段信息
-     * 
-     * @param ids 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteGenTableColumnByIds(String ids);
-}
+package com.acupuncture.generator.service;
+
+import java.util.List;
+import com.acupuncture.generator.domain.GenTableColumn;
+
+/**
+ * 业务字段 服务层
+ * 
+ * @author acupuncture
+ */
+public interface IGenTableColumnService
+{
+    /**
+     * 查询业务字段列表
+     * 
+     * @param tableId 业务字段编号
+     * @return 业务字段集合
+     */
+    public List<GenTableColumn> selectGenTableColumnListByTableId(Long tableId);
+
+    /**
+     * 新增业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+    public int insertGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 修改业务字段
+     * 
+     * @param genTableColumn 业务字段信息
+     * @return 结果
+     */
+    public int updateGenTableColumn(GenTableColumn genTableColumn);
+
+    /**
+     * 删除业务字段信息
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteGenTableColumnByIds(String ids);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableService.java
similarity index 91%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableService.java
index 526038d5..eb33ba42 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/service/IGenTableService.java
@@ -1,130 +1,130 @@
-package com.ruoyi.generator.service;
-
-import java.util.List;
-import java.util.Map;
-import com.ruoyi.generator.domain.GenTable;
-
-/**
- * 业务 服务层
- * 
- * @author ruoyi
- */
-public interface IGenTableService
-{
-    /**
-     * 查询业务列表
-     * 
-     * @param genTable 业务信息
-     * @return 业务集合
-     */
-    public List<GenTable> selectGenTableList(GenTable genTable);
-
-    /**
-     * 查询据库列表
-     * 
-     * @param genTable 业务信息
-     * @return 数据库表集合
-     */
-    public List<GenTable> selectDbTableList(GenTable genTable);
-
-    /**
-     * 查询据库列表
-     * 
-     * @param tableNames 表名称组
-     * @return 数据库表集合
-     */
-    public List<GenTable> selectDbTableListByNames(String[] tableNames);
-
-    /**
-     * 查询所有表信息
-     * 
-     * @return 表信息集合
-     */
-    public List<GenTable> selectGenTableAll();
-
-    /**
-     * 查询业务信息
-     * 
-     * @param id 业务ID
-     * @return 业务信息
-     */
-    public GenTable selectGenTableById(Long id);
-
-    /**
-     * 修改业务
-     * 
-     * @param genTable 业务信息
-     * @return 结果
-     */
-    public void updateGenTable(GenTable genTable);
-
-    /**
-     * 删除业务信息
-     * 
-     * @param tableIds 需要删除的表数据ID
-     * @return 结果
-     */
-    public void deleteGenTableByIds(Long[] tableIds);
-
-    /**
-     * 创建表
-     *
-     * @param sql 创建表语句
-     * @return 结果
-     */
-    public boolean createTable(String sql);
-
-    /**
-     * 导入表结构
-     *
-     * @param tableList 导入表列表
-     * @param operName 操作人员
-     */
-    public void importGenTable(List<GenTable> tableList, String operName);
-
-    /**
-     * 预览代码
-     * 
-     * @param tableId 表编号
-     * @return 预览数据列表
-     */
-    public Map<String, String> previewCode(Long tableId);
-
-    /**
-     * 生成代码(下载方式)
-     * 
-     * @param tableName 表名称
-     * @return 数据
-     */
-    public byte[] downloadCode(String tableName);
-
-    /**
-     * 生成代码(自定义路径)
-     * 
-     * @param tableName 表名称
-     * @return 数据
-     */
-    public void generatorCode(String tableName);
-
-    /**
-     * 同步数据库
-     * 
-     * @param tableName 表名称
-     */
-    public void synchDb(String tableName);
-
-    /**
-     * 批量生成代码(下载方式)
-     * 
-     * @param tableNames 表数组
-     * @return 数据
-     */
-    public byte[] downloadCode(String[] tableNames);
-
-    /**
-     * 修改保存参数校验
-     * 
-     * @param genTable 业务信息
-     */
-    public void validateEdit(GenTable genTable);
-}
+package com.acupuncture.generator.service;
+
+import java.util.List;
+import java.util.Map;
+import com.acupuncture.generator.domain.GenTable;
+
+/**
+ * 业务 服务层
+ * 
+ * @author acupuncture
+ */
+public interface IGenTableService
+{
+    /**
+     * 查询业务列表
+     * 
+     * @param genTable 业务信息
+     * @return 业务集合
+     */
+    public List<GenTable> selectGenTableList(GenTable genTable);
+
+    /**
+     * 查询据库列表
+     * 
+     * @param genTable 业务信息
+     * @return 数据库表集合
+     */
+    public List<GenTable> selectDbTableList(GenTable genTable);
+
+    /**
+     * 查询据库列表
+     * 
+     * @param tableNames 表名称组
+     * @return 数据库表集合
+     */
+    public List<GenTable> selectDbTableListByNames(String[] tableNames);
+
+    /**
+     * 查询所有表信息
+     * 
+     * @return 表信息集合
+     */
+    public List<GenTable> selectGenTableAll();
+
+    /**
+     * 查询业务信息
+     * 
+     * @param id 业务ID
+     * @return 业务信息
+     */
+    public GenTable selectGenTableById(Long id);
+
+    /**
+     * 修改业务
+     * 
+     * @param genTable 业务信息
+     * @return 结果
+     */
+    public void updateGenTable(GenTable genTable);
+
+    /**
+     * 删除业务信息
+     * 
+     * @param tableIds 需要删除的表数据ID
+     * @return 结果
+     */
+    public void deleteGenTableByIds(Long[] tableIds);
+
+    /**
+     * 创建表
+     *
+     * @param sql 创建表语句
+     * @return 结果
+     */
+    public boolean createTable(String sql);
+
+    /**
+     * 导入表结构
+     *
+     * @param tableList 导入表列表
+     * @param operName 操作人员
+     */
+    public void importGenTable(List<GenTable> tableList, String operName);
+
+    /**
+     * 预览代码
+     * 
+     * @param tableId 表编号
+     * @return 预览数据列表
+     */
+    public Map<String, String> previewCode(Long tableId);
+
+    /**
+     * 生成代码(下载方式)
+     * 
+     * @param tableName 表名称
+     * @return 数据
+     */
+    public byte[] downloadCode(String tableName);
+
+    /**
+     * 生成代码(自定义路径)
+     * 
+     * @param tableName 表名称
+     * @return 数据
+     */
+    public void generatorCode(String tableName);
+
+    /**
+     * 同步数据库
+     * 
+     * @param tableName 表名称
+     */
+    public void synchDb(String tableName);
+
+    /**
+     * 批量生成代码(下载方式)
+     * 
+     * @param tableNames 表数组
+     * @return 数据
+     */
+    public byte[] downloadCode(String[] tableNames);
+
+    /**
+     * 修改保存参数校验
+     * 
+     * @param genTable 业务信息
+     */
+    public void validateEdit(GenTable genTable);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/GenUtils.java
similarity index 93%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/util/GenUtils.java
index e28c0bb0..033d3c3e 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/GenUtils.java
@@ -1,257 +1,257 @@
-package com.ruoyi.generator.util;
-
-import java.util.Arrays;
-import org.apache.commons.lang3.RegExUtils;
-import com.ruoyi.common.constant.GenConstants;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.generator.config.GenConfig;
-import com.ruoyi.generator.domain.GenTable;
-import com.ruoyi.generator.domain.GenTableColumn;
-
-/**
- * 代码生成器 工具类
- * 
- * @author ruoyi
- */
-public class GenUtils
-{
-    /**
-     * 初始化表信息
-     */
-    public static void initTable(GenTable genTable, String operName)
-    {
-        genTable.setClassName(convertClassName(genTable.getTableName()));
-        genTable.setPackageName(GenConfig.getPackageName());
-        genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
-        genTable.setBusinessName(getBusinessName(genTable.getTableName()));
-        genTable.setFunctionName(replaceText(genTable.getTableComment()));
-        genTable.setFunctionAuthor(GenConfig.getAuthor());
-        genTable.setCreateBy(operName);
-    }
-
-    /**
-     * 初始化列属性字段
-     */
-    public static void initColumnField(GenTableColumn column, GenTable table)
-    {
-        String dataType = getDbType(column.getColumnType());
-        String columnName = column.getColumnName();
-        column.setTableId(table.getTableId());
-        column.setCreateBy(table.getCreateBy());
-        // 设置java字段名
-        column.setJavaField(StringUtils.toCamelCase(columnName));
-        // 设置默认类型
-        column.setJavaType(GenConstants.TYPE_STRING);
-        column.setQueryType(GenConstants.QUERY_EQ);
-
-        if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
-        {
-            // 字符串长度超过500设置为文本域
-            Integer columnLength = getColumnLength(column.getColumnType());
-            String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
-            column.setHtmlType(htmlType);
-        }
-        else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
-        {
-            column.setJavaType(GenConstants.TYPE_DATE);
-            column.setHtmlType(GenConstants.HTML_DATETIME);
-        }
-        else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))
-        {
-            column.setHtmlType(GenConstants.HTML_INPUT);
-
-            // 如果是浮点型 统一用BigDecimal
-            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
-            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
-            {
-                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
-            }
-            // 如果是整形
-            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
-            {
-                column.setJavaType(GenConstants.TYPE_INTEGER);
-            }
-            // 长整形
-            else
-            {
-                column.setJavaType(GenConstants.TYPE_LONG);
-            }
-        }
-
-        // 插入字段(默认所有字段都需要插入)
-        column.setIsInsert(GenConstants.REQUIRE);
-
-        // 编辑字段
-        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
-        {
-            column.setIsEdit(GenConstants.REQUIRE);
-        }
-        // 列表字段
-        if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
-        {
-            column.setIsList(GenConstants.REQUIRE);
-        }
-        // 查询字段
-        if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
-        {
-            column.setIsQuery(GenConstants.REQUIRE);
-        }
-
-        // 查询字段类型
-        if (StringUtils.endsWithIgnoreCase(columnName, "name"))
-        {
-            column.setQueryType(GenConstants.QUERY_LIKE);
-        }
-        // 状态字段设置单选框
-        if (StringUtils.endsWithIgnoreCase(columnName, "status"))
-        {
-            column.setHtmlType(GenConstants.HTML_RADIO);
-        }
-        // 类型&性别字段设置下拉框
-        else if (StringUtils.endsWithIgnoreCase(columnName, "type")
-                || StringUtils.endsWithIgnoreCase(columnName, "sex"))
-        {
-            column.setHtmlType(GenConstants.HTML_SELECT);
-        }
-        // 图片字段设置图片上传控件
-        else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
-        {
-            column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
-        }
-        // 文件字段设置文件上传控件
-        else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
-        {
-            column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
-        }
-        // 内容字段设置富文本控件
-        else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
-        {
-            column.setHtmlType(GenConstants.HTML_EDITOR);
-        }
-    }
-
-    /**
-     * 校验数组是否包含指定值
-     * 
-     * @param arr 数组
-     * @param targetValue 值
-     * @return 是否包含
-     */
-    public static boolean arraysContains(String[] arr, String targetValue)
-    {
-        return Arrays.asList(arr).contains(targetValue);
-    }
-
-    /**
-     * 获取模块名
-     * 
-     * @param packageName 包名
-     * @return 模块名
-     */
-    public static String getModuleName(String packageName)
-    {
-        int lastIndex = packageName.lastIndexOf(".");
-        int nameLength = packageName.length();
-        return StringUtils.substring(packageName, lastIndex + 1, nameLength);
-    }
-
-    /**
-     * 获取业务名
-     * 
-     * @param tableName 表名
-     * @return 业务名
-     */
-    public static String getBusinessName(String tableName)
-    {
-        int lastIndex = tableName.lastIndexOf("_");
-        int nameLength = tableName.length();
-        return StringUtils.substring(tableName, lastIndex + 1, nameLength);
-    }
-
-    /**
-     * 表名转换成Java类名
-     * 
-     * @param tableName 表名称
-     * @return 类名
-     */
-    public static String convertClassName(String tableName)
-    {
-        boolean autoRemovePre = GenConfig.getAutoRemovePre();
-        String tablePrefix = GenConfig.getTablePrefix();
-        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
-        {
-            String[] searchList = StringUtils.split(tablePrefix, ",");
-            tableName = replaceFirst(tableName, searchList);
-        }
-        return StringUtils.convertToCamelCase(tableName);
-    }
-
-    /**
-     * 批量替换前缀
-     * 
-     * @param replacementm 替换值
-     * @param searchList 替换列表
-     * @return
-     */
-    public static String replaceFirst(String replacementm, String[] searchList)
-    {
-        String text = replacementm;
-        for (String searchString : searchList)
-        {
-            if (replacementm.startsWith(searchString))
-            {
-                text = replacementm.replaceFirst(searchString, "");
-                break;
-            }
-        }
-        return text;
-    }
-
-    /**
-     * 关键字替换
-     * 
-     * @param text 需要被替换的名字
-     * @return 替换后的名字
-     */
-    public static String replaceText(String text)
-    {
-        return RegExUtils.replaceAll(text, "(?:表|若依)", "");
-    }
-
-    /**
-     * 获取数据库类型字段
-     * 
-     * @param columnType 列类型
-     * @return 截取后的列类型
-     */
-    public static String getDbType(String columnType)
-    {
-        if (StringUtils.indexOf(columnType, "(") > 0)
-        {
-            return StringUtils.substringBefore(columnType, "(");
-        }
-        else
-        {
-            return columnType;
-        }
-    }
-
-    /**
-     * 获取字段长度
-     * 
-     * @param columnType 列类型
-     * @return 截取后的列类型
-     */
-    public static Integer getColumnLength(String columnType)
-    {
-        if (StringUtils.indexOf(columnType, "(") > 0)
-        {
-            String length = StringUtils.substringBetween(columnType, "(", ")");
-            return Integer.valueOf(length);
-        }
-        else
-        {
-            return 0;
-        }
-    }
-}
+package com.acupuncture.generator.util;
+
+import java.util.Arrays;
+import org.apache.commons.lang3.RegExUtils;
+import com.acupuncture.common.constant.GenConstants;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.generator.config.GenConfig;
+import com.acupuncture.generator.domain.GenTable;
+import com.acupuncture.generator.domain.GenTableColumn;
+
+/**
+ * 代码生成器 工具类
+ * 
+ * @author acupuncture
+ */
+public class GenUtils
+{
+    /**
+     * 初始化表信息
+     */
+    public static void initTable(GenTable genTable, String operName)
+    {
+        genTable.setClassName(convertClassName(genTable.getTableName()));
+        genTable.setPackageName(GenConfig.getPackageName());
+        genTable.setModuleName(getModuleName(GenConfig.getPackageName()));
+        genTable.setBusinessName(getBusinessName(genTable.getTableName()));
+        genTable.setFunctionName(replaceText(genTable.getTableComment()));
+        genTable.setFunctionAuthor(GenConfig.getAuthor());
+        genTable.setCreateBy(operName);
+    }
+
+    /**
+     * 初始化列属性字段
+     */
+    public static void initColumnField(GenTableColumn column, GenTable table)
+    {
+        String dataType = getDbType(column.getColumnType());
+        String columnName = column.getColumnName();
+        column.setTableId(table.getTableId());
+        column.setCreateBy(table.getCreateBy());
+        // 设置java字段名
+        column.setJavaField(StringUtils.toCamelCase(columnName));
+        // 设置默认类型
+        column.setJavaType(GenConstants.TYPE_STRING);
+        column.setQueryType(GenConstants.QUERY_EQ);
+
+        if (arraysContains(GenConstants.COLUMNTYPE_STR, dataType) || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType))
+        {
+            // 字符串长度超过500设置为文本域
+            Integer columnLength = getColumnLength(column.getColumnType());
+            String htmlType = columnLength >= 500 || arraysContains(GenConstants.COLUMNTYPE_TEXT, dataType) ? GenConstants.HTML_TEXTAREA : GenConstants.HTML_INPUT;
+            column.setHtmlType(htmlType);
+        }
+        else if (arraysContains(GenConstants.COLUMNTYPE_TIME, dataType))
+        {
+            column.setJavaType(GenConstants.TYPE_DATE);
+            column.setHtmlType(GenConstants.HTML_DATETIME);
+        }
+        else if (arraysContains(GenConstants.COLUMNTYPE_NUMBER, dataType))
+        {
+            column.setHtmlType(GenConstants.HTML_INPUT);
+
+            // 如果是浮点型 统一用BigDecimal
+            String[] str = StringUtils.split(StringUtils.substringBetween(column.getColumnType(), "(", ")"), ",");
+            if (str != null && str.length == 2 && Integer.parseInt(str[1]) > 0)
+            {
+                column.setJavaType(GenConstants.TYPE_BIGDECIMAL);
+            }
+            // 如果是整形
+            else if (str != null && str.length == 1 && Integer.parseInt(str[0]) <= 10)
+            {
+                column.setJavaType(GenConstants.TYPE_INTEGER);
+            }
+            // 长整形
+            else
+            {
+                column.setJavaType(GenConstants.TYPE_LONG);
+            }
+        }
+
+        // 插入字段(默认所有字段都需要插入)
+        column.setIsInsert(GenConstants.REQUIRE);
+
+        // 编辑字段
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_EDIT, columnName) && !column.isPk())
+        {
+            column.setIsEdit(GenConstants.REQUIRE);
+        }
+        // 列表字段
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_LIST, columnName) && !column.isPk())
+        {
+            column.setIsList(GenConstants.REQUIRE);
+        }
+        // 查询字段
+        if (!arraysContains(GenConstants.COLUMNNAME_NOT_QUERY, columnName) && !column.isPk())
+        {
+            column.setIsQuery(GenConstants.REQUIRE);
+        }
+
+        // 查询字段类型
+        if (StringUtils.endsWithIgnoreCase(columnName, "name"))
+        {
+            column.setQueryType(GenConstants.QUERY_LIKE);
+        }
+        // 状态字段设置单选框
+        if (StringUtils.endsWithIgnoreCase(columnName, "status"))
+        {
+            column.setHtmlType(GenConstants.HTML_RADIO);
+        }
+        // 类型&性别字段设置下拉框
+        else if (StringUtils.endsWithIgnoreCase(columnName, "type")
+                || StringUtils.endsWithIgnoreCase(columnName, "sex"))
+        {
+            column.setHtmlType(GenConstants.HTML_SELECT);
+        }
+        // 图片字段设置图片上传控件
+        else if (StringUtils.endsWithIgnoreCase(columnName, "image"))
+        {
+            column.setHtmlType(GenConstants.HTML_IMAGE_UPLOAD);
+        }
+        // 文件字段设置文件上传控件
+        else if (StringUtils.endsWithIgnoreCase(columnName, "file"))
+        {
+            column.setHtmlType(GenConstants.HTML_FILE_UPLOAD);
+        }
+        // 内容字段设置富文本控件
+        else if (StringUtils.endsWithIgnoreCase(columnName, "content"))
+        {
+            column.setHtmlType(GenConstants.HTML_EDITOR);
+        }
+    }
+
+    /**
+     * 校验数组是否包含指定值
+     * 
+     * @param arr 数组
+     * @param targetValue 值
+     * @return 是否包含
+     */
+    public static boolean arraysContains(String[] arr, String targetValue)
+    {
+        return Arrays.asList(arr).contains(targetValue);
+    }
+
+    /**
+     * 获取模块名
+     * 
+     * @param packageName 包名
+     * @return 模块名
+     */
+    public static String getModuleName(String packageName)
+    {
+        int lastIndex = packageName.lastIndexOf(".");
+        int nameLength = packageName.length();
+        return StringUtils.substring(packageName, lastIndex + 1, nameLength);
+    }
+
+    /**
+     * 获取业务名
+     * 
+     * @param tableName 表名
+     * @return 业务名
+     */
+    public static String getBusinessName(String tableName)
+    {
+        int lastIndex = tableName.lastIndexOf("_");
+        int nameLength = tableName.length();
+        return StringUtils.substring(tableName, lastIndex + 1, nameLength);
+    }
+
+    /**
+     * 表名转换成Java类名
+     * 
+     * @param tableName 表名称
+     * @return 类名
+     */
+    public static String convertClassName(String tableName)
+    {
+        boolean autoRemovePre = GenConfig.getAutoRemovePre();
+        String tablePrefix = GenConfig.getTablePrefix();
+        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
+        {
+            String[] searchList = StringUtils.split(tablePrefix, ",");
+            tableName = replaceFirst(tableName, searchList);
+        }
+        return StringUtils.convertToCamelCase(tableName);
+    }
+
+    /**
+     * 批量替换前缀
+     * 
+     * @param replacementm 替换值
+     * @param searchList 替换列表
+     * @return
+     */
+    public static String replaceFirst(String replacementm, String[] searchList)
+    {
+        String text = replacementm;
+        for (String searchString : searchList)
+        {
+            if (replacementm.startsWith(searchString))
+            {
+                text = replacementm.replaceFirst(searchString, "");
+                break;
+            }
+        }
+        return text;
+    }
+
+    /**
+     * 关键字替换
+     * 
+     * @param text 需要被替换的名字
+     * @return 替换后的名字
+     */
+    public static String replaceText(String text)
+    {
+        return RegExUtils.replaceAll(text, "(?:表|若依)", "");
+    }
+
+    /**
+     * 获取数据库类型字段
+     * 
+     * @param columnType 列类型
+     * @return 截取后的列类型
+     */
+    public static String getDbType(String columnType)
+    {
+        if (StringUtils.indexOf(columnType, "(") > 0)
+        {
+            return StringUtils.substringBefore(columnType, "(");
+        }
+        else
+        {
+            return columnType;
+        }
+    }
+
+    /**
+     * 获取字段长度
+     * 
+     * @param columnType 列类型
+     * @return 截取后的列类型
+     */
+    public static Integer getColumnLength(String columnType)
+    {
+        if (StringUtils.indexOf(columnType, "(") > 0)
+        {
+            String length = StringUtils.substringBetween(columnType, "(", ")");
+            return Integer.valueOf(length);
+        }
+        else
+        {
+            return 0;
+        }
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityInitializer.java
similarity index 85%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityInitializer.java
index 26456335..6eb171e4 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityInitializer.java
@@ -1,34 +1,34 @@
-package com.ruoyi.generator.util;
-
-import java.util.Properties;
-import org.apache.velocity.app.Velocity;
-import com.ruoyi.common.constant.Constants;
-
-/**
- * VelocityEngine工厂
- * 
- * @author ruoyi
- */
-public class VelocityInitializer
-{
-    /**
-     * 初始化vm方法
-     */
-    public static void initVelocity()
-    {
-        Properties p = new Properties();
-        try
-        {
-            // 加载classpath目录下的vm文件
-            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
-            // 定义字符集
-            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
-            // 初始化Velocity引擎,指定配置Properties
-            Velocity.init(p);
-        }
-        catch (Exception e)
-        {
-            throw new RuntimeException(e);
-        }
-    }
-}
+package com.acupuncture.generator.util;
+
+import java.util.Properties;
+import org.apache.velocity.app.Velocity;
+import com.acupuncture.common.constant.Constants;
+
+/**
+ * VelocityEngine工厂
+ * 
+ * @author acupuncture
+ */
+public class VelocityInitializer
+{
+    /**
+     * 初始化vm方法
+     */
+    public static void initVelocity()
+    {
+        Properties p = new Properties();
+        try
+        {
+            // 加载classpath目录下的vm文件
+            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+            // 定义字符集
+            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+            // 初始化Velocity引擎,指定配置Properties
+            Velocity.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityUtils.java
similarity index 95%
rename from ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
rename to acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityUtils.java
index d64ab08f..78e2bc83 100644
--- a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
+++ b/acupuncture-generator/src/main/java/com/acupuncture/generator/util/VelocityUtils.java
@@ -1,408 +1,408 @@
-package com.ruoyi.generator.util;
-
-import java.util.ArrayList;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Set;
-import org.apache.velocity.VelocityContext;
-import com.alibaba.fastjson2.JSON;
-import com.alibaba.fastjson2.JSONObject;
-import com.ruoyi.common.constant.GenConstants;
-import com.ruoyi.common.utils.DateUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.generator.domain.GenTable;
-import com.ruoyi.generator.domain.GenTableColumn;
-
-/**
- * 模板处理工具类
- * 
- * @author ruoyi
- */
-public class VelocityUtils
-{
-    /** 项目空间路径 */
-    private static final String PROJECT_PATH = "main/java";
-
-    /** mybatis空间路径 */
-    private static final String MYBATIS_PATH = "main/resources/mapper";
-
-    /** 默认上级菜单,系统工具 */
-    private static final String DEFAULT_PARENT_MENU_ID = "3";
-
-    /**
-     * 设置模板变量信息
-     *
-     * @return 模板列表
-     */
-    public static VelocityContext prepareContext(GenTable genTable)
-    {
-        String moduleName = genTable.getModuleName();
-        String businessName = genTable.getBusinessName();
-        String packageName = genTable.getPackageName();
-        String tplCategory = genTable.getTplCategory();
-        String functionName = genTable.getFunctionName();
-
-        VelocityContext velocityContext = new VelocityContext();
-        velocityContext.put("tplCategory", genTable.getTplCategory());
-        velocityContext.put("tableName", genTable.getTableName());
-        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
-        velocityContext.put("ClassName", genTable.getClassName());
-        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
-        velocityContext.put("moduleName", genTable.getModuleName());
-        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
-        velocityContext.put("businessName", genTable.getBusinessName());
-        velocityContext.put("basePackage", getPackagePrefix(packageName));
-        velocityContext.put("packageName", packageName);
-        velocityContext.put("author", genTable.getFunctionAuthor());
-        velocityContext.put("datetime", DateUtils.getDate());
-        velocityContext.put("pkColumn", genTable.getPkColumn());
-        velocityContext.put("importList", getImportList(genTable));
-        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
-        velocityContext.put("columns", genTable.getColumns());
-        velocityContext.put("table", genTable);
-        velocityContext.put("dicts", getDicts(genTable));
-        setMenuVelocityContext(velocityContext, genTable);
-        if (GenConstants.TPL_TREE.equals(tplCategory))
-        {
-            setTreeVelocityContext(velocityContext, genTable);
-        }
-        if (GenConstants.TPL_SUB.equals(tplCategory))
-        {
-            setSubVelocityContext(velocityContext, genTable);
-        }
-        return velocityContext;
-    }
-
-    public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
-    {
-        String options = genTable.getOptions();
-        JSONObject paramsObj = JSON.parseObject(options);
-        String parentMenuId = getParentMenuId(paramsObj);
-        context.put("parentMenuId", parentMenuId);
-    }
-
-    public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
-    {
-        String options = genTable.getOptions();
-        JSONObject paramsObj = JSON.parseObject(options);
-        String treeCode = getTreecode(paramsObj);
-        String treeParentCode = getTreeParentCode(paramsObj);
-        String treeName = getTreeName(paramsObj);
-
-        context.put("treeCode", treeCode);
-        context.put("treeParentCode", treeParentCode);
-        context.put("treeName", treeName);
-        context.put("expandColumn", getExpandColumn(genTable));
-        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
-        {
-            context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
-        }
-        if (paramsObj.containsKey(GenConstants.TREE_NAME))
-        {
-            context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
-        }
-    }
-
-    public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
-    {
-        GenTable subTable = genTable.getSubTable();
-        String subTableName = genTable.getSubTableName();
-        String subTableFkName = genTable.getSubTableFkName();
-        String subClassName = genTable.getSubTable().getClassName();
-        String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
-
-        context.put("subTable", subTable);
-        context.put("subTableName", subTableName);
-        context.put("subTableFkName", subTableFkName);
-        context.put("subTableFkClassName", subTableFkClassName);
-        context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
-        context.put("subClassName", subClassName);
-        context.put("subclassName", StringUtils.uncapitalize(subClassName));
-        context.put("subImportList", getImportList(genTable.getSubTable()));
-    }
-
-    /**
-     * 获取模板信息
-     * @param tplCategory 生成的模板
-     * @param tplWebType 前端类型
-     * @return 模板列表
-     */
-    public static List<String> getTemplateList(String tplCategory, String tplWebType)
-    {
-        String useWebType = "vm/vue";
-        if ("element-plus".equals(tplWebType))
-        {
-            useWebType = "vm/vue/v3";
-        }
-        List<String> templates = new ArrayList<String>();
-        templates.add("vm/java/domain.java.vm");
-        templates.add("vm/java/mapper.java.vm");
-        templates.add("vm/java/service.java.vm");
-        templates.add("vm/java/serviceImpl.java.vm");
-        templates.add("vm/java/controller.java.vm");
-        templates.add("vm/xml/mapper.xml.vm");
-        templates.add("vm/sql/sql.vm");
-        templates.add("vm/js/api.js.vm");
-        if (GenConstants.TPL_CRUD.equals(tplCategory))
-        {
-            templates.add(useWebType + "/index.vue.vm");
-        }
-        else if (GenConstants.TPL_TREE.equals(tplCategory))
-        {
-            templates.add(useWebType + "/index-tree.vue.vm");
-        }
-        else if (GenConstants.TPL_SUB.equals(tplCategory))
-        {
-            templates.add(useWebType + "/index.vue.vm");
-            templates.add("vm/java/sub-domain.java.vm");
-        }
-        return templates;
-    }
-
-    /**
-     * 获取文件名
-     */
-    public static String getFileName(String template, GenTable genTable)
-    {
-        // 文件名称
-        String fileName = "";
-        // 包路径
-        String packageName = genTable.getPackageName();
-        // 模块名
-        String moduleName = genTable.getModuleName();
-        // 大写类名
-        String className = genTable.getClassName();
-        // 业务名称
-        String businessName = genTable.getBusinessName();
-
-        String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
-        String mybatisPath = MYBATIS_PATH + "/" + moduleName;
-        String vuePath = "vue";
-
-        if (template.contains("domain.java.vm"))
-        {
-            fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
-        }
-        if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
-        {
-            fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
-        }
-        else if (template.contains("mapper.java.vm"))
-        {
-            fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
-        }
-        else if (template.contains("service.java.vm"))
-        {
-            fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
-        }
-        else if (template.contains("serviceImpl.java.vm"))
-        {
-            fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
-        }
-        else if (template.contains("controller.java.vm"))
-        {
-            fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
-        }
-        else if (template.contains("mapper.xml.vm"))
-        {
-            fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
-        }
-        else if (template.contains("sql.vm"))
-        {
-            fileName = businessName + "Menu.sql";
-        }
-        else if (template.contains("api.js.vm"))
-        {
-            fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
-        }
-        else if (template.contains("index.vue.vm"))
-        {
-            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
-        }
-        else if (template.contains("index-tree.vue.vm"))
-        {
-            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
-        }
-        return fileName;
-    }
-
-    /**
-     * 获取包前缀
-     *
-     * @param packageName 包名称
-     * @return 包前缀名称
-     */
-    public static String getPackagePrefix(String packageName)
-    {
-        int lastIndex = packageName.lastIndexOf(".");
-        return StringUtils.substring(packageName, 0, lastIndex);
-    }
-
-    /**
-     * 根据列类型获取导入包
-     * 
-     * @param genTable 业务表对象
-     * @return 返回需要导入的包列表
-     */
-    public static HashSet<String> getImportList(GenTable genTable)
-    {
-        List<GenTableColumn> columns = genTable.getColumns();
-        GenTable subGenTable = genTable.getSubTable();
-        HashSet<String> importList = new HashSet<String>();
-        if (StringUtils.isNotNull(subGenTable))
-        {
-            importList.add("java.util.List");
-        }
-        for (GenTableColumn column : columns)
-        {
-            if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))
-            {
-                importList.add("java.util.Date");
-                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
-            }
-            else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))
-            {
-                importList.add("java.math.BigDecimal");
-            }
-        }
-        return importList;
-    }
-
-    /**
-     * 根据列类型获取字典组
-     * 
-     * @param genTable 业务表对象
-     * @return 返回字典组
-     */
-    public static String getDicts(GenTable genTable)
-    {
-        List<GenTableColumn> columns = genTable.getColumns();
-        Set<String> dicts = new HashSet<String>();
-        addDicts(dicts, columns);
-        if (StringUtils.isNotNull(genTable.getSubTable()))
-        {
-            List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
-            addDicts(dicts, subColumns);
-        }
-        return StringUtils.join(dicts, ", ");
-    }
-
-    /**
-     * 添加字典列表
-     * 
-     * @param dicts 字典列表
-     * @param columns 列集合
-     */
-    public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
-    {
-        for (GenTableColumn column : columns)
-        {
-            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
-                    column.getHtmlType(),
-                    new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX }))
-            {
-                dicts.add("'" + column.getDictType() + "'");
-            }
-        }
-    }
-
-    /**
-     * 获取权限前缀
-     *
-     * @param moduleName 模块名称
-     * @param businessName 业务名称
-     * @return 返回权限前缀
-     */
-    public static String getPermissionPrefix(String moduleName, String businessName)
-    {
-        return StringUtils.format("{}:{}", moduleName, businessName);
-    }
-
-    /**
-     * 获取上级菜单ID字段
-     *
-     * @param paramsObj 生成其他选项
-     * @return 上级菜单ID字段
-     */
-    public static String getParentMenuId(JSONObject paramsObj)
-    {
-        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
-                && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
-        {
-            return paramsObj.getString(GenConstants.PARENT_MENU_ID);
-        }
-        return DEFAULT_PARENT_MENU_ID;
-    }
-
-    /**
-     * 获取树编码
-     *
-     * @param paramsObj 生成其他选项
-     * @return 树编码
-     */
-    public static String getTreecode(JSONObject paramsObj)
-    {
-        if (paramsObj.containsKey(GenConstants.TREE_CODE))
-        {
-            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
-        }
-        return StringUtils.EMPTY;
-    }
-
-    /**
-     * 获取树父编码
-     *
-     * @param paramsObj 生成其他选项
-     * @return 树父编码
-     */
-    public static String getTreeParentCode(JSONObject paramsObj)
-    {
-        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
-        {
-            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
-        }
-        return StringUtils.EMPTY;
-    }
-
-    /**
-     * 获取树名称
-     *
-     * @param paramsObj 生成其他选项
-     * @return 树名称
-     */
-    public static String getTreeName(JSONObject paramsObj)
-    {
-        if (paramsObj.containsKey(GenConstants.TREE_NAME))
-        {
-            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
-        }
-        return StringUtils.EMPTY;
-    }
-
-    /**
-     * 获取需要在哪一列上面显示展开按钮
-     *
-     * @param genTable 业务表对象
-     * @return 展开按钮列序号
-     */
-    public static int getExpandColumn(GenTable genTable)
-    {
-        String options = genTable.getOptions();
-        JSONObject paramsObj = JSON.parseObject(options);
-        String treeName = paramsObj.getString(GenConstants.TREE_NAME);
-        int num = 0;
-        for (GenTableColumn column : genTable.getColumns())
-        {
-            if (column.isList())
-            {
-                num++;
-                String columnName = column.getColumnName();
-                if (columnName.equals(treeName))
-                {
-                    break;
-                }
-            }
-        }
-        return num;
-    }
-}
+package com.acupuncture.generator.util;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.apache.velocity.VelocityContext;
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.acupuncture.common.constant.GenConstants;
+import com.acupuncture.common.utils.DateUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.generator.domain.GenTable;
+import com.acupuncture.generator.domain.GenTableColumn;
+
+/**
+ * 模板处理工具类
+ * 
+ * @author acupuncture
+ */
+public class VelocityUtils
+{
+    /** 项目空间路径 */
+    private static final String PROJECT_PATH = "main/java";
+
+    /** mybatis空间路径 */
+    private static final String MYBATIS_PATH = "main/resources/mapper";
+
+    /** 默认上级菜单,系统工具 */
+    private static final String DEFAULT_PARENT_MENU_ID = "3";
+
+    /**
+     * 设置模板变量信息
+     *
+     * @return 模板列表
+     */
+    public static VelocityContext prepareContext(GenTable genTable)
+    {
+        String moduleName = genTable.getModuleName();
+        String businessName = genTable.getBusinessName();
+        String packageName = genTable.getPackageName();
+        String tplCategory = genTable.getTplCategory();
+        String functionName = genTable.getFunctionName();
+
+        VelocityContext velocityContext = new VelocityContext();
+        velocityContext.put("tplCategory", genTable.getTplCategory());
+        velocityContext.put("tableName", genTable.getTableName());
+        velocityContext.put("functionName", StringUtils.isNotEmpty(functionName) ? functionName : "【请填写功能名称】");
+        velocityContext.put("ClassName", genTable.getClassName());
+        velocityContext.put("className", StringUtils.uncapitalize(genTable.getClassName()));
+        velocityContext.put("moduleName", genTable.getModuleName());
+        velocityContext.put("BusinessName", StringUtils.capitalize(genTable.getBusinessName()));
+        velocityContext.put("businessName", genTable.getBusinessName());
+        velocityContext.put("basePackage", getPackagePrefix(packageName));
+        velocityContext.put("packageName", packageName);
+        velocityContext.put("author", genTable.getFunctionAuthor());
+        velocityContext.put("datetime", DateUtils.getDate());
+        velocityContext.put("pkColumn", genTable.getPkColumn());
+        velocityContext.put("importList", getImportList(genTable));
+        velocityContext.put("permissionPrefix", getPermissionPrefix(moduleName, businessName));
+        velocityContext.put("columns", genTable.getColumns());
+        velocityContext.put("table", genTable);
+        velocityContext.put("dicts", getDicts(genTable));
+        setMenuVelocityContext(velocityContext, genTable);
+        if (GenConstants.TPL_TREE.equals(tplCategory))
+        {
+            setTreeVelocityContext(velocityContext, genTable);
+        }
+        if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            setSubVelocityContext(velocityContext, genTable);
+        }
+        return velocityContext;
+    }
+
+    public static void setMenuVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String parentMenuId = getParentMenuId(paramsObj);
+        context.put("parentMenuId", parentMenuId);
+    }
+
+    public static void setTreeVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String treeCode = getTreecode(paramsObj);
+        String treeParentCode = getTreeParentCode(paramsObj);
+        String treeName = getTreeName(paramsObj);
+
+        context.put("treeCode", treeCode);
+        context.put("treeParentCode", treeParentCode);
+        context.put("treeName", treeName);
+        context.put("expandColumn", getExpandColumn(genTable));
+        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+        {
+            context.put("tree_parent_code", paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+        }
+        if (paramsObj.containsKey(GenConstants.TREE_NAME))
+        {
+            context.put("tree_name", paramsObj.getString(GenConstants.TREE_NAME));
+        }
+    }
+
+    public static void setSubVelocityContext(VelocityContext context, GenTable genTable)
+    {
+        GenTable subTable = genTable.getSubTable();
+        String subTableName = genTable.getSubTableName();
+        String subTableFkName = genTable.getSubTableFkName();
+        String subClassName = genTable.getSubTable().getClassName();
+        String subTableFkClassName = StringUtils.convertToCamelCase(subTableFkName);
+
+        context.put("subTable", subTable);
+        context.put("subTableName", subTableName);
+        context.put("subTableFkName", subTableFkName);
+        context.put("subTableFkClassName", subTableFkClassName);
+        context.put("subTableFkclassName", StringUtils.uncapitalize(subTableFkClassName));
+        context.put("subClassName", subClassName);
+        context.put("subclassName", StringUtils.uncapitalize(subClassName));
+        context.put("subImportList", getImportList(genTable.getSubTable()));
+    }
+
+    /**
+     * 获取模板信息
+     * @param tplCategory 生成的模板
+     * @param tplWebType 前端类型
+     * @return 模板列表
+     */
+    public static List<String> getTemplateList(String tplCategory, String tplWebType)
+    {
+        String useWebType = "vm/vue";
+        if ("element-plus".equals(tplWebType))
+        {
+            useWebType = "vm/vue/v3";
+        }
+        List<String> templates = new ArrayList<String>();
+        templates.add("vm/java/domain.java.vm");
+        templates.add("vm/java/mapper.java.vm");
+        templates.add("vm/java/service.java.vm");
+        templates.add("vm/java/serviceImpl.java.vm");
+        templates.add("vm/java/controller.java.vm");
+        templates.add("vm/xml/mapper.xml.vm");
+        templates.add("vm/sql/sql.vm");
+        templates.add("vm/js/api.js.vm");
+        if (GenConstants.TPL_CRUD.equals(tplCategory))
+        {
+            templates.add(useWebType + "/index.vue.vm");
+        }
+        else if (GenConstants.TPL_TREE.equals(tplCategory))
+        {
+            templates.add(useWebType + "/index-tree.vue.vm");
+        }
+        else if (GenConstants.TPL_SUB.equals(tplCategory))
+        {
+            templates.add(useWebType + "/index.vue.vm");
+            templates.add("vm/java/sub-domain.java.vm");
+        }
+        return templates;
+    }
+
+    /**
+     * 获取文件名
+     */
+    public static String getFileName(String template, GenTable genTable)
+    {
+        // 文件名称
+        String fileName = "";
+        // 包路径
+        String packageName = genTable.getPackageName();
+        // 模块名
+        String moduleName = genTable.getModuleName();
+        // 大写类名
+        String className = genTable.getClassName();
+        // 业务名称
+        String businessName = genTable.getBusinessName();
+
+        String javaPath = PROJECT_PATH + "/" + StringUtils.replace(packageName, ".", "/");
+        String mybatisPath = MYBATIS_PATH + "/" + moduleName;
+        String vuePath = "vue";
+
+        if (template.contains("domain.java.vm"))
+        {
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, className);
+        }
+        if (template.contains("sub-domain.java.vm") && StringUtils.equals(GenConstants.TPL_SUB, genTable.getTplCategory()))
+        {
+            fileName = StringUtils.format("{}/domain/{}.java", javaPath, genTable.getSubTable().getClassName());
+        }
+        else if (template.contains("mapper.java.vm"))
+        {
+            fileName = StringUtils.format("{}/mapper/{}Mapper.java", javaPath, className);
+        }
+        else if (template.contains("service.java.vm"))
+        {
+            fileName = StringUtils.format("{}/service/I{}Service.java", javaPath, className);
+        }
+        else if (template.contains("serviceImpl.java.vm"))
+        {
+            fileName = StringUtils.format("{}/service/impl/{}ServiceImpl.java", javaPath, className);
+        }
+        else if (template.contains("controller.java.vm"))
+        {
+            fileName = StringUtils.format("{}/controller/{}Controller.java", javaPath, className);
+        }
+        else if (template.contains("mapper.xml.vm"))
+        {
+            fileName = StringUtils.format("{}/{}Mapper.xml", mybatisPath, className);
+        }
+        else if (template.contains("sql.vm"))
+        {
+            fileName = businessName + "Menu.sql";
+        }
+        else if (template.contains("api.js.vm"))
+        {
+            fileName = StringUtils.format("{}/api/{}/{}.js", vuePath, moduleName, businessName);
+        }
+        else if (template.contains("index.vue.vm"))
+        {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        }
+        else if (template.contains("index-tree.vue.vm"))
+        {
+            fileName = StringUtils.format("{}/views/{}/{}/index.vue", vuePath, moduleName, businessName);
+        }
+        return fileName;
+    }
+
+    /**
+     * 获取包前缀
+     *
+     * @param packageName 包名称
+     * @return 包前缀名称
+     */
+    public static String getPackagePrefix(String packageName)
+    {
+        int lastIndex = packageName.lastIndexOf(".");
+        return StringUtils.substring(packageName, 0, lastIndex);
+    }
+
+    /**
+     * 根据列类型获取导入包
+     * 
+     * @param genTable 业务表对象
+     * @return 返回需要导入的包列表
+     */
+    public static HashSet<String> getImportList(GenTable genTable)
+    {
+        List<GenTableColumn> columns = genTable.getColumns();
+        GenTable subGenTable = genTable.getSubTable();
+        HashSet<String> importList = new HashSet<String>();
+        if (StringUtils.isNotNull(subGenTable))
+        {
+            importList.add("java.util.List");
+        }
+        for (GenTableColumn column : columns)
+        {
+            if (!column.isSuperColumn() && GenConstants.TYPE_DATE.equals(column.getJavaType()))
+            {
+                importList.add("java.util.Date");
+                importList.add("com.fasterxml.jackson.annotation.JsonFormat");
+            }
+            else if (!column.isSuperColumn() && GenConstants.TYPE_BIGDECIMAL.equals(column.getJavaType()))
+            {
+                importList.add("java.math.BigDecimal");
+            }
+        }
+        return importList;
+    }
+
+    /**
+     * 根据列类型获取字典组
+     * 
+     * @param genTable 业务表对象
+     * @return 返回字典组
+     */
+    public static String getDicts(GenTable genTable)
+    {
+        List<GenTableColumn> columns = genTable.getColumns();
+        Set<String> dicts = new HashSet<String>();
+        addDicts(dicts, columns);
+        if (StringUtils.isNotNull(genTable.getSubTable()))
+        {
+            List<GenTableColumn> subColumns = genTable.getSubTable().getColumns();
+            addDicts(dicts, subColumns);
+        }
+        return StringUtils.join(dicts, ", ");
+    }
+
+    /**
+     * 添加字典列表
+     * 
+     * @param dicts 字典列表
+     * @param columns 列集合
+     */
+    public static void addDicts(Set<String> dicts, List<GenTableColumn> columns)
+    {
+        for (GenTableColumn column : columns)
+        {
+            if (!column.isSuperColumn() && StringUtils.isNotEmpty(column.getDictType()) && StringUtils.equalsAny(
+                    column.getHtmlType(),
+                    new String[] { GenConstants.HTML_SELECT, GenConstants.HTML_RADIO, GenConstants.HTML_CHECKBOX }))
+            {
+                dicts.add("'" + column.getDictType() + "'");
+            }
+        }
+    }
+
+    /**
+     * 获取权限前缀
+     *
+     * @param moduleName 模块名称
+     * @param businessName 业务名称
+     * @return 返回权限前缀
+     */
+    public static String getPermissionPrefix(String moduleName, String businessName)
+    {
+        return StringUtils.format("{}:{}", moduleName, businessName);
+    }
+
+    /**
+     * 获取上级菜单ID字段
+     *
+     * @param paramsObj 生成其他选项
+     * @return 上级菜单ID字段
+     */
+    public static String getParentMenuId(JSONObject paramsObj)
+    {
+        if (StringUtils.isNotEmpty(paramsObj) && paramsObj.containsKey(GenConstants.PARENT_MENU_ID)
+                && StringUtils.isNotEmpty(paramsObj.getString(GenConstants.PARENT_MENU_ID)))
+        {
+            return paramsObj.getString(GenConstants.PARENT_MENU_ID);
+        }
+        return DEFAULT_PARENT_MENU_ID;
+    }
+
+    /**
+     * 获取树编码
+     *
+     * @param paramsObj 生成其他选项
+     * @return 树编码
+     */
+    public static String getTreecode(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_CODE))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_CODE));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 获取树父编码
+     *
+     * @param paramsObj 生成其他选项
+     * @return 树父编码
+     */
+    public static String getTreeParentCode(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_PARENT_CODE))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_PARENT_CODE));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 获取树名称
+     *
+     * @param paramsObj 生成其他选项
+     * @return 树名称
+     */
+    public static String getTreeName(JSONObject paramsObj)
+    {
+        if (paramsObj.containsKey(GenConstants.TREE_NAME))
+        {
+            return StringUtils.toCamelCase(paramsObj.getString(GenConstants.TREE_NAME));
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 获取需要在哪一列上面显示展开按钮
+     *
+     * @param genTable 业务表对象
+     * @return 展开按钮列序号
+     */
+    public static int getExpandColumn(GenTable genTable)
+    {
+        String options = genTable.getOptions();
+        JSONObject paramsObj = JSON.parseObject(options);
+        String treeName = paramsObj.getString(GenConstants.TREE_NAME);
+        int num = 0;
+        for (GenTableColumn column : genTable.getColumns())
+        {
+            if (column.isList())
+            {
+                num++;
+                String columnName = column.getColumnName();
+                if (columnName.equals(treeName))
+                {
+                    break;
+                }
+            }
+        }
+        return num;
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/generator.yml b/acupuncture-generator/src/main/resources/generator.yml
similarity index 86%
rename from ruoyi-generator/src/main/resources/generator.yml
rename to acupuncture-generator/src/main/resources/generator.yml
index db66353f..495c8a8b 100644
--- a/ruoyi-generator/src/main/resources/generator.yml
+++ b/acupuncture-generator/src/main/resources/generator.yml
@@ -1,12 +1,12 @@
-# 代码生成
-gen:
-  # 作者
-  author: ruoyi
-  # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
-  packageName: com.ruoyi.system
-  # 自动去除表前缀,默认是false
-  autoRemovePre: false
-  # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
-  tablePrefix: sys_
-  # 是否允许生成文件覆盖到本地(自定义路径),默认不允许
+# 代码生成
+gen:
+  # 作者
+  author: acupuncture
+  # 默认生成包路径 system 需改成自己的模块名称 如 system monitor tool
+  packageName: com.acupuncture.system
+  # 自动去除表前缀,默认是false
+  autoRemovePre: false
+  # 表前缀(生成类名不会包含表前缀,多个用逗号分隔)
+  tablePrefix: sys_
+  # 是否允许生成文件覆盖到本地(自定义路径),默认不允许
   allowOverwrite: false
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml b/acupuncture-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
similarity index 97%
rename from ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
rename to acupuncture-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
index efd0e70d..69d2e53a 100644
--- a/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
+++ b/acupuncture-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -1,127 +1,127 @@
-<?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.generator.mapper.GenTableColumnMapper">
-
-    <resultMap type="GenTableColumn" id="GenTableColumnResult">
-        <id     property="columnId"       column="column_id"      />
-        <result property="tableId"        column="table_id"       />
-        <result property="columnName"     column="column_name"    />
-        <result property="columnComment"  column="column_comment" />
-        <result property="columnType"     column="column_type"    />
-        <result property="javaType"       column="java_type"      />
-        <result property="javaField"      column="java_field"     />
-        <result property="isPk"           column="is_pk"          />
-        <result property="isIncrement"    column="is_increment"   />
-        <result property="isRequired"     column="is_required"    />
-        <result property="isInsert"       column="is_insert"      />
-        <result property="isEdit"         column="is_edit"        />
-        <result property="isList"         column="is_list"        />
-        <result property="isQuery"        column="is_query"       />
-        <result property="queryType"      column="query_type"     />
-        <result property="htmlType"       column="html_type"      />
-        <result property="dictType"       column="dict_type"      />
-        <result property="sort"           column="sort"           />
-        <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="selectGenTableColumnVo">
-        select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column
-    </sql>
-
-    <select id="selectGenTableColumnListByTableId" parameterType="Long" resultMap="GenTableColumnResult">
-        <include refid="selectGenTableColumnVo"/>
-        where table_id = #{tableId}
-        order by sort
-    </select>
-
-    <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
-		select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
-		from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
-		order by ordinal_position
-	</select>
-
-    <insert id="insertGenTableColumn" parameterType="GenTableColumn" useGeneratedKeys="true" keyProperty="columnId">
-        insert into gen_table_column (
-			<if test="tableId != null and tableId != ''">table_id,</if>
-			<if test="columnName != null and columnName != ''">column_name,</if>
-			<if test="columnComment != null and columnComment != ''">column_comment,</if>
-			<if test="columnType != null and columnType != ''">column_type,</if>
-			<if test="javaType != null and javaType != ''">java_type,</if>
-			<if test="javaField != null  and javaField != ''">java_field,</if>
-			<if test="isPk != null and isPk != ''">is_pk,</if>
-			<if test="isIncrement != null and isIncrement != ''">is_increment,</if>
-			<if test="isRequired != null and isRequired != ''">is_required,</if>
-			<if test="isInsert != null and isInsert != ''">is_insert,</if>
-			<if test="isEdit != null and isEdit != ''">is_edit,</if>
-			<if test="isList != null and isList != ''">is_list,</if>
-			<if test="isQuery != null and isQuery != ''">is_query,</if>
-			<if test="queryType != null and queryType != ''">query_type,</if>
-			<if test="htmlType != null and htmlType != ''">html_type,</if>
-			<if test="dictType != null and dictType != ''">dict_type,</if>
-			<if test="sort != null">sort,</if>
-			<if test="createBy != null and createBy != ''">create_by,</if>
-			create_time
-         )values(
-			<if test="tableId != null and tableId != ''">#{tableId},</if>
-			<if test="columnName != null and columnName != ''">#{columnName},</if>
-			<if test="columnComment != null and columnComment != ''">#{columnComment},</if>
-			<if test="columnType != null and columnType != ''">#{columnType},</if>
-			<if test="javaType != null and javaType != ''">#{javaType},</if>
-			<if test="javaField != null and javaField != ''">#{javaField},</if>
-			<if test="isPk != null and isPk != ''">#{isPk},</if>
-			<if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if>
-			<if test="isRequired != null and isRequired != ''">#{isRequired},</if>
-			<if test="isInsert != null and isInsert != ''">#{isInsert},</if>
-			<if test="isEdit != null and isEdit != ''">#{isEdit},</if>
-			<if test="isList != null and isList != ''">#{isList},</if>
-			<if test="isQuery != null and isQuery != ''">#{isQuery},</if>
-			<if test="queryType != null and queryType != ''">#{queryType},</if>
-			<if test="htmlType != null and htmlType != ''">#{htmlType},</if>
-			<if test="dictType != null and dictType != ''">#{dictType},</if>
-			<if test="sort != null">#{sort},</if>
-			<if test="createBy != null and createBy != ''">#{createBy},</if>
-			sysdate()
-         )
-    </insert>
-
-    <update id="updateGenTableColumn" parameterType="GenTableColumn">
-        update gen_table_column
-        <set>
-            <if test="columnComment != null">column_comment = #{columnComment},</if>
-            <if test="javaType != null">java_type = #{javaType},</if>
-            <if test="javaField != null">java_field = #{javaField},</if>
-            <if test="isInsert != null">is_insert = #{isInsert},</if>
-            <if test="isEdit != null">is_edit = #{isEdit},</if>
-            <if test="isList != null">is_list = #{isList},</if>
-            <if test="isQuery != null">is_query = #{isQuery},</if>
-            <if test="isRequired != null">is_required = #{isRequired},</if>
-            <if test="queryType != null">query_type = #{queryType},</if>
-            <if test="htmlType != null">html_type = #{htmlType},</if>
-            <if test="dictType != null">dict_type = #{dictType},</if>
-            <if test="sort != null">sort = #{sort},</if>
-            <if test="updateBy != null">update_by = #{updateBy},</if>
-            update_time = sysdate()
-        </set>
-        where column_id = #{columnId}
-    </update>
-
-    <delete id="deleteGenTableColumnByIds" parameterType="Long">
-        delete from gen_table_column where table_id in
-        <foreach collection="array" item="tableId" open="(" separator="," close=")">
-            #{tableId}
-        </foreach>
-    </delete>
-
-    <delete id="deleteGenTableColumns">
-        delete from gen_table_column where column_id in
-        <foreach collection="list" item="item" open="(" separator="," close=")">
-            #{item.columnId}
-        </foreach>
-    </delete>
-
+<?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.acupuncture.generator.mapper.GenTableColumnMapper">
+
+    <resultMap type="GenTableColumn" id="GenTableColumnResult">
+        <id     property="columnId"       column="column_id"      />
+        <result property="tableId"        column="table_id"       />
+        <result property="columnName"     column="column_name"    />
+        <result property="columnComment"  column="column_comment" />
+        <result property="columnType"     column="column_type"    />
+        <result property="javaType"       column="java_type"      />
+        <result property="javaField"      column="java_field"     />
+        <result property="isPk"           column="is_pk"          />
+        <result property="isIncrement"    column="is_increment"   />
+        <result property="isRequired"     column="is_required"    />
+        <result property="isInsert"       column="is_insert"      />
+        <result property="isEdit"         column="is_edit"        />
+        <result property="isList"         column="is_list"        />
+        <result property="isQuery"        column="is_query"       />
+        <result property="queryType"      column="query_type"     />
+        <result property="htmlType"       column="html_type"      />
+        <result property="dictType"       column="dict_type"      />
+        <result property="sort"           column="sort"           />
+        <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="selectGenTableColumnVo">
+        select column_id, table_id, column_name, column_comment, column_type, java_type, java_field, is_pk, is_increment, is_required, is_insert, is_edit, is_list, is_query, query_type, html_type, dict_type, sort, create_by, create_time, update_by, update_time from gen_table_column
+    </sql>
+
+    <select id="selectGenTableColumnListByTableId" parameterType="Long" resultMap="GenTableColumnResult">
+        <include refid="selectGenTableColumnVo"/>
+        where table_id = #{tableId}
+        order by sort
+    </select>
+
+    <select id="selectDbTableColumnsByName" parameterType="String" resultMap="GenTableColumnResult">
+		select column_name, (case when (is_nullable = 'no' <![CDATA[ && ]]> column_key != 'PRI') then '1' else '0' end) as is_required, (case when column_key = 'PRI' then '1' else '0' end) as is_pk, ordinal_position as sort, column_comment, (case when extra = 'auto_increment' then '1' else '0' end) as is_increment, column_type
+		from information_schema.columns where table_schema = (select database()) and table_name = (#{tableName})
+		order by ordinal_position
+	</select>
+
+    <insert id="insertGenTableColumn" parameterType="GenTableColumn" useGeneratedKeys="true" keyProperty="columnId">
+        insert into gen_table_column (
+			<if test="tableId != null and tableId != ''">table_id,</if>
+			<if test="columnName != null and columnName != ''">column_name,</if>
+			<if test="columnComment != null and columnComment != ''">column_comment,</if>
+			<if test="columnType != null and columnType != ''">column_type,</if>
+			<if test="javaType != null and javaType != ''">java_type,</if>
+			<if test="javaField != null  and javaField != ''">java_field,</if>
+			<if test="isPk != null and isPk != ''">is_pk,</if>
+			<if test="isIncrement != null and isIncrement != ''">is_increment,</if>
+			<if test="isRequired != null and isRequired != ''">is_required,</if>
+			<if test="isInsert != null and isInsert != ''">is_insert,</if>
+			<if test="isEdit != null and isEdit != ''">is_edit,</if>
+			<if test="isList != null and isList != ''">is_list,</if>
+			<if test="isQuery != null and isQuery != ''">is_query,</if>
+			<if test="queryType != null and queryType != ''">query_type,</if>
+			<if test="htmlType != null and htmlType != ''">html_type,</if>
+			<if test="dictType != null and dictType != ''">dict_type,</if>
+			<if test="sort != null">sort,</if>
+			<if test="createBy != null and createBy != ''">create_by,</if>
+			create_time
+         )values(
+			<if test="tableId != null and tableId != ''">#{tableId},</if>
+			<if test="columnName != null and columnName != ''">#{columnName},</if>
+			<if test="columnComment != null and columnComment != ''">#{columnComment},</if>
+			<if test="columnType != null and columnType != ''">#{columnType},</if>
+			<if test="javaType != null and javaType != ''">#{javaType},</if>
+			<if test="javaField != null and javaField != ''">#{javaField},</if>
+			<if test="isPk != null and isPk != ''">#{isPk},</if>
+			<if test="isIncrement != null and isIncrement != ''">#{isIncrement},</if>
+			<if test="isRequired != null and isRequired != ''">#{isRequired},</if>
+			<if test="isInsert != null and isInsert != ''">#{isInsert},</if>
+			<if test="isEdit != null and isEdit != ''">#{isEdit},</if>
+			<if test="isList != null and isList != ''">#{isList},</if>
+			<if test="isQuery != null and isQuery != ''">#{isQuery},</if>
+			<if test="queryType != null and queryType != ''">#{queryType},</if>
+			<if test="htmlType != null and htmlType != ''">#{htmlType},</if>
+			<if test="dictType != null and dictType != ''">#{dictType},</if>
+			<if test="sort != null">#{sort},</if>
+			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			sysdate()
+         )
+    </insert>
+
+    <update id="updateGenTableColumn" parameterType="GenTableColumn">
+        update gen_table_column
+        <set>
+            <if test="columnComment != null">column_comment = #{columnComment},</if>
+            <if test="javaType != null">java_type = #{javaType},</if>
+            <if test="javaField != null">java_field = #{javaField},</if>
+            <if test="isInsert != null">is_insert = #{isInsert},</if>
+            <if test="isEdit != null">is_edit = #{isEdit},</if>
+            <if test="isList != null">is_list = #{isList},</if>
+            <if test="isQuery != null">is_query = #{isQuery},</if>
+            <if test="isRequired != null">is_required = #{isRequired},</if>
+            <if test="queryType != null">query_type = #{queryType},</if>
+            <if test="htmlType != null">html_type = #{htmlType},</if>
+            <if test="dictType != null">dict_type = #{dictType},</if>
+            <if test="sort != null">sort = #{sort},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            update_time = sysdate()
+        </set>
+        where column_id = #{columnId}
+    </update>
+
+    <delete id="deleteGenTableColumnByIds" parameterType="Long">
+        delete from gen_table_column where table_id in
+        <foreach collection="array" item="tableId" open="(" separator="," close=")">
+            #{tableId}
+        </foreach>
+    </delete>
+
+    <delete id="deleteGenTableColumns">
+        delete from gen_table_column where column_id in
+        <foreach collection="list" item="item" open="(" separator="," close=")">
+            #{item.columnId}
+        </foreach>
+    </delete>
+
 </mapper>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/acupuncture-generator/src/main/resources/mapper/generator/GenTableMapper.xml
similarity index 97%
rename from ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
rename to acupuncture-generator/src/main/resources/mapper/generator/GenTableMapper.xml
index 8d7dd8bf..66bcdc9d 100644
--- a/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
+++ b/acupuncture-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -1,210 +1,210 @@
-<?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.generator.mapper.GenTableMapper">
-
-	<resultMap type="GenTable" id="GenTableResult">
-	    <id     property="tableId"        column="table_id"          />
-		<result property="tableName"      column="table_name"        />
-		<result property="tableComment"   column="table_comment"     />
-		<result property="subTableName"   column="sub_table_name"    />
-		<result property="subTableFkName" column="sub_table_fk_name" />
-		<result property="className"      column="class_name"        />
-		<result property="tplCategory"    column="tpl_category"      />
-		<result property="tplWebType"     column="tpl_web_type"      />
-		<result property="packageName"    column="package_name"      />
-		<result property="moduleName"     column="module_name"       />
-		<result property="businessName"   column="business_name"     />
-		<result property="functionName"   column="function_name"     />
-		<result property="functionAuthor" column="function_author"   />
-		<result property="genType"        column="gen_type"          />
-		<result property="genPath"        column="gen_path"          />
-		<result property="options"        column="options"           />
-		<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"            />
-		<collection  property="columns"   javaType="java.util.List"  resultMap="GenTableColumnResult" />
-	</resultMap>
-	
-	<resultMap type="GenTableColumn" id="GenTableColumnResult">
-        <id     property="columnId"       column="column_id"      />
-        <result property="tableId"        column="table_id"       />
-        <result property="columnName"     column="column_name"    />
-        <result property="columnComment"  column="column_comment" />
-        <result property="columnType"     column="column_type"    />
-        <result property="javaType"       column="java_type"      />
-        <result property="javaField"      column="java_field"     />
-        <result property="isPk"           column="is_pk"          />
-        <result property="isIncrement"    column="is_increment"   />
-        <result property="isRequired"     column="is_required"    />
-        <result property="isInsert"       column="is_insert"      />
-        <result property="isEdit"         column="is_edit"        />
-        <result property="isList"         column="is_list"        />
-        <result property="isQuery"        column="is_query"       />
-        <result property="queryType"      column="query_type"     />
-        <result property="htmlType"       column="html_type"      />
-        <result property="dictType"       column="dict_type"      />
-        <result property="sort"           column="sort"           />
-        <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="selectGenTableVo">
-        select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, tpl_web_type, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
-    </sql>
-    
-    <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
-		<include refid="selectGenTableVo"/>
-		<where>
-			<if test="tableName != null and tableName != ''">
-				AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
-			</if>
-			<if test="tableComment != null and tableComment != ''">
-				AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
-			</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="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
-		select table_name, table_comment, create_time, update_time from information_schema.tables
-		where table_schema = (select database())
-		AND table_name NOT LIKE 'qrtz\_%' AND table_name NOT LIKE 'gen\_%'
-		AND table_name NOT IN (select table_name from gen_table)
-		<if test="tableName != null and tableName != ''">
-			AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
-		</if>
-		<if test="tableComment != null and tableComment != ''">
-			AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
-		</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>
-        order by create_time desc
-	</select>
-	
-	<select id="selectDbTableListByNames" resultMap="GenTableResult">
-		select table_name, table_comment, create_time, update_time from information_schema.tables
-		where table_name NOT LIKE 'qrtz\_%' and table_name NOT LIKE 'gen\_%' and table_schema = (select database())
-		and table_name in
-	    <foreach collection="array" item="name" open="(" separator="," close=")">
- 			#{name}
-        </foreach> 
-	</select>
-	
-	<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
-		select table_name, table_comment, create_time, update_time from information_schema.tables
-		where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())
-		and table_name = #{tableName}
-	</select>
-	
-	<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
-	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
-			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
-		FROM gen_table t
-			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
-		where t.table_id = #{tableId} order by c.sort
-	</select>
-	
-	<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
-	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
-			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
-		FROM gen_table t
-			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
-		where t.table_name = #{tableName} order by c.sort
-	</select>
-	
-	<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
-	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
-			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
-		FROM gen_table t
-			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
-		order by c.sort
-	</select>
-	
-	<insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId">
-        insert into gen_table (
-			<if test="tableName != null">table_name,</if>
-			<if test="tableComment != null and tableComment != ''">table_comment,</if>
-			<if test="className != null and className != ''">class_name,</if>
-			<if test="tplCategory != null and tplCategory != ''">tpl_category,</if>
-			<if test="tplWebType != null and tplWebType != ''">tpl_web_type,</if>
-			<if test="packageName != null and packageName != ''">package_name,</if>
-			<if test="moduleName != null and moduleName != ''">module_name,</if>
-			<if test="businessName != null and businessName != ''">business_name,</if>
-			<if test="functionName != null and functionName != ''">function_name,</if>
-			<if test="functionAuthor != null and functionAuthor != ''">function_author,</if>
-			<if test="genType != null and genType != ''">gen_type,</if>
-			<if test="genPath != null and genPath != ''">gen_path,</if>
-			<if test="remark != null and remark != ''">remark,</if>
- 			<if test="createBy != null and createBy != ''">create_by,</if>
-			create_time
-         )values(
-			<if test="tableName != null">#{tableName},</if>
-			<if test="tableComment != null and tableComment != ''">#{tableComment},</if>
-			<if test="className != null and className != ''">#{className},</if>
-			<if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if>
-			<if test="tplWebType != null and tplWebType != ''">#{tplWebType},</if>
-			<if test="packageName != null and packageName != ''">#{packageName},</if>
-			<if test="moduleName != null and moduleName != ''">#{moduleName},</if>
-			<if test="businessName != null and businessName != ''">#{businessName},</if>
-			<if test="functionName != null and functionName != ''">#{functionName},</if>
-			<if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if>
-			<if test="genType != null and genType != ''">#{genType},</if>
-			<if test="genPath != null and genPath != ''">#{genPath},</if>
-			<if test="remark != null and remark != ''">#{remark},</if>
- 			<if test="createBy != null and createBy != ''">#{createBy},</if>
-			sysdate()
-         )
-    </insert>
-    
-    <update id="createTable">
-        ${sql}
-    </update>
-    
-    <update id="updateGenTable" parameterType="GenTable">
-        update gen_table
-        <set>
-            <if test="tableName != null">table_name = #{tableName},</if>
-            <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
-            <if test="subTableName != null">sub_table_name = #{subTableName},</if>
-            <if test="subTableFkName != null">sub_table_fk_name = #{subTableFkName},</if>
-            <if test="className != null and className != ''">class_name = #{className},</if>
-            <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
-            <if test="genType != null and genType != ''">gen_type = #{genType},</if>
-            <if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
-            <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
-            <if test="tplWebType != null and tplWebType != ''">tpl_web_type = #{tplWebType},</if>
-            <if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
-            <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>
-            <if test="businessName != null and businessName != ''">business_name = #{businessName},</if>
-            <if test="functionName != null and functionName != ''">function_name = #{functionName},</if>
-            <if test="options != null and options != ''">options = #{options},</if>
-            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
-            <if test="remark != null">remark = #{remark},</if>
-            update_time = sysdate()
-        </set>
-        where table_id = #{tableId}
-    </update>
-    
-    <delete id="deleteGenTableByIds" parameterType="Long">
-        delete from gen_table where table_id in 
-        <foreach collection="array" item="tableId" open="(" separator="," close=")">
-            #{tableId}
-        </foreach>
-    </delete>
-
+<?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.acupuncture.generator.mapper.GenTableMapper">
+
+	<resultMap type="GenTable" id="GenTableResult">
+	    <id     property="tableId"        column="table_id"          />
+		<result property="tableName"      column="table_name"        />
+		<result property="tableComment"   column="table_comment"     />
+		<result property="subTableName"   column="sub_table_name"    />
+		<result property="subTableFkName" column="sub_table_fk_name" />
+		<result property="className"      column="class_name"        />
+		<result property="tplCategory"    column="tpl_category"      />
+		<result property="tplWebType"     column="tpl_web_type"      />
+		<result property="packageName"    column="package_name"      />
+		<result property="moduleName"     column="module_name"       />
+		<result property="businessName"   column="business_name"     />
+		<result property="functionName"   column="function_name"     />
+		<result property="functionAuthor" column="function_author"   />
+		<result property="genType"        column="gen_type"          />
+		<result property="genPath"        column="gen_path"          />
+		<result property="options"        column="options"           />
+		<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"            />
+		<collection  property="columns"   javaType="java.util.List"  resultMap="GenTableColumnResult" />
+	</resultMap>
+	
+	<resultMap type="GenTableColumn" id="GenTableColumnResult">
+        <id     property="columnId"       column="column_id"      />
+        <result property="tableId"        column="table_id"       />
+        <result property="columnName"     column="column_name"    />
+        <result property="columnComment"  column="column_comment" />
+        <result property="columnType"     column="column_type"    />
+        <result property="javaType"       column="java_type"      />
+        <result property="javaField"      column="java_field"     />
+        <result property="isPk"           column="is_pk"          />
+        <result property="isIncrement"    column="is_increment"   />
+        <result property="isRequired"     column="is_required"    />
+        <result property="isInsert"       column="is_insert"      />
+        <result property="isEdit"         column="is_edit"        />
+        <result property="isList"         column="is_list"        />
+        <result property="isQuery"        column="is_query"       />
+        <result property="queryType"      column="query_type"     />
+        <result property="htmlType"       column="html_type"      />
+        <result property="dictType"       column="dict_type"      />
+        <result property="sort"           column="sort"           />
+        <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="selectGenTableVo">
+        select table_id, table_name, table_comment, sub_table_name, sub_table_fk_name, class_name, tpl_category, tpl_web_type, package_name, module_name, business_name, function_name, function_author, gen_type, gen_path, options, create_by, create_time, update_by, update_time, remark from gen_table
+    </sql>
+    
+    <select id="selectGenTableList" parameterType="GenTable" resultMap="GenTableResult">
+		<include refid="selectGenTableVo"/>
+		<where>
+			<if test="tableName != null and tableName != ''">
+				AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
+			</if>
+			<if test="tableComment != null and tableComment != ''">
+				AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
+			</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="selectDbTableList" parameterType="GenTable" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_schema = (select database())
+		AND table_name NOT LIKE 'qrtz\_%' AND table_name NOT LIKE 'gen\_%'
+		AND table_name NOT IN (select table_name from gen_table)
+		<if test="tableName != null and tableName != ''">
+			AND lower(table_name) like lower(concat('%', #{tableName}, '%'))
+		</if>
+		<if test="tableComment != null and tableComment != ''">
+			AND lower(table_comment) like lower(concat('%', #{tableComment}, '%'))
+		</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>
+        order by create_time desc
+	</select>
+	
+	<select id="selectDbTableListByNames" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_name NOT LIKE 'qrtz\_%' and table_name NOT LIKE 'gen\_%' and table_schema = (select database())
+		and table_name in
+	    <foreach collection="array" item="name" open="(" separator="," close=")">
+ 			#{name}
+        </foreach> 
+	</select>
+	
+	<select id="selectTableByName" parameterType="String" resultMap="GenTableResult">
+		select table_name, table_comment, create_time, update_time from information_schema.tables
+		where table_comment <![CDATA[ <> ]]> '' and table_schema = (select database())
+		and table_name = #{tableName}
+	</select>
+	
+	<select id="selectGenTableById" parameterType="Long" resultMap="GenTableResult">
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
+			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+		FROM gen_table t
+			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+		where t.table_id = #{tableId} order by c.sort
+	</select>
+	
+	<select id="selectGenTableByName" parameterType="String" resultMap="GenTableResult">
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.gen_type, t.gen_path, t.options, t.remark,
+			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+		FROM gen_table t
+			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+		where t.table_name = #{tableName} order by c.sort
+	</select>
+	
+	<select id="selectGenTableAll" parameterType="String" resultMap="GenTableResult">
+	    SELECT t.table_id, t.table_name, t.table_comment, t.sub_table_name, t.sub_table_fk_name, t.class_name, t.tpl_category, t.tpl_web_type, t.package_name, t.module_name, t.business_name, t.function_name, t.function_author, t.options, t.remark,
+			   c.column_id, c.column_name, c.column_comment, c.column_type, c.java_type, c.java_field, c.is_pk, c.is_increment, c.is_required, c.is_insert, c.is_edit, c.is_list, c.is_query, c.query_type, c.html_type, c.dict_type, c.sort
+		FROM gen_table t
+			 LEFT JOIN gen_table_column c ON t.table_id = c.table_id
+		order by c.sort
+	</select>
+	
+	<insert id="insertGenTable" parameterType="GenTable" useGeneratedKeys="true" keyProperty="tableId">
+        insert into gen_table (
+			<if test="tableName != null">table_name,</if>
+			<if test="tableComment != null and tableComment != ''">table_comment,</if>
+			<if test="className != null and className != ''">class_name,</if>
+			<if test="tplCategory != null and tplCategory != ''">tpl_category,</if>
+			<if test="tplWebType != null and tplWebType != ''">tpl_web_type,</if>
+			<if test="packageName != null and packageName != ''">package_name,</if>
+			<if test="moduleName != null and moduleName != ''">module_name,</if>
+			<if test="businessName != null and businessName != ''">business_name,</if>
+			<if test="functionName != null and functionName != ''">function_name,</if>
+			<if test="functionAuthor != null and functionAuthor != ''">function_author,</if>
+			<if test="genType != null and genType != ''">gen_type,</if>
+			<if test="genPath != null and genPath != ''">gen_path,</if>
+			<if test="remark != null and remark != ''">remark,</if>
+ 			<if test="createBy != null and createBy != ''">create_by,</if>
+			create_time
+         )values(
+			<if test="tableName != null">#{tableName},</if>
+			<if test="tableComment != null and tableComment != ''">#{tableComment},</if>
+			<if test="className != null and className != ''">#{className},</if>
+			<if test="tplCategory != null and tplCategory != ''">#{tplCategory},</if>
+			<if test="tplWebType != null and tplWebType != ''">#{tplWebType},</if>
+			<if test="packageName != null and packageName != ''">#{packageName},</if>
+			<if test="moduleName != null and moduleName != ''">#{moduleName},</if>
+			<if test="businessName != null and businessName != ''">#{businessName},</if>
+			<if test="functionName != null and functionName != ''">#{functionName},</if>
+			<if test="functionAuthor != null and functionAuthor != ''">#{functionAuthor},</if>
+			<if test="genType != null and genType != ''">#{genType},</if>
+			<if test="genPath != null and genPath != ''">#{genPath},</if>
+			<if test="remark != null and remark != ''">#{remark},</if>
+ 			<if test="createBy != null and createBy != ''">#{createBy},</if>
+			sysdate()
+         )
+    </insert>
+    
+    <update id="createTable">
+        ${sql}
+    </update>
+    
+    <update id="updateGenTable" parameterType="GenTable">
+        update gen_table
+        <set>
+            <if test="tableName != null">table_name = #{tableName},</if>
+            <if test="tableComment != null and tableComment != ''">table_comment = #{tableComment},</if>
+            <if test="subTableName != null">sub_table_name = #{subTableName},</if>
+            <if test="subTableFkName != null">sub_table_fk_name = #{subTableFkName},</if>
+            <if test="className != null and className != ''">class_name = #{className},</if>
+            <if test="functionAuthor != null and functionAuthor != ''">function_author = #{functionAuthor},</if>
+            <if test="genType != null and genType != ''">gen_type = #{genType},</if>
+            <if test="genPath != null and genPath != ''">gen_path = #{genPath},</if>
+            <if test="tplCategory != null and tplCategory != ''">tpl_category = #{tplCategory},</if>
+            <if test="tplWebType != null and tplWebType != ''">tpl_web_type = #{tplWebType},</if>
+            <if test="packageName != null and packageName != ''">package_name = #{packageName},</if>
+            <if test="moduleName != null and moduleName != ''">module_name = #{moduleName},</if>
+            <if test="businessName != null and businessName != ''">business_name = #{businessName},</if>
+            <if test="functionName != null and functionName != ''">function_name = #{functionName},</if>
+            <if test="options != null and options != ''">options = #{options},</if>
+            <if test="updateBy != null and updateBy != ''">update_by = #{updateBy},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            update_time = sysdate()
+        </set>
+        where table_id = #{tableId}
+    </update>
+    
+    <delete id="deleteGenTableByIds" parameterType="Long">
+        delete from gen_table where table_id in 
+        <foreach collection="array" item="tableId" open="(" separator="," close=")">
+            #{tableId}
+        </foreach>
+    </delete>
+
 </mapper>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/acupuncture-generator/src/main/resources/vm/java/controller.java.vm
similarity index 92%
rename from ruoyi-generator/src/main/resources/vm/java/controller.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/controller.java.vm
index bf889887..b3c9ce84 100644
--- a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
+++ b/acupuncture-generator/src/main/resources/vm/java/controller.java.vm
@@ -12,15 +12,15 @@ import org.springframework.web.bind.annotation.PathVariable;
 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.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.enums.BusinessType;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.enums.BusinessType;
 import ${packageName}.domain.${ClassName};
 import ${packageName}.service.I${ClassName}Service;
-import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.acupuncture.common.utils.poi.ExcelUtil;
 #if($table.crud || $table.sub)
-import com.ruoyi.common.core.page.TableDataInfo;
+import com.acupuncture.common.core.page.TableDataInfo;
 #elseif($table.tree)
 #end
 
diff --git a/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/acupuncture-generator/src/main/resources/vm/java/domain.java.vm
similarity index 88%
rename from ruoyi-generator/src/main/resources/vm/java/domain.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/domain.java.vm
index 94a40a96..8ffedacf 100644
--- a/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
+++ b/acupuncture-generator/src/main/resources/vm/java/domain.java.vm
@@ -1,105 +1,101 @@
-package ${packageName}.domain;
-
-#foreach ($import in $importList)
-import ${import};
-#end
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-#if($table.crud || $table.sub)
-import com.ruoyi.common.core.domain.BaseEntity;
-#elseif($table.tree)
-import com.ruoyi.common.core.domain.TreeEntity;
-#end
-
-/**
- * ${functionName}对象 ${tableName}
- * 
- * @author ${author}
- * @date ${datetime}
- */
-#if($table.crud || $table.sub)
-#set($Entity="BaseEntity")
-#elseif($table.tree)
-#set($Entity="TreeEntity")
-#end
-public class ${ClassName} extends ${Entity}
-{
-    private static final long serialVersionUID = 1L;
-
-#foreach ($column in $columns)
-#if(!$table.isSuperColumn($column.javaField))
-    /** $column.columnComment */
-#if($column.list)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($parentheseIndex != -1)
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
-#elseif($column.javaType == 'Date')
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
-#else
-    @Excel(name = "${comment}")
-#end
-#end
-    private $column.javaType $column.javaField;
-
-#end
-#end
-#if($table.sub)
-    /** $table.subTable.functionName信息 */
-    private List<${subClassName}> ${subclassName}List;
-
-#end
-#foreach ($column in $columns)
-#if(!$table.isSuperColumn($column.javaField))
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
-    public void set${AttrName}($column.javaType $column.javaField) 
-    {
-        this.$column.javaField = $column.javaField;
-    }
-
-    public $column.javaType get${AttrName}() 
-    {
-        return $column.javaField;
-    }
-#end
-#end
-
-#if($table.sub)
-    public List<${subClassName}> get${subClassName}List()
-    {
-        return ${subclassName}List;
-    }
-
-    public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
-    {
-        this.${subclassName}List = ${subclassName}List;
-    }
-
-#end
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-#foreach ($column in $columns)
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
-            .append("${column.javaField}", get${AttrName}())
-#end
-#if($table.sub)
-            .append("${subclassName}List", get${subClassName}List())
-#end
-            .toString();
-    }
-}
+package ${packageName}.domain;
+
+#foreach ($import in $importList)
+import ${import};
+#end
+import com.acupuncture.common.annotation.Excel;
+#if($table.crud || $table.sub)
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}对象 ${tableName}
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+#if($table.crud || $table.sub)
+#set($Entity="BaseEntity")
+#elseif($table.tree)
+#set($Entity="TreeEntity")
+#end
+public class ${ClassName} extends ${Entity}
+{
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+    /** $column.columnComment */
+#if($column.list)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($parentheseIndex != -1)
+    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+#elseif($column.javaType == 'Date')
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
+#else
+    @Excel(name = "${comment}")
+#end
+#end
+    private $column.javaType $column.javaField;
+
+#end
+#end
+#if($table.sub)
+    /** $table.subTable.functionName信息 */
+    private List<${subClassName}> ${subclassName}List;
+
+#end
+#foreach ($column in $columns)
+#if(!$table.isSuperColumn($column.javaField))
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+    public void set${AttrName}($column.javaType $column.javaField) 
+    {
+        this.$column.javaField = $column.javaField;
+    }
+
+    public $column.javaType get${AttrName}() 
+    {
+        return $column.javaField;
+    }
+#end
+#end
+
+#if($table.sub)
+    public List<${subClassName}> get${subClassName}List()
+    {
+        return ${subclassName}List;
+    }
+
+    public void set${subClassName}List(List<${subClassName}> ${subclassName}List)
+    {
+        this.${subclassName}List = ${subclassName}List;
+    }
+
+#end
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+#foreach ($column in $columns)
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+            .append("${column.javaField}", get${AttrName}())
+#end
+#if($table.sub)
+            .append("${subclassName}List", get${subClassName}List())
+#end
+            .toString();
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/acupuncture-generator/src/main/resources/vm/java/mapper.java.vm
similarity index 100%
rename from ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/mapper.java.vm
diff --git a/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/acupuncture-generator/src/main/resources/vm/java/service.java.vm
similarity index 96%
rename from ruoyi-generator/src/main/resources/vm/java/service.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/service.java.vm
index 250f68c8..264882b2 100644
--- a/ruoyi-generator/src/main/resources/vm/java/service.java.vm
+++ b/acupuncture-generator/src/main/resources/vm/java/service.java.vm
@@ -1,61 +1,61 @@
-package ${packageName}.service;
-
-import java.util.List;
-import ${packageName}.domain.${ClassName};
-
-/**
- * ${functionName}Service接口
- * 
- * @author ${author}
- * @date ${datetime}
- */
-public interface I${ClassName}Service 
-{
-    /**
-     * 查询${functionName}
-     * 
-     * @param ${pkColumn.javaField} ${functionName}主键
-     * @return ${functionName}
-     */
-    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-
-    /**
-     * 查询${functionName}列表
-     * 
-     * @param ${className} ${functionName}
-     * @return ${functionName}集合
-     */
-    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
-
-    /**
-     * 新增${functionName}
-     * 
-     * @param ${className} ${functionName}
-     * @return 结果
-     */
-    public int insert${ClassName}(${ClassName} ${className});
-
-    /**
-     * 修改${functionName}
-     * 
-     * @param ${className} ${functionName}
-     * @return 结果
-     */
-    public int update${ClassName}(${ClassName} ${className});
-
-    /**
-     * 批量删除${functionName}
-     * 
-     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
-     * @return 结果
-     */
-    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
-
-    /**
-     * 删除${functionName}信息
-     * 
-     * @param ${pkColumn.javaField} ${functionName}主键
-     * @return 结果
-     */
-    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
-}
+package ${packageName}.service;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+
+/**
+ * ${functionName}Service接口
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface I${ClassName}Service 
+{
+    /**
+     * 查询${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}主键
+     * @return ${functionName}
+     */
+    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+    /**
+     * 查询${functionName}列表
+     * 
+     * @param ${className} ${functionName}
+     * @return ${functionName}集合
+     */
+    public List<${ClassName}> select${ClassName}List(${ClassName} ${className});
+
+    /**
+     * 新增${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 结果
+     */
+    public int insert${ClassName}(${ClassName} ${className});
+
+    /**
+     * 修改${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 结果
+     */
+    public int update${ClassName}(${ClassName} ${className});
+
+    /**
+     * 批量删除${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键集合
+     * @return 结果
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+
+    /**
+     * 删除${functionName}信息
+     * 
+     * @param ${pkColumn.javaField} ${functionName}主键
+     * @return 结果
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/acupuncture-generator/src/main/resources/vm/java/serviceImpl.java.vm
similarity index 94%
rename from ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/serviceImpl.java.vm
index 116f6c54..97640eec 100644
--- a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
+++ b/acupuncture-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -1,169 +1,169 @@
-package ${packageName}.service.impl;
-
-import java.util.List;
-#foreach ($column in $columns)
-#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
-import com.ruoyi.common.utils.DateUtils;
-#break
-#end
-#end
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-#if($table.sub)
-import java.util.ArrayList;
-import com.ruoyi.common.utils.StringUtils;
-import org.springframework.transaction.annotation.Transactional;
-import ${packageName}.domain.${subClassName};
-#end
-import ${packageName}.mapper.${ClassName}Mapper;
-import ${packageName}.domain.${ClassName};
-import ${packageName}.service.I${ClassName}Service;
-
-/**
- * ${functionName}Service业务层处理
- * 
- * @author ${author}
- * @date ${datetime}
- */
-@Service
-public class ${ClassName}ServiceImpl implements I${ClassName}Service 
-{
-    @Autowired
-    private ${ClassName}Mapper ${className}Mapper;
-
-    /**
-     * 查询${functionName}
-     * 
-     * @param ${pkColumn.javaField} ${functionName}主键
-     * @return ${functionName}
-     */
-    @Override
-    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
-    {
-        return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
-    }
-
-    /**
-     * 查询${functionName}列表
-     * 
-     * @param ${className} ${functionName}
-     * @return ${functionName}
-     */
-    @Override
-    public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
-    {
-        return ${className}Mapper.select${ClassName}List(${className});
-    }
-
-    /**
-     * 新增${functionName}
-     * 
-     * @param ${className} ${functionName}
-     * @return 结果
-     */
-#if($table.sub)
-    @Transactional
-#end
-    @Override
-    public int insert${ClassName}(${ClassName} ${className})
-    {
-#foreach ($column in $columns)
-#if($column.javaField == 'createTime')
-        ${className}.setCreateTime(DateUtils.getNowDate());
-#end
-#end
-#if($table.sub)
-        int rows = ${className}Mapper.insert${ClassName}(${className});
-        insert${subClassName}(${className});
-        return rows;
-#else
-        return ${className}Mapper.insert${ClassName}(${className});
-#end
-    }
-
-    /**
-     * 修改${functionName}
-     * 
-     * @param ${className} ${functionName}
-     * @return 结果
-     */
-#if($table.sub)
-    @Transactional
-#end
-    @Override
-    public int update${ClassName}(${ClassName} ${className})
-    {
-#foreach ($column in $columns)
-#if($column.javaField == 'updateTime')
-        ${className}.setUpdateTime(DateUtils.getNowDate());
-#end
-#end
-#if($table.sub)
-        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
-        insert${subClassName}(${className});
-#end
-        return ${className}Mapper.update${ClassName}(${className});
-    }
-
-    /**
-     * 批量删除${functionName}
-     * 
-     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
-     * @return 结果
-     */
-#if($table.sub)
-    @Transactional
-#end
-    @Override
-    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
-    {
-#if($table.sub)
-        ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
-#end
-        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
-    }
-
-    /**
-     * 删除${functionName}信息
-     * 
-     * @param ${pkColumn.javaField} ${functionName}主键
-     * @return 结果
-     */
-#if($table.sub)
-    @Transactional
-#end
-    @Override
-    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
-    {
-#if($table.sub)
-        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
-#end
-        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
-    }
-#if($table.sub)
-
-    /**
-     * 新增${subTable.functionName}信息
-     * 
-     * @param ${className} ${functionName}对象
-     */
-    public void insert${subClassName}(${ClassName} ${className})
-    {
-        List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
-        ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
-        if (StringUtils.isNotNull(${subclassName}List))
-        {
-            List<${subClassName}> list = new ArrayList<${subClassName}>();
-            for (${subClassName} ${subclassName} : ${subclassName}List)
-            {
-                ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
-                list.add(${subclassName});
-            }
-            if (list.size() > 0)
-            {
-                ${className}Mapper.batch${subClassName}(list);
-            }
-        }
-    }
-#end
-}
+package ${packageName}.service.impl;
+
+import java.util.List;
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime' || $column.javaField == 'updateTime')
+import com.acupuncture.common.utils.DateUtils;
+#break
+#end
+#end
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+#if($table.sub)
+import java.util.ArrayList;
+import com.acupuncture.common.utils.StringUtils;
+import org.springframework.transaction.annotation.Transactional;
+import ${packageName}.domain.${subClassName};
+#end
+import ${packageName}.mapper.${ClassName}Mapper;
+import ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+
+/**
+ * ${functionName}Service业务层处理
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+@Service
+public class ${ClassName}ServiceImpl implements I${ClassName}Service 
+{
+    @Autowired
+    private ${ClassName}Mapper ${className}Mapper;
+
+    /**
+     * 查询${functionName}
+     * 
+     * @param ${pkColumn.javaField} ${functionName}主键
+     * @return ${functionName}
+     */
+    @Override
+    public ${ClassName} select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+    {
+        return ${className}Mapper.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+    }
+
+    /**
+     * 查询${functionName}列表
+     * 
+     * @param ${className} ${functionName}
+     * @return ${functionName}
+     */
+    @Override
+    public List<${ClassName}> select${ClassName}List(${ClassName} ${className})
+    {
+        return ${className}Mapper.select${ClassName}List(${className});
+    }
+
+    /**
+     * 新增${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 结果
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int insert${ClassName}(${ClassName} ${className})
+    {
+#foreach ($column in $columns)
+#if($column.javaField == 'createTime')
+        ${className}.setCreateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+        int rows = ${className}Mapper.insert${ClassName}(${className});
+        insert${subClassName}(${className});
+        return rows;
+#else
+        return ${className}Mapper.insert${ClassName}(${className});
+#end
+    }
+
+    /**
+     * 修改${functionName}
+     * 
+     * @param ${className} ${functionName}
+     * @return 结果
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int update${ClassName}(${ClassName} ${className})
+    {
+#foreach ($column in $columns)
+#if($column.javaField == 'updateTime')
+        ${className}.setUpdateTime(DateUtils.getNowDate());
+#end
+#end
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${className}.get${pkColumn.capJavaField}());
+        insert${subClassName}(${className});
+#end
+        return ${className}Mapper.update${ClassName}(${className});
+    }
+
+    /**
+     * 批量删除${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 需要删除的${functionName}主键
+     * @return 结果
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s)
+    {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaField}s);
+#end
+        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s);
+    }
+
+    /**
+     * 删除${functionName}信息
+     * 
+     * @param ${pkColumn.javaField} ${functionName}主键
+     * @return 结果
+     */
+#if($table.sub)
+    @Transactional
+#end
+    @Override
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField})
+    {
+#if($table.sub)
+        ${className}Mapper.delete${subClassName}By${subTableFkClassName}(${pkColumn.javaField});
+#end
+        return ${className}Mapper.delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField});
+    }
+#if($table.sub)
+
+    /**
+     * 新增${subTable.functionName}信息
+     * 
+     * @param ${className} ${functionName}对象
+     */
+    public void insert${subClassName}(${ClassName} ${className})
+    {
+        List<${subClassName}> ${subclassName}List = ${className}.get${subClassName}List();
+        ${pkColumn.javaType} ${pkColumn.javaField} = ${className}.get${pkColumn.capJavaField}();
+        if (StringUtils.isNotNull(${subclassName}List))
+        {
+            List<${subClassName}> list = new ArrayList<${subClassName}>();
+            for (${subClassName} ${subclassName} : ${subclassName}List)
+            {
+                ${subclassName}.set${subTableFkClassName}(${pkColumn.javaField});
+                list.add(${subclassName});
+            }
+            if (list.size() > 0)
+            {
+                ${className}Mapper.batch${subClassName}(list);
+            }
+        }
+    }
+#end
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm b/acupuncture-generator/src/main/resources/vm/java/sub-domain.java.vm
similarity index 88%
rename from ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm
rename to acupuncture-generator/src/main/resources/vm/java/sub-domain.java.vm
index b5e308cf..308fea1a 100644
--- a/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm
+++ b/acupuncture-generator/src/main/resources/vm/java/sub-domain.java.vm
@@ -1,76 +1,73 @@
-package ${packageName}.domain;
-
-#foreach ($import in $subImportList)
-import ${import};
-#end
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * ${subTable.functionName}对象 ${subTableName}
- * 
- * @author ${author}
- * @date ${datetime}
- */
-public class ${subClassName} extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-#foreach ($column in $subTable.columns)
-#if(!$table.isSuperColumn($column.javaField))
-    /** $column.columnComment */
-#if($column.list)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($parentheseIndex != -1)
-    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
-#elseif($column.javaType == 'Date')
-    @JsonFormat(pattern = "yyyy-MM-dd")
-    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
-#else
-    @Excel(name = "${comment}")
-#end
-#end
-    private $column.javaType $column.javaField;
-
-#end
-#end
-#foreach ($column in $subTable.columns)
-#if(!$table.isSuperColumn($column.javaField))
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
-    public void set${AttrName}($column.javaType $column.javaField) 
-    {
-        this.$column.javaField = $column.javaField;
-    }
-
-    public $column.javaType get${AttrName}() 
-    {
-        return $column.javaField;
-    }
-#end
-#end
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-#foreach ($column in $subTable.columns)
-#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
-#set($AttrName=$column.javaField)
-#else
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#end
-            .append("${column.javaField}", get${AttrName}())
-#end
-            .toString();
-    }
-}
+package ${packageName}.domain;
+
+#foreach ($import in $subImportList)
+import ${import};
+#end
+import com.acupuncture.common.annotation.Excel;
+
+/**
+ * ${subTable.functionName}对象 ${subTableName}
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public class ${subClassName} extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+#foreach ($column in $subTable.columns)
+#if(!$table.isSuperColumn($column.javaField))
+    /** $column.columnComment */
+#if($column.list)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($parentheseIndex != -1)
+    @Excel(name = "${comment}", readConverterExp = "$column.readConverterExp()")
+#elseif($column.javaType == 'Date')
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    @Excel(name = "${comment}", width = 30, dateFormat = "yyyy-MM-dd")
+#else
+    @Excel(name = "${comment}")
+#end
+#end
+    private $column.javaType $column.javaField;
+
+#end
+#end
+#foreach ($column in $subTable.columns)
+#if(!$table.isSuperColumn($column.javaField))
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+    public void set${AttrName}($column.javaType $column.javaField) 
+    {
+        this.$column.javaField = $column.javaField;
+    }
+
+    public $column.javaType get${AttrName}() 
+    {
+        return $column.javaField;
+    }
+#end
+#end
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+#foreach ($column in $subTable.columns)
+#if($column.javaField.length() > 2 && $column.javaField.substring(1,2).matches("[A-Z]"))
+#set($AttrName=$column.javaField)
+#else
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#end
+            .append("${column.javaField}", get${AttrName}())
+#end
+            .toString();
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/acupuncture-generator/src/main/resources/vm/js/api.js.vm
similarity index 95%
rename from ruoyi-generator/src/main/resources/vm/js/api.js.vm
rename to acupuncture-generator/src/main/resources/vm/js/api.js.vm
index d78cd2f6..9295524a 100644
--- a/ruoyi-generator/src/main/resources/vm/js/api.js.vm
+++ b/acupuncture-generator/src/main/resources/vm/js/api.js.vm
@@ -1,44 +1,44 @@
-import request from '@/utils/request'
-
-// 查询${functionName}列表
-export function list${BusinessName}(query) {
-  return request({
-    url: '/${moduleName}/${businessName}/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询${functionName}详细
-export function get${BusinessName}(${pkColumn.javaField}) {
-  return request({
-    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
-    method: 'get'
-  })
-}
-
-// 新增${functionName}
-export function add${BusinessName}(data) {
-  return request({
-    url: '/${moduleName}/${businessName}',
-    method: 'post',
-    data: data
-  })
-}
-
-// 修改${functionName}
-export function update${BusinessName}(data) {
-  return request({
-    url: '/${moduleName}/${businessName}',
-    method: 'put',
-    data: data
-  })
-}
-
-// 删除${functionName}
-export function del${BusinessName}(${pkColumn.javaField}) {
-  return request({
-    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
-    method: 'delete'
-  })
-}
+import request from '@/utils/request'
+
+// 查询${functionName}列表
+export function list${BusinessName}(query) {
+  return request({
+    url: '/${moduleName}/${businessName}/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询${functionName}详细
+export function get${BusinessName}(${pkColumn.javaField}) {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'get'
+  })
+}
+
+// 新增${functionName}
+export function add${BusinessName}(data) {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'post',
+    data: data
+  })
+}
+
+// 修改${functionName}
+export function update${BusinessName}(data) {
+  return request({
+    url: '/${moduleName}/${businessName}',
+    method: 'put',
+    data: data
+  })
+}
+
+// 删除${functionName}
+export function del${BusinessName}(${pkColumn.javaField}) {
+  return request({
+    url: '/${moduleName}/${businessName}/' + ${pkColumn.javaField},
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-generator/src/main/resources/vm/sql/sql.vm b/acupuncture-generator/src/main/resources/vm/sql/sql.vm
similarity index 99%
rename from ruoyi-generator/src/main/resources/vm/sql/sql.vm
rename to acupuncture-generator/src/main/resources/vm/sql/sql.vm
index b50ef215..05755835 100644
--- a/ruoyi-generator/src/main/resources/vm/sql/sql.vm
+++ b/acupuncture-generator/src/main/resources/vm/sql/sql.vm
@@ -1,22 +1,22 @@
--- 菜单 SQL
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
-
--- 按钮父菜单ID
-SELECT @parentId := LAST_INSERT_ID();
-
--- 按钮 SQL
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}查询', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}新增', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}修改', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
-values('${functionName}删除', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 'admin', sysdate(), '', null, '');
-
-insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+-- 菜单 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}', '${parentMenuId}', '1', '${businessName}', '${moduleName}/${businessName}/index', 1, 0, 'C', '0', '0', '${permissionPrefix}:list', '#', 'admin', sysdate(), '', null, '${functionName}菜单');
+
+-- 按钮父菜单ID
+SELECT @parentId := LAST_INSERT_ID();
+
+-- 按钮 SQL
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}查询', @parentId, '1',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:query',        '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}新增', @parentId, '2',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:add',          '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}修改', @parentId, '3',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:edit',         '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
+values('${functionName}删除', @parentId, '4',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:remove',       '#', 'admin', sysdate(), '', null, '');
+
+insert into sys_menu (menu_name, parent_id, order_num, path, component, is_frame, is_cache, menu_type, visible, status, perms, icon, create_by, create_time, update_by, update_time, remark)
 values('${functionName}导出', @parentId, '5',  '#', '', 1, 0, 'F', '0', '0', '${permissionPrefix}:export',       '#', 'admin', sysdate(), '', null, '');
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm b/acupuncture-generator/src/main/resources/vm/vue/index-tree.vue.vm
similarity index 97%
rename from ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
rename to acupuncture-generator/src/main/resources/vm/vue/index-tree.vue.vm
index cbfb7cd7..4819c2a9 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
+++ b/acupuncture-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -1,505 +1,505 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-#foreach($column in $columns)
-#if($column.query)
-#set($dictType=$column.dictType)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.htmlType == "input")
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-input
-          v-model="queryParams.${column.javaField}"
-          placeholder="请输入${comment}"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
-          <el-option
-            v-for="dict in dict.type.${dictType}"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-date-picker clearable
-          v-model="queryParams.${column.javaField}"
-          type="date"
-          value-format="yyyy-MM-dd"
-          placeholder="选择${comment}">
-        </el-date-picker>
-      </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-      <el-form-item label="${comment}">
-        <el-date-picker
-          v-model="daterange${AttrName}"
-          style="width: 240px"
-          value-format="yyyy-MM-dd"
-          type="daterange"
-          range-separator="-"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-        ></el-date-picker>
-      </el-form-item>
-#end
-#end
-#end
-      <el-form-item>
-	    <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['${moduleName}:${businessName}:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="info"
-          plain
-          icon="el-icon-sort"
-          size="mini"
-          @click="toggleExpandAll"
-        >展开/折叠</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table
-      v-if="refreshTable"
-      v-loading="loading"
-      :data="${businessName}List"
-      row-key="${treeCode}"
-      :default-expand-all="isExpandAll"
-      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
-    >
-#foreach($column in $columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk)
-#elseif($column.list && $column.htmlType == "datetime")
-      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
-        </template>
-      </el-table-column>
-#elseif($column.list && $column.htmlType == "imageUpload")
-      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
-        <template slot-scope="scope">
-          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
-        </template>
-      </el-table-column>
-#elseif($column.list && "" != $column.dictType)
-      <el-table-column label="${comment}" align="center" prop="${javaField}">
-        <template slot-scope="scope">
-#if($column.htmlType == "checkbox")
-          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
-#else
-          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
-#end
-        </template>
-      </el-table-column>
-#elseif($column.list && "" != $javaField)
-#if(${foreach.index} == 1)
-      <el-table-column label="${comment}" prop="${javaField}" />
-#else
-      <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#end
-#end
-#end
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['${moduleName}:${businessName}:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-plus"
-            @click="handleAdd(scope.row)"
-            v-hasPermi="['${moduleName}:${businessName}:add']"
-          >新增</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['${moduleName}:${businessName}:remove']"
-          >删除</el-button>
-        </template>
-      </el-table-column>
-    </el-table>
-
-    <!-- 添加或修改${functionName}对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-#foreach($column in $columns)
-#set($field=$column.javaField)
-#if($column.insert && !$column.pk)
-#if(($column.usableColumn) || (!$column.superColumn))
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#set($dictType=$column.dictType)
-#if("" != $treeParentCode && $column.javaField == $treeParentCode)
-        <el-form-item label="${comment}" prop="${treeParentCode}">
-          <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="请选择${comment}" />
-        </el-form-item>
-#elseif($column.htmlType == "input")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
-        </el-form-item>
-#elseif($column.htmlType == "imageUpload")
-        <el-form-item label="${comment}" prop="${field}">
-          <image-upload v-model="form.${field}"/>
-        </el-form-item>
-#elseif($column.htmlType == "fileUpload")
-        <el-form-item label="${comment}" prop="${field}">
-          <file-upload v-model="form.${field}"/>
-        </el-form-item>
-#elseif($column.htmlType == "editor")
-        <el-form-item label="${comment}">
-          <editor v-model="form.${field}" :min-height="192"/>
-        </el-form-item>
-#elseif($column.htmlType == "select" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-select v-model="form.${field}" placeholder="请选择${comment}">
-            <el-option
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-              :label="dict.label"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
-              :value="parseInt(dict.value)"
-#else
-              :value="dict.value"
-#end
-            ></el-option>
-          </el-select>
-        </el-form-item>
-#elseif($column.htmlType == "select" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-select v-model="form.${field}" placeholder="请选择${comment}">
-            <el-option label="请选择字典生成" value="" />
-          </el-select>
-        </el-form-item>
-#elseif($column.htmlType == "checkbox" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-checkbox-group v-model="form.${field}">
-            <el-checkbox
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-              :label="dict.value">
-              {{dict.label}}
-            </el-checkbox>
-          </el-checkbox-group>
-        </el-form-item>
-#elseif($column.htmlType == "checkbox" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-checkbox-group v-model="form.${field}">
-            <el-checkbox>请选择字典生成</el-checkbox>
-          </el-checkbox-group>
-        </el-form-item>
-#elseif($column.htmlType == "radio" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-radio-group v-model="form.${field}">
-            <el-radio
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
-              :label="parseInt(dict.value)"
-#else
-              :label="dict.value"
-#end
-            >{{dict.label}}</el-radio>
-          </el-radio-group>
-        </el-form-item>
-#elseif($column.htmlType == "radio" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-radio-group v-model="form.${field}">
-            <el-radio label="1">请选择字典生成</el-radio>
-          </el-radio-group>
-        </el-form-item>
-#elseif($column.htmlType == "datetime")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-date-picker clearable
-            v-model="form.${field}"
-            type="date"
-            value-format="yyyy-MM-dd"
-            placeholder="选择${comment}">
-          </el-date-picker>
-        </el-form-item>
-#elseif($column.htmlType == "textarea")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
-        </el-form-item>
-#end
-#end
-#end
-#end
-      </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 { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
-import Treeselect from "@riophae/vue-treeselect";
-import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-
-export default {
-  name: "${BusinessName}",
-#if(${dicts} != '')
-  dicts: [${dicts}],
-#end
-  components: {
-    Treeselect
-  },
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 显示搜索条件
-      showSearch: true,
-      // ${functionName}表格数据
-      ${businessName}List: [],
-      // ${functionName}树选项
-      ${businessName}Options: [],
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-      // 是否展开,默认全部展开
-      isExpandAll: true,
-      // 重新渲染表格状态
-      refreshTable: true,
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      // $comment时间范围
-      daterange${AttrName}: [],
-#end
-#end
-      // 查询参数
-      queryParams: {
-#foreach ($column in $columns)
-#if($column.query)
-        $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-#foreach ($column in $columns)
-#if($column.required)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-        $column.javaField: [
-          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
-        ]#if($foreach.count != $columns.size()),#end
-#end
-#end
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询${functionName}列表 */
-    getList() {
-      this.loading = true;
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-      this.queryParams.params = {};
-#break
-#end
-#end
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
-        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
-        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
-      }
-#end
-#end
-      list${BusinessName}(this.queryParams).then(response => {
-        this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
-        this.loading = false;
-      });
-    },
-    /** 转换${functionName}数据结构 */
-    normalizer(node) {
-      if (node.children && !node.children.length) {
-        delete node.children;
-      }
-      return {
-        id: node.${treeCode},
-        label: node.${treeName},
-        children: node.children
-      };
-    },
-	/** 查询${functionName}下拉树结构 */
-    getTreeselect() {
-      list${BusinessName}().then(response => {
-        this.${businessName}Options = [];
-        const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
-        data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
-        this.${businessName}Options.push(data);
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-        $column.javaField: []#if($foreach.count != $columns.size()),#end
-#else
-        $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
-      };
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      this.daterange${AttrName} = [];
-#end
-#end
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    /** 新增按钮操作 */
-    handleAdd(row) {
-      this.reset();
-      this.getTreeselect();
-      if (row != null && row.${treeCode}) {
-        this.form.${treeParentCode} = row.${treeCode};
-      } else {
-        this.form.${treeParentCode} = 0;
-      }
-      this.open = true;
-      this.title = "添加${functionName}";
-    },
-    /** 展开/折叠操作 */
-    toggleExpandAll() {
-      this.refreshTable = false;
-      this.isExpandAll = !this.isExpandAll;
-      this.$nextTick(() => {
-        this.refreshTable = true;
-      });
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      this.getTreeselect();
-      if (row != null) {
-        this.form.${treeParentCode} = row.${treeParentCode};
-      }
-      get${BusinessName}(row.${pkColumn.javaField}).then(response => {
-        this.form = response.data;
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-        this.form.$column.javaField = this.form.${column.javaField}.split(",");
-#end
-#end
-        this.open = true;
-        this.title = "修改${functionName}";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.#[[$]]#refs["form"].validate(valid => {
-        if (valid) {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-          this.form.$column.javaField = this.form.${column.javaField}.join(",");
-#end
-#end
-          if (this.form.${pkColumn.javaField} != null) {
-            update${BusinessName}(this.form).then(response => {
-              this.#[[$modal]]#.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            add${BusinessName}(this.form).then(response => {
-              this.#[[$modal]]#.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
-        return del${BusinessName}(row.${pkColumn.javaField});
-      }).then(() => {
-        this.getList();
-        this.#[[$modal]]#.msgSuccess("删除成功");
-      }).catch(() => {});
-    }
-  }
-};
-</script>
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="请输入${comment}"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+          <el-option
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="选择${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+	    <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-sort"
+          size="mini"
+          @click="toggleExpandAll"
+        >展开/折叠</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table
+      v-if="refreshTable"
+      v-loading="loading"
+      :data="${businessName}List"
+      row-key="${treeCode}"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template slot-scope="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+      <el-table-column label="${comment}" prop="${javaField}" />
+#else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:add']"
+          >新增</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:remove']"
+          >删除</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 添加或修改${functionName}对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if("" != $treeParentCode && $column.javaField == $treeParentCode)
+        <el-form-item label="${comment}" prop="${treeParentCode}">
+          <treeselect v-model="form.${treeParentCode}" :options="${businessName}Options" :normalizer="normalizer" placeholder="请选择${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>请选择字典生成</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="选择${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+      </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 { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
+  components: {
+    Treeselect
+  },
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 显示搜索条件
+      showSearch: true,
+      // ${functionName}表格数据
+      ${businessName}List: [],
+      // ${functionName}树选项
+      ${businessName}Options: [],
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+      // 是否展开,默认全部展开
+      isExpandAll: true,
+      // 重新渲染表格状态
+      refreshTable: true,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      // $comment时间范围
+      daterange${AttrName}: [],
+#end
+#end
+      // 查询参数
+      queryParams: {
+#foreach ($column in $columns)
+#if($column.query)
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+        $column.javaField: [
+          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+        ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询${functionName}列表 */
+    getList() {
+      this.loading = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      this.queryParams.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
+        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
+      }
+#end
+#end
+      list${BusinessName}(this.queryParams).then(response => {
+        this.${businessName}List = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+        this.loading = false;
+      });
+    },
+    /** 转换${functionName}数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.${treeCode},
+        label: node.${treeName},
+        children: node.children
+      };
+    },
+	/** 查询${functionName}下拉树结构 */
+    getTreeselect() {
+      list${BusinessName}().then(response => {
+        this.${businessName}Options = [];
+        const data = { ${treeCode}: 0, ${treeName}: '顶级节点', children: [] };
+        data.children = this.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+        this.${businessName}Options.push(data);
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      };
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      this.daterange${AttrName} = [];
+#end
+#end
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 新增按钮操作 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null && row.${treeCode}) {
+        this.form.${treeParentCode} = row.${treeCode};
+      } else {
+        this.form.${treeParentCode} = 0;
+      }
+      this.open = true;
+      this.title = "添加${functionName}";
+    },
+    /** 展开/折叠操作 */
+    toggleExpandAll() {
+      this.refreshTable = false;
+      this.isExpandAll = !this.isExpandAll;
+      this.$nextTick(() => {
+        this.refreshTable = true;
+      });
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null) {
+        this.form.${treeParentCode} = row.${treeParentCode};
+      }
+      get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+        this.form = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        this.form.$column.javaField = this.form.${column.javaField}.split(",");
+#end
+#end
+        this.open = true;
+        this.title = "修改${functionName}";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.#[[$]]#refs["form"].validate(valid => {
+        if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+          this.form.$column.javaField = this.form.${column.javaField}.join(",");
+#end
+#end
+          if (this.form.${pkColumn.javaField} != null) {
+            update${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            add${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + row.${pkColumn.javaField} + '"的数据项?').then(function() {
+        return del${BusinessName}(row.${pkColumn.javaField});
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("删除成功");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/acupuncture-generator/src/main/resources/vm/vue/index.vue.vm
similarity index 97%
rename from ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
rename to acupuncture-generator/src/main/resources/vm/vue/index.vue.vm
index 70ff30dd..6296014b 100644
--- a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
+++ b/acupuncture-generator/src/main/resources/vm/vue/index.vue.vm
@@ -1,602 +1,602 @@
-<template>
-  <div class="app-container">
-    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
-#foreach($column in $columns)
-#if($column.query)
-#set($dictType=$column.dictType)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.htmlType == "input")
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-input
-          v-model="queryParams.${column.javaField}"
-          placeholder="请输入${comment}"
-          clearable
-          @keyup.enter.native="handleQuery"
-        />
-      </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
-          <el-option
-            v-for="dict in dict.type.${dictType}"
-            :key="dict.value"
-            :label="dict.label"
-            :value="dict.value"
-          />
-        </el-select>
-      </el-form-item>
-#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
-          <el-option label="请选择字典生成" value="" />
-        </el-select>
-      </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
-      <el-form-item label="${comment}" prop="${column.javaField}">
-        <el-date-picker clearable
-          v-model="queryParams.${column.javaField}"
-          type="date"
-          value-format="yyyy-MM-dd"
-          placeholder="请选择${comment}">
-        </el-date-picker>
-      </el-form-item>
-#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-      <el-form-item label="${comment}">
-        <el-date-picker
-          v-model="daterange${AttrName}"
-          style="width: 240px"
-          value-format="yyyy-MM-dd"
-          type="daterange"
-          range-separator="-"
-          start-placeholder="开始日期"
-          end-placeholder="结束日期"
-        ></el-date-picker>
-      </el-form-item>
-#end
-#end
-#end
-      <el-form-item>
-        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
-        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
-      </el-form-item>
-    </el-form>
-
-    <el-row :gutter="10" class="mb8">
-      <el-col :span="1.5">
-        <el-button
-          type="primary"
-          plain
-          icon="el-icon-plus"
-          size="mini"
-          @click="handleAdd"
-          v-hasPermi="['${moduleName}:${businessName}:add']"
-        >新增</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="success"
-          plain
-          icon="el-icon-edit"
-          size="mini"
-          :disabled="single"
-          @click="handleUpdate"
-          v-hasPermi="['${moduleName}:${businessName}:edit']"
-        >修改</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="danger"
-          plain
-          icon="el-icon-delete"
-          size="mini"
-          :disabled="multiple"
-          @click="handleDelete"
-          v-hasPermi="['${moduleName}:${businessName}:remove']"
-        >删除</el-button>
-      </el-col>
-      <el-col :span="1.5">
-        <el-button
-          type="warning"
-          plain
-          icon="el-icon-download"
-          size="mini"
-          @click="handleExport"
-          v-hasPermi="['${moduleName}:${businessName}:export']"
-        >导出</el-button>
-      </el-col>
-      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
-    </el-row>
-
-    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
-      <el-table-column type="selection" width="55" align="center" />
-#foreach($column in $columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk)
-      <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#elseif($column.list && $column.htmlType == "datetime")
-      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
-        <template slot-scope="scope">
-          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
-        </template>
-      </el-table-column>
-#elseif($column.list && $column.htmlType == "imageUpload")
-      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
-        <template slot-scope="scope">
-          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
-        </template>
-      </el-table-column>
-#elseif($column.list && "" != $column.dictType)
-      <el-table-column label="${comment}" align="center" prop="${javaField}">
-        <template slot-scope="scope">
-#if($column.htmlType == "checkbox")
-          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
-#else
-          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
-#end
-        </template>
-      </el-table-column>
-#elseif($column.list && "" != $javaField)
-      <el-table-column label="${comment}" align="center" prop="${javaField}" />
-#end
-#end
-      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
-        <template slot-scope="scope">
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-edit"
-            @click="handleUpdate(scope.row)"
-            v-hasPermi="['${moduleName}:${businessName}:edit']"
-          >修改</el-button>
-          <el-button
-            size="mini"
-            type="text"
-            icon="el-icon-delete"
-            @click="handleDelete(scope.row)"
-            v-hasPermi="['${moduleName}:${businessName}: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"
-    />
-
-    <!-- 添加或修改${functionName}对话框 -->
-    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
-      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
-#foreach($column in $columns)
-#set($field=$column.javaField)
-#if($column.insert && !$column.pk)
-#if(($column.usableColumn) || (!$column.superColumn))
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#set($dictType=$column.dictType)
-#if($column.htmlType == "input")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
-        </el-form-item>
-#elseif($column.htmlType == "imageUpload")
-        <el-form-item label="${comment}" prop="${field}">
-          <image-upload v-model="form.${field}"/>
-        </el-form-item>
-#elseif($column.htmlType == "fileUpload")
-        <el-form-item label="${comment}" prop="${field}">
-          <file-upload v-model="form.${field}"/>
-        </el-form-item>
-#elseif($column.htmlType == "editor")
-        <el-form-item label="${comment}">
-          <editor v-model="form.${field}" :min-height="192"/>
-        </el-form-item>
-#elseif($column.htmlType == "select" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-select v-model="form.${field}" placeholder="请选择${comment}">
-            <el-option
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-              :label="dict.label"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
-              :value="parseInt(dict.value)"
-#else
-              :value="dict.value"
-#end
-            ></el-option>
-          </el-select>
-        </el-form-item>
-#elseif($column.htmlType == "select" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-select v-model="form.${field}" placeholder="请选择${comment}">
-            <el-option label="请选择字典生成" value="" />
-          </el-select>
-        </el-form-item>
-#elseif($column.htmlType == "checkbox" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-checkbox-group v-model="form.${field}">
-            <el-checkbox
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-              :label="dict.value">
-              {{dict.label}}
-            </el-checkbox>
-          </el-checkbox-group>
-        </el-form-item>
-#elseif($column.htmlType == "checkbox" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-checkbox-group v-model="form.${field}">
-            <el-checkbox>请选择字典生成</el-checkbox>
-          </el-checkbox-group>
-        </el-form-item>
-#elseif($column.htmlType == "radio" && "" != $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-radio-group v-model="form.${field}">
-            <el-radio
-              v-for="dict in dict.type.${dictType}"
-              :key="dict.value"
-#if($column.javaType == "Integer" || $column.javaType == "Long")
-              :label="parseInt(dict.value)"
-#else
-              :label="dict.value"
-#end
-            >{{dict.label}}</el-radio>
-          </el-radio-group>
-        </el-form-item>
-#elseif($column.htmlType == "radio" && $dictType)
-        <el-form-item label="${comment}" prop="${field}">
-          <el-radio-group v-model="form.${field}">
-            <el-radio label="1">请选择字典生成</el-radio>
-          </el-radio-group>
-        </el-form-item>
-#elseif($column.htmlType == "datetime")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-date-picker clearable
-            v-model="form.${field}"
-            type="date"
-            value-format="yyyy-MM-dd"
-            placeholder="请选择${comment}">
-          </el-date-picker>
-        </el-form-item>
-#elseif($column.htmlType == "textarea")
-        <el-form-item label="${comment}" prop="${field}">
-          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
-        </el-form-item>
-#end
-#end
-#end
-#end
-#if($table.sub)
-        <el-divider content-position="center">${subTable.functionName}信息</el-divider>
-        <el-row :gutter="10" class="mb8">
-          <el-col :span="1.5">
-            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
-          </el-col>
-          <el-col :span="1.5">
-            <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
-          </el-col>
-        </el-row>
-        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
-          <el-table-column type="selection" width="50" align="center" />
-          <el-table-column label="序号" align="center" prop="index" width="50"/>
-#foreach($column in $subTable.columns)
-#set($javaField=$column.javaField)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-#if($column.pk || $javaField == ${subTableFkclassName})
-#elseif($column.list && $column.htmlType == "input")
-          <el-table-column label="$comment" prop="${javaField}" width="150">
-            <template slot-scope="scope">
-              <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
-            </template>
-          </el-table-column>
-#elseif($column.list && $column.htmlType == "datetime")
-          <el-table-column label="$comment" prop="${javaField}" width="240">
-            <template slot-scope="scope">
-              <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
-            </template>
-          </el-table-column>
-#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
-          <el-table-column label="$comment" prop="${javaField}" width="150">
-            <template slot-scope="scope">
-              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
-                <el-option
-                  v-for="dict in dict.type.$column.dictType"
-                  :key="dict.value"
-                  :label="dict.label"
-                  :value="dict.value"
-                ></el-option>
-              </el-select>
-            </template>
-          </el-table-column>
-#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
-          <el-table-column label="$comment" prop="${javaField}" width="150">
-            <template slot-scope="scope">
-              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
-                <el-option label="请选择字典生成" value="" />
-              </el-select>
-            </template>
-          </el-table-column>
-#end
-#end
-        </el-table>
-#end
-      </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 { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
-
-export default {
-  name: "${BusinessName}",
-#if(${dicts} != '')
-  dicts: [${dicts}],
-#end
-  data() {
-    return {
-      // 遮罩层
-      loading: true,
-      // 选中数组
-      ids: [],
-#if($table.sub)
-      // 子表选中数据
-      checked${subClassName}: [],
-#end
-      // 非单个禁用
-      single: true,
-      // 非多个禁用
-      multiple: true,
-      // 显示搜索条件
-      showSearch: true,
-      // 总条数
-      total: 0,
-      // ${functionName}表格数据
-      ${businessName}List: [],
-#if($table.sub)
-      // ${subTable.functionName}表格数据
-      ${subclassName}List: [],
-#end
-      // 弹出层标题
-      title: "",
-      // 是否显示弹出层
-      open: false,
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      // $comment时间范围
-      daterange${AttrName}: [],
-#end
-#end
-      // 查询参数
-      queryParams: {
-        pageNum: 1,
-        pageSize: 10,
-#foreach ($column in $columns)
-#if($column.query)
-        $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
-      },
-      // 表单参数
-      form: {},
-      // 表单校验
-      rules: {
-#foreach ($column in $columns)
-#if($column.required)
-#set($parentheseIndex=$column.columnComment.indexOf("("))
-#if($parentheseIndex != -1)
-#set($comment=$column.columnComment.substring(0, $parentheseIndex))
-#else
-#set($comment=$column.columnComment)
-#end
-        $column.javaField: [
-          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
-        ]#if($foreach.count != $columns.size()),#end
-#end
-#end
-      }
-    };
-  },
-  created() {
-    this.getList();
-  },
-  methods: {
-    /** 查询${functionName}列表 */
-    getList() {
-      this.loading = true;
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-      this.queryParams.params = {};
-#break
-#end
-#end
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
-        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
-        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
-      }
-#end
-#end
-      list${BusinessName}(this.queryParams).then(response => {
-        this.${businessName}List = response.rows;
-        this.total = response.total;
-        this.loading = false;
-      });
-    },
-    // 取消按钮
-    cancel() {
-      this.open = false;
-      this.reset();
-    },
-    // 表单重置
-    reset() {
-      this.form = {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-        $column.javaField: []#if($foreach.count != $columns.size()),#end
-#else
-        $column.javaField: null#if($foreach.count != $columns.size()),#end
-#end
-#end
-      };
-#if($table.sub)
-      this.${subclassName}List = [];
-#end
-      this.resetForm("form");
-    },
-    /** 搜索按钮操作 */
-    handleQuery() {
-      this.queryParams.pageNum = 1;
-      this.getList();
-    },
-    /** 重置按钮操作 */
-    resetQuery() {
-#foreach ($column in $columns)
-#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-      this.daterange${AttrName} = [];
-#end
-#end
-      this.resetForm("queryForm");
-      this.handleQuery();
-    },
-    // 多选框选中数据
-    handleSelectionChange(selection) {
-      this.ids = selection.map(item => item.${pkColumn.javaField})
-      this.single = selection.length!==1
-      this.multiple = !selection.length
-    },
-    /** 新增按钮操作 */
-    handleAdd() {
-      this.reset();
-      this.open = true;
-      this.title = "添加${functionName}";
-    },
-    /** 修改按钮操作 */
-    handleUpdate(row) {
-      this.reset();
-      const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
-      get${BusinessName}(${pkColumn.javaField}).then(response => {
-        this.form = response.data;
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-        this.form.$column.javaField = this.form.${column.javaField}.split(",");
-#end
-#end
-#if($table.sub)
-        this.${subclassName}List = response.data.${subclassName}List;
-#end
-        this.open = true;
-        this.title = "修改${functionName}";
-      });
-    },
-    /** 提交按钮 */
-    submitForm() {
-      this.#[[$]]#refs["form"].validate(valid => {
-        if (valid) {
-#foreach ($column in $columns)
-#if($column.htmlType == "checkbox")
-          this.form.$column.javaField = this.form.${column.javaField}.join(",");
-#end
-#end
-#if($table.sub)
-          this.form.${subclassName}List = this.${subclassName}List;
-#end
-          if (this.form.${pkColumn.javaField} != null) {
-            update${BusinessName}(this.form).then(response => {
-              this.#[[$modal]]#.msgSuccess("修改成功");
-              this.open = false;
-              this.getList();
-            });
-          } else {
-            add${BusinessName}(this.form).then(response => {
-              this.#[[$modal]]#.msgSuccess("新增成功");
-              this.open = false;
-              this.getList();
-            });
-          }
-        }
-      });
-    },
-    /** 删除按钮操作 */
-    handleDelete(row) {
-      const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
-      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
-        return del${BusinessName}(${pkColumn.javaField}s);
-      }).then(() => {
-        this.getList();
-        this.#[[$modal]]#.msgSuccess("删除成功");
-      }).catch(() => {});
-    },
-#if($table.sub)
-	/** ${subTable.functionName}序号 */
-    row${subClassName}Index({ row, rowIndex }) {
-      row.index = rowIndex + 1;
-    },
-    /** ${subTable.functionName}添加按钮操作 */
-    handleAdd${subClassName}() {
-      let obj = {};
-#foreach($column in $subTable.columns)
-#if($column.pk || $column.javaField == ${subTableFkclassName})
-#elseif($column.list && "" != $javaField)
-      obj.$column.javaField = "";
-#end
-#end
-      this.${subclassName}List.push(obj);
-    },
-    /** ${subTable.functionName}删除按钮操作 */
-    handleDelete${subClassName}() {
-      if (this.checked${subClassName}.length == 0) {
-        this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
-      } else {
-        const ${subclassName}List = this.${subclassName}List;
-        const checked${subClassName} = this.checked${subClassName};
-        this.${subclassName}List = ${subclassName}List.filter(function(item) {
-          return checked${subClassName}.indexOf(item.index) == -1
-        });
-      }
-    },
-    /** 复选框选中数据 */
-    handle${subClassName}SelectionChange(selection) {
-      this.checked${subClassName} = selection.map(item => item.index)
-    },
-#end
-    /** 导出按钮操作 */
-    handleExport() {
-      this.download('${moduleName}/${businessName}/export', {
-        ...this.queryParams
-      }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
-    }
-  }
-};
-</script>
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+#foreach($column in $columns)
+#if($column.query)
+#set($dictType=$column.dictType)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.htmlType == "input")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-input
+          v-model="queryParams.${column.javaField}"
+          placeholder="请输入${comment}"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+          <el-option
+            v-for="dict in dict.type.${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="请选择${comment}" clearable>
+          <el-option label="请选择字典生成" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="yyyy-MM-dd"
+          placeholder="请选择${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="开始日期"
+          end-placeholder="结束日期"
+        ></el-date-picker>
+      </el-form-item>
+#end
+#end
+#end
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">搜索</el-button>
+        <el-button icon="el-icon-refresh" size="mini" @click="resetQuery">重置</el-button>
+      </el-form-item>
+    </el-form>
+
+    <el-row :gutter="10" class="mb8">
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >新增</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['${moduleName}:${businessName}:edit']"
+        >修改</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['${moduleName}:${businessName}:remove']"
+        >删除</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['${moduleName}:${businessName}:export']"
+        >导出</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="${businessName}List" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+#foreach($column in $columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#elseif($column.list && $column.htmlType == "datetime")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template slot-scope="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template slot-scope="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="dict.type.${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+      <el-table-column label="操作" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}:edit']"
+          >修改</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['${moduleName}:${businessName}: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"
+    />
+
+    <!-- 添加或修改${functionName}对话框 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+#foreach($column in $columns)
+#set($field=$column.javaField)
+#if($column.insert && !$column.pk)
+#if(($column.usableColumn) || (!$column.superColumn))
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#set($dictType=$column.dictType)
+#if($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="请输入${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="请选择${comment}">
+            <el-option label="请选择字典生成" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>请选择字典生成</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in dict.type.${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">请选择字典生成</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="date"
+            value-format="yyyy-MM-dd"
+            placeholder="请选择${comment}">
+          </el-date-picker>
+        </el-form-item>
+#elseif($column.htmlType == "textarea")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" type="textarea" placeholder="请输入内容" />
+        </el-form-item>
+#end
+#end
+#end
+#end
+#if($table.sub)
+        <el-divider content-position="center">${subTable.functionName}信息</el-divider>
+        <el-row :gutter="10" class="mb8">
+          <el-col :span="1.5">
+            <el-button type="primary" icon="el-icon-plus" size="mini" @click="handleAdd${subClassName}">添加</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" icon="el-icon-delete" size="mini" @click="handleDelete${subClassName}">删除</el-button>
+          </el-col>
+        </el-row>
+        <el-table :data="${subclassName}List" :row-class-name="row${subClassName}Index" @selection-change="handle${subClassName}SelectionChange" ref="${subclassName}">
+          <el-table-column type="selection" width="50" align="center" />
+          <el-table-column label="序号" align="center" prop="index" width="50"/>
+#foreach($column in $subTable.columns)
+#set($javaField=$column.javaField)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+#if($column.pk || $javaField == ${subTableFkclassName})
+#elseif($column.list && $column.htmlType == "input")
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.$javaField" placeholder="请输入$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && $column.htmlType == "datetime")
+          <el-table-column label="$comment" prop="${javaField}" width="240">
+            <template slot-scope="scope">
+              <el-date-picker clearable v-model="scope.row.$javaField" type="date" value-format="yyyy-MM-dd" placeholder="请选择$comment" />
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" != $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option
+                  v-for="dict in dict.type.$column.dictType"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+#elseif($column.list && ($column.htmlType == "select" || $column.htmlType == "radio") && "" == $column.dictType)
+          <el-table-column label="$comment" prop="${javaField}" width="150">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="请选择$comment">
+                <el-option label="请选择字典生成" value="" />
+              </el-select>
+            </template>
+          </el-table-column>
+#end
+#end
+        </el-table>
+#end
+      </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 { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+export default {
+  name: "${BusinessName}",
+#if(${dicts} != '')
+  dicts: [${dicts}],
+#end
+  data() {
+    return {
+      // 遮罩层
+      loading: true,
+      // 选中数组
+      ids: [],
+#if($table.sub)
+      // 子表选中数据
+      checked${subClassName}: [],
+#end
+      // 非单个禁用
+      single: true,
+      // 非多个禁用
+      multiple: true,
+      // 显示搜索条件
+      showSearch: true,
+      // 总条数
+      total: 0,
+      // ${functionName}表格数据
+      ${businessName}List: [],
+#if($table.sub)
+      // ${subTable.functionName}表格数据
+      ${subclassName}List: [],
+#end
+      // 弹出层标题
+      title: "",
+      // 是否显示弹出层
+      open: false,
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      // $comment时间范围
+      daterange${AttrName}: [],
+#end
+#end
+      // 查询参数
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+#foreach ($column in $columns)
+#if($column.query)
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      },
+      // 表单参数
+      form: {},
+      // 表单校验
+      rules: {
+#foreach ($column in $columns)
+#if($column.required)
+#set($parentheseIndex=$column.columnComment.indexOf("("))
+#if($parentheseIndex != -1)
+#set($comment=$column.columnComment.substring(0, $parentheseIndex))
+#else
+#set($comment=$column.columnComment)
+#end
+        $column.javaField: [
+          { required: true, message: "$comment不能为空", trigger: #if($column.htmlType == "select" || $column.htmlType == "radio")"change"#else"blur"#end }
+        ]#if($foreach.count != $columns.size()),#end
+#end
+#end
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 查询${functionName}列表 */
+    getList() {
+      this.loading = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      this.queryParams.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      if (null != this.daterange${AttrName} && '' != this.daterange${AttrName}) {
+        this.queryParams.params["begin${AttrName}"] = this.daterange${AttrName}[0];
+        this.queryParams.params["end${AttrName}"] = this.daterange${AttrName}[1];
+      }
+#end
+#end
+      list${BusinessName}(this.queryParams).then(response => {
+        this.${businessName}List = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 取消按钮
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 表单重置
+    reset() {
+      this.form = {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        $column.javaField: []#if($foreach.count != $columns.size()),#end
+#else
+        $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+      };
+#if($table.sub)
+      this.${subclassName}List = [];
+#end
+      this.resetForm("form");
+    },
+    /** 搜索按钮操作 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 重置按钮操作 */
+    resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+      this.daterange${AttrName} = [];
+#end
+#end
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 多选框选中数据
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.${pkColumn.javaField})
+      this.single = selection.length!==1
+      this.multiple = !selection.length
+    },
+    /** 新增按钮操作 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "添加${functionName}";
+    },
+    /** 修改按钮操作 */
+    handleUpdate(row) {
+      this.reset();
+      const ${pkColumn.javaField} = row.${pkColumn.javaField} || this.ids
+      get${BusinessName}(${pkColumn.javaField}).then(response => {
+        this.form = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+        this.form.$column.javaField = this.form.${column.javaField}.split(",");
+#end
+#end
+#if($table.sub)
+        this.${subclassName}List = response.data.${subclassName}List;
+#end
+        this.open = true;
+        this.title = "修改${functionName}";
+      });
+    },
+    /** 提交按钮 */
+    submitForm() {
+      this.#[[$]]#refs["form"].validate(valid => {
+        if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+          this.form.$column.javaField = this.form.${column.javaField}.join(",");
+#end
+#end
+#if($table.sub)
+          this.form.${subclassName}List = this.${subclassName}List;
+#end
+          if (this.form.${pkColumn.javaField} != null) {
+            update${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("修改成功");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            add${BusinessName}(this.form).then(response => {
+              this.#[[$modal]]#.msgSuccess("新增成功");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 删除按钮操作 */
+    handleDelete(row) {
+      const ${pkColumn.javaField}s = row.${pkColumn.javaField} || this.ids;
+      this.#[[$modal]]#.confirm('是否确认删除${functionName}编号为"' + ${pkColumn.javaField}s + '"的数据项?').then(function() {
+        return del${BusinessName}(${pkColumn.javaField}s);
+      }).then(() => {
+        this.getList();
+        this.#[[$modal]]#.msgSuccess("删除成功");
+      }).catch(() => {});
+    },
+#if($table.sub)
+	/** ${subTable.functionName}序号 */
+    row${subClassName}Index({ row, rowIndex }) {
+      row.index = rowIndex + 1;
+    },
+    /** ${subTable.functionName}添加按钮操作 */
+    handleAdd${subClassName}() {
+      let obj = {};
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+      obj.$column.javaField = "";
+#end
+#end
+      this.${subclassName}List.push(obj);
+    },
+    /** ${subTable.functionName}删除按钮操作 */
+    handleDelete${subClassName}() {
+      if (this.checked${subClassName}.length == 0) {
+        this.#[[$modal]]#.msgError("请先选择要删除的${subTable.functionName}数据");
+      } else {
+        const ${subclassName}List = this.${subclassName}List;
+        const checked${subClassName} = this.checked${subClassName};
+        this.${subclassName}List = ${subclassName}List.filter(function(item) {
+          return checked${subClassName}.indexOf(item.index) == -1
+        });
+      }
+    },
+    /** 复选框选中数据 */
+    handle${subClassName}SelectionChange(selection) {
+      this.checked${subClassName} = selection.map(item => item.index)
+    },
+#end
+    /** 导出按钮操作 */
+    handleExport() {
+      this.download('${moduleName}/${businessName}/export', {
+        ...this.queryParams
+      }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/acupuncture-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
similarity index 100%
rename from ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
rename to acupuncture-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm b/acupuncture-generator/src/main/resources/vm/vue/v3/index.vue.vm
similarity index 100%
rename from ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
rename to acupuncture-generator/src/main/resources/vm/vue/v3/index.vue.vm
diff --git a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/acupuncture-generator/src/main/resources/vm/xml/mapper.xml.vm
similarity index 98%
rename from ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
rename to acupuncture-generator/src/main/resources/vm/xml/mapper.xml.vm
index 84ce337b..456755b5 100644
--- a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
+++ b/acupuncture-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -1,140 +1,140 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<!DOCTYPE mapper
-PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
-"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
-<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
-    
-    <resultMap type="${ClassName}" id="${ClassName}Result">
-#foreach ($column in $columns)
-        <result property="${column.javaField}"    column="${column.columnName}"    />
-#end
-    </resultMap>
-#if($table.sub)
-
-    <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
-        <collection property="${subclassName}List" ofType="${subClassName}" column="${pkColumn.columnName}" select="select${subClassName}List" />
-    </resultMap>
-
-    <resultMap type="${subClassName}" id="${subClassName}Result">
-#foreach ($column in $subTable.columns)
-        <result property="${column.javaField}"    column="${column.columnName}"    />
-#end
-    </resultMap>
-#end
-
-    <sql id="select${ClassName}Vo">
-        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
-    </sql>
-
-    <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
-        <include refid="select${ClassName}Vo"/>
-        <where>  
-#foreach($column in $columns)
-#set($queryType=$column.queryType)
-#set($javaField=$column.javaField)
-#set($javaType=$column.javaType)
-#set($columnName=$column.columnName)
-#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
-#if($column.query)
-#if($column.queryType == "EQ")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if>
-#elseif($queryType == "NE")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if>
-#elseif($queryType == "GT")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt; #{$javaField}</if>
-#elseif($queryType == "GTE")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt;= #{$javaField}</if>
-#elseif($queryType == "LT")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt; #{$javaField}</if>
-#elseif($queryType == "LTE")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt;= #{$javaField}</if>
-#elseif($queryType == "LIKE")
-            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if>
-#elseif($queryType == "BETWEEN")
-            <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>
-#end
-#end
-#end
-        </where>
-    </select>
-    
-    <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
-#if($table.crud || $table.tree)
-        <include refid="select${ClassName}Vo"/>
-        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-#elseif($table.sub)
-        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end
-        from ${tableName}
-        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-#end
-    </select>
-#if($table.sub)
-
-    <select id="select${subClassName}List" resultMap="${subClassName}Result">
-        select#foreach ($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end
-        from ${subTableName}
-        where ${subTableFkName} = #{${subTableFkName}}
-    </select>
-#end
-
-    <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
-        insert into ${tableName}
-        <trim prefix="(" suffix=")" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
-            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if>
-#end
-#end
-         </trim>
-        <trim prefix="values (" suffix=")" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
-            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if>
-#end
-#end
-         </trim>
-    </insert>
-
-    <update id="update${ClassName}" parameterType="${ClassName}">
-        update ${tableName}
-        <trim prefix="SET" suffixOverrides=",">
-#foreach($column in $columns)
-#if($column.columnName != $pkColumn.columnName)
-            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if>
-#end
-#end
-        </trim>
-        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-    </update>
-
-    <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
-        delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
-    </delete>
-
-    <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
-        delete from ${tableName} where ${pkColumn.columnName} in 
-        <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
-            #{${pkColumn.javaField}}
-        </foreach>
-    </delete>
-#if($table.sub)
-    
-    <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
-        delete from ${subTableName} where ${subTableFkName} in 
-        <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
-            #{${subTableFkclassName}}
-        </foreach>
-    </delete>
-
-    <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}">
-        delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
-    </delete>
-
-    <insert id="batch${subClassName}">
-        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
-        <foreach item="item" index="index" collection="list" separator=",">
-            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
-        </foreach>
-    </insert>
-#end
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="${packageName}.mapper.${ClassName}Mapper">
+    
+    <resultMap type="${ClassName}" id="${ClassName}Result">
+#foreach ($column in $columns)
+        <result property="${column.javaField}"    column="${column.columnName}"    />
+#end
+    </resultMap>
+#if($table.sub)
+
+    <resultMap id="${ClassName}${subClassName}Result" type="${ClassName}" extends="${ClassName}Result">
+        <collection property="${subclassName}List" ofType="${subClassName}" column="${pkColumn.columnName}" select="select${subClassName}List" />
+    </resultMap>
+
+    <resultMap type="${subClassName}" id="${subClassName}Result">
+#foreach ($column in $subTable.columns)
+        <result property="${column.javaField}"    column="${column.columnName}"    />
+#end
+    </resultMap>
+#end
+
+    <sql id="select${ClassName}Vo">
+        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end from ${tableName}
+    </sql>
+
+    <select id="select${ClassName}List" parameterType="${ClassName}" resultMap="${ClassName}Result">
+        <include refid="select${ClassName}Vo"/>
+        <where>  
+#foreach($column in $columns)
+#set($queryType=$column.queryType)
+#set($javaField=$column.javaField)
+#set($javaType=$column.javaType)
+#set($columnName=$column.columnName)
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+#if($column.query)
+#if($column.queryType == "EQ")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName = #{$javaField}</if>
+#elseif($queryType == "NE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName != #{$javaField}</if>
+#elseif($queryType == "GT")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt; #{$javaField}</if>
+#elseif($queryType == "GTE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &gt;= #{$javaField}</if>
+#elseif($queryType == "LT")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt; #{$javaField}</if>
+#elseif($queryType == "LTE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName &lt;= #{$javaField}</if>
+#elseif($queryType == "LIKE")
+            <if test="$javaField != null #if($javaType == 'String' ) and $javaField.trim() != ''#end"> and $columnName like concat('%', #{$javaField}, '%')</if>
+#elseif($queryType == "BETWEEN")
+            <if test="params.begin$AttrName != null and params.begin$AttrName != '' and params.end$AttrName != null and params.end$AttrName != ''"> and $columnName between #{params.begin$AttrName} and #{params.end$AttrName}</if>
+#end
+#end
+#end
+        </where>
+    </select>
+    
+    <select id="select${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}" resultMap="#if($table.sub)${ClassName}${subClassName}Result#else${ClassName}Result#end">
+#if($table.crud || $table.tree)
+        <include refid="select${ClassName}Vo"/>
+        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+#elseif($table.sub)
+        select#foreach($column in $columns) $column.columnName#if($foreach.count != $columns.size()),#end#end
+        from ${tableName}
+        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+#end
+    </select>
+#if($table.sub)
+
+    <select id="select${subClassName}List" resultMap="${subClassName}Result">
+        select#foreach ($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end
+        from ${subTableName}
+        where ${subTableFkName} = #{${subTableFkName}}
+    </select>
+#end
+
+    <insert id="insert${ClassName}" parameterType="${ClassName}"#if($pkColumn.increment) useGeneratedKeys="true" keyProperty="$pkColumn.javaField"#end>
+        insert into ${tableName}
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName,</if>
+#end
+#end
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName || !$pkColumn.increment)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">#{$column.javaField},</if>
+#end
+#end
+         </trim>
+    </insert>
+
+    <update id="update${ClassName}" parameterType="${ClassName}">
+        update ${tableName}
+        <trim prefix="SET" suffixOverrides=",">
+#foreach($column in $columns)
+#if($column.columnName != $pkColumn.columnName)
+            <if test="$column.javaField != null#if($column.javaType == 'String' && $column.required) and $column.javaField != ''#end">$column.columnName = #{$column.javaField},</if>
+#end
+#end
+        </trim>
+        where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+    </update>
+
+    <delete id="delete${ClassName}By${pkColumn.capJavaField}" parameterType="${pkColumn.javaType}">
+        delete from ${tableName} where ${pkColumn.columnName} = #{${pkColumn.javaField}}
+    </delete>
+
+    <delete id="delete${ClassName}By${pkColumn.capJavaField}s" parameterType="String">
+        delete from ${tableName} where ${pkColumn.columnName} in 
+        <foreach item="${pkColumn.javaField}" collection="array" open="(" separator="," close=")">
+            #{${pkColumn.javaField}}
+        </foreach>
+    </delete>
+#if($table.sub)
+    
+    <delete id="delete${subClassName}By${subTableFkClassName}s" parameterType="String">
+        delete from ${subTableName} where ${subTableFkName} in 
+        <foreach item="${subTableFkclassName}" collection="array" open="(" separator="," close=")">
+            #{${subTableFkclassName}}
+        </foreach>
+    </delete>
+
+    <delete id="delete${subClassName}By${subTableFkClassName}" parameterType="${pkColumn.javaType}">
+        delete from ${subTableName} where ${subTableFkName} = #{${subTableFkclassName}}
+    </delete>
+
+    <insert id="batch${subClassName}">
+        insert into ${subTableName}(#foreach($column in $subTable.columns) $column.columnName#if($foreach.count != $subTable.columns.size()),#end#end) values
+        <foreach item="item" index="index" collection="list" separator=",">
+            (#foreach($column in $subTable.columns) #{item.$column.javaField}#if($foreach.count != $subTable.columns.size()),#end#end)
+        </foreach>
+    </insert>
+#end
 </mapper>
\ No newline at end of file
diff --git a/ruoyi-quartz/pom.xml b/acupuncture-quartz/pom.xml
similarity index 78%
rename from ruoyi-quartz/pom.xml
rename to acupuncture-quartz/pom.xml
index a07542ab..6f2547b7 100644
--- a/ruoyi-quartz/pom.xml
+++ b/acupuncture-quartz/pom.xml
@@ -1,40 +1,40 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ruoyi-quartz</artifactId>
-
-    <description>
-        quartz定时任务
-    </description>
-
-    <dependencies>
-
-        <!-- 定时任务 -->
-        <dependency>
-            <groupId>org.quartz-scheduler</groupId>
-            <artifactId>quartz</artifactId>
-            <exclusions>
-                <exclusion>
-                    <groupId>com.mchange</groupId>
-                    <artifactId>c3p0</artifactId>
-                </exclusion>
-            </exclusions>
-        </dependency>
-
-        <!-- 通用工具-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-common</artifactId>
-        </dependency>
-
-    </dependencies>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>acupuncture-quartz</artifactId>
+
+    <description>
+        quartz定时任务
+    </description>
+
+    <dependencies>
+
+        <!-- 定时任务 -->
+        <dependency>
+            <groupId>org.quartz-scheduler</groupId>
+            <artifactId>quartz</artifactId>
+            <exclusions>
+                <exclusion>
+                    <groupId>com.mchange</groupId>
+                    <artifactId>c3p0</artifactId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-common</artifactId>
+        </dependency>
+
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/config/ScheduleConfig.java
similarity index 90%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/config/ScheduleConfig.java
index 6e79de08..b62cec36 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/config/ScheduleConfig.java
@@ -1,57 +1,57 @@
-//package com.ruoyi.quartz.config;
-//
-//import org.springframework.context.annotation.Bean;
-//import org.springframework.context.annotation.Configuration;
-//import org.springframework.scheduling.quartz.SchedulerFactoryBean;
-//import javax.sql.DataSource;
-//import java.util.Properties;
-//
-///**
-// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效)
-// * 
-// * @author ruoyi
-// */
-//@Configuration
-//public class ScheduleConfig
-//{
-//    @Bean
-//    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
-//    {
-//        SchedulerFactoryBean factory = new SchedulerFactoryBean();
-//        factory.setDataSource(dataSource);
-//
-//        // quartz参数
-//        Properties prop = new Properties();
-//        prop.put("org.quartz.scheduler.instanceName", "RuoyiScheduler");
-//        prop.put("org.quartz.scheduler.instanceId", "AUTO");
-//        // 线程池配置
-//        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
-//        prop.put("org.quartz.threadPool.threadCount", "20");
-//        prop.put("org.quartz.threadPool.threadPriority", "5");
-//        // JobStore配置
-//        prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
-//        // 集群配置
-//        prop.put("org.quartz.jobStore.isClustered", "true");
-//        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
-//        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
-//        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
-//
-//        // sqlserver 启用
-//        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
-//        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
-//        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
-//        factory.setQuartzProperties(prop);
-//
-//        factory.setSchedulerName("RuoyiScheduler");
-//        // 延时启动
-//        factory.setStartupDelay(1);
-//        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
-//        // 可选,QuartzScheduler
-//        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
-//        factory.setOverwriteExistingJobs(true);
-//        // 设置自动启动,默认为true
-//        factory.setAutoStartup(true);
-//
-//        return factory;
-//    }
-//}
+//package com.acupuncture.quartz.config;
+//
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import org.springframework.scheduling.quartz.SchedulerFactoryBean;
+//import javax.sql.DataSource;
+//import java.util.Properties;
+//
+///**
+// * 定时任务配置(单机部署建议删除此类和qrtz数据库表,默认走内存会最高效)
+// * 
+// * @author acupuncture
+// */
+//@Configuration
+//public class ScheduleConfig
+//{
+//    @Bean
+//    public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource)
+//    {
+//        SchedulerFactoryBean factory = new SchedulerFactoryBean();
+//        factory.setDataSource(dataSource);
+//
+//        // quartz参数
+//        Properties prop = new Properties();
+//        prop.put("org.quartz.scheduler.instanceName", "acupunctureScheduler");
+//        prop.put("org.quartz.scheduler.instanceId", "AUTO");
+//        // 线程池配置
+//        prop.put("org.quartz.threadPool.class", "org.quartz.simpl.SimpleThreadPool");
+//        prop.put("org.quartz.threadPool.threadCount", "20");
+//        prop.put("org.quartz.threadPool.threadPriority", "5");
+//        // JobStore配置
+//        prop.put("org.quartz.jobStore.class", "org.springframework.scheduling.quartz.LocalDataSourceJobStore");
+//        // 集群配置
+//        prop.put("org.quartz.jobStore.isClustered", "true");
+//        prop.put("org.quartz.jobStore.clusterCheckinInterval", "15000");
+//        prop.put("org.quartz.jobStore.maxMisfiresToHandleAtATime", "10");
+//        prop.put("org.quartz.jobStore.txIsolationLevelSerializable", "true");
+//
+//        // sqlserver 启用
+//        // prop.put("org.quartz.jobStore.selectWithLockSQL", "SELECT * FROM {0}LOCKS UPDLOCK WHERE LOCK_NAME = ?");
+//        prop.put("org.quartz.jobStore.misfireThreshold", "12000");
+//        prop.put("org.quartz.jobStore.tablePrefix", "QRTZ_");
+//        factory.setQuartzProperties(prop);
+//
+//        factory.setSchedulerName("acupunctureScheduler");
+//        // 延时启动
+//        factory.setStartupDelay(1);
+//        factory.setApplicationContextSchedulerContextKey("applicationContextKey");
+//        // 可选,QuartzScheduler
+//        // 启动时更新己存在的Job,这样就不用每次修改targetObject后删除qrtz_job_details表对应记录了
+//        factory.setOverwriteExistingJobs(true);
+//        // 设置自动启动,默认为true
+//        factory.setAutoStartup(true);
+//
+//        return factory;
+//    }
+//}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobController.java
similarity index 89%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobController.java
index f8189bab..072b111e 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobController.java
@@ -1,185 +1,185 @@
-package com.ruoyi.quartz.controller;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-import org.quartz.SchedulerException;
-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.annotation.Log;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.quartz.domain.SysJob;
-import com.ruoyi.quartz.service.ISysJobService;
-import com.ruoyi.quartz.util.CronUtils;
-import com.ruoyi.quartz.util.ScheduleUtils;
-
-/**
- * 调度任务信息操作处理
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/job")
-public class SysJobController extends BaseController
-{
-    @Autowired
-    private ISysJobService jobService;
-
-    /**
-     * 查询定时任务列表
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysJob sysJob)
-    {
-        startPage();
-        List<SysJob> list = jobService.selectJobList(sysJob);
-        return getDataTable(list);
-    }
-
-    /**
-     * 导出定时任务列表
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
-    @Log(title = "定时任务", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysJob sysJob)
-    {
-        List<SysJob> list = jobService.selectJobList(sysJob);
-        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
-        util.exportExcel(response, list, "定时任务");
-    }
-
-    /**
-     * 获取定时任务详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
-    @GetMapping(value = "/{jobId}")
-    public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
-    {
-        return success(jobService.selectJobById(jobId));
-    }
-
-    /**
-     * 新增定时任务
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
-    @Log(title = "定时任务", businessType = BusinessType.INSERT)
-    @PostMapping
-    public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
-    {
-        if (!CronUtils.isValid(job.getCronExpression()))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
-        }
-        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
-        }
-        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
-        {
-            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
-        }
-        job.setCreateBy(getUsername());
-        return toAjax(jobService.insertJob(job));
-    }
-
-    /**
-     * 修改定时任务
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
-    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
-    @PutMapping
-    public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
-    {
-        if (!CronUtils.isValid(job.getCronExpression()))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
-        }
-        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
-        }
-        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
-        }
-        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
-        {
-            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
-        }
-        job.setUpdateBy(getUsername());
-        return toAjax(jobService.updateJob(job));
-    }
-
-    /**
-     * 定时任务状态修改
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
-    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
-    @PutMapping("/changeStatus")
-    public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
-    {
-        SysJob newJob = jobService.selectJobById(job.getJobId());
-        newJob.setStatus(job.getStatus());
-        return toAjax(jobService.changeStatus(newJob));
-    }
-
-    /**
-     * 定时任务立即执行一次
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
-    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
-    @PutMapping("/run")
-    public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
-    {
-        boolean result = jobService.run(job);
-        return result ? success() : error("任务不存在或已过期!");
-    }
-
-    /**
-     * 删除定时任务
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "定时任务", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{jobIds}")
-    public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException
-    {
-        jobService.deleteJobByIds(jobIds);
-        return success();
-    }
-}
+package com.acupuncture.quartz.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+import org.quartz.SchedulerException;
+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.acupuncture.common.annotation.Log;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.exception.job.TaskException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.quartz.domain.SysJob;
+import com.acupuncture.quartz.service.ISysJobService;
+import com.acupuncture.quartz.util.CronUtils;
+import com.acupuncture.quartz.util.ScheduleUtils;
+
+/**
+ * 调度任务信息操作处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/job")
+public class SysJobController extends BaseController
+{
+    @Autowired
+    private ISysJobService jobService;
+
+    /**
+     * 查询定时任务列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJob sysJob)
+    {
+        startPage();
+        List<SysJob> list = jobService.selectJobList(sysJob);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出定时任务列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "定时任务", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJob sysJob)
+    {
+        List<SysJob> list = jobService.selectJobList(sysJob);
+        ExcelUtil<SysJob> util = new ExcelUtil<SysJob>(SysJob.class);
+        util.exportExcel(response, list, "定时任务");
+    }
+
+    /**
+     * 获取定时任务详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobId}")
+    public AjaxResult getInfo(@PathVariable("jobId") Long jobId)
+    {
+        return success(jobService.selectJobById(jobId));
+    }
+
+    /**
+     * 新增定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:add')")
+    @Log(title = "定时任务", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody SysJob job) throws SchedulerException, TaskException
+    {
+        if (!CronUtils.isValid(job.getCronExpression()))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        }
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        }
+        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+        {
+            return error("新增任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        job.setCreateBy(getUsername());
+        return toAjax(jobService.insertJob(job));
+    }
+
+    /**
+     * 修改定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:edit')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody SysJob job) throws SchedulerException, TaskException
+    {
+        if (!CronUtils.isValid(job.getCronExpression()))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,Cron表达式不正确");
+        }
+        else if (StringUtils.containsIgnoreCase(job.getInvokeTarget(), Constants.LOOKUP_RMI))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'rmi'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.LOOKUP_LDAP, Constants.LOOKUP_LDAPS }))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'ldap(s)'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), new String[] { Constants.HTTP, Constants.HTTPS }))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不允许'http(s)'调用");
+        }
+        else if (StringUtils.containsAnyIgnoreCase(job.getInvokeTarget(), Constants.JOB_ERROR_STR))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串存在违规");
+        }
+        else if (!ScheduleUtils.whiteList(job.getInvokeTarget()))
+        {
+            return error("修改任务'" + job.getJobName() + "'失败,目标字符串不在白名单内");
+        }
+        job.setUpdateBy(getUsername());
+        return toAjax(jobService.updateJob(job));
+    }
+
+    /**
+     * 定时任务状态修改
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @PutMapping("/changeStatus")
+    public AjaxResult changeStatus(@RequestBody SysJob job) throws SchedulerException
+    {
+        SysJob newJob = jobService.selectJobById(job.getJobId());
+        newJob.setStatus(job.getStatus());
+        return toAjax(jobService.changeStatus(newJob));
+    }
+
+    /**
+     * 定时任务立即执行一次
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:changeStatus')")
+    @Log(title = "定时任务", businessType = BusinessType.UPDATE)
+    @PutMapping("/run")
+    public AjaxResult run(@RequestBody SysJob job) throws SchedulerException
+    {
+        boolean result = jobService.run(job);
+        return result ? success() : error("任务不存在或已过期!");
+    }
+
+    /**
+     * 删除定时任务
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "定时任务", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobIds}")
+    public AjaxResult remove(@PathVariable Long[] jobIds) throws SchedulerException, TaskException
+    {
+        jobService.deleteJobByIds(jobIds);
+        return success();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobLogController.java
similarity index 83%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobLogController.java
index 67f44abf..a7513fe0 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/controller/SysJobLogController.java
@@ -1,92 +1,92 @@
-package com.ruoyi.quartz.controller;
-
-import java.util.List;
-import javax.servlet.http.HttpServletResponse;
-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.RequestMapping;
-import org.springframework.web.bind.annotation.RestController;
-import com.ruoyi.common.annotation.Log;
-import com.ruoyi.common.core.controller.BaseController;
-import com.ruoyi.common.core.domain.AjaxResult;
-import com.ruoyi.common.core.page.TableDataInfo;
-import com.ruoyi.common.enums.BusinessType;
-import com.ruoyi.common.utils.poi.ExcelUtil;
-import com.ruoyi.quartz.domain.SysJobLog;
-import com.ruoyi.quartz.service.ISysJobLogService;
-
-/**
- * 调度日志操作处理
- * 
- * @author ruoyi
- */
-@RestController
-@RequestMapping("/monitor/jobLog")
-public class SysJobLogController extends BaseController
-{
-    @Autowired
-    private ISysJobLogService jobLogService;
-
-    /**
-     * 查询定时任务调度日志列表
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
-    @GetMapping("/list")
-    public TableDataInfo list(SysJobLog sysJobLog)
-    {
-        startPage();
-        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
-        return getDataTable(list);
-    }
-
-    /**
-     * 导出定时任务调度日志列表
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
-    @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
-    @PostMapping("/export")
-    public void export(HttpServletResponse response, SysJobLog sysJobLog)
-    {
-        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
-        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
-        util.exportExcel(response, list, "调度日志");
-    }
-    
-    /**
-     * 根据调度编号获取详细信息
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
-    @GetMapping(value = "/{jobLogId}")
-    public AjaxResult getInfo(@PathVariable Long jobLogId)
-    {
-        return success(jobLogService.selectJobLogById(jobLogId));
-    }
-
-
-    /**
-     * 删除定时任务调度日志
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE)
-    @DeleteMapping("/{jobLogIds}")
-    public AjaxResult remove(@PathVariable Long[] jobLogIds)
-    {
-        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
-    }
-
-    /**
-     * 清空定时任务调度日志
-     */
-    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
-    @Log(title = "调度日志", businessType = BusinessType.CLEAN)
-    @DeleteMapping("/clean")
-    public AjaxResult clean()
-    {
-        jobLogService.cleanJobLog();
-        return success();
-    }
-}
+package com.acupuncture.quartz.controller;
+
+import java.util.List;
+import javax.servlet.http.HttpServletResponse;
+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.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+import com.acupuncture.common.annotation.Log;
+import com.acupuncture.common.core.controller.BaseController;
+import com.acupuncture.common.core.domain.AjaxResult;
+import com.acupuncture.common.core.page.TableDataInfo;
+import com.acupuncture.common.enums.BusinessType;
+import com.acupuncture.common.utils.poi.ExcelUtil;
+import com.acupuncture.quartz.domain.SysJobLog;
+import com.acupuncture.quartz.service.ISysJobLogService;
+
+/**
+ * 调度日志操作处理
+ * 
+ * @author acupuncture
+ */
+@RestController
+@RequestMapping("/monitor/jobLog")
+public class SysJobLogController extends BaseController
+{
+    @Autowired
+    private ISysJobLogService jobLogService;
+
+    /**
+     * 查询定时任务调度日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysJobLog sysJobLog)
+    {
+        startPage();
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出定时任务调度日志列表
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:export')")
+    @Log(title = "任务调度日志", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysJobLog sysJobLog)
+    {
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+        ExcelUtil<SysJobLog> util = new ExcelUtil<SysJobLog>(SysJobLog.class);
+        util.exportExcel(response, list, "调度日志");
+    }
+    
+    /**
+     * 根据调度编号获取详细信息
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:query')")
+    @GetMapping(value = "/{jobLogId}")
+    public AjaxResult getInfo(@PathVariable Long jobLogId)
+    {
+        return success(jobLogService.selectJobLogById(jobLogId));
+    }
+
+
+    /**
+     * 删除定时任务调度日志
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "定时任务调度日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{jobLogIds}")
+    public AjaxResult remove(@PathVariable Long[] jobLogIds)
+    {
+        return toAjax(jobLogService.deleteJobLogByIds(jobLogIds));
+    }
+
+    /**
+     * 清空定时任务调度日志
+     */
+    @PreAuthorize("@ss.hasPermi('monitor:job:remove')")
+    @Log(title = "调度日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean()
+    {
+        jobLogService.cleanJobLog();
+        return success();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJob.java
similarity index 89%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJob.java
index 4776e5fe..94461b2e 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJob.java
@@ -1,171 +1,171 @@
-package com.ruoyi.quartz.domain;
-
-import java.util.Date;
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.constant.ScheduleConstants;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.quartz.util.CronUtils;
-
-/**
- * 定时任务调度表 sys_job
- * 
- * @author ruoyi
- */
-public class SysJob extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 任务ID */
-    @Excel(name = "任务序号", cellType = ColumnType.NUMERIC)
-    private Long jobId;
-
-    /** 任务名称 */
-    @Excel(name = "任务名称")
-    private String jobName;
-
-    /** 任务组名 */
-    @Excel(name = "任务组名")
-    private String jobGroup;
-
-    /** 调用目标字符串 */
-    @Excel(name = "调用目标字符串")
-    private String invokeTarget;
-
-    /** cron执行表达式 */
-    @Excel(name = "执行表达式 ")
-    private String cronExpression;
-
-    /** cron计划策略 */
-    @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
-    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
-
-    /** 是否并发执行(0允许 1禁止) */
-    @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止")
-    private String concurrent;
-
-    /** 任务状态(0正常 1暂停) */
-    @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停")
-    private String status;
-
-    public Long getJobId()
-    {
-        return jobId;
-    }
-
-    public void setJobId(Long jobId)
-    {
-        this.jobId = jobId;
-    }
-
-    @NotBlank(message = "任务名称不能为空")
-    @Size(min = 0, max = 64, message = "任务名称不能超过64个字符")
-    public String getJobName()
-    {
-        return jobName;
-    }
-
-    public void setJobName(String jobName)
-    {
-        this.jobName = jobName;
-    }
-
-    public String getJobGroup()
-    {
-        return jobGroup;
-    }
-
-    public void setJobGroup(String jobGroup)
-    {
-        this.jobGroup = jobGroup;
-    }
-
-    @NotBlank(message = "调用目标字符串不能为空")
-    @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符")
-    public String getInvokeTarget()
-    {
-        return invokeTarget;
-    }
-
-    public void setInvokeTarget(String invokeTarget)
-    {
-        this.invokeTarget = invokeTarget;
-    }
-
-    @NotBlank(message = "Cron执行表达式不能为空")
-    @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符")
-    public String getCronExpression()
-    {
-        return cronExpression;
-    }
-
-    public void setCronExpression(String cronExpression)
-    {
-        this.cronExpression = cronExpression;
-    }
-
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    public Date getNextValidTime()
-    {
-        if (StringUtils.isNotEmpty(cronExpression))
-        {
-            return CronUtils.getNextExecution(cronExpression);
-        }
-        return null;
-    }
-
-    public String getMisfirePolicy()
-    {
-        return misfirePolicy;
-    }
-
-    public void setMisfirePolicy(String misfirePolicy)
-    {
-        this.misfirePolicy = misfirePolicy;
-    }
-
-    public String getConcurrent()
-    {
-        return concurrent;
-    }
-
-    public void setConcurrent(String concurrent)
-    {
-        this.concurrent = concurrent;
-    }
-
-    public String getStatus()
-    {
-        return status;
-    }
-
-    public void setStatus(String status)
-    {
-        this.status = status;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("jobId", getJobId())
-            .append("jobName", getJobName())
-            .append("jobGroup", getJobGroup())
-            .append("cronExpression", getCronExpression())
-            .append("nextValidTime", getNextValidTime())
-            .append("misfirePolicy", getMisfirePolicy())
-            .append("concurrent", getConcurrent())
-            .append("status", getStatus())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.quartz.domain;
+
+import java.util.Date;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.constant.ScheduleConstants;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.quartz.util.CronUtils;
+
+/**
+ * 定时任务调度表 sys_job
+ * 
+ * @author acupuncture
+ */
+public class SysJob extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 任务ID */
+    @Excel(name = "任务序号", cellType = ColumnType.NUMERIC)
+    private Long jobId;
+
+    /** 任务名称 */
+    @Excel(name = "任务名称")
+    private String jobName;
+
+    /** 任务组名 */
+    @Excel(name = "任务组名")
+    private String jobGroup;
+
+    /** 调用目标字符串 */
+    @Excel(name = "调用目标字符串")
+    private String invokeTarget;
+
+    /** cron执行表达式 */
+    @Excel(name = "执行表达式 ")
+    private String cronExpression;
+
+    /** cron计划策略 */
+    @Excel(name = "计划策略 ", readConverterExp = "0=默认,1=立即触发执行,2=触发一次执行,3=不触发立即执行")
+    private String misfirePolicy = ScheduleConstants.MISFIRE_DEFAULT;
+
+    /** 是否并发执行(0允许 1禁止) */
+    @Excel(name = "并发执行", readConverterExp = "0=允许,1=禁止")
+    private String concurrent;
+
+    /** 任务状态(0正常 1暂停) */
+    @Excel(name = "任务状态", readConverterExp = "0=正常,1=暂停")
+    private String status;
+
+    public Long getJobId()
+    {
+        return jobId;
+    }
+
+    public void setJobId(Long jobId)
+    {
+        this.jobId = jobId;
+    }
+
+    @NotBlank(message = "任务名称不能为空")
+    @Size(min = 0, max = 64, message = "任务名称不能超过64个字符")
+    public String getJobName()
+    {
+        return jobName;
+    }
+
+    public void setJobName(String jobName)
+    {
+        this.jobName = jobName;
+    }
+
+    public String getJobGroup()
+    {
+        return jobGroup;
+    }
+
+    public void setJobGroup(String jobGroup)
+    {
+        this.jobGroup = jobGroup;
+    }
+
+    @NotBlank(message = "调用目标字符串不能为空")
+    @Size(min = 0, max = 500, message = "调用目标字符串长度不能超过500个字符")
+    public String getInvokeTarget()
+    {
+        return invokeTarget;
+    }
+
+    public void setInvokeTarget(String invokeTarget)
+    {
+        this.invokeTarget = invokeTarget;
+    }
+
+    @NotBlank(message = "Cron执行表达式不能为空")
+    @Size(min = 0, max = 255, message = "Cron执行表达式不能超过255个字符")
+    public String getCronExpression()
+    {
+        return cronExpression;
+    }
+
+    public void setCronExpression(String cronExpression)
+    {
+        this.cronExpression = cronExpression;
+    }
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    public Date getNextValidTime()
+    {
+        if (StringUtils.isNotEmpty(cronExpression))
+        {
+            return CronUtils.getNextExecution(cronExpression);
+        }
+        return null;
+    }
+
+    public String getMisfirePolicy()
+    {
+        return misfirePolicy;
+    }
+
+    public void setMisfirePolicy(String misfirePolicy)
+    {
+        this.misfirePolicy = misfirePolicy;
+    }
+
+    public String getConcurrent()
+    {
+        return concurrent;
+    }
+
+    public void setConcurrent(String concurrent)
+    {
+        this.concurrent = concurrent;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("jobId", getJobId())
+            .append("jobName", getJobName())
+            .append("jobGroup", getJobGroup())
+            .append("cronExpression", getCronExpression())
+            .append("nextValidTime", getNextValidTime())
+            .append("misfirePolicy", getMisfirePolicy())
+            .append("concurrent", getConcurrent())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJobLog.java
similarity index 91%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJobLog.java
index 63c4cd69..fa581683 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/domain/SysJobLog.java
@@ -1,155 +1,155 @@
-package com.ruoyi.quartz.domain;
-
-import java.util.Date;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 定时任务调度日志表 sys_job_log
- * 
- * @author ruoyi
- */
-public class SysJobLog extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** ID */
-    @Excel(name = "日志序号")
-    private Long jobLogId;
-
-    /** 任务名称 */
-    @Excel(name = "任务名称")
-    private String jobName;
-
-    /** 任务组名 */
-    @Excel(name = "任务组名")
-    private String jobGroup;
-
-    /** 调用目标字符串 */
-    @Excel(name = "调用目标字符串")
-    private String invokeTarget;
-
-    /** 日志信息 */
-    @Excel(name = "日志信息")
-    private String jobMessage;
-
-    /** 执行状态(0正常 1失败) */
-    @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败")
-    private String status;
-
-    /** 异常信息 */
-    @Excel(name = "异常信息")
-    private String exceptionInfo;
-
-    /** 开始时间 */
-    private Date startTime;
-
-    /** 停止时间 */
-    private Date stopTime;
-
-    public Long getJobLogId()
-    {
-        return jobLogId;
-    }
-
-    public void setJobLogId(Long jobLogId)
-    {
-        this.jobLogId = jobLogId;
-    }
-
-    public String getJobName()
-    {
-        return jobName;
-    }
-
-    public void setJobName(String jobName)
-    {
-        this.jobName = jobName;
-    }
-
-    public String getJobGroup()
-    {
-        return jobGroup;
-    }
-
-    public void setJobGroup(String jobGroup)
-    {
-        this.jobGroup = jobGroup;
-    }
-
-    public String getInvokeTarget()
-    {
-        return invokeTarget;
-    }
-
-    public void setInvokeTarget(String invokeTarget)
-    {
-        this.invokeTarget = invokeTarget;
-    }
-
-    public String getJobMessage()
-    {
-        return jobMessage;
-    }
-
-    public void setJobMessage(String jobMessage)
-    {
-        this.jobMessage = jobMessage;
-    }
-
-    public String getStatus()
-    {
-        return status;
-    }
-
-    public void setStatus(String status)
-    {
-        this.status = status;
-    }
-
-    public String getExceptionInfo()
-    {
-        return exceptionInfo;
-    }
-
-    public void setExceptionInfo(String exceptionInfo)
-    {
-        this.exceptionInfo = exceptionInfo;
-    }
-
-    public Date getStartTime()
-    {
-        return startTime;
-    }
-
-    public void setStartTime(Date startTime)
-    {
-        this.startTime = startTime;
-    }
-    
-    public Date getStopTime()
-    {
-        return stopTime;
-    }
-
-    public void setStopTime(Date stopTime)
-    {
-        this.stopTime = stopTime;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("jobLogId", getJobLogId())
-            .append("jobName", getJobName())
-            .append("jobGroup", getJobGroup())
-            .append("jobMessage", getJobMessage())
-            .append("status", getStatus())
-            .append("exceptionInfo", getExceptionInfo())
-            .append("startTime", getStartTime())
-            .append("stopTime", getStopTime())
-            .toString();
-    }
-}
+package com.acupuncture.quartz.domain;
+
+import java.util.Date;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 定时任务调度日志表 sys_job_log
+ * 
+ * @author acupuncture
+ */
+public class SysJobLog extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    @Excel(name = "日志序号")
+    private Long jobLogId;
+
+    /** 任务名称 */
+    @Excel(name = "任务名称")
+    private String jobName;
+
+    /** 任务组名 */
+    @Excel(name = "任务组名")
+    private String jobGroup;
+
+    /** 调用目标字符串 */
+    @Excel(name = "调用目标字符串")
+    private String invokeTarget;
+
+    /** 日志信息 */
+    @Excel(name = "日志信息")
+    private String jobMessage;
+
+    /** 执行状态(0正常 1失败) */
+    @Excel(name = "执行状态", readConverterExp = "0=正常,1=失败")
+    private String status;
+
+    /** 异常信息 */
+    @Excel(name = "异常信息")
+    private String exceptionInfo;
+
+    /** 开始时间 */
+    private Date startTime;
+
+    /** 停止时间 */
+    private Date stopTime;
+
+    public Long getJobLogId()
+    {
+        return jobLogId;
+    }
+
+    public void setJobLogId(Long jobLogId)
+    {
+        this.jobLogId = jobLogId;
+    }
+
+    public String getJobName()
+    {
+        return jobName;
+    }
+
+    public void setJobName(String jobName)
+    {
+        this.jobName = jobName;
+    }
+
+    public String getJobGroup()
+    {
+        return jobGroup;
+    }
+
+    public void setJobGroup(String jobGroup)
+    {
+        this.jobGroup = jobGroup;
+    }
+
+    public String getInvokeTarget()
+    {
+        return invokeTarget;
+    }
+
+    public void setInvokeTarget(String invokeTarget)
+    {
+        this.invokeTarget = invokeTarget;
+    }
+
+    public String getJobMessage()
+    {
+        return jobMessage;
+    }
+
+    public void setJobMessage(String jobMessage)
+    {
+        this.jobMessage = jobMessage;
+    }
+
+    public String getStatus()
+    {
+        return status;
+    }
+
+    public void setStatus(String status)
+    {
+        this.status = status;
+    }
+
+    public String getExceptionInfo()
+    {
+        return exceptionInfo;
+    }
+
+    public void setExceptionInfo(String exceptionInfo)
+    {
+        this.exceptionInfo = exceptionInfo;
+    }
+
+    public Date getStartTime()
+    {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime)
+    {
+        this.startTime = startTime;
+    }
+    
+    public Date getStopTime()
+    {
+        return stopTime;
+    }
+
+    public void setStopTime(Date stopTime)
+    {
+        this.stopTime = stopTime;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("jobLogId", getJobLogId())
+            .append("jobName", getJobName())
+            .append("jobGroup", getJobGroup())
+            .append("jobMessage", getJobMessage())
+            .append("status", getStatus())
+            .append("exceptionInfo", getExceptionInfo())
+            .append("startTime", getStartTime())
+            .append("stopTime", getStopTime())
+            .toString();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobLogMapper.java
similarity index 89%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobLogMapper.java
index ed01ef72..833de50b 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobLogMapper.java
@@ -1,64 +1,64 @@
-package com.ruoyi.quartz.mapper;
-
-import java.util.List;
-import com.ruoyi.quartz.domain.SysJobLog;
-
-/**
- * 调度任务日志信息 数据层
- * 
- * @author ruoyi
- */
-public interface SysJobLogMapper
-{
-    /**
-     * 获取quartz调度器日志的计划任务
-     * 
-     * @param jobLog 调度日志信息
-     * @return 调度任务日志集合
-     */
-    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
-
-    /**
-     * 查询所有调度任务日志
-     *
-     * @return 调度任务日志列表
-     */
-    public List<SysJobLog> selectJobLogAll();
-
-    /**
-     * 通过调度任务日志ID查询调度信息
-     * 
-     * @param jobLogId 调度任务日志ID
-     * @return 调度任务日志对象信息
-     */
-    public SysJobLog selectJobLogById(Long jobLogId);
-
-    /**
-     * 新增任务日志
-     * 
-     * @param jobLog 调度日志信息
-     * @return 结果
-     */
-    public int insertJobLog(SysJobLog jobLog);
-
-    /**
-     * 批量删除调度日志信息
-     * 
-     * @param logIds 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteJobLogByIds(Long[] logIds);
-
-    /**
-     * 删除任务日志
-     * 
-     * @param jobId 调度日志ID
-     * @return 结果
-     */
-    public int deleteJobLogById(Long jobId);
-
-    /**
-     * 清空任务日志
-     */
-    public void cleanJobLog();
-}
+package com.acupuncture.quartz.mapper;
+
+import java.util.List;
+import com.acupuncture.quartz.domain.SysJobLog;
+
+/**
+ * 调度任务日志信息 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysJobLogMapper
+{
+    /**
+     * 获取quartz调度器日志的计划任务
+     * 
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 查询所有调度任务日志
+     *
+     * @return 调度任务日志列表
+     */
+    public List<SysJobLog> selectJobLogAll();
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     * 
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    public SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     * @return 结果
+     */
+    public int insertJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     * 
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     * 
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    public int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    public void cleanJobLog();
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobMapper.java
similarity index 88%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobMapper.java
index f481ea12..e438c287 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/mapper/SysJobMapper.java
@@ -1,67 +1,67 @@
-package com.ruoyi.quartz.mapper;
-
-import java.util.List;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 调度任务信息 数据层
- * 
- * @author ruoyi
- */
-public interface SysJobMapper
-{
-    /**
-     * 查询调度任务日志集合
-     * 
-     * @param job 调度信息
-     * @return 操作日志集合
-     */
-    public List<SysJob> selectJobList(SysJob job);
-
-    /**
-     * 查询所有调度任务
-     * 
-     * @return 调度任务列表
-     */
-    public List<SysJob> selectJobAll();
-
-    /**
-     * 通过调度ID查询调度任务信息
-     * 
-     * @param jobId 调度ID
-     * @return 角色对象信息
-     */
-    public SysJob selectJobById(Long jobId);
-
-    /**
-     * 通过调度ID删除调度任务信息
-     * 
-     * @param jobId 调度ID
-     * @return 结果
-     */
-    public int deleteJobById(Long jobId);
-
-    /**
-     * 批量删除调度任务信息
-     * 
-     * @param ids 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteJobByIds(Long[] ids);
-
-    /**
-     * 修改调度任务信息
-     * 
-     * @param job 调度任务信息
-     * @return 结果
-     */
-    public int updateJob(SysJob job);
-
-    /**
-     * 新增调度任务信息
-     * 
-     * @param job 调度任务信息
-     * @return 结果
-     */
-    public int insertJob(SysJob job);
-}
+package com.acupuncture.quartz.mapper;
+
+import java.util.List;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 调度任务信息 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysJobMapper
+{
+    /**
+     * 查询调度任务日志集合
+     * 
+     * @param job 调度信息
+     * @return 操作日志集合
+     */
+    public List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 查询所有调度任务
+     * 
+     * @return 调度任务列表
+     */
+    public List<SysJob> selectJobAll();
+
+    /**
+     * 通过调度ID查询调度任务信息
+     * 
+     * @param jobId 调度ID
+     * @return 角色对象信息
+     */
+    public SysJob selectJobById(Long jobId);
+
+    /**
+     * 通过调度ID删除调度任务信息
+     * 
+     * @param jobId 调度ID
+     * @return 结果
+     */
+    public int deleteJobById(Long jobId);
+
+    /**
+     * 批量删除调度任务信息
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteJobByIds(Long[] ids);
+
+    /**
+     * 修改调度任务信息
+     * 
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    public int updateJob(SysJob job);
+
+    /**
+     * 新增调度任务信息
+     * 
+     * @param job 调度任务信息
+     * @return 结果
+     */
+    public int insertJob(SysJob job);
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobLogService.java
similarity index 88%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobLogService.java
index 5291a63a..b2ade0b3 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobLogService.java
@@ -1,56 +1,56 @@
-package com.ruoyi.quartz.service;
-
-import java.util.List;
-import com.ruoyi.quartz.domain.SysJobLog;
-
-/**
- * 定时任务调度日志信息信息 服务层
- * 
- * @author ruoyi
- */
-public interface ISysJobLogService
-{
-    /**
-     * 获取quartz调度器日志的计划任务
-     * 
-     * @param jobLog 调度日志信息
-     * @return 调度任务日志集合
-     */
-    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
-
-    /**
-     * 通过调度任务日志ID查询调度信息
-     * 
-     * @param jobLogId 调度任务日志ID
-     * @return 调度任务日志对象信息
-     */
-    public SysJobLog selectJobLogById(Long jobLogId);
-
-    /**
-     * 新增任务日志
-     * 
-     * @param jobLog 调度日志信息
-     */
-    public void addJobLog(SysJobLog jobLog);
-
-    /**
-     * 批量删除调度日志信息
-     * 
-     * @param logIds 需要删除的日志ID
-     * @return 结果
-     */
-    public int deleteJobLogByIds(Long[] logIds);
-
-    /**
-     * 删除任务日志
-     * 
-     * @param jobId 调度日志ID
-     * @return 结果
-     */
-    public int deleteJobLogById(Long jobId);
-
-    /**
-     * 清空任务日志
-     */
-    public void cleanJobLog();
-}
+package com.acupuncture.quartz.service;
+
+import java.util.List;
+import com.acupuncture.quartz.domain.SysJobLog;
+
+/**
+ * 定时任务调度日志信息信息 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysJobLogService
+{
+    /**
+     * 获取quartz调度器日志的计划任务
+     * 
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    public List<SysJobLog> selectJobLogList(SysJobLog jobLog);
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     * 
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    public SysJobLog selectJobLogById(Long jobLogId);
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     */
+    public void addJobLog(SysJobLog jobLog);
+
+    /**
+     * 批量删除调度日志信息
+     * 
+     * @param logIds 需要删除的日志ID
+     * @return 结果
+     */
+    public int deleteJobLogByIds(Long[] logIds);
+
+    /**
+     * 删除任务日志
+     * 
+     * @param jobId 调度日志ID
+     * @return 结果
+     */
+    public int deleteJobLogById(Long jobId);
+
+    /**
+     * 清空任务日志
+     */
+    public void cleanJobLog();
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobService.java
similarity index 89%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobService.java
index afdb707b..e7f61d3c 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/ISysJobService.java
@@ -1,102 +1,102 @@
-package com.ruoyi.quartz.service;
-
-import java.util.List;
-import org.quartz.SchedulerException;
-import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 定时任务调度信息信息 服务层
- * 
- * @author ruoyi
- */
-public interface ISysJobService
-{
-    /**
-     * 获取quartz调度器的计划任务
-     * 
-     * @param job 调度信息
-     * @return 调度任务集合
-     */
-    public List<SysJob> selectJobList(SysJob job);
-
-    /**
-     * 通过调度任务ID查询调度信息
-     * 
-     * @param jobId 调度任务ID
-     * @return 调度任务对象信息
-     */
-    public SysJob selectJobById(Long jobId);
-
-    /**
-     * 暂停任务
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int pauseJob(SysJob job) throws SchedulerException;
-
-    /**
-     * 恢复任务
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int resumeJob(SysJob job) throws SchedulerException;
-
-    /**
-     * 删除任务后,所对应的trigger也将被删除
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int deleteJob(SysJob job) throws SchedulerException;
-
-    /**
-     * 批量删除调度信息
-     * 
-     * @param jobIds 需要删除的任务ID
-     * @return 结果
-     */
-    public void deleteJobByIds(Long[] jobIds) throws SchedulerException;
-
-    /**
-     * 任务调度状态修改
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int changeStatus(SysJob job) throws SchedulerException;
-
-    /**
-     * 立即运行任务
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public boolean run(SysJob job) throws SchedulerException;
-
-    /**
-     * 新增任务
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int insertJob(SysJob job) throws SchedulerException, TaskException;
-
-    /**
-     * 更新任务
-     * 
-     * @param job 调度信息
-     * @return 结果
-     */
-    public int updateJob(SysJob job) throws SchedulerException, TaskException;
-
-    /**
-     * 校验cron表达式是否有效
-     * 
-     * @param cronExpression 表达式
-     * @return 结果
-     */
-    public boolean checkCronExpressionIsValid(String cronExpression);
-}
+package com.acupuncture.quartz.service;
+
+import java.util.List;
+import org.quartz.SchedulerException;
+import com.acupuncture.common.exception.job.TaskException;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 定时任务调度信息信息 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysJobService
+{
+    /**
+     * 获取quartz调度器的计划任务
+     * 
+     * @param job 调度信息
+     * @return 调度任务集合
+     */
+    public List<SysJob> selectJobList(SysJob job);
+
+    /**
+     * 通过调度任务ID查询调度信息
+     * 
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    public SysJob selectJobById(Long jobId);
+
+    /**
+     * 暂停任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int pauseJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 恢复任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int resumeJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int deleteJob(SysJob job) throws SchedulerException;
+
+    /**
+     * 批量删除调度信息
+     * 
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    public void deleteJobByIds(Long[] jobIds) throws SchedulerException;
+
+    /**
+     * 任务调度状态修改
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int changeStatus(SysJob job) throws SchedulerException;
+
+    /**
+     * 立即运行任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public boolean run(SysJob job) throws SchedulerException;
+
+    /**
+     * 新增任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int insertJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 更新任务
+     * 
+     * @param job 调度信息
+     * @return 结果
+     */
+    public int updateJob(SysJob job) throws SchedulerException, TaskException;
+
+    /**
+     * 校验cron表达式是否有效
+     * 
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    public boolean checkCronExpressionIsValid(String cronExpression);
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobLogServiceImpl.java
similarity index 85%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobLogServiceImpl.java
index f68a5482..14c483e0 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobLogServiceImpl.java
@@ -1,87 +1,87 @@
-package com.ruoyi.quartz.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.quartz.domain.SysJobLog;
-import com.ruoyi.quartz.mapper.SysJobLogMapper;
-import com.ruoyi.quartz.service.ISysJobLogService;
-
-/**
- * 定时任务调度日志信息 服务层
- * 
- * @author ruoyi
- */
-@Service
-public class SysJobLogServiceImpl implements ISysJobLogService
-{
-    @Autowired
-    private SysJobLogMapper jobLogMapper;
-
-    /**
-     * 获取quartz调度器日志的计划任务
-     * 
-     * @param jobLog 调度日志信息
-     * @return 调度任务日志集合
-     */
-    @Override
-    public List<SysJobLog> selectJobLogList(SysJobLog jobLog)
-    {
-        return jobLogMapper.selectJobLogList(jobLog);
-    }
-
-    /**
-     * 通过调度任务日志ID查询调度信息
-     * 
-     * @param jobLogId 调度任务日志ID
-     * @return 调度任务日志对象信息
-     */
-    @Override
-    public SysJobLog selectJobLogById(Long jobLogId)
-    {
-        return jobLogMapper.selectJobLogById(jobLogId);
-    }
-
-    /**
-     * 新增任务日志
-     * 
-     * @param jobLog 调度日志信息
-     */
-    @Override
-    public void addJobLog(SysJobLog jobLog)
-    {
-        jobLogMapper.insertJobLog(jobLog);
-    }
-
-    /**
-     * 批量删除调度日志信息
-     * 
-     * @param logIds 需要删除的数据ID
-     * @return 结果
-     */
-    @Override
-    public int deleteJobLogByIds(Long[] logIds)
-    {
-        return jobLogMapper.deleteJobLogByIds(logIds);
-    }
-
-    /**
-     * 删除任务日志
-     * 
-     * @param jobId 调度日志ID
-     */
-    @Override
-    public int deleteJobLogById(Long jobId)
-    {
-        return jobLogMapper.deleteJobLogById(jobId);
-    }
-
-    /**
-     * 清空任务日志
-     */
-    @Override
-    public void cleanJobLog()
-    {
-        jobLogMapper.cleanJobLog();
-    }
-}
+package com.acupuncture.quartz.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.quartz.domain.SysJobLog;
+import com.acupuncture.quartz.mapper.SysJobLogMapper;
+import com.acupuncture.quartz.service.ISysJobLogService;
+
+/**
+ * 定时任务调度日志信息 服务层
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysJobLogServiceImpl implements ISysJobLogService
+{
+    @Autowired
+    private SysJobLogMapper jobLogMapper;
+
+    /**
+     * 获取quartz调度器日志的计划任务
+     * 
+     * @param jobLog 调度日志信息
+     * @return 调度任务日志集合
+     */
+    @Override
+    public List<SysJobLog> selectJobLogList(SysJobLog jobLog)
+    {
+        return jobLogMapper.selectJobLogList(jobLog);
+    }
+
+    /**
+     * 通过调度任务日志ID查询调度信息
+     * 
+     * @param jobLogId 调度任务日志ID
+     * @return 调度任务日志对象信息
+     */
+    @Override
+    public SysJobLog selectJobLogById(Long jobLogId)
+    {
+        return jobLogMapper.selectJobLogById(jobLogId);
+    }
+
+    /**
+     * 新增任务日志
+     * 
+     * @param jobLog 调度日志信息
+     */
+    @Override
+    public void addJobLog(SysJobLog jobLog)
+    {
+        jobLogMapper.insertJobLog(jobLog);
+    }
+
+    /**
+     * 批量删除调度日志信息
+     * 
+     * @param logIds 需要删除的数据ID
+     * @return 结果
+     */
+    @Override
+    public int deleteJobLogByIds(Long[] logIds)
+    {
+        return jobLogMapper.deleteJobLogByIds(logIds);
+    }
+
+    /**
+     * 删除任务日志
+     * 
+     * @param jobId 调度日志ID
+     */
+    @Override
+    public int deleteJobLogById(Long jobId)
+    {
+        return jobLogMapper.deleteJobLogById(jobId);
+    }
+
+    /**
+     * 清空任务日志
+     */
+    @Override
+    public void cleanJobLog()
+    {
+        jobLogMapper.cleanJobLog();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobServiceImpl.java
similarity index 91%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobServiceImpl.java
index 71540b36..c23d046f 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/service/impl/SysJobServiceImpl.java
@@ -1,261 +1,261 @@
-package com.ruoyi.quartz.service.impl;
-
-import java.util.List;
-import javax.annotation.PostConstruct;
-import org.quartz.JobDataMap;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import com.ruoyi.common.constant.ScheduleConstants;
-import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.quartz.domain.SysJob;
-import com.ruoyi.quartz.mapper.SysJobMapper;
-import com.ruoyi.quartz.service.ISysJobService;
-import com.ruoyi.quartz.util.CronUtils;
-import com.ruoyi.quartz.util.ScheduleUtils;
-
-/**
- * 定时任务调度信息 服务层
- * 
- * @author ruoyi
- */
-@Service
-public class SysJobServiceImpl implements ISysJobService
-{
-    @Autowired
-    private Scheduler scheduler;
-
-    @Autowired
-    private SysJobMapper jobMapper;
-
-    /**
-     * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
-     */
-    @PostConstruct
-    public void init() throws SchedulerException, TaskException
-    {
-        scheduler.clear();
-        List<SysJob> jobList = jobMapper.selectJobAll();
-        for (SysJob job : jobList)
-        {
-            ScheduleUtils.createScheduleJob(scheduler, job);
-        }
-    }
-
-    /**
-     * 获取quartz调度器的计划任务列表
-     * 
-     * @param job 调度信息
-     * @return
-     */
-    @Override
-    public List<SysJob> selectJobList(SysJob job)
-    {
-        return jobMapper.selectJobList(job);
-    }
-
-    /**
-     * 通过调度任务ID查询调度信息
-     * 
-     * @param jobId 调度任务ID
-     * @return 调度任务对象信息
-     */
-    @Override
-    public SysJob selectJobById(Long jobId)
-    {
-        return jobMapper.selectJobById(jobId);
-    }
-
-    /**
-     * 暂停任务
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int pauseJob(SysJob job) throws SchedulerException
-    {
-        Long jobId = job.getJobId();
-        String jobGroup = job.getJobGroup();
-        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
-        int rows = jobMapper.updateJob(job);
-        if (rows > 0)
-        {
-            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
-        }
-        return rows;
-    }
-
-    /**
-     * 恢复任务
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int resumeJob(SysJob job) throws SchedulerException
-    {
-        Long jobId = job.getJobId();
-        String jobGroup = job.getJobGroup();
-        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
-        int rows = jobMapper.updateJob(job);
-        if (rows > 0)
-        {
-            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
-        }
-        return rows;
-    }
-
-    /**
-     * 删除任务后,所对应的trigger也将被删除
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int deleteJob(SysJob job) throws SchedulerException
-    {
-        Long jobId = job.getJobId();
-        String jobGroup = job.getJobGroup();
-        int rows = jobMapper.deleteJobById(jobId);
-        if (rows > 0)
-        {
-            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
-        }
-        return rows;
-    }
-
-    /**
-     * 批量删除调度信息
-     * 
-     * @param jobIds 需要删除的任务ID
-     * @return 结果
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public void deleteJobByIds(Long[] jobIds) throws SchedulerException
-    {
-        for (Long jobId : jobIds)
-        {
-            SysJob job = jobMapper.selectJobById(jobId);
-            deleteJob(job);
-        }
-    }
-
-    /**
-     * 任务调度状态修改
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int changeStatus(SysJob job) throws SchedulerException
-    {
-        int rows = 0;
-        String status = job.getStatus();
-        if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
-        {
-            rows = resumeJob(job);
-        }
-        else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
-        {
-            rows = pauseJob(job);
-        }
-        return rows;
-    }
-
-    /**
-     * 立即运行任务
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public boolean run(SysJob job) throws SchedulerException
-    {
-        boolean result = false;
-        Long jobId = job.getJobId();
-        String jobGroup = job.getJobGroup();
-        SysJob properties = selectJobById(job.getJobId());
-        // 参数
-        JobDataMap dataMap = new JobDataMap();
-        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
-        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
-        if (scheduler.checkExists(jobKey))
-        {
-            result = true;
-            scheduler.triggerJob(jobKey, dataMap);
-        }
-        return result;
-    }
-
-    /**
-     * 新增任务
-     * 
-     * @param job 调度信息 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int insertJob(SysJob job) throws SchedulerException, TaskException
-    {
-        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
-        int rows = jobMapper.insertJob(job);
-        if (rows > 0)
-        {
-            ScheduleUtils.createScheduleJob(scheduler, job);
-        }
-        return rows;
-    }
-
-    /**
-     * 更新任务的时间表达式
-     * 
-     * @param job 调度信息
-     */
-    @Override
-    @Transactional(rollbackFor = Exception.class)
-    public int updateJob(SysJob job) throws SchedulerException, TaskException
-    {
-        SysJob properties = selectJobById(job.getJobId());
-        int rows = jobMapper.updateJob(job);
-        if (rows > 0)
-        {
-            updateSchedulerJob(job, properties.getJobGroup());
-        }
-        return rows;
-    }
-
-    /**
-     * 更新任务
-     * 
-     * @param job 任务对象
-     * @param jobGroup 任务组名
-     */
-    public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException
-    {
-        Long jobId = job.getJobId();
-        // 判断是否存在
-        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
-        if (scheduler.checkExists(jobKey))
-        {
-            // 防止创建时存在数据问题 先移除,然后在执行创建操作
-            scheduler.deleteJob(jobKey);
-        }
-        ScheduleUtils.createScheduleJob(scheduler, job);
-    }
-
-    /**
-     * 校验cron表达式是否有效
-     * 
-     * @param cronExpression 表达式
-     * @return 结果
-     */
-    @Override
-    public boolean checkCronExpressionIsValid(String cronExpression)
-    {
-        return CronUtils.isValid(cronExpression);
-    }
-}
+package com.acupuncture.quartz.service.impl;
+
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.quartz.JobDataMap;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.acupuncture.common.constant.ScheduleConstants;
+import com.acupuncture.common.exception.job.TaskException;
+import com.acupuncture.quartz.domain.SysJob;
+import com.acupuncture.quartz.mapper.SysJobMapper;
+import com.acupuncture.quartz.service.ISysJobService;
+import com.acupuncture.quartz.util.CronUtils;
+import com.acupuncture.quartz.util.ScheduleUtils;
+
+/**
+ * 定时任务调度信息 服务层
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysJobServiceImpl implements ISysJobService
+{
+    @Autowired
+    private Scheduler scheduler;
+
+    @Autowired
+    private SysJobMapper jobMapper;
+
+    /**
+     * 项目启动时,初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理(注:不能手动修改数据库ID和任务组名,否则会导致脏数据)
+     */
+    @PostConstruct
+    public void init() throws SchedulerException, TaskException
+    {
+        scheduler.clear();
+        List<SysJob> jobList = jobMapper.selectJobAll();
+        for (SysJob job : jobList)
+        {
+            ScheduleUtils.createScheduleJob(scheduler, job);
+        }
+    }
+
+    /**
+     * 获取quartz调度器的计划任务列表
+     * 
+     * @param job 调度信息
+     * @return
+     */
+    @Override
+    public List<SysJob> selectJobList(SysJob job)
+    {
+        return jobMapper.selectJobList(job);
+    }
+
+    /**
+     * 通过调度任务ID查询调度信息
+     * 
+     * @param jobId 调度任务ID
+     * @return 调度任务对象信息
+     */
+    @Override
+    public SysJob selectJobById(Long jobId)
+    {
+        return jobMapper.selectJobById(jobId);
+    }
+
+    /**
+     * 暂停任务
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int pauseJob(SysJob job) throws SchedulerException
+    {
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
+        int rows = jobMapper.updateJob(job);
+        if (rows > 0)
+        {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+        return rows;
+    }
+
+    /**
+     * 恢复任务
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int resumeJob(SysJob job) throws SchedulerException
+    {
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        job.setStatus(ScheduleConstants.Status.NORMAL.getValue());
+        int rows = jobMapper.updateJob(job);
+        if (rows > 0)
+        {
+            scheduler.resumeJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+        return rows;
+    }
+
+    /**
+     * 删除任务后,所对应的trigger也将被删除
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int deleteJob(SysJob job) throws SchedulerException
+    {
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        int rows = jobMapper.deleteJobById(jobId);
+        if (rows > 0)
+        {
+            scheduler.deleteJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+        return rows;
+    }
+
+    /**
+     * 批量删除调度信息
+     * 
+     * @param jobIds 需要删除的任务ID
+     * @return 结果
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public void deleteJobByIds(Long[] jobIds) throws SchedulerException
+    {
+        for (Long jobId : jobIds)
+        {
+            SysJob job = jobMapper.selectJobById(jobId);
+            deleteJob(job);
+        }
+    }
+
+    /**
+     * 任务调度状态修改
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int changeStatus(SysJob job) throws SchedulerException
+    {
+        int rows = 0;
+        String status = job.getStatus();
+        if (ScheduleConstants.Status.NORMAL.getValue().equals(status))
+        {
+            rows = resumeJob(job);
+        }
+        else if (ScheduleConstants.Status.PAUSE.getValue().equals(status))
+        {
+            rows = pauseJob(job);
+        }
+        return rows;
+    }
+
+    /**
+     * 立即运行任务
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public boolean run(SysJob job) throws SchedulerException
+    {
+        boolean result = false;
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        SysJob properties = selectJobById(job.getJobId());
+        // 参数
+        JobDataMap dataMap = new JobDataMap();
+        dataMap.put(ScheduleConstants.TASK_PROPERTIES, properties);
+        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
+        if (scheduler.checkExists(jobKey))
+        {
+            result = true;
+            scheduler.triggerJob(jobKey, dataMap);
+        }
+        return result;
+    }
+
+    /**
+     * 新增任务
+     * 
+     * @param job 调度信息 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int insertJob(SysJob job) throws SchedulerException, TaskException
+    {
+        job.setStatus(ScheduleConstants.Status.PAUSE.getValue());
+        int rows = jobMapper.insertJob(job);
+        if (rows > 0)
+        {
+            ScheduleUtils.createScheduleJob(scheduler, job);
+        }
+        return rows;
+    }
+
+    /**
+     * 更新任务的时间表达式
+     * 
+     * @param job 调度信息
+     */
+    @Override
+    @Transactional(rollbackFor = Exception.class)
+    public int updateJob(SysJob job) throws SchedulerException, TaskException
+    {
+        SysJob properties = selectJobById(job.getJobId());
+        int rows = jobMapper.updateJob(job);
+        if (rows > 0)
+        {
+            updateSchedulerJob(job, properties.getJobGroup());
+        }
+        return rows;
+    }
+
+    /**
+     * 更新任务
+     * 
+     * @param job 任务对象
+     * @param jobGroup 任务组名
+     */
+    public void updateSchedulerJob(SysJob job, String jobGroup) throws SchedulerException, TaskException
+    {
+        Long jobId = job.getJobId();
+        // 判断是否存在
+        JobKey jobKey = ScheduleUtils.getJobKey(jobId, jobGroup);
+        if (scheduler.checkExists(jobKey))
+        {
+            // 防止创建时存在数据问题 先移除,然后在执行创建操作
+            scheduler.deleteJob(jobKey);
+        }
+        ScheduleUtils.createScheduleJob(scheduler, job);
+    }
+
+    /**
+     * 校验cron表达式是否有效
+     * 
+     * @param cronExpression 表达式
+     * @return 结果
+     */
+    @Override
+    public boolean checkCronExpressionIsValid(String cronExpression)
+    {
+        return CronUtils.isValid(cronExpression);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/task/RyTask.java
similarity index 83%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/task/RyTask.java
index 25d1ddd0..c9f74f96 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/task/RyTask.java
@@ -1,28 +1,28 @@
-package com.ruoyi.quartz.task;
-
-import org.springframework.stereotype.Component;
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 定时任务调度测试
- * 
- * @author ruoyi
- */
-@Component("ryTask")
-public class RyTask
-{
-    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
-    {
-        System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
-    }
-
-    public void ryParams(String params)
-    {
-        System.out.println("执行有参方法:" + params);
-    }
-
-    public void ryNoParams()
-    {
-        System.out.println("执行无参方法");
-    }
-}
+package com.acupuncture.quartz.task;
+
+import org.springframework.stereotype.Component;
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 定时任务调度测试
+ * 
+ * @author acupuncture
+ */
+@Component("ryTask")
+public class RyTask
+{
+    public void ryMultipleParams(String s, Boolean b, Long l, Double d, Integer i)
+    {
+        System.out.println(StringUtils.format("执行多参方法: 字符串类型{},布尔类型{},长整型{},浮点型{},整形{}", s, b, l, d, i));
+    }
+
+    public void ryParams(String params)
+    {
+        System.out.println("执行有参方法:" + params);
+    }
+
+    public void ryNoParams()
+    {
+        System.out.println("执行无参方法");
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/AbstractQuartzJob.java
similarity index 83%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/AbstractQuartzJob.java
index fd652d67..71e139a3 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/AbstractQuartzJob.java
@@ -1,107 +1,107 @@
-package com.ruoyi.quartz.util;
-
-import java.util.Date;
-import org.quartz.Job;
-import org.quartz.JobExecutionContext;
-import org.quartz.JobExecutionException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.ScheduleConstants;
-import com.ruoyi.common.utils.ExceptionUtil;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.bean.BeanUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.quartz.domain.SysJob;
-import com.ruoyi.quartz.domain.SysJobLog;
-import com.ruoyi.quartz.service.ISysJobLogService;
-
-/**
- * 抽象quartz调用
- *
- * @author ruoyi
- */
-public abstract class AbstractQuartzJob implements Job
-{
-    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
-
-    /**
-     * 线程本地变量
-     */
-    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
-
-    @Override
-    public void execute(JobExecutionContext context) throws JobExecutionException
-    {
-        SysJob sysJob = new SysJob();
-        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
-        try
-        {
-            before(context, sysJob);
-            if (sysJob != null)
-            {
-                doExecute(context, sysJob);
-            }
-            after(context, sysJob, null);
-        }
-        catch (Exception e)
-        {
-            log.error("任务执行异常  - :", e);
-            after(context, sysJob, e);
-        }
-    }
-
-    /**
-     * 执行前
-     *
-     * @param context 工作执行上下文对象
-     * @param sysJob 系统计划任务
-     */
-    protected void before(JobExecutionContext context, SysJob sysJob)
-    {
-        threadLocal.set(new Date());
-    }
-
-    /**
-     * 执行后
-     *
-     * @param context 工作执行上下文对象
-     * @param sysJob 系统计划任务
-     */
-    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
-    {
-        Date startTime = threadLocal.get();
-        threadLocal.remove();
-
-        final SysJobLog sysJobLog = new SysJobLog();
-        sysJobLog.setJobName(sysJob.getJobName());
-        sysJobLog.setJobGroup(sysJob.getJobGroup());
-        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
-        sysJobLog.setStartTime(startTime);
-        sysJobLog.setStopTime(new Date());
-        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
-        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
-        if (e != null)
-        {
-            sysJobLog.setStatus(Constants.FAIL);
-            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
-            sysJobLog.setExceptionInfo(errorMsg);
-        }
-        else
-        {
-            sysJobLog.setStatus(Constants.SUCCESS);
-        }
-
-        // 写入数据库当中
-        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
-    }
-
-    /**
-     * 执行方法,由子类重载
-     *
-     * @param context 工作执行上下文对象
-     * @param sysJob 系统计划任务
-     * @throws Exception 执行过程中的异常
-     */
-    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
-}
+package com.acupuncture.quartz.util;
+
+import java.util.Date;
+import org.quartz.Job;
+import org.quartz.JobExecutionContext;
+import org.quartz.JobExecutionException;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.ScheduleConstants;
+import com.acupuncture.common.utils.ExceptionUtil;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.bean.BeanUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.quartz.domain.SysJob;
+import com.acupuncture.quartz.domain.SysJobLog;
+import com.acupuncture.quartz.service.ISysJobLogService;
+
+/**
+ * 抽象quartz调用
+ *
+ * @author acupuncture
+ */
+public abstract class AbstractQuartzJob implements Job
+{
+    private static final Logger log = LoggerFactory.getLogger(AbstractQuartzJob.class);
+
+    /**
+     * 线程本地变量
+     */
+    private static ThreadLocal<Date> threadLocal = new ThreadLocal<>();
+
+    @Override
+    public void execute(JobExecutionContext context) throws JobExecutionException
+    {
+        SysJob sysJob = new SysJob();
+        BeanUtils.copyBeanProp(sysJob, context.getMergedJobDataMap().get(ScheduleConstants.TASK_PROPERTIES));
+        try
+        {
+            before(context, sysJob);
+            if (sysJob != null)
+            {
+                doExecute(context, sysJob);
+            }
+            after(context, sysJob, null);
+        }
+        catch (Exception e)
+        {
+            log.error("任务执行异常  - :", e);
+            after(context, sysJob, e);
+        }
+    }
+
+    /**
+     * 执行前
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob 系统计划任务
+     */
+    protected void before(JobExecutionContext context, SysJob sysJob)
+    {
+        threadLocal.set(new Date());
+    }
+
+    /**
+     * 执行后
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob 系统计划任务
+     */
+    protected void after(JobExecutionContext context, SysJob sysJob, Exception e)
+    {
+        Date startTime = threadLocal.get();
+        threadLocal.remove();
+
+        final SysJobLog sysJobLog = new SysJobLog();
+        sysJobLog.setJobName(sysJob.getJobName());
+        sysJobLog.setJobGroup(sysJob.getJobGroup());
+        sysJobLog.setInvokeTarget(sysJob.getInvokeTarget());
+        sysJobLog.setStartTime(startTime);
+        sysJobLog.setStopTime(new Date());
+        long runMs = sysJobLog.getStopTime().getTime() - sysJobLog.getStartTime().getTime();
+        sysJobLog.setJobMessage(sysJobLog.getJobName() + " 总共耗时:" + runMs + "毫秒");
+        if (e != null)
+        {
+            sysJobLog.setStatus(Constants.FAIL);
+            String errorMsg = StringUtils.substring(ExceptionUtil.getExceptionMessage(e), 0, 2000);
+            sysJobLog.setExceptionInfo(errorMsg);
+        }
+        else
+        {
+            sysJobLog.setStatus(Constants.SUCCESS);
+        }
+
+        // 写入数据库当中
+        SpringUtils.getBean(ISysJobLogService.class).addJobLog(sysJobLog);
+    }
+
+    /**
+     * 执行方法,由子类重载
+     *
+     * @param context 工作执行上下文对象
+     * @param sysJob 系统计划任务
+     * @throws Exception 执行过程中的异常
+     */
+    protected abstract void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception;
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/CronUtils.java
similarity index 93%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/CronUtils.java
index 6826787a..ff647259 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/CronUtils.java
@@ -1,63 +1,63 @@
-package com.ruoyi.quartz.util;
-
-import java.text.ParseException;
-import java.util.Date;
-import org.quartz.CronExpression;
-
-/**
- * cron表达式工具类
- * 
- * @author ruoyi
- *
- */
-public class CronUtils
-{
-    /**
-     * 返回一个布尔值代表一个给定的Cron表达式的有效性
-     *
-     * @param cronExpression Cron表达式
-     * @return boolean 表达式是否有效
-     */
-    public static boolean isValid(String cronExpression)
-    {
-        return CronExpression.isValidExpression(cronExpression);
-    }
-
-    /**
-     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
-     *
-     * @param cronExpression Cron表达式
-     * @return String 无效时返回表达式错误描述,如果有效返回null
-     */
-    public static String getInvalidMessage(String cronExpression)
-    {
-        try
-        {
-            new CronExpression(cronExpression);
-            return null;
-        }
-        catch (ParseException pe)
-        {
-            return pe.getMessage();
-        }
-    }
-
-    /**
-     * 返回下一个执行时间根据给定的Cron表达式
-     *
-     * @param cronExpression Cron表达式
-     * @return Date 下次Cron表达式执行时间
-     */
-    public static Date getNextExecution(String cronExpression)
-    {
-        try
-        {
-            CronExpression cron = new CronExpression(cronExpression);
-            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
-        }
-        catch (ParseException e)
-        {
-            throw new IllegalArgumentException(e.getMessage());
-        }
-    }
-}
+package com.acupuncture.quartz.util;
+
+import java.text.ParseException;
+import java.util.Date;
+import org.quartz.CronExpression;
+
+/**
+ * cron表达式工具类
+ * 
+ * @author acupuncture
+ *
+ */
+public class CronUtils
+{
+    /**
+     * 返回一个布尔值代表一个给定的Cron表达式的有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return boolean 表达式是否有效
+     */
+    public static boolean isValid(String cronExpression)
+    {
+        return CronExpression.isValidExpression(cronExpression);
+    }
+
+    /**
+     * 返回一个字符串值,表示该消息无效Cron表达式给出有效性
+     *
+     * @param cronExpression Cron表达式
+     * @return String 无效时返回表达式错误描述,如果有效返回null
+     */
+    public static String getInvalidMessage(String cronExpression)
+    {
+        try
+        {
+            new CronExpression(cronExpression);
+            return null;
+        }
+        catch (ParseException pe)
+        {
+            return pe.getMessage();
+        }
+    }
+
+    /**
+     * 返回下一个执行时间根据给定的Cron表达式
+     *
+     * @param cronExpression Cron表达式
+     * @return Date 下次Cron表达式执行时间
+     */
+    public static Date getNextExecution(String cronExpression)
+    {
+        try
+        {
+            CronExpression cron = new CronExpression(cronExpression);
+            return cron.getNextValidTimeAfter(new Date(System.currentTimeMillis()));
+        }
+        catch (ParseException e)
+        {
+            throw new IllegalArgumentException(e.getMessage());
+        }
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/JobInvokeUtil.java
similarity index 93%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/JobInvokeUtil.java
index 9a90d7b1..91d5683e 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/JobInvokeUtil.java
@@ -1,182 +1,182 @@
-package com.ruoyi.quartz.util;
-
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.util.LinkedList;
-import java.util.List;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 任务执行工具
- *
- * @author ruoyi
- */
-public class JobInvokeUtil
-{
-    /**
-     * 执行方法
-     *
-     * @param sysJob 系统任务
-     */
-    public static void invokeMethod(SysJob sysJob) throws Exception
-    {
-        String invokeTarget = sysJob.getInvokeTarget();
-        String beanName = getBeanName(invokeTarget);
-        String methodName = getMethodName(invokeTarget);
-        List<Object[]> methodParams = getMethodParams(invokeTarget);
-
-        if (!isValidClassName(beanName))
-        {
-            Object bean = SpringUtils.getBean(beanName);
-            invokeMethod(bean, methodName, methodParams);
-        }
-        else
-        {
-            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
-            invokeMethod(bean, methodName, methodParams);
-        }
-    }
-
-    /**
-     * 调用任务方法
-     *
-     * @param bean 目标对象
-     * @param methodName 方法名称
-     * @param methodParams 方法参数
-     */
-    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
-            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
-            InvocationTargetException
-    {
-        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0)
-        {
-            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
-            method.invoke(bean, getMethodParamsValue(methodParams));
-        }
-        else
-        {
-            Method method = bean.getClass().getMethod(methodName);
-            method.invoke(bean);
-        }
-    }
-
-    /**
-     * 校验是否为为class包名
-     * 
-     * @param invokeTarget 名称
-     * @return true是 false否
-     */
-    public static boolean isValidClassName(String invokeTarget)
-    {
-        return StringUtils.countMatches(invokeTarget, ".") > 1;
-    }
-
-    /**
-     * 获取bean名称
-     * 
-     * @param invokeTarget 目标字符串
-     * @return bean名称
-     */
-    public static String getBeanName(String invokeTarget)
-    {
-        String beanName = StringUtils.substringBefore(invokeTarget, "(");
-        return StringUtils.substringBeforeLast(beanName, ".");
-    }
-
-    /**
-     * 获取bean方法
-     * 
-     * @param invokeTarget 目标字符串
-     * @return method方法
-     */
-    public static String getMethodName(String invokeTarget)
-    {
-        String methodName = StringUtils.substringBefore(invokeTarget, "(");
-        return StringUtils.substringAfterLast(methodName, ".");
-    }
-
-    /**
-     * 获取method方法参数相关列表
-     * 
-     * @param invokeTarget 目标字符串
-     * @return method方法相关参数列表
-     */
-    public static List<Object[]> getMethodParams(String invokeTarget)
-    {
-        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
-        if (StringUtils.isEmpty(methodStr))
-        {
-            return null;
-        }
-        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
-        List<Object[]> classs = new LinkedList<>();
-        for (int i = 0; i < methodParams.length; i++)
-        {
-            String str = StringUtils.trimToEmpty(methodParams[i]);
-            // String字符串类型,以'或"开头
-            if (StringUtils.startsWithAny(str, "'", "\""))
-            {
-                classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });
-            }
-            // boolean布尔类型,等于true或者false
-            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
-            {
-                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
-            }
-            // long长整形,以L结尾
-            else if (StringUtils.endsWith(str, "L"))
-            {
-                classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
-            }
-            // double浮点类型,以D结尾
-            else if (StringUtils.endsWith(str, "D"))
-            {
-                classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });
-            }
-            // 其他类型归类为整形
-            else
-            {
-                classs.add(new Object[] { Integer.valueOf(str), Integer.class });
-            }
-        }
-        return classs;
-    }
-
-    /**
-     * 获取参数类型
-     * 
-     * @param methodParams 参数相关列表
-     * @return 参数类型列表
-     */
-    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
-    {
-        Class<?>[] classs = new Class<?>[methodParams.size()];
-        int index = 0;
-        for (Object[] os : methodParams)
-        {
-            classs[index] = (Class<?>) os[1];
-            index++;
-        }
-        return classs;
-    }
-
-    /**
-     * 获取参数值
-     * 
-     * @param methodParams 参数相关列表
-     * @return 参数值列表
-     */
-    public static Object[] getMethodParamsValue(List<Object[]> methodParams)
-    {
-        Object[] classs = new Object[methodParams.size()];
-        int index = 0;
-        for (Object[] os : methodParams)
-        {
-            classs[index] = (Object) os[0];
-            index++;
-        }
-        return classs;
-    }
-}
+package com.acupuncture.quartz.util;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.util.LinkedList;
+import java.util.List;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 任务执行工具
+ *
+ * @author acupuncture
+ */
+public class JobInvokeUtil
+{
+    /**
+     * 执行方法
+     *
+     * @param sysJob 系统任务
+     */
+    public static void invokeMethod(SysJob sysJob) throws Exception
+    {
+        String invokeTarget = sysJob.getInvokeTarget();
+        String beanName = getBeanName(invokeTarget);
+        String methodName = getMethodName(invokeTarget);
+        List<Object[]> methodParams = getMethodParams(invokeTarget);
+
+        if (!isValidClassName(beanName))
+        {
+            Object bean = SpringUtils.getBean(beanName);
+            invokeMethod(bean, methodName, methodParams);
+        }
+        else
+        {
+            Object bean = Class.forName(beanName).getDeclaredConstructor().newInstance();
+            invokeMethod(bean, methodName, methodParams);
+        }
+    }
+
+    /**
+     * 调用任务方法
+     *
+     * @param bean 目标对象
+     * @param methodName 方法名称
+     * @param methodParams 方法参数
+     */
+    private static void invokeMethod(Object bean, String methodName, List<Object[]> methodParams)
+            throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException,
+            InvocationTargetException
+    {
+        if (StringUtils.isNotNull(methodParams) && methodParams.size() > 0)
+        {
+            Method method = bean.getClass().getMethod(methodName, getMethodParamsType(methodParams));
+            method.invoke(bean, getMethodParamsValue(methodParams));
+        }
+        else
+        {
+            Method method = bean.getClass().getMethod(methodName);
+            method.invoke(bean);
+        }
+    }
+
+    /**
+     * 校验是否为为class包名
+     * 
+     * @param invokeTarget 名称
+     * @return true是 false否
+     */
+    public static boolean isValidClassName(String invokeTarget)
+    {
+        return StringUtils.countMatches(invokeTarget, ".") > 1;
+    }
+
+    /**
+     * 获取bean名称
+     * 
+     * @param invokeTarget 目标字符串
+     * @return bean名称
+     */
+    public static String getBeanName(String invokeTarget)
+    {
+        String beanName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringBeforeLast(beanName, ".");
+    }
+
+    /**
+     * 获取bean方法
+     * 
+     * @param invokeTarget 目标字符串
+     * @return method方法
+     */
+    public static String getMethodName(String invokeTarget)
+    {
+        String methodName = StringUtils.substringBefore(invokeTarget, "(");
+        return StringUtils.substringAfterLast(methodName, ".");
+    }
+
+    /**
+     * 获取method方法参数相关列表
+     * 
+     * @param invokeTarget 目标字符串
+     * @return method方法相关参数列表
+     */
+    public static List<Object[]> getMethodParams(String invokeTarget)
+    {
+        String methodStr = StringUtils.substringBetween(invokeTarget, "(", ")");
+        if (StringUtils.isEmpty(methodStr))
+        {
+            return null;
+        }
+        String[] methodParams = methodStr.split(",(?=([^\"']*[\"'][^\"']*[\"'])*[^\"']*$)");
+        List<Object[]> classs = new LinkedList<>();
+        for (int i = 0; i < methodParams.length; i++)
+        {
+            String str = StringUtils.trimToEmpty(methodParams[i]);
+            // String字符串类型,以'或"开头
+            if (StringUtils.startsWithAny(str, "'", "\""))
+            {
+                classs.add(new Object[] { StringUtils.substring(str, 1, str.length() - 1), String.class });
+            }
+            // boolean布尔类型,等于true或者false
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
+            {
+                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
+            }
+            // long长整形,以L结尾
+            else if (StringUtils.endsWith(str, "L"))
+            {
+                classs.add(new Object[] { Long.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Long.class });
+            }
+            // double浮点类型,以D结尾
+            else if (StringUtils.endsWith(str, "D"))
+            {
+                classs.add(new Object[] { Double.valueOf(StringUtils.substring(str, 0, str.length() - 1)), Double.class });
+            }
+            // 其他类型归类为整形
+            else
+            {
+                classs.add(new Object[] { Integer.valueOf(str), Integer.class });
+            }
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数类型
+     * 
+     * @param methodParams 参数相关列表
+     * @return 参数类型列表
+     */
+    public static Class<?>[] getMethodParamsType(List<Object[]> methodParams)
+    {
+        Class<?>[] classs = new Class<?>[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams)
+        {
+            classs[index] = (Class<?>) os[1];
+            index++;
+        }
+        return classs;
+    }
+
+    /**
+     * 获取参数值
+     * 
+     * @param methodParams 参数相关列表
+     * @return 参数值列表
+     */
+    public static Object[] getMethodParamsValue(List<Object[]> methodParams)
+    {
+        Object[] classs = new Object[methodParams.size()];
+        int index = 0;
+        for (Object[] os : methodParams)
+        {
+            classs[index] = (Object) os[0];
+            index++;
+        }
+        return classs;
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzDisallowConcurrentExecution.java
similarity index 79%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzDisallowConcurrentExecution.java
index 96a6dcf8..ec4a2a05 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzDisallowConcurrentExecution.java
@@ -1,21 +1,21 @@
-package com.ruoyi.quartz.util;
-
-import org.quartz.DisallowConcurrentExecution;
-import org.quartz.JobExecutionContext;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 定时任务处理(禁止并发执行)
- * 
- * @author ruoyi
- *
- */
-@DisallowConcurrentExecution
-public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
-{
-    @Override
-    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
-    {
-        JobInvokeUtil.invokeMethod(sysJob);
-    }
-}
+package com.acupuncture.quartz.util;
+
+import org.quartz.DisallowConcurrentExecution;
+import org.quartz.JobExecutionContext;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 定时任务处理(禁止并发执行)
+ * 
+ * @author acupuncture
+ *
+ */
+@DisallowConcurrentExecution
+public class QuartzDisallowConcurrentExecution extends AbstractQuartzJob
+{
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
+    {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzJobExecution.java
similarity index 75%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzJobExecution.java
index 87a06bc1..15aa8c9e 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/QuartzJobExecution.java
@@ -1,19 +1,19 @@
-package com.ruoyi.quartz.util;
-
-import org.quartz.JobExecutionContext;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 定时任务处理(允许并发执行)
- * 
- * @author ruoyi
- *
- */
-public class QuartzJobExecution extends AbstractQuartzJob
-{
-    @Override
-    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
-    {
-        JobInvokeUtil.invokeMethod(sysJob);
-    }
-}
+package com.acupuncture.quartz.util;
+
+import org.quartz.JobExecutionContext;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 定时任务处理(允许并发执行)
+ * 
+ * @author acupuncture
+ *
+ */
+public class QuartzJobExecution extends AbstractQuartzJob
+{
+    @Override
+    protected void doExecute(JobExecutionContext context, SysJob sysJob) throws Exception
+    {
+        JobInvokeUtil.invokeMethod(sysJob);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/ScheduleUtils.java
similarity index 89%
rename from ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java
rename to acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/ScheduleUtils.java
index ab829e69..09153472 100644
--- a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java
+++ b/acupuncture-quartz/src/main/java/com/acupuncture/quartz/util/ScheduleUtils.java
@@ -1,141 +1,141 @@
-package com.ruoyi.quartz.util;
-
-import org.quartz.CronScheduleBuilder;
-import org.quartz.CronTrigger;
-import org.quartz.Job;
-import org.quartz.JobBuilder;
-import org.quartz.JobDetail;
-import org.quartz.JobKey;
-import org.quartz.Scheduler;
-import org.quartz.SchedulerException;
-import org.quartz.TriggerBuilder;
-import org.quartz.TriggerKey;
-import com.ruoyi.common.constant.Constants;
-import com.ruoyi.common.constant.ScheduleConstants;
-import com.ruoyi.common.exception.job.TaskException;
-import com.ruoyi.common.exception.job.TaskException.Code;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.quartz.domain.SysJob;
-
-/**
- * 定时任务工具类
- * 
- * @author ruoyi
- *
- */
-public class ScheduleUtils
-{
-    /**
-     * 得到quartz任务类
-     *
-     * @param sysJob 执行计划
-     * @return 具体执行任务类
-     */
-    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)
-    {
-        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
-        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
-    }
-
-    /**
-     * 构建任务触发对象
-     */
-    public static TriggerKey getTriggerKey(Long jobId, String jobGroup)
-    {
-        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
-    }
-
-    /**
-     * 构建任务键对象
-     */
-    public static JobKey getJobKey(Long jobId, String jobGroup)
-    {
-        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
-    }
-
-    /**
-     * 创建定时任务
-     */
-    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException
-    {
-        Class<? extends Job> jobClass = getQuartzJobClass(job);
-        // 构建job信息
-        Long jobId = job.getJobId();
-        String jobGroup = job.getJobGroup();
-        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
-
-        // 表达式调度构建器
-        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
-        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
-
-        // 按新的cronExpression表达式构建一个新的trigger
-        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
-                .withSchedule(cronScheduleBuilder).build();
-
-        // 放入参数,运行时的方法可以获取
-        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
-
-        // 判断是否存在
-        if (scheduler.checkExists(getJobKey(jobId, jobGroup)))
-        {
-            // 防止创建时存在数据问题 先移除,然后在执行创建操作
-            scheduler.deleteJob(getJobKey(jobId, jobGroup));
-        }
-
-        // 判断任务是否过期
-        if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression())))
-        {
-            // 执行调度任务
-            scheduler.scheduleJob(jobDetail, trigger);
-        }
-
-        // 暂停任务
-        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
-        {
-            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
-        }
-    }
-
-    /**
-     * 设置定时任务策略
-     */
-    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
-            throws TaskException
-    {
-        switch (job.getMisfirePolicy())
-        {
-            case ScheduleConstants.MISFIRE_DEFAULT:
-                return cb;
-            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
-                return cb.withMisfireHandlingInstructionIgnoreMisfires();
-            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
-                return cb.withMisfireHandlingInstructionFireAndProceed();
-            case ScheduleConstants.MISFIRE_DO_NOTHING:
-                return cb.withMisfireHandlingInstructionDoNothing();
-            default:
-                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
-                        + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
-        }
-    }
-
-    /**
-     * 检查包名是否为白名单配置
-     * 
-     * @param invokeTarget 目标字符串
-     * @return 结果
-     */
-    public static boolean whiteList(String invokeTarget)
-    {
-        String packageName = StringUtils.substringBefore(invokeTarget, "(");
-        int count = StringUtils.countMatches(packageName, ".");
-        if (count > 1)
-        {
-            return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
-        }
-        Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
-        String beanPackageName = obj.getClass().getPackage().getName();
-        return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
-                && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
-    }
-}
+package com.acupuncture.quartz.util;
+
+import org.quartz.CronScheduleBuilder;
+import org.quartz.CronTrigger;
+import org.quartz.Job;
+import org.quartz.JobBuilder;
+import org.quartz.JobDetail;
+import org.quartz.JobKey;
+import org.quartz.Scheduler;
+import org.quartz.SchedulerException;
+import org.quartz.TriggerBuilder;
+import org.quartz.TriggerKey;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.ScheduleConstants;
+import com.acupuncture.common.exception.job.TaskException;
+import com.acupuncture.common.exception.job.TaskException.Code;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.quartz.domain.SysJob;
+
+/**
+ * 定时任务工具类
+ * 
+ * @author acupuncture
+ *
+ */
+public class ScheduleUtils
+{
+    /**
+     * 得到quartz任务类
+     *
+     * @param sysJob 执行计划
+     * @return 具体执行任务类
+     */
+    private static Class<? extends Job> getQuartzJobClass(SysJob sysJob)
+    {
+        boolean isConcurrent = "0".equals(sysJob.getConcurrent());
+        return isConcurrent ? QuartzJobExecution.class : QuartzDisallowConcurrentExecution.class;
+    }
+
+    /**
+     * 构建任务触发对象
+     */
+    public static TriggerKey getTriggerKey(Long jobId, String jobGroup)
+    {
+        return TriggerKey.triggerKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 构建任务键对象
+     */
+    public static JobKey getJobKey(Long jobId, String jobGroup)
+    {
+        return JobKey.jobKey(ScheduleConstants.TASK_CLASS_NAME + jobId, jobGroup);
+    }
+
+    /**
+     * 创建定时任务
+     */
+    public static void createScheduleJob(Scheduler scheduler, SysJob job) throws SchedulerException, TaskException
+    {
+        Class<? extends Job> jobClass = getQuartzJobClass(job);
+        // 构建job信息
+        Long jobId = job.getJobId();
+        String jobGroup = job.getJobGroup();
+        JobDetail jobDetail = JobBuilder.newJob(jobClass).withIdentity(getJobKey(jobId, jobGroup)).build();
+
+        // 表达式调度构建器
+        CronScheduleBuilder cronScheduleBuilder = CronScheduleBuilder.cronSchedule(job.getCronExpression());
+        cronScheduleBuilder = handleCronScheduleMisfirePolicy(job, cronScheduleBuilder);
+
+        // 按新的cronExpression表达式构建一个新的trigger
+        CronTrigger trigger = TriggerBuilder.newTrigger().withIdentity(getTriggerKey(jobId, jobGroup))
+                .withSchedule(cronScheduleBuilder).build();
+
+        // 放入参数,运行时的方法可以获取
+        jobDetail.getJobDataMap().put(ScheduleConstants.TASK_PROPERTIES, job);
+
+        // 判断是否存在
+        if (scheduler.checkExists(getJobKey(jobId, jobGroup)))
+        {
+            // 防止创建时存在数据问题 先移除,然后在执行创建操作
+            scheduler.deleteJob(getJobKey(jobId, jobGroup));
+        }
+
+        // 判断任务是否过期
+        if (StringUtils.isNotNull(CronUtils.getNextExecution(job.getCronExpression())))
+        {
+            // 执行调度任务
+            scheduler.scheduleJob(jobDetail, trigger);
+        }
+
+        // 暂停任务
+        if (job.getStatus().equals(ScheduleConstants.Status.PAUSE.getValue()))
+        {
+            scheduler.pauseJob(ScheduleUtils.getJobKey(jobId, jobGroup));
+        }
+    }
+
+    /**
+     * 设置定时任务策略
+     */
+    public static CronScheduleBuilder handleCronScheduleMisfirePolicy(SysJob job, CronScheduleBuilder cb)
+            throws TaskException
+    {
+        switch (job.getMisfirePolicy())
+        {
+            case ScheduleConstants.MISFIRE_DEFAULT:
+                return cb;
+            case ScheduleConstants.MISFIRE_IGNORE_MISFIRES:
+                return cb.withMisfireHandlingInstructionIgnoreMisfires();
+            case ScheduleConstants.MISFIRE_FIRE_AND_PROCEED:
+                return cb.withMisfireHandlingInstructionFireAndProceed();
+            case ScheduleConstants.MISFIRE_DO_NOTHING:
+                return cb.withMisfireHandlingInstructionDoNothing();
+            default:
+                throw new TaskException("The task misfire policy '" + job.getMisfirePolicy()
+                        + "' cannot be used in cron schedule tasks", Code.CONFIG_ERROR);
+        }
+    }
+
+    /**
+     * 检查包名是否为白名单配置
+     * 
+     * @param invokeTarget 目标字符串
+     * @return 结果
+     */
+    public static boolean whiteList(String invokeTarget)
+    {
+        String packageName = StringUtils.substringBefore(invokeTarget, "(");
+        int count = StringUtils.countMatches(packageName, ".");
+        if (count > 1)
+        {
+            return StringUtils.containsAnyIgnoreCase(invokeTarget, Constants.JOB_WHITELIST_STR);
+        }
+        Object obj = SpringUtils.getBean(StringUtils.split(invokeTarget, ".")[0]);
+        String beanPackageName = obj.getClass().getPackage().getName();
+        return StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_WHITELIST_STR)
+                && !StringUtils.containsAnyIgnoreCase(beanPackageName, Constants.JOB_ERROR_STR);
+    }
+}
diff --git a/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml b/acupuncture-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
similarity index 96%
rename from ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
rename to acupuncture-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
index 5ed72647..1ea1fd28 100644
--- a/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
+++ b/acupuncture-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
@@ -1,94 +1,94 @@
-<?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.quartz.mapper.SysJobLogMapper">
-
-	<resultMap type="SysJobLog" id="SysJobLogResult">
-		<id     property="jobLogId"       column="job_log_id"      />
-		<result property="jobName"        column="job_name"        />
-		<result property="jobGroup"       column="job_group"       />
-		<result property="invokeTarget"   column="invoke_target"   />
-		<result property="jobMessage"     column="job_message"     />
-		<result property="status"         column="status"          />
-		<result property="exceptionInfo"  column="exception_info"  />
-		<result property="createTime"     column="create_time"     />
-	</resultMap>
-	
-	<sql id="selectJobLogVo">
-        select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, create_time 
-		from sys_job_log
-    </sql>
-	
-	<select id="selectJobLogList" parameterType="SysJobLog" resultMap="SysJobLogResult">
-		<include refid="selectJobLogVo"/>
-		<where>
-			<if test="jobName != null and jobName != ''">
-				AND job_name like concat('%', #{jobName}, '%')
-			</if>
-			<if test="jobGroup != null and jobGroup != ''">
-				AND job_group = #{jobGroup}
-			</if>
-			<if test="status != null and status != ''">
-				AND status = #{status}
-			</if>
-			<if test="invokeTarget != null and invokeTarget != ''">
-				AND invoke_target like concat('%', #{invokeTarget}, '%')
-			</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>
-		order by create_time desc
-	</select>
-	
-	<select id="selectJobLogAll" resultMap="SysJobLogResult">
-		<include refid="selectJobLogVo"/>
-	</select>
-	
-	<select id="selectJobLogById" parameterType="Long" resultMap="SysJobLogResult">
-		<include refid="selectJobLogVo"/>
-		where job_log_id = #{jobLogId}
-	</select>
-	
-	<delete id="deleteJobLogById" parameterType="Long">
- 		delete from sys_job_log where job_log_id = #{jobLogId}
- 	</delete>
- 	
- 	<delete id="deleteJobLogByIds" parameterType="Long">
- 		delete from sys_job_log where job_log_id in
- 		<foreach collection="array" item="jobLogId" open="(" separator="," close=")">
- 			#{jobLogId}
-        </foreach> 
- 	</delete>
- 	
- 	<update id="cleanJobLog">
-        truncate table sys_job_log
-    </update>
- 	
- 	<insert id="insertJobLog" parameterType="SysJobLog">
- 		insert into sys_job_log(
- 			<if test="jobLogId != null and jobLogId != 0">job_log_id,</if>
- 			<if test="jobName != null and jobName != ''">job_name,</if>
- 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
- 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
- 			<if test="jobMessage != null and jobMessage != ''">job_message,</if>
- 			<if test="status != null and status != ''">status,</if>
- 			<if test="exceptionInfo != null and exceptionInfo != ''">exception_info,</if>
- 			create_time
- 		)values(
- 			<if test="jobLogId != null and jobLogId != 0">#{jobLogId},</if>
- 			<if test="jobName != null and jobName != ''">#{jobName},</if>
- 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
- 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
- 			<if test="jobMessage != null and jobMessage != ''">#{jobMessage},</if>
- 			<if test="status != null and status != ''">#{status},</if>
- 			<if test="exceptionInfo != null and exceptionInfo != ''">#{exceptionInfo},</if>
- 			sysdate()
- 		)
-	</insert>
-
+<?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.acupuncture.quartz.mapper.SysJobLogMapper">
+
+	<resultMap type="SysJobLog" id="SysJobLogResult">
+		<id     property="jobLogId"       column="job_log_id"      />
+		<result property="jobName"        column="job_name"        />
+		<result property="jobGroup"       column="job_group"       />
+		<result property="invokeTarget"   column="invoke_target"   />
+		<result property="jobMessage"     column="job_message"     />
+		<result property="status"         column="status"          />
+		<result property="exceptionInfo"  column="exception_info"  />
+		<result property="createTime"     column="create_time"     />
+	</resultMap>
+	
+	<sql id="selectJobLogVo">
+        select job_log_id, job_name, job_group, invoke_target, job_message, status, exception_info, create_time 
+		from sys_job_log
+    </sql>
+	
+	<select id="selectJobLogList" parameterType="SysJobLog" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		<where>
+			<if test="jobName != null and jobName != ''">
+				AND job_name like concat('%', #{jobName}, '%')
+			</if>
+			<if test="jobGroup != null and jobGroup != ''">
+				AND job_group = #{jobGroup}
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="invokeTarget != null and invokeTarget != ''">
+				AND invoke_target like concat('%', #{invokeTarget}, '%')
+			</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>
+		order by create_time desc
+	</select>
+	
+	<select id="selectJobLogAll" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+	</select>
+	
+	<select id="selectJobLogById" parameterType="Long" resultMap="SysJobLogResult">
+		<include refid="selectJobLogVo"/>
+		where job_log_id = #{jobLogId}
+	</select>
+	
+	<delete id="deleteJobLogById" parameterType="Long">
+ 		delete from sys_job_log where job_log_id = #{jobLogId}
+ 	</delete>
+ 	
+ 	<delete id="deleteJobLogByIds" parameterType="Long">
+ 		delete from sys_job_log where job_log_id in
+ 		<foreach collection="array" item="jobLogId" open="(" separator="," close=")">
+ 			#{jobLogId}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<update id="cleanJobLog">
+        truncate table sys_job_log
+    </update>
+ 	
+ 	<insert id="insertJobLog" parameterType="SysJobLog">
+ 		insert into sys_job_log(
+ 			<if test="jobLogId != null and jobLogId != 0">job_log_id,</if>
+ 			<if test="jobName != null and jobName != ''">job_name,</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
+ 			<if test="jobMessage != null and jobMessage != ''">job_message,</if>
+ 			<if test="status != null and status != ''">status,</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">exception_info,</if>
+ 			create_time
+ 		)values(
+ 			<if test="jobLogId != null and jobLogId != 0">#{jobLogId},</if>
+ 			<if test="jobName != null and jobName != ''">#{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
+ 			<if test="jobMessage != null and jobMessage != ''">#{jobMessage},</if>
+ 			<if test="status != null and status != ''">#{status},</if>
+ 			<if test="exceptionInfo != null and exceptionInfo != ''">#{exceptionInfo},</if>
+ 			sysdate()
+ 		)
+	</insert>
+
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml b/acupuncture-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
similarity index 96%
rename from ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
rename to acupuncture-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
index 69233bdf..9f4022da 100644
--- a/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
+++ b/acupuncture-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
@@ -1,111 +1,111 @@
-<?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.quartz.mapper.SysJobMapper">
-
-	<resultMap type="SysJob" id="SysJobResult">
-		<id     property="jobId"          column="job_id"          />
-		<result property="jobName"        column="job_name"        />
-		<result property="jobGroup"       column="job_group"       />
-		<result property="invokeTarget"   column="invoke_target"   />
-		<result property="cronExpression" column="cron_expression" />
-		<result property="misfirePolicy"  column="misfire_policy"  />
-		<result property="concurrent"     column="concurrent"      />
-		<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="selectJobVo">
-        select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark 
-		from sys_job
-    </sql>
-	
-	<select id="selectJobList" parameterType="SysJob" resultMap="SysJobResult">
-		<include refid="selectJobVo"/>
-		<where>
-			<if test="jobName != null and jobName != ''">
-				AND job_name like concat('%', #{jobName}, '%')
-			</if>
-			<if test="jobGroup != null and jobGroup != ''">
-				AND job_group = #{jobGroup}
-			</if>
-			<if test="status != null and status != ''">
-				AND status = #{status}
-			</if>
-			<if test="invokeTarget != null and invokeTarget != ''">
-				AND invoke_target like concat('%', #{invokeTarget}, '%')
-			</if>
-		</where>
-	</select>
-	
-	<select id="selectJobAll" resultMap="SysJobResult">
-		<include refid="selectJobVo"/>
-	</select>
-	
-	<select id="selectJobById" parameterType="Long" resultMap="SysJobResult">
-		<include refid="selectJobVo"/>
-		where job_id = #{jobId}
-	</select>
-	
-	<delete id="deleteJobById" parameterType="Long">
- 		delete from sys_job where job_id = #{jobId}
- 	</delete>
- 	
- 	<delete id="deleteJobByIds" parameterType="Long">
- 		delete from sys_job where job_id in
- 		<foreach collection="array" item="jobId" open="(" separator="," close=")">
- 			#{jobId}
-        </foreach> 
- 	</delete>
- 	
- 	<update id="updateJob" parameterType="SysJob">
- 		update sys_job
- 		<set>
- 			<if test="jobName != null and jobName != ''">job_name = #{jobName},</if>
- 			<if test="jobGroup != null and jobGroup != ''">job_group = #{jobGroup},</if>
- 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target = #{invokeTarget},</if>
- 			<if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if>
- 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy = #{misfirePolicy},</if>
- 			<if test="concurrent != null and concurrent != ''">concurrent = #{concurrent},</if>
- 			<if test="status !=null">status = #{status},</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 job_id = #{jobId}
-	</update>
- 	
- 	<insert id="insertJob" parameterType="SysJob" useGeneratedKeys="true" keyProperty="jobId">
- 		insert into sys_job(
- 			<if test="jobId != null and jobId != 0">job_id,</if>
- 			<if test="jobName != null and jobName != ''">job_name,</if>
- 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
- 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
- 			<if test="cronExpression != null and cronExpression != ''">cron_expression,</if>
- 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy,</if>
- 			<if test="concurrent != null and concurrent != ''">concurrent,</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="jobId != null and jobId != 0">#{jobId},</if>
- 			<if test="jobName != null and jobName != ''">#{jobName},</if>
- 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
- 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
- 			<if test="cronExpression != null and cronExpression != ''">#{cronExpression},</if>
- 			<if test="misfirePolicy != null and misfirePolicy != ''">#{misfirePolicy},</if>
- 			<if test="concurrent != null and concurrent != ''">#{concurrent},</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>
-
+<?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.acupuncture.quartz.mapper.SysJobMapper">
+
+	<resultMap type="SysJob" id="SysJobResult">
+		<id     property="jobId"          column="job_id"          />
+		<result property="jobName"        column="job_name"        />
+		<result property="jobGroup"       column="job_group"       />
+		<result property="invokeTarget"   column="invoke_target"   />
+		<result property="cronExpression" column="cron_expression" />
+		<result property="misfirePolicy"  column="misfire_policy"  />
+		<result property="concurrent"     column="concurrent"      />
+		<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="selectJobVo">
+        select job_id, job_name, job_group, invoke_target, cron_expression, misfire_policy, concurrent, status, create_by, create_time, remark 
+		from sys_job
+    </sql>
+	
+	<select id="selectJobList" parameterType="SysJob" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+		<where>
+			<if test="jobName != null and jobName != ''">
+				AND job_name like concat('%', #{jobName}, '%')
+			</if>
+			<if test="jobGroup != null and jobGroup != ''">
+				AND job_group = #{jobGroup}
+			</if>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</if>
+			<if test="invokeTarget != null and invokeTarget != ''">
+				AND invoke_target like concat('%', #{invokeTarget}, '%')
+			</if>
+		</where>
+	</select>
+	
+	<select id="selectJobAll" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+	</select>
+	
+	<select id="selectJobById" parameterType="Long" resultMap="SysJobResult">
+		<include refid="selectJobVo"/>
+		where job_id = #{jobId}
+	</select>
+	
+	<delete id="deleteJobById" parameterType="Long">
+ 		delete from sys_job where job_id = #{jobId}
+ 	</delete>
+ 	
+ 	<delete id="deleteJobByIds" parameterType="Long">
+ 		delete from sys_job where job_id in
+ 		<foreach collection="array" item="jobId" open="(" separator="," close=")">
+ 			#{jobId}
+        </foreach> 
+ 	</delete>
+ 	
+ 	<update id="updateJob" parameterType="SysJob">
+ 		update sys_job
+ 		<set>
+ 			<if test="jobName != null and jobName != ''">job_name = #{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group = #{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target = #{invokeTarget},</if>
+ 			<if test="cronExpression != null and cronExpression != ''">cron_expression = #{cronExpression},</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy = #{misfirePolicy},</if>
+ 			<if test="concurrent != null and concurrent != ''">concurrent = #{concurrent},</if>
+ 			<if test="status !=null">status = #{status},</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 job_id = #{jobId}
+	</update>
+ 	
+ 	<insert id="insertJob" parameterType="SysJob" useGeneratedKeys="true" keyProperty="jobId">
+ 		insert into sys_job(
+ 			<if test="jobId != null and jobId != 0">job_id,</if>
+ 			<if test="jobName != null and jobName != ''">job_name,</if>
+ 			<if test="jobGroup != null and jobGroup != ''">job_group,</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">invoke_target,</if>
+ 			<if test="cronExpression != null and cronExpression != ''">cron_expression,</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">misfire_policy,</if>
+ 			<if test="concurrent != null and concurrent != ''">concurrent,</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="jobId != null and jobId != 0">#{jobId},</if>
+ 			<if test="jobName != null and jobName != ''">#{jobName},</if>
+ 			<if test="jobGroup != null and jobGroup != ''">#{jobGroup},</if>
+ 			<if test="invokeTarget != null and invokeTarget != ''">#{invokeTarget},</if>
+ 			<if test="cronExpression != null and cronExpression != ''">#{cronExpression},</if>
+ 			<if test="misfirePolicy != null and misfirePolicy != ''">#{misfirePolicy},</if>
+ 			<if test="concurrent != null and concurrent != ''">#{concurrent},</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>
+
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/pom.xml b/acupuncture-system/pom.xml
similarity index 69%
rename from ruoyi-system/pom.xml
rename to acupuncture-system/pom.xml
index 19652939..1113f09b 100644
--- a/ruoyi-system/pom.xml
+++ b/acupuncture-system/pom.xml
@@ -1,28 +1,28 @@
-<?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">
-    <parent>
-        <artifactId>ruoyi</artifactId>
-        <groupId>com.ruoyi</groupId>
-        <version>3.8.9</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>ruoyi-system</artifactId>
-
-    <description>
-        system系统模块
-    </description>
-
-    <dependencies>
-
-        <!-- 通用工具-->
-        <dependency>
-            <groupId>com.ruoyi</groupId>
-            <artifactId>ruoyi-common</artifactId>
-        </dependency>
-
-    </dependencies>
-
+<?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">
+    <parent>
+        <artifactId>acupuncture</artifactId>
+        <groupId>com.acupuncture</groupId>
+        <version>3.8.9</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>acupuncture-system</artifactId>
+
+    <description>
+        system系统模块
+    </description>
+
+    <dependencies>
+
+        <!-- 通用工具-->
+        <dependency>
+            <groupId>com.acupuncture</groupId>
+            <artifactId>acupuncture-common</artifactId>
+        </dependency>
+
+    </dependencies>
+
 </project>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysCache.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysCache.java
index 2ee82120..2970b453 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysCache.java
@@ -1,81 +1,81 @@
-package com.ruoyi.system.domain;
-
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 缓存信息
- * 
- * @author ruoyi
- */
-public class SysCache
-{
-    /** 缓存名称 */
-    private String cacheName = "";
-
-    /** 缓存键名 */
-    private String cacheKey = "";
-
-    /** 缓存内容 */
-    private String cacheValue = "";
-
-    /** 备注 */
-    private String remark = "";
-
-    public SysCache()
-    {
-
-    }
-
-    public SysCache(String cacheName, String remark)
-    {
-        this.cacheName = cacheName;
-        this.remark = remark;
-    }
-
-    public SysCache(String cacheName, String cacheKey, String cacheValue)
-    {
-        this.cacheName = StringUtils.replace(cacheName, ":", "");
-        this.cacheKey = StringUtils.replace(cacheKey, cacheName, "");
-        this.cacheValue = cacheValue;
-    }
-
-    public String getCacheName()
-    {
-        return cacheName;
-    }
-
-    public void setCacheName(String cacheName)
-    {
-        this.cacheName = cacheName;
-    }
-
-    public String getCacheKey()
-    {
-        return cacheKey;
-    }
-
-    public void setCacheKey(String cacheKey)
-    {
-        this.cacheKey = cacheKey;
-    }
-
-    public String getCacheValue()
-    {
-        return cacheValue;
-    }
-
-    public void setCacheValue(String cacheValue)
-    {
-        this.cacheValue = cacheValue;
-    }
-
-    public String getRemark()
-    {
-        return remark;
-    }
-
-    public void setRemark(String remark)
-    {
-        this.remark = remark;
-    }
-}
+package com.acupuncture.system.domain;
+
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 缓存信息
+ * 
+ * @author acupuncture
+ */
+public class SysCache
+{
+    /** 缓存名称 */
+    private String cacheName = "";
+
+    /** 缓存键名 */
+    private String cacheKey = "";
+
+    /** 缓存内容 */
+    private String cacheValue = "";
+
+    /** 备注 */
+    private String remark = "";
+
+    public SysCache()
+    {
+
+    }
+
+    public SysCache(String cacheName, String remark)
+    {
+        this.cacheName = cacheName;
+        this.remark = remark;
+    }
+
+    public SysCache(String cacheName, String cacheKey, String cacheValue)
+    {
+        this.cacheName = StringUtils.replace(cacheName, ":", "");
+        this.cacheKey = StringUtils.replace(cacheKey, cacheName, "");
+        this.cacheValue = cacheValue;
+    }
+
+    public String getCacheName()
+    {
+        return cacheName;
+    }
+
+    public void setCacheName(String cacheName)
+    {
+        this.cacheName = cacheName;
+    }
+
+    public String getCacheKey()
+    {
+        return cacheKey;
+    }
+
+    public void setCacheKey(String cacheKey)
+    {
+        this.cacheKey = cacheKey;
+    }
+
+    public String getCacheValue()
+    {
+        return cacheValue;
+    }
+
+    public void setCacheValue(String cacheValue)
+    {
+        this.cacheValue = cacheValue;
+    }
+
+    public String getRemark()
+    {
+        return remark;
+    }
+
+    public void setRemark(String remark)
+    {
+        this.remark = remark;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysConfig.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysConfig.java
index 676a8916..be335546 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysConfig.java
@@ -1,111 +1,111 @@
-package com.ruoyi.system.domain;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 参数配置表 sys_config
- * 
- * @author ruoyi
- */
-public class SysConfig extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 参数主键 */
-    @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
-    private Long configId;
-
-    /** 参数名称 */
-    @Excel(name = "参数名称")
-    private String configName;
-
-    /** 参数键名 */
-    @Excel(name = "参数键名")
-    private String configKey;
-
-    /** 参数键值 */
-    @Excel(name = "参数键值")
-    private String configValue;
-
-    /** 系统内置(Y是 N否) */
-    @Excel(name = "系统内置", readConverterExp = "Y=是,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;
-    }
-    
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("configId", getConfigId())
-            .append("configName", getConfigName())
-            .append("configKey", getConfigKey())
-            .append("configValue", getConfigValue())
-            .append("configType", getConfigType())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 参数配置表 sys_config
+ * 
+ * @author acupuncture
+ */
+public class SysConfig extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 参数主键 */
+    @Excel(name = "参数主键", cellType = ColumnType.NUMERIC)
+    private Long configId;
+
+    /** 参数名称 */
+    @Excel(name = "参数名称")
+    private String configName;
+
+    /** 参数键名 */
+    @Excel(name = "参数键名")
+    private String configKey;
+
+    /** 参数键值 */
+    @Excel(name = "参数键值")
+    private String configValue;
+
+    /** 系统内置(Y是 N否) */
+    @Excel(name = "系统内置", readConverterExp = "Y=是,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;
+    }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("configId", getConfigId())
+            .append("configName", getConfigName())
+            .append("configKey", getConfigKey())
+            .append("configValue", getConfigValue())
+            .append("configType", getConfigType())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysLogininfor.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysLogininfor.java
index 02a7fb5c..a6b8ba89 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysLogininfor.java
@@ -1,144 +1,144 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 系统访问记录表 sys_logininfor
- * 
- * @author ruoyi
- */
-public class SysLogininfor extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** ID */
-    @Excel(name = "序号", cellType = ColumnType.NUMERIC)
-    private Long infoId;
-
-    /** 用户账号 */
-    @Excel(name = "用户账号")
-    private String userName;
-
-    /** 登录状态 0成功 1失败 */
-    @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败")
-    private String status;
-
-    /** 登录IP地址 */
-    @Excel(name = "登录地址")
-    private String ipaddr;
-
-    /** 登录地点 */
-    @Excel(name = "登录地点")
-    private String loginLocation;
-
-    /** 浏览器类型 */
-    @Excel(name = "浏览器")
-    private String browser;
-
-    /** 操作系统 */
-    @Excel(name = "操作系统")
-    private String os;
-
-    /** 提示消息 */
-    @Excel(name = "提示消息")
-    private String msg;
-
-    /** 访问时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
-    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;
-    }
-}
+package com.acupuncture.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 系统访问记录表 sys_logininfor
+ * 
+ * @author acupuncture
+ */
+public class SysLogininfor extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** ID */
+    @Excel(name = "序号", cellType = ColumnType.NUMERIC)
+    private Long infoId;
+
+    /** 用户账号 */
+    @Excel(name = "用户账号")
+    private String userName;
+
+    /** 登录状态 0成功 1失败 */
+    @Excel(name = "登录状态", readConverterExp = "0=成功,1=失败")
+    private String status;
+
+    /** 登录IP地址 */
+    @Excel(name = "登录地址")
+    private String ipaddr;
+
+    /** 登录地点 */
+    @Excel(name = "登录地点")
+    private String loginLocation;
+
+    /** 浏览器类型 */
+    @Excel(name = "浏览器")
+    private String browser;
+
+    /** 操作系统 */
+    @Excel(name = "操作系统")
+    private String os;
+
+    /** 提示消息 */
+    @Excel(name = "提示消息")
+    private String msg;
+
+    /** 访问时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "访问时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysNotice.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysNotice.java
index b5c6187b..59b25036 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysNotice.java
@@ -1,102 +1,102 @@
-package com.ruoyi.system.domain;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.core.domain.BaseEntity;
-import com.ruoyi.common.xss.Xss;
-
-/**
- * 通知公告表 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正常 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;
-    }
-
-    @Xss(message = "公告标题不能包含脚本字符")
-    @NotBlank(message = "公告标题不能为空")
-    @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
-    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;
-    }
-
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("noticeId", getNoticeId())
-            .append("noticeTitle", getNoticeTitle())
-            .append("noticeType", getNoticeType())
-            .append("noticeContent", getNoticeContent())
-            .append("status", getStatus())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.core.domain.BaseEntity;
+import com.acupuncture.common.xss.Xss;
+
+/**
+ * 通知公告表 sys_notice
+ * 
+ * @author acupuncture
+ */
+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正常 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;
+    }
+
+    @Xss(message = "公告标题不能包含脚本字符")
+    @NotBlank(message = "公告标题不能为空")
+    @Size(min = 0, max = 50, message = "公告标题不能超过50个字符")
+    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;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("noticeId", getNoticeId())
+            .append("noticeTitle", getNoticeTitle())
+            .append("noticeType", getNoticeType())
+            .append("noticeContent", getNoticeContent())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysOperLog.java
similarity index 91%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysOperLog.java
index 7286573e..dbe7a900 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysOperLog.java
@@ -1,269 +1,269 @@
-package com.ruoyi.system.domain;
-
-import java.util.Date;
-import com.fasterxml.jackson.annotation.JsonFormat;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 操作日志记录表 oper_log
- * 
- * @author ruoyi
- */
-public class SysOperLog extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 日志主键 */
-    @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
-    private Long operId;
-
-    /** 操作模块 */
-    @Excel(name = "操作模块")
-    private String title;
-
-    /** 业务类型(0其它 1新增 2修改 3删除) */
-    @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
-    private Integer businessType;
-
-    /** 业务类型数组 */
-    private Integer[] businessTypes;
-
-    /** 请求方法 */
-    @Excel(name = "请求方法")
-    private String method;
-
-    /** 请求方式 */
-    @Excel(name = "请求方式")
-    private String requestMethod;
-
-    /** 操作类别(0其它 1后台用户 2手机端用户) */
-    @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
-    private Integer operatorType;
-
-    /** 操作人员 */
-    @Excel(name = "操作人员")
-    private String operName;
-
-    /** 部门名称 */
-    @Excel(name = "部门名称")
-    private String deptName;
-
-    /** 请求url */
-    @Excel(name = "请求地址")
-    private String operUrl;
-
-    /** 操作地址 */
-    @Excel(name = "操作地址")
-    private String operIp;
-
-    /** 操作地点 */
-    @Excel(name = "操作地点")
-    private String operLocation;
-
-    /** 请求参数 */
-    @Excel(name = "请求参数")
-    private String operParam;
-
-    /** 返回参数 */
-    @Excel(name = "返回参数")
-    private String jsonResult;
-
-    /** 操作状态(0正常 1异常) */
-    @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
-    private Integer status;
-
-    /** 错误消息 */
-    @Excel(name = "错误消息")
-    private String errorMsg;
-
-    /** 操作时间 */
-    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
-    @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
-    private Date operTime;
-
-    /** 消耗时间 */
-    @Excel(name = "消耗时间", suffix = "毫秒")
-    private Long costTime;
-
-    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;
-    }
-
-    public Long getCostTime()
-    {
-        return costTime;
-    }
-
-    public void setCostTime(Long costTime)
-    {
-        this.costTime = costTime;
-    }
-}
+package com.acupuncture.system.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 操作日志记录表 oper_log
+ * 
+ * @author acupuncture
+ */
+public class SysOperLog extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 日志主键 */
+    @Excel(name = "操作序号", cellType = ColumnType.NUMERIC)
+    private Long operId;
+
+    /** 操作模块 */
+    @Excel(name = "操作模块")
+    private String title;
+
+    /** 业务类型(0其它 1新增 2修改 3删除) */
+    @Excel(name = "业务类型", readConverterExp = "0=其它,1=新增,2=修改,3=删除,4=授权,5=导出,6=导入,7=强退,8=生成代码,9=清空数据")
+    private Integer businessType;
+
+    /** 业务类型数组 */
+    private Integer[] businessTypes;
+
+    /** 请求方法 */
+    @Excel(name = "请求方法")
+    private String method;
+
+    /** 请求方式 */
+    @Excel(name = "请求方式")
+    private String requestMethod;
+
+    /** 操作类别(0其它 1后台用户 2手机端用户) */
+    @Excel(name = "操作类别", readConverterExp = "0=其它,1=后台用户,2=手机端用户")
+    private Integer operatorType;
+
+    /** 操作人员 */
+    @Excel(name = "操作人员")
+    private String operName;
+
+    /** 部门名称 */
+    @Excel(name = "部门名称")
+    private String deptName;
+
+    /** 请求url */
+    @Excel(name = "请求地址")
+    private String operUrl;
+
+    /** 操作地址 */
+    @Excel(name = "操作地址")
+    private String operIp;
+
+    /** 操作地点 */
+    @Excel(name = "操作地点")
+    private String operLocation;
+
+    /** 请求参数 */
+    @Excel(name = "请求参数")
+    private String operParam;
+
+    /** 返回参数 */
+    @Excel(name = "返回参数")
+    private String jsonResult;
+
+    /** 操作状态(0正常 1异常) */
+    @Excel(name = "状态", readConverterExp = "0=正常,1=异常")
+    private Integer status;
+
+    /** 错误消息 */
+    @Excel(name = "错误消息")
+    private String errorMsg;
+
+    /** 操作时间 */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @Excel(name = "操作时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date operTime;
+
+    /** 消耗时间 */
+    @Excel(name = "消耗时间", suffix = "毫秒")
+    private Long costTime;
+
+    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;
+    }
+
+    public Long getCostTime()
+    {
+        return costTime;
+    }
+
+    public void setCostTime(Long costTime)
+    {
+        this.costTime = costTime;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysPost.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysPost.java
index a36ed791..7cc96349 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysPost.java
@@ -1,124 +1,124 @@
-package com.ruoyi.system.domain;
-
-import javax.validation.constraints.NotBlank;
-import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Size;
-import org.apache.commons.lang3.builder.ToStringBuilder;
-import org.apache.commons.lang3.builder.ToStringStyle;
-import com.ruoyi.common.annotation.Excel;
-import com.ruoyi.common.annotation.Excel.ColumnType;
-import com.ruoyi.common.core.domain.BaseEntity;
-
-/**
- * 岗位表 sys_post
- * 
- * @author ruoyi
- */
-public class SysPost extends BaseEntity
-{
-    private static final long serialVersionUID = 1L;
-
-    /** 岗位序号 */
-    @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
-    private Long postId;
-
-    /** 岗位编码 */
-    @Excel(name = "岗位编码")
-    private String postCode;
-
-    /** 岗位名称 */
-    @Excel(name = "岗位名称")
-    private String postName;
-
-    /** 岗位排序 */
-    @Excel(name = "岗位排序")
-    private Integer postSort;
-
-    /** 状态(0正常 1停用) */
-    @Excel(name = "状态", readConverterExp = "0=正常,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;
-    }
-
-    @NotNull(message = "显示顺序不能为空")
-    public Integer getPostSort()
-    {
-        return postSort;
-    }
-
-    public void setPostSort(Integer 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;
-    }
-    
-    @Override
-    public String toString() {
-        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
-            .append("postId", getPostId())
-            .append("postCode", getPostCode())
-            .append("postName", getPostName())
-            .append("postSort", getPostSort())
-            .append("status", getStatus())
-            .append("createBy", getCreateBy())
-            .append("createTime", getCreateTime())
-            .append("updateBy", getUpdateBy())
-            .append("updateTime", getUpdateTime())
-            .append("remark", getRemark())
-            .toString();
-    }
-}
+package com.acupuncture.system.domain;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+import com.acupuncture.common.annotation.Excel;
+import com.acupuncture.common.annotation.Excel.ColumnType;
+import com.acupuncture.common.core.domain.BaseEntity;
+
+/**
+ * 岗位表 sys_post
+ * 
+ * @author acupuncture
+ */
+public class SysPost extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 岗位序号 */
+    @Excel(name = "岗位序号", cellType = ColumnType.NUMERIC)
+    private Long postId;
+
+    /** 岗位编码 */
+    @Excel(name = "岗位编码")
+    private String postCode;
+
+    /** 岗位名称 */
+    @Excel(name = "岗位名称")
+    private String postName;
+
+    /** 岗位排序 */
+    @Excel(name = "岗位排序")
+    private Integer postSort;
+
+    /** 状态(0正常 1停用) */
+    @Excel(name = "状态", readConverterExp = "0=正常,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;
+    }
+
+    @NotNull(message = "显示顺序不能为空")
+    public Integer getPostSort()
+    {
+        return postSort;
+    }
+
+    public void setPostSort(Integer 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;
+    }
+    
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("postId", getPostId())
+            .append("postCode", getPostCode())
+            .append("postName", getPostName())
+            .append("postSort", getPostSort())
+            .append("status", getStatus())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("remark", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleDept.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleDept.java
index 8ed8e473..9788e4e8 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleDept.java
@@ -1,46 +1,46 @@
-package com.ruoyi.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();
-    }
-}
+package com.acupuncture.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 角色和部门关联 sys_role_dept
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleMenu.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleMenu.java
index 59d28699..bb850366 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysRoleMenu.java
@@ -1,46 +1,46 @@
-package com.ruoyi.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();
-    }
-}
+package com.acupuncture.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 角色和菜单关联 sys_role_menu
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserOnline.java
similarity index 91%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserOnline.java
index e1495aaa..12087158 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserOnline.java
@@ -1,113 +1,113 @@
-package com.ruoyi.system.domain;
-
-/**
- * 当前在线会话
- * 
- * @author ruoyi
- */
-public class SysUserOnline
-{
-    /** 会话编号 */
-    private String tokenId;
-
-    /** 部门名称 */
-    private String deptName;
-
-    /** 用户名称 */
-    private String userName;
-
-    /** 登录IP地址 */
-    private String ipaddr;
-
-    /** 登录地址 */
-    private String loginLocation;
-
-    /** 浏览器类型 */
-    private String browser;
-
-    /** 操作系统 */
-    private String os;
-
-    /** 登录时间 */
-    private Long loginTime;
-
-    public String getTokenId()
-    {
-        return tokenId;
-    }
-
-    public void setTokenId(String tokenId)
-    {
-        this.tokenId = tokenId;
-    }
-
-    public String getDeptName()
-    {
-        return deptName;
-    }
-
-    public void setDeptName(String deptName)
-    {
-        this.deptName = deptName;
-    }
-
-    public String getUserName()
-    {
-        return userName;
-    }
-
-    public void setUserName(String userName)
-    {
-        this.userName = userName;
-    }
-
-    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 Long getLoginTime()
-    {
-        return loginTime;
-    }
-
-    public void setLoginTime(Long loginTime)
-    {
-        this.loginTime = loginTime;
-    }
-}
+package com.acupuncture.system.domain;
+
+/**
+ * 当前在线会话
+ * 
+ * @author acupuncture
+ */
+public class SysUserOnline
+{
+    /** 会话编号 */
+    private String tokenId;
+
+    /** 部门名称 */
+    private String deptName;
+
+    /** 用户名称 */
+    private String userName;
+
+    /** 登录IP地址 */
+    private String ipaddr;
+
+    /** 登录地址 */
+    private String loginLocation;
+
+    /** 浏览器类型 */
+    private String browser;
+
+    /** 操作系统 */
+    private String os;
+
+    /** 登录时间 */
+    private Long loginTime;
+
+    public String getTokenId()
+    {
+        return tokenId;
+    }
+
+    public void setTokenId(String tokenId)
+    {
+        this.tokenId = tokenId;
+    }
+
+    public String getDeptName()
+    {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName)
+    {
+        this.deptName = deptName;
+    }
+
+    public String getUserName()
+    {
+        return userName;
+    }
+
+    public void setUserName(String userName)
+    {
+        this.userName = userName;
+    }
+
+    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 Long getLoginTime()
+    {
+        return loginTime;
+    }
+
+    public void setLoginTime(Long loginTime)
+    {
+        this.loginTime = loginTime;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserPost.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserPost.java
index 07ceb85c..bd10ba1f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserPost.java
@@ -1,46 +1,46 @@
-package com.ruoyi.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();
-    }
-}
+package com.acupuncture.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 用户和岗位关联 sys_user_post
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserRole.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserRole.java
index ce2af2bd..a6e54f7d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/SysUserRole.java
@@ -1,46 +1,46 @@
-package com.ruoyi.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();
-    }
-}
+package com.acupuncture.system.domain;
+
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+/**
+ * 用户和角色关联 sys_user_role
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/MetaVo.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/MetaVo.java
index 68263261..f1bfe6e4 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/MetaVo.java
@@ -1,106 +1,106 @@
-package com.ruoyi.system.domain.vo;
-
-import com.ruoyi.common.utils.StringUtils;
-
-/**
- * 路由显示信息
- * 
- * @author ruoyi
- */
-public class MetaVo
-{
-    /**
-     * 设置该路由在侧边栏和面包屑中展示的名字
-     */
-    private String title;
-
-    /**
-     * 设置该路由的图标,对应路径src/assets/icons/svg
-     */
-    private String icon;
-
-    /**
-     * 设置为true,则不会被 <keep-alive>缓存
-     */
-    private boolean noCache;
-
-    /**
-     * 内链地址(http(s)://开头)
-     */
-    private String link;
-
-    public MetaVo()
-    {
-    }
-
-    public MetaVo(String title, String icon)
-    {
-        this.title = title;
-        this.icon = icon;
-    }
-
-    public MetaVo(String title, String icon, boolean noCache)
-    {
-        this.title = title;
-        this.icon = icon;
-        this.noCache = noCache;
-    }
-
-    public MetaVo(String title, String icon, String link)
-    {
-        this.title = title;
-        this.icon = icon;
-        this.link = link;
-    }
-
-    public MetaVo(String title, String icon, boolean noCache, String link)
-    {
-        this.title = title;
-        this.icon = icon;
-        this.noCache = noCache;
-        if (StringUtils.ishttp(link))
-        {
-            this.link = link;
-        }
-    }
-
-    public boolean isNoCache()
-    {
-        return noCache;
-    }
-
-    public void setNoCache(boolean noCache)
-    {
-        this.noCache = noCache;
-    }
-
-    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;
-    }
-
-    public String getLink()
-    {
-        return link;
-    }
-
-    public void setLink(String link)
-    {
-        this.link = link;
-    }
-}
+package com.acupuncture.system.domain.vo;
+
+import com.acupuncture.common.utils.StringUtils;
+
+/**
+ * 路由显示信息
+ * 
+ * @author acupuncture
+ */
+public class MetaVo
+{
+    /**
+     * 设置该路由在侧边栏和面包屑中展示的名字
+     */
+    private String title;
+
+    /**
+     * 设置该路由的图标,对应路径src/assets/icons/svg
+     */
+    private String icon;
+
+    /**
+     * 设置为true,则不会被 <keep-alive>缓存
+     */
+    private boolean noCache;
+
+    /**
+     * 内链地址(http(s)://开头)
+     */
+    private String link;
+
+    public MetaVo()
+    {
+    }
+
+    public MetaVo(String title, String icon)
+    {
+        this.title = title;
+        this.icon = icon;
+    }
+
+    public MetaVo(String title, String icon, boolean noCache)
+    {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+    }
+
+    public MetaVo(String title, String icon, String link)
+    {
+        this.title = title;
+        this.icon = icon;
+        this.link = link;
+    }
+
+    public MetaVo(String title, String icon, boolean noCache, String link)
+    {
+        this.title = title;
+        this.icon = icon;
+        this.noCache = noCache;
+        if (StringUtils.ishttp(link))
+        {
+            this.link = link;
+        }
+    }
+
+    public boolean isNoCache()
+    {
+        return noCache;
+    }
+
+    public void setNoCache(boolean noCache)
+    {
+        this.noCache = noCache;
+    }
+
+    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;
+    }
+
+    public String getLink()
+    {
+        return link;
+    }
+
+    public void setLink(String link)
+    {
+        this.link = link;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/RouterVo.java
similarity index 92%
rename from ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/RouterVo.java
index 2d4a2b80..59364a29 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/domain/vo/RouterVo.java
@@ -1,148 +1,148 @@
-package com.ruoyi.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 boolean hidden;
-
-    /**
-     * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
-     */
-    private String redirect;
-
-    /**
-     * 组件地址
-     */
-    private String component;
-
-    /**
-     * 路由参数:如 {"id": 1, "name": "ry"}
-     */
-    private String query;
-
-    /**
-     * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
-     */
-    private Boolean alwaysShow;
-
-    /**
-     * 其他元素
-     */
-    private MetaVo meta;
-
-    /**
-     * 子路由
-     */
-    private List<RouterVo> children;
-
-    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 boolean getHidden()
-    {
-        return hidden;
-    }
-
-    public void setHidden(boolean 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 String getQuery()
-    {
-        return query;
-    }
-
-    public void setQuery(String query)
-    {
-        this.query = query;
-    }
-
-    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;
-    }
-}
+package com.acupuncture.system.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonInclude;
+import java.util.List;
+
+/**
+ * 路由配置信息
+ * 
+ * @author acupuncture
+ */
+@JsonInclude(JsonInclude.Include.NON_EMPTY)
+public class RouterVo
+{
+    /**
+     * 路由名字
+     */
+    private String name;
+
+    /**
+     * 路由地址
+     */
+    private String path;
+
+    /**
+     * 是否隐藏路由,当设置 true 的时候该路由不会再侧边栏出现
+     */
+    private boolean hidden;
+
+    /**
+     * 重定向地址,当设置 noRedirect 的时候该路由在面包屑导航中不可被点击
+     */
+    private String redirect;
+
+    /**
+     * 组件地址
+     */
+    private String component;
+
+    /**
+     * 路由参数:如 {"id": 1, "name": "ry"}
+     */
+    private String query;
+
+    /**
+     * 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面
+     */
+    private Boolean alwaysShow;
+
+    /**
+     * 其他元素
+     */
+    private MetaVo meta;
+
+    /**
+     * 子路由
+     */
+    private List<RouterVo> children;
+
+    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 boolean getHidden()
+    {
+        return hidden;
+    }
+
+    public void setHidden(boolean 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 String getQuery()
+    {
+        return query;
+    }
+
+    public void setQuery(String query)
+    {
+        this.query = query;
+    }
+
+    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-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysConfigMapper.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysConfigMapper.java
index 999995d7..5f9a307d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysConfigMapper.java
@@ -1,76 +1,76 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysConfig;
-
-/**
- * 参数配置 数据层
- * 
- * @author ruoyi
- */
-public interface SysConfigMapper
-{
-    /**
-     * 查询参数配置信息
-     * 
-     * @param config 参数配置信息
-     * @return 参数配置信息
-     */
-    public SysConfig selectConfig(SysConfig config);
-
-    /**
-     * 通过ID查询配置
-     * 
-     * @param configId 参数ID
-     * @return 参数配置信息
-     */
-    public SysConfig selectConfigById(Long configId);
-
-    /**
-     * 查询参数配置列表
-     * 
-     * @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);
-
-    /**
-     * 批量删除参数信息
-     * 
-     * @param configIds 需要删除的参数ID
-     * @return 结果
-     */
-    public int deleteConfigByIds(Long[] configIds);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysConfig;
+
+/**
+ * 参数配置 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysConfigMapper
+{
+    /**
+     * 查询参数配置信息
+     * 
+     * @param config 参数配置信息
+     * @return 参数配置信息
+     */
+    public SysConfig selectConfig(SysConfig config);
+
+    /**
+     * 通过ID查询配置
+     * 
+     * @param configId 参数ID
+     * @return 参数配置信息
+     */
+    public SysConfig selectConfigById(Long configId);
+
+    /**
+     * 查询参数配置列表
+     * 
+     * @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);
+
+    /**
+     * 批量删除参数信息
+     * 
+     * @param configIds 需要删除的参数ID
+     * @return 结果
+     */
+    public int deleteConfigByIds(Long[] configIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDeptMapper.java
similarity index 92%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDeptMapper.java
index f3b58474..63717217 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDeptMapper.java
@@ -1,118 +1,118 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.common.core.domain.entity.SysDept;
-
-/**
- * 部门管理 数据层
- * 
- * @author ruoyi
- */
-public interface SysDeptMapper
-{
-    /**
-     * 查询部门管理数据
-     * 
-     * @param dept 部门信息
-     * @return 部门信息集合
-     */
-    public List<SysDept> selectDeptList(SysDept dept);
-
-    /**
-     * 根据角色ID查询部门树信息
-     * 
-     * @param roleId 角色ID
-     * @param deptCheckStrictly 部门树选择项是否关联显示
-     * @return 选中部门列表
-     */
-    public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
-
-    /**
-     * 根据部门ID查询信息
-     * 
-     * @param deptId 部门ID
-     * @return 部门信息
-     */
-    public SysDept selectDeptById(Long deptId);
-
-    /**
-     * 根据ID查询所有子部门
-     * 
-     * @param deptId 部门ID
-     * @return 部门列表
-     */
-    public List<SysDept> selectChildrenDeptById(Long deptId);
-
-    /**
-     * 根据ID查询所有子部门(正常状态)
-     * 
-     * @param deptId 部门ID
-     * @return 子部门数
-     */
-    public int selectNormalChildrenDeptById(Long deptId);
-
-    /**
-     * 是否存在子节点
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    public int hasChildByDeptId(Long deptId);
-
-    /**
-     * 查询部门是否存在用户
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    public int checkDeptExistUser(Long deptId);
-
-    /**
-     * 校验部门名称是否唯一
-     * 
-     * @param deptName 部门名称
-     * @param parentId 父部门ID
-     * @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 deptIds 部门ID组
-     */
-    public void updateDeptStatusNormal(Long[] deptIds);
-
-    /**
-     * 修改子元素关系
-     * 
-     * @param depts 子元素
-     * @return 结果
-     */
-    public int updateDeptChildren(@Param("depts") List<SysDept> depts);
-
-    /**
-     * 删除部门管理信息
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    public int deleteDeptById(Long deptId);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.acupuncture.common.core.domain.entity.SysDept;
+
+/**
+ * 部门管理 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysDeptMapper
+{
+    /**
+     * 查询部门管理数据
+     * 
+     * @param dept 部门信息
+     * @return 部门信息集合
+     */
+    public List<SysDept> selectDeptList(SysDept dept);
+
+    /**
+     * 根据角色ID查询部门树信息
+     * 
+     * @param roleId 角色ID
+     * @param deptCheckStrictly 部门树选择项是否关联显示
+     * @return 选中部门列表
+     */
+    public List<Long> selectDeptListByRoleId(@Param("roleId") Long roleId, @Param("deptCheckStrictly") boolean deptCheckStrictly);
+
+    /**
+     * 根据部门ID查询信息
+     * 
+     * @param deptId 部门ID
+     * @return 部门信息
+     */
+    public SysDept selectDeptById(Long deptId);
+
+    /**
+     * 根据ID查询所有子部门
+     * 
+     * @param deptId 部门ID
+     * @return 部门列表
+     */
+    public List<SysDept> selectChildrenDeptById(Long deptId);
+
+    /**
+     * 根据ID查询所有子部门(正常状态)
+     * 
+     * @param deptId 部门ID
+     * @return 子部门数
+     */
+    public int selectNormalChildrenDeptById(Long deptId);
+
+    /**
+     * 是否存在子节点
+     * 
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    public int hasChildByDeptId(Long deptId);
+
+    /**
+     * 查询部门是否存在用户
+     * 
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    public int checkDeptExistUser(Long deptId);
+
+    /**
+     * 校验部门名称是否唯一
+     * 
+     * @param deptName 部门名称
+     * @param parentId 父部门ID
+     * @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 deptIds 部门ID组
+     */
+    public void updateDeptStatusNormal(Long[] deptIds);
+
+    /**
+     * 修改子元素关系
+     * 
+     * @param depts 子元素
+     * @return 结果
+     */
+    public int updateDeptChildren(@Param("depts") List<SysDept> depts);
+
+    /**
+     * 删除部门管理信息
+     * 
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    public int deleteDeptById(Long deptId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictDataMapper.java
similarity index 91%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictDataMapper.java
index 92f799e5..0fd96e8b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictDataMapper.java
@@ -1,95 +1,95 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.common.core.domain.entity.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 dictCodes 需要删除的字典数据ID
-     * @return 结果
-     */
-    public int deleteDictDataByIds(Long[] dictCodes);
-
-    /**
-     * 新增字典数据信息
-     * 
-     * @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);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+
+/**
+ * 字典表 数据层
+ * 
+ * @author acupuncture
+ */
+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 dictCodes 需要删除的字典数据ID
+     * @return 结果
+     */
+    public int deleteDictDataByIds(Long[] dictCodes);
+
+    /**
+     * 新增字典数据信息
+     * 
+     * @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-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictTypeMapper.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictTypeMapper.java
index 132a72ed..b35d77d7 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysDictTypeMapper.java
@@ -1,83 +1,83 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.entity.SysDictType;
-
-/**
- * 字典表 数据层
- * 
- * @author ruoyi
- */
-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 dictIds 需要删除的字典ID
-     * @return 结果
-     */
-    public int deleteDictTypeByIds(Long[] dictIds);
-
-    /**
-     * 新增字典类型信息
-     * 
-     * @param dictType 字典类型信息
-     * @return 结果
-     */
-    public int insertDictType(SysDictType dictType);
-
-    /**
-     * 修改字典类型信息
-     * 
-     * @param dictType 字典类型信息
-     * @return 结果
-     */
-    public int updateDictType(SysDictType dictType);
-
-    /**
-     * 校验字典类型称是否唯一
-     * 
-     * @param dictType 字典类型
-     * @return 结果
-     */
-    public SysDictType checkDictTypeUnique(String dictType);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.entity.SysDictType;
+
+/**
+ * 字典表 数据层
+ * 
+ * @author acupuncture
+ */
+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 dictIds 需要删除的字典ID
+     * @return 结果
+     */
+    public int deleteDictTypeByIds(Long[] dictIds);
+
+    /**
+     * 新增字典类型信息
+     * 
+     * @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-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysLogininforMapper.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysLogininforMapper.java
index 480dd9ff..9841573b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysLogininforMapper.java
@@ -1,42 +1,42 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysLogininfor;
-
-/**
- * 系统访问日志情况信息 数据层
- * 
- * @author ruoyi
- */
-public interface SysLogininforMapper
-{
-    /**
-     * 新增系统登录日志
-     * 
-     * @param logininfor 访问日志对象
-     */
-    public void insertLogininfor(SysLogininfor logininfor);
-
-    /**
-     * 查询系统登录日志集合
-     * 
-     * @param logininfor 访问日志对象
-     * @return 登录记录集合
-     */
-    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
-
-    /**
-     * 批量删除系统登录日志
-     * 
-     * @param infoIds 需要删除的登录日志ID
-     * @return 结果
-     */
-    public int deleteLogininforByIds(Long[] infoIds);
-
-    /**
-     * 清空系统登录日志
-     * 
-     * @return 结果
-     */
-    public int cleanLogininfor();
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysLogininfor;
+
+/**
+ * 系统访问日志情况信息 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysLogininforMapper
+{
+    /**
+     * 新增系统登录日志
+     * 
+     * @param logininfor 访问日志对象
+     */
+    public void insertLogininfor(SysLogininfor logininfor);
+
+    /**
+     * 查询系统登录日志集合
+     * 
+     * @param logininfor 访问日志对象
+     * @return 登录记录集合
+     */
+    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
+
+    /**
+     * 批量删除系统登录日志
+     * 
+     * @param infoIds 需要删除的登录日志ID
+     * @return 结果
+     */
+    public int deleteLogininforByIds(Long[] infoIds);
+
+    /**
+     * 清空系统登录日志
+     * 
+     * @return 结果
+     */
+    public int cleanLogininfor();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysMenuMapper.java
similarity index 92%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysMenuMapper.java
index f3e2eb9e..1df62fb2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysMenuMapper.java
@@ -1,125 +1,125 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-
-/**
- * 菜单表 数据层
- *
- * @author ruoyi
- */
-public interface SysMenuMapper
-{
-    /**
-     * 查询系统菜单列表
-     *
-     * @param menu 菜单信息
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuList(SysMenu menu);
-
-    /**
-     * 根据用户所有权限
-     *
-     * @return 权限列表
-     */
-    public List<String> selectMenuPerms();
-
-    /**
-     * 根据用户查询系统菜单列表
-     *
-     * @param menu 菜单信息
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuListByUserId(SysMenu menu);
-
-    /**
-     * 根据角色ID查询权限
-     * 
-     * @param roleId 角色ID
-     * @return 权限列表
-     */
-    public List<String> selectMenuPermsByRoleId(Long roleId);
-
-    /**
-     * 根据用户ID查询权限
-     *
-     * @param userId 用户ID
-     * @return 权限列表
-     */
-    public List<String> selectMenuPermsByUserId(Long userId);
-
-    /**
-     * 根据用户ID查询菜单
-     *
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuTreeAll();
-
-    /**
-     * 根据用户ID查询菜单
-     *
-     * @param userId 用户ID
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuTreeByUserId(Long userId);
-
-    /**
-     * 根据角色ID查询菜单树信息
-     * 
-     * @param roleId 角色ID
-     * @param menuCheckStrictly 菜单树选择项是否关联显示
-     * @return 选中菜单列表
-     */
-    public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
-
-    /**
-     * 根据菜单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 父菜单ID
-     * @return 结果
-     */
-    public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+
+/**
+ * 菜单表 数据层
+ *
+ * @author acupuncture
+ */
+public interface SysMenuMapper
+{
+    /**
+     * 查询系统菜单列表
+     *
+     * @param menu 菜单信息
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuList(SysMenu menu);
+
+    /**
+     * 根据用户所有权限
+     *
+     * @return 权限列表
+     */
+    public List<String> selectMenuPerms();
+
+    /**
+     * 根据用户查询系统菜单列表
+     *
+     * @param menu 菜单信息
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuListByUserId(SysMenu menu);
+
+    /**
+     * 根据角色ID查询权限
+     * 
+     * @param roleId 角色ID
+     * @return 权限列表
+     */
+    public List<String> selectMenuPermsByRoleId(Long roleId);
+
+    /**
+     * 根据用户ID查询权限
+     *
+     * @param userId 用户ID
+     * @return 权限列表
+     */
+    public List<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 根据用户ID查询菜单
+     *
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuTreeAll();
+
+    /**
+     * 根据用户ID查询菜单
+     *
+     * @param userId 用户ID
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 根据角色ID查询菜单树信息
+     * 
+     * @param roleId 角色ID
+     * @param menuCheckStrictly 菜单树选择项是否关联显示
+     * @return 选中菜单列表
+     */
+    public List<Long> selectMenuListByRoleId(@Param("roleId") Long roleId, @Param("menuCheckStrictly") boolean menuCheckStrictly);
+
+    /**
+     * 根据菜单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 父菜单ID
+     * @return 结果
+     */
+    public SysMenu checkMenuNameUnique(@Param("menuName") String menuName, @Param("parentId") Long parentId);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysNoticeMapper.java
similarity index 87%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysNoticeMapper.java
index cc267ac0..01e128db 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysNoticeMapper.java
@@ -1,60 +1,60 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.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);
-
-    /**
-     * 批量删除公告信息
-     * 
-     * @param noticeIds 需要删除的公告ID
-     * @return 结果
-     */
-    public int deleteNoticeByIds(Long[] noticeIds);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysNotice;
+
+/**
+ * 通知公告表 数据层
+ * 
+ * @author acupuncture
+ */
+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);
+
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    public int deleteNoticeByIds(Long[] noticeIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysOperLogMapper.java
similarity index 86%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysOperLogMapper.java
index 3bf69bb8..f34aae36 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysOperLogMapper.java
@@ -1,48 +1,48 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysOperLog;
-
-/**
- * 操作日志 数据层
- * 
- * @author ruoyi
- */
-public interface SysOperLogMapper
-{
-    /**
-     * 新增操作日志
-     * 
-     * @param operLog 操作日志对象
-     */
-    public void insertOperlog(SysOperLog operLog);
-
-    /**
-     * 查询系统操作日志集合
-     * 
-     * @param operLog 操作日志对象
-     * @return 操作日志集合
-     */
-    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
-
-    /**
-     * 批量删除系统操作日志
-     * 
-     * @param operIds 需要删除的操作日志ID
-     * @return 结果
-     */
-    public int deleteOperLogByIds(Long[] operIds);
-
-    /**
-     * 查询操作日志详细
-     * 
-     * @param operId 操作ID
-     * @return 操作日志对象
-     */
-    public SysOperLog selectOperLogById(Long operId);
-
-    /**
-     * 清空操作日志
-     */
-    public void cleanOperLog();
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysOperLog;
+
+/**
+ * 操作日志 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysOperLogMapper
+{
+    /**
+     * 新增操作日志
+     * 
+     * @param operLog 操作日志对象
+     */
+    public void insertOperlog(SysOperLog operLog);
+
+    /**
+     * 查询系统操作日志集合
+     * 
+     * @param operLog 操作日志对象
+     * @return 操作日志集合
+     */
+    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
+
+    /**
+     * 批量删除系统操作日志
+     * 
+     * @param operIds 需要删除的操作日志ID
+     * @return 结果
+     */
+    public int deleteOperLogByIds(Long[] operIds);
+
+    /**
+     * 查询操作日志详细
+     * 
+     * @param operId 操作ID
+     * @return 操作日志对象
+     */
+    public SysOperLog selectOperLogById(Long operId);
+
+    /**
+     * 清空操作日志
+     */
+    public void cleanOperLog();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysPostMapper.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysPostMapper.java
index 8603d9ae..d88449ac 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysPostMapper.java
@@ -1,99 +1,99 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.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<Long> selectPostListByUserId(Long userId);
-
-    /**
-     * 查询用户所属岗位组
-     * 
-     * @param userName 用户名
-     * @return 结果
-     */
-    public List<SysPost> selectPostsByUserName(String userName);
-
-    /**
-     * 删除岗位信息
-     * 
-     * @param postId 岗位ID
-     * @return 结果
-     */
-    public int deletePostById(Long postId);
-
-    /**
-     * 批量删除岗位信息
-     * 
-     * @param postIds 需要删除的岗位ID
-     * @return 结果
-     */
-    public int deletePostByIds(Long[] postIds);
-
-    /**
-     * 修改岗位信息
-     * 
-     * @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);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysPost;
+
+/**
+ * 岗位信息 数据层
+ * 
+ * @author acupuncture
+ */
+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<Long> selectPostListByUserId(Long userId);
+
+    /**
+     * 查询用户所属岗位组
+     * 
+     * @param userName 用户名
+     * @return 结果
+     */
+    public List<SysPost> selectPostsByUserName(String userName);
+
+    /**
+     * 删除岗位信息
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    public int deletePostById(Long postId);
+
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     */
+    public int deletePostByIds(Long[] postIds);
+
+    /**
+     * 修改岗位信息
+     * 
+     * @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-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleDeptMapper.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleDeptMapper.java
index a4ad4de2..d7b74555 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleDeptMapper.java
@@ -1,44 +1,44 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.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);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysRoleDept;
+
+/**
+ * 角色与部门关联表 数据层
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMapper.java
similarity index 91%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMapper.java
index 58ede18e..d169baa0 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMapper.java
@@ -1,107 +1,107 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.entity.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<Long> 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);
-
-    /**
-     * 批量删除角色信息
-     * 
-     * @param roleIds 需要删除的角色ID
-     * @return 结果
-     */
-    public int deleteRoleByIds(Long[] roleIds);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.entity.SysRole;
+
+/**
+ * 角色表 数据层
+ * 
+ * @author acupuncture
+ */
+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<Long> 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);
+
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    public int deleteRoleByIds(Long[] roleIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMenuMapper.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMenuMapper.java
index 23391557..167c55a5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysRoleMenuMapper.java
@@ -1,44 +1,44 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.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 ids 需要删除的数据ID
-     * @return 结果
-     */
-    public int deleteRoleMenu(Long[] ids);
-
-    /**
-     * 批量新增角色菜单信息
-     * 
-     * @param roleMenuList 角色菜单列表
-     * @return 结果
-     */
-    public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysRoleMenu;
+
+/**
+ * 角色与菜单关联表 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysRoleMenuMapper
+{
+    /**
+     * 查询菜单使用数量
+     * 
+     * @param menuId 菜单ID
+     * @return 结果
+     */
+    public int checkMenuExistRole(Long menuId);
+
+    /**
+     * 通过角色ID删除角色和菜单关联
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    public int deleteRoleMenuByRoleId(Long roleId);
+
+    /**
+     * 批量删除角色菜单关联信息
+     * 
+     * @param ids 需要删除的数据ID
+     * @return 结果
+     */
+    public int deleteRoleMenu(Long[] ids);
+
+    /**
+     * 批量新增角色菜单信息
+     * 
+     * @param roleMenuList 角色菜单列表
+     * @return 结果
+     */
+    public int batchRoleMenu(List<SysRoleMenu> roleMenuList);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserMapper.java
similarity index 92%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserMapper.java
index c86acea4..064bfb77 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserMapper.java
@@ -1,127 +1,127 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.common.core.domain.entity.SysUser;
-
-/**
- * 用户表 数据层
- * 
- * @author ruoyi
- */
-public interface SysUserMapper
-{
-    /**
-     * 根据条件分页查询用户列表
-     * 
-     * @param sysUser 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectUserList(SysUser sysUser);
-
-    /**
-     * 根据条件分页查询已配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectAllocatedList(SysUser user);
-
-    /**
-     * 根据条件分页查询未分配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectUnallocatedList(SysUser user);
-
-    /**
-     * 通过用户名查询用户
-     * 
-     * @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 userIds 需要删除的用户ID
-     * @return 结果
-     */
-    public int deleteUserByIds(Long[] userIds);
-
-    /**
-     * 校验用户名称是否唯一
-     * 
-     * @param userName 用户名称
-     * @return 结果
-     */
-    public SysUser checkUserNameUnique(String userName);
-
-    /**
-     * 校验手机号码是否唯一
-     *
-     * @param phonenumber 手机号码
-     * @return 结果
-     */
-    public SysUser checkPhoneUnique(String phonenumber);
-
-    /**
-     * 校验email是否唯一
-     *
-     * @param email 用户邮箱
-     * @return 结果
-     */
-    public SysUser checkEmailUnique(String email);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.acupuncture.common.core.domain.entity.SysUser;
+
+/**
+ * 用户表 数据层
+ * 
+ * @author acupuncture
+ */
+public interface SysUserMapper
+{
+    /**
+     * 根据条件分页查询用户列表
+     * 
+     * @param sysUser 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectUserList(SysUser sysUser);
+
+    /**
+     * 根据条件分页查询已配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectAllocatedList(SysUser user);
+
+    /**
+     * 根据条件分页查询未分配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectUnallocatedList(SysUser user);
+
+    /**
+     * 通过用户名查询用户
+     * 
+     * @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 userIds 需要删除的用户ID
+     * @return 结果
+     */
+    public int deleteUserByIds(Long[] userIds);
+
+    /**
+     * 校验用户名称是否唯一
+     * 
+     * @param userName 用户名称
+     * @return 结果
+     */
+    public SysUser checkUserNameUnique(String userName);
+
+    /**
+     * 校验手机号码是否唯一
+     *
+     * @param phonenumber 手机号码
+     * @return 结果
+     */
+    public SysUser checkPhoneUnique(String phonenumber);
+
+    /**
+     * 校验email是否唯一
+     *
+     * @param email 用户邮箱
+     * @return 结果
+     */
+    public SysUser checkEmailUnique(String email);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserPostMapper.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserPostMapper.java
index 81d6e719..fcbe7b75 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserPostMapper.java
@@ -1,44 +1,44 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import com.ruoyi.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);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysUserPost;
+
+/**
+ * 用户与岗位关联表 数据层
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserRoleMapper.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserRoleMapper.java
index ad3fe62c..4bbbb5f9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/mapper/SysUserRoleMapper.java
@@ -1,62 +1,62 @@
-package com.ruoyi.system.mapper;
-
-import java.util.List;
-import org.apache.ibatis.annotations.Param;
-import com.ruoyi.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);
-}
+package com.acupuncture.system.mapper;
+
+import java.util.List;
+import org.apache.ibatis.annotations.Param;
+import com.acupuncture.system.domain.SysUserRole;
+
+/**
+ * 用户与角色关联表 数据层
+ * 
+ * @author acupuncture
+ */
+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-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysConfigService.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysConfigService.java
index 20961378..ea650deb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysConfigService.java
@@ -1,89 +1,89 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysConfig;
-
-/**
- * 参数配置 服务层
- * 
- * @author ruoyi
- */
-public interface ISysConfigService
-{
-    /**
-     * 查询参数配置信息
-     * 
-     * @param configId 参数配置ID
-     * @return 参数配置信息
-     */
-    public SysConfig selectConfigById(Long configId);
-
-    /**
-     * 根据键名查询参数配置信息
-     * 
-     * @param configKey 参数键名
-     * @return 参数键值
-     */
-    public String selectConfigByKey(String configKey);
-
-    /**
-     * 获取验证码开关
-     * 
-     * @return true开启,false关闭
-     */
-    public boolean selectCaptchaEnabled();
-
-    /**
-     * 查询参数配置列表
-     * 
-     * @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 configIds 需要删除的参数ID
-     */
-    public void deleteConfigByIds(Long[] configIds);
-
-    /**
-     * 加载参数缓存数据
-     */
-    public void loadingConfigCache();
-
-    /**
-     * 清空参数缓存数据
-     */
-    public void clearConfigCache();
-
-    /**
-     * 重置参数缓存数据
-     */
-    public void resetConfigCache();
-
-    /**
-     * 校验参数键名是否唯一
-     * 
-     * @param config 参数信息
-     * @return 结果
-     */
-    public boolean checkConfigKeyUnique(SysConfig config);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysConfig;
+
+/**
+ * 参数配置 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysConfigService
+{
+    /**
+     * 查询参数配置信息
+     * 
+     * @param configId 参数配置ID
+     * @return 参数配置信息
+     */
+    public SysConfig selectConfigById(Long configId);
+
+    /**
+     * 根据键名查询参数配置信息
+     * 
+     * @param configKey 参数键名
+     * @return 参数键值
+     */
+    public String selectConfigByKey(String configKey);
+
+    /**
+     * 获取验证码开关
+     * 
+     * @return true开启,false关闭
+     */
+    public boolean selectCaptchaEnabled();
+
+    /**
+     * 查询参数配置列表
+     * 
+     * @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 configIds 需要删除的参数ID
+     */
+    public void deleteConfigByIds(Long[] configIds);
+
+    /**
+     * 加载参数缓存数据
+     */
+    public void loadingConfigCache();
+
+    /**
+     * 清空参数缓存数据
+     */
+    public void clearConfigCache();
+
+    /**
+     * 重置参数缓存数据
+     */
+    public void resetConfigCache();
+
+    /**
+     * 校验参数键名是否唯一
+     * 
+     * @param config 参数信息
+     * @return 结果
+     */
+    public boolean checkConfigKeyUnique(SysConfig config);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDeptService.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDeptService.java
index 302d7a1f..a850397d 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDeptService.java
@@ -1,124 +1,124 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.TreeSelect;
-import com.ruoyi.common.core.domain.entity.SysDept;
-
-/**
- * 部门管理 服务层
- * 
- * @author ruoyi
- */
-public interface ISysDeptService
-{
-    /**
-     * 查询部门管理数据
-     * 
-     * @param dept 部门信息
-     * @return 部门信息集合
-     */
-    public List<SysDept> selectDeptList(SysDept dept);
-
-    /**
-     * 查询部门树结构信息
-     * 
-     * @param dept 部门信息
-     * @return 部门树信息集合
-     */
-    public List<TreeSelect> selectDeptTreeList(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<Long> selectDeptListByRoleId(Long roleId);
-
-    /**
-     * 根据部门ID查询信息
-     * 
-     * @param deptId 部门ID
-     * @return 部门信息
-     */
-    public SysDept selectDeptById(Long deptId);
-
-    /**
-     * 根据ID查询所有子部门(正常状态)
-     * 
-     * @param deptId 部门ID
-     * @return 子部门数
-     */
-    public int selectNormalChildrenDeptById(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 boolean checkDeptNameUnique(SysDept dept);
-
-    /**
-     * 校验部门是否有数据权限
-     * 
-     * @param deptId 部门id
-     */
-    public void checkDeptDataScope(Long deptId);
-
-    /**
-     * 新增保存部门信息
-     * 
-     * @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);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.TreeSelect;
+import com.acupuncture.common.core.domain.entity.SysDept;
+
+/**
+ * 部门管理 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysDeptService
+{
+    /**
+     * 查询部门管理数据
+     * 
+     * @param dept 部门信息
+     * @return 部门信息集合
+     */
+    public List<SysDept> selectDeptList(SysDept dept);
+
+    /**
+     * 查询部门树结构信息
+     * 
+     * @param dept 部门信息
+     * @return 部门树信息集合
+     */
+    public List<TreeSelect> selectDeptTreeList(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<Long> selectDeptListByRoleId(Long roleId);
+
+    /**
+     * 根据部门ID查询信息
+     * 
+     * @param deptId 部门ID
+     * @return 部门信息
+     */
+    public SysDept selectDeptById(Long deptId);
+
+    /**
+     * 根据ID查询所有子部门(正常状态)
+     * 
+     * @param deptId 部门ID
+     * @return 子部门数
+     */
+    public int selectNormalChildrenDeptById(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 boolean checkDeptNameUnique(SysDept dept);
+
+    /**
+     * 校验部门是否有数据权限
+     * 
+     * @param deptId 部门id
+     */
+    public void checkDeptDataScope(Long deptId);
+
+    /**
+     * 新增保存部门信息
+     * 
+     * @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-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictDataService.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictDataService.java
index 9a5cf190..5f4e988f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictDataService.java
@@ -1,60 +1,60 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-
-/**
- * 字典 业务层
- * 
- * @author ruoyi
- */
-public interface ISysDictDataService
-{
-    /**
-     * 根据条件分页查询字典数据
-     * 
-     * @param dictData 字典数据信息
-     * @return 字典数据集合信息
-     */
-    public List<SysDictData> selectDictDataList(SysDictData dictData);
-
-    /**
-     * 根据字典类型和字典键值查询字典数据信息
-     * 
-     * @param dictType 字典类型
-     * @param dictValue 字典键值
-     * @return 字典标签
-     */
-    public String selectDictLabel(String dictType, String dictValue);
-
-    /**
-     * 根据字典数据ID查询信息
-     * 
-     * @param dictCode 字典数据ID
-     * @return 字典数据
-     */
-    public SysDictData selectDictDataById(Long dictCode);
-
-    /**
-     * 批量删除字典数据信息
-     * 
-     * @param dictCodes 需要删除的字典数据ID
-     */
-    public void deleteDictDataByIds(Long[] dictCodes);
-
-    /**
-     * 新增保存字典数据信息
-     * 
-     * @param dictData 字典数据信息
-     * @return 结果
-     */
-    public int insertDictData(SysDictData dictData);
-
-    /**
-     * 修改保存字典数据信息
-     * 
-     * @param dictData 字典数据信息
-     * @return 结果
-     */
-    public int updateDictData(SysDictData dictData);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+
+/**
+ * 字典 业务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysDictDataService
+{
+    /**
+     * 根据条件分页查询字典数据
+     * 
+     * @param dictData 字典数据信息
+     * @return 字典数据集合信息
+     */
+    public List<SysDictData> selectDictDataList(SysDictData dictData);
+
+    /**
+     * 根据字典类型和字典键值查询字典数据信息
+     * 
+     * @param dictType 字典类型
+     * @param dictValue 字典键值
+     * @return 字典标签
+     */
+    public String selectDictLabel(String dictType, String dictValue);
+
+    /**
+     * 根据字典数据ID查询信息
+     * 
+     * @param dictCode 字典数据ID
+     * @return 字典数据
+     */
+    public SysDictData selectDictDataById(Long dictCode);
+
+    /**
+     * 批量删除字典数据信息
+     * 
+     * @param dictCodes 需要删除的字典数据ID
+     */
+    public void deleteDictDataByIds(Long[] dictCodes);
+
+    /**
+     * 新增保存字典数据信息
+     * 
+     * @param dictData 字典数据信息
+     * @return 结果
+     */
+    public int insertDictData(SysDictData dictData);
+
+    /**
+     * 修改保存字典数据信息
+     * 
+     * @param dictData 字典数据信息
+     * @return 结果
+     */
+    public int updateDictData(SysDictData dictData);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictTypeService.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictTypeService.java
index f01a3584..277b2878 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysDictTypeService.java
@@ -1,98 +1,98 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.domain.entity.SysDictType;
-
-/**
- * 字典 业务层
- * 
- * @author ruoyi
- */
-public interface ISysDictTypeService
-{
-    /**
-     * 根据条件分页查询字典类型
-     * 
-     * @param dictType 字典类型信息
-     * @return 字典类型集合信息
-     */
-    public List<SysDictType> selectDictTypeList(SysDictType dictType);
-
-    /**
-     * 根据所有字典类型
-     * 
-     * @return 字典类型集合信息
-     */
-    public List<SysDictType> selectDictTypeAll();
-
-    /**
-     * 根据字典类型查询字典数据
-     * 
-     * @param dictType 字典类型
-     * @return 字典数据集合信息
-     */
-    public List<SysDictData> selectDictDataByType(String dictType);
-
-    /**
-     * 根据字典类型ID查询信息
-     * 
-     * @param dictId 字典类型ID
-     * @return 字典类型
-     */
-    public SysDictType selectDictTypeById(Long dictId);
-
-    /**
-     * 根据字典类型查询信息
-     * 
-     * @param dictType 字典类型
-     * @return 字典类型
-     */
-    public SysDictType selectDictTypeByType(String dictType);
-
-    /**
-     * 批量删除字典信息
-     * 
-     * @param dictIds 需要删除的字典ID
-     */
-    public void deleteDictTypeByIds(Long[] dictIds);
-
-    /**
-     * 加载字典缓存数据
-     */
-    public void loadingDictCache();
-
-    /**
-     * 清空字典缓存数据
-     */
-    public void clearDictCache();
-
-    /**
-     * 重置字典缓存数据
-     */
-    public void resetDictCache();
-
-    /**
-     * 新增保存字典类型信息
-     * 
-     * @param dictType 字典类型信息
-     * @return 结果
-     */
-    public int insertDictType(SysDictType dictType);
-
-    /**
-     * 修改保存字典类型信息
-     * 
-     * @param dictType 字典类型信息
-     * @return 结果
-     */
-    public int updateDictType(SysDictType dictType);
-
-    /**
-     * 校验字典类型称是否唯一
-     * 
-     * @param dictType 字典类型
-     * @return 结果
-     */
-    public boolean checkDictTypeUnique(SysDictType dictType);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+import com.acupuncture.common.core.domain.entity.SysDictType;
+
+/**
+ * 字典 业务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysDictTypeService
+{
+    /**
+     * 根据条件分页查询字典类型
+     * 
+     * @param dictType 字典类型信息
+     * @return 字典类型集合信息
+     */
+    public List<SysDictType> selectDictTypeList(SysDictType dictType);
+
+    /**
+     * 根据所有字典类型
+     * 
+     * @return 字典类型集合信息
+     */
+    public List<SysDictType> selectDictTypeAll();
+
+    /**
+     * 根据字典类型查询字典数据
+     * 
+     * @param dictType 字典类型
+     * @return 字典数据集合信息
+     */
+    public List<SysDictData> selectDictDataByType(String dictType);
+
+    /**
+     * 根据字典类型ID查询信息
+     * 
+     * @param dictId 字典类型ID
+     * @return 字典类型
+     */
+    public SysDictType selectDictTypeById(Long dictId);
+
+    /**
+     * 根据字典类型查询信息
+     * 
+     * @param dictType 字典类型
+     * @return 字典类型
+     */
+    public SysDictType selectDictTypeByType(String dictType);
+
+    /**
+     * 批量删除字典信息
+     * 
+     * @param dictIds 需要删除的字典ID
+     */
+    public void deleteDictTypeByIds(Long[] dictIds);
+
+    /**
+     * 加载字典缓存数据
+     */
+    public void loadingDictCache();
+
+    /**
+     * 清空字典缓存数据
+     */
+    public void clearDictCache();
+
+    /**
+     * 重置字典缓存数据
+     */
+    public void resetDictCache();
+
+    /**
+     * 新增保存字典类型信息
+     * 
+     * @param dictType 字典类型信息
+     * @return 结果
+     */
+    public int insertDictType(SysDictType dictType);
+
+    /**
+     * 修改保存字典类型信息
+     * 
+     * @param dictType 字典类型信息
+     * @return 结果
+     */
+    public int updateDictType(SysDictType dictType);
+
+    /**
+     * 校验字典类型称是否唯一
+     * 
+     * @param dictType 字典类型
+     * @return 结果
+     */
+    public boolean checkDictTypeUnique(SysDictType dictType);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysLogininforService.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysLogininforService.java
index 0a832083..11c8dca2 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysLogininforService.java
@@ -1,40 +1,40 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysLogininfor;
-
-/**
- * 系统访问日志情况信息 服务层
- * 
- * @author ruoyi
- */
-public interface ISysLogininforService
-{
-    /**
-     * 新增系统登录日志
-     * 
-     * @param logininfor 访问日志对象
-     */
-    public void insertLogininfor(SysLogininfor logininfor);
-
-    /**
-     * 查询系统登录日志集合
-     * 
-     * @param logininfor 访问日志对象
-     * @return 登录记录集合
-     */
-    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
-
-    /**
-     * 批量删除系统登录日志
-     * 
-     * @param infoIds 需要删除的登录日志ID
-     * @return 结果
-     */
-    public int deleteLogininforByIds(Long[] infoIds);
-
-    /**
-     * 清空系统登录日志
-     */
-    public void cleanLogininfor();
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysLogininfor;
+
+/**
+ * 系统访问日志情况信息 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysLogininforService
+{
+    /**
+     * 新增系统登录日志
+     * 
+     * @param logininfor 访问日志对象
+     */
+    public void insertLogininfor(SysLogininfor logininfor);
+
+    /**
+     * 查询系统登录日志集合
+     * 
+     * @param logininfor 访问日志对象
+     * @return 登录记录集合
+     */
+    public List<SysLogininfor> selectLogininforList(SysLogininfor logininfor);
+
+    /**
+     * 批量删除系统登录日志
+     * 
+     * @param infoIds 需要删除的登录日志ID
+     * @return 结果
+     */
+    public int deleteLogininforByIds(Long[] infoIds);
+
+    /**
+     * 清空系统登录日志
+     */
+    public void cleanLogininfor();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysMenuService.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysMenuService.java
index 134b9ebd..cc933773 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysMenuService.java
@@ -1,144 +1,144 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import java.util.Set;
-import com.ruoyi.common.core.domain.TreeSelect;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.system.domain.vo.RouterVo;
-
-/**
- * 菜单 业务层
- * 
- * @author ruoyi
- */
-public interface ISysMenuService
-{
-    /**
-     * 根据用户查询系统菜单列表
-     * 
-     * @param userId 用户ID
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuList(Long userId);
-
-    /**
-     * 根据用户查询系统菜单列表
-     * 
-     * @param menu 菜单信息
-     * @param userId 用户ID
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuList(SysMenu menu, Long userId);
-
-    /**
-     * 根据用户ID查询权限
-     * 
-     * @param userId 用户ID
-     * @return 权限列表
-     */
-    public Set<String> selectMenuPermsByUserId(Long userId);
-
-    /**
-     * 根据角色ID查询权限
-     * 
-     * @param roleId 角色ID
-     * @return 权限列表
-     */
-    public Set<String> selectMenuPermsByRoleId(Long roleId);
-
-    /**
-     * 根据用户ID查询菜单树信息
-     * 
-     * @param userId 用户ID
-     * @return 菜单列表
-     */
-    public List<SysMenu> selectMenuTreeByUserId(Long userId);
-
-    /**
-     * 根据角色ID查询菜单树信息
-     * 
-     * @param roleId 角色ID
-     * @return 选中菜单列表
-     */
-    public List<Long> 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 boolean checkMenuNameUnique(SysMenu menu);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import java.util.Set;
+import com.acupuncture.common.core.domain.TreeSelect;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+import com.acupuncture.system.domain.vo.RouterVo;
+
+/**
+ * 菜单 业务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysMenuService
+{
+    /**
+     * 根据用户查询系统菜单列表
+     * 
+     * @param userId 用户ID
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuList(Long userId);
+
+    /**
+     * 根据用户查询系统菜单列表
+     * 
+     * @param menu 菜单信息
+     * @param userId 用户ID
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuList(SysMenu menu, Long userId);
+
+    /**
+     * 根据用户ID查询权限
+     * 
+     * @param userId 用户ID
+     * @return 权限列表
+     */
+    public Set<String> selectMenuPermsByUserId(Long userId);
+
+    /**
+     * 根据角色ID查询权限
+     * 
+     * @param roleId 角色ID
+     * @return 权限列表
+     */
+    public Set<String> selectMenuPermsByRoleId(Long roleId);
+
+    /**
+     * 根据用户ID查询菜单树信息
+     * 
+     * @param userId 用户ID
+     * @return 菜单列表
+     */
+    public List<SysMenu> selectMenuTreeByUserId(Long userId);
+
+    /**
+     * 根据角色ID查询菜单树信息
+     * 
+     * @param roleId 角色ID
+     * @return 选中菜单列表
+     */
+    public List<Long> 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 boolean checkMenuNameUnique(SysMenu menu);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysNoticeService.java
similarity index 87%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysNoticeService.java
index fb1e420f..98f04287 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysNoticeService.java
@@ -1,60 +1,60 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.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);
-    
-    /**
-     * 批量删除公告信息
-     * 
-     * @param noticeIds 需要删除的公告ID
-     * @return 结果
-     */
-    public int deleteNoticeByIds(Long[] noticeIds);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysNotice;
+
+/**
+ * 公告 服务层
+ * 
+ * @author acupuncture
+ */
+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);
+    
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    public int deleteNoticeByIds(Long[] noticeIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysOperLogService.java
similarity index 86%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysOperLogService.java
index 241f121a..182f5c61 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysOperLogService.java
@@ -1,48 +1,48 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.system.domain.SysOperLog;
-
-/**
- * 操作日志 服务层
- * 
- * @author ruoyi
- */
-public interface ISysOperLogService
-{
-    /**
-     * 新增操作日志
-     * 
-     * @param operLog 操作日志对象
-     */
-    public void insertOperlog(SysOperLog operLog);
-
-    /**
-     * 查询系统操作日志集合
-     * 
-     * @param operLog 操作日志对象
-     * @return 操作日志集合
-     */
-    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
-
-    /**
-     * 批量删除系统操作日志
-     * 
-     * @param operIds 需要删除的操作日志ID
-     * @return 结果
-     */
-    public int deleteOperLogByIds(Long[] operIds);
-
-    /**
-     * 查询操作日志详细
-     * 
-     * @param operId 操作ID
-     * @return 操作日志对象
-     */
-    public SysOperLog selectOperLogById(Long operId);
-
-    /**
-     * 清空操作日志
-     */
-    public void cleanOperLog();
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysOperLog;
+
+/**
+ * 操作日志 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysOperLogService
+{
+    /**
+     * 新增操作日志
+     * 
+     * @param operLog 操作日志对象
+     */
+    public void insertOperlog(SysOperLog operLog);
+
+    /**
+     * 查询系统操作日志集合
+     * 
+     * @param operLog 操作日志对象
+     * @return 操作日志集合
+     */
+    public List<SysOperLog> selectOperLogList(SysOperLog operLog);
+
+    /**
+     * 批量删除系统操作日志
+     * 
+     * @param operIds 需要删除的操作日志ID
+     * @return 结果
+     */
+    public int deleteOperLogByIds(Long[] operIds);
+
+    /**
+     * 查询操作日志详细
+     * 
+     * @param operId 操作ID
+     * @return 操作日志对象
+     */
+    public SysOperLog selectOperLogById(Long operId);
+
+    /**
+     * 清空操作日志
+     */
+    public void cleanOperLog();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysPostService.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysPostService.java
index 590634b9..710bf8da 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysPostService.java
@@ -1,99 +1,99 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.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<Long> selectPostListByUserId(Long userId);
-
-    /**
-     * 校验岗位名称
-     * 
-     * @param post 岗位信息
-     * @return 结果
-     */
-    public boolean checkPostNameUnique(SysPost post);
-
-    /**
-     * 校验岗位编码
-     * 
-     * @param post 岗位信息
-     * @return 结果
-     */
-    public boolean checkPostCodeUnique(SysPost post);
-
-    /**
-     * 通过岗位ID查询岗位使用数量
-     * 
-     * @param postId 岗位ID
-     * @return 结果
-     */
-    public int countUserPostById(Long postId);
-
-    /**
-     * 删除岗位信息
-     * 
-     * @param postId 岗位ID
-     * @return 结果
-     */
-    public int deletePostById(Long postId);
-
-    /**
-     * 批量删除岗位信息
-     * 
-     * @param postIds 需要删除的岗位ID
-     * @return 结果
-     */
-    public int deletePostByIds(Long[] postIds);
-
-    /**
-     * 新增保存岗位信息
-     * 
-     * @param post 岗位信息
-     * @return 结果
-     */
-    public int insertPost(SysPost post);
-
-    /**
-     * 修改保存岗位信息
-     * 
-     * @param post 岗位信息
-     * @return 结果
-     */
-    public int updatePost(SysPost post);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.system.domain.SysPost;
+
+/**
+ * 岗位信息 服务层
+ * 
+ * @author acupuncture
+ */
+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<Long> selectPostListByUserId(Long userId);
+
+    /**
+     * 校验岗位名称
+     * 
+     * @param post 岗位信息
+     * @return 结果
+     */
+    public boolean checkPostNameUnique(SysPost post);
+
+    /**
+     * 校验岗位编码
+     * 
+     * @param post 岗位信息
+     * @return 结果
+     */
+    public boolean checkPostCodeUnique(SysPost post);
+
+    /**
+     * 通过岗位ID查询岗位使用数量
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    public int countUserPostById(Long postId);
+
+    /**
+     * 删除岗位信息
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    public int deletePostById(Long postId);
+
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     */
+    public int deletePostByIds(Long[] postIds);
+
+    /**
+     * 新增保存岗位信息
+     * 
+     * @param post 岗位信息
+     * @return 结果
+     */
+    public int insertPost(SysPost post);
+
+    /**
+     * 修改保存岗位信息
+     * 
+     * @param post 岗位信息
+     * @return 结果
+     */
+    public int updatePost(SysPost post);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysRoleService.java
similarity index 91%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysRoleService.java
index 5df679ae..2403d017 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysRoleService.java
@@ -1,173 +1,173 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import java.util.Set;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.system.domain.SysUserRole;
-
-/**
- * 角色业务层
- * 
- * @author ruoyi
- */
-public interface ISysRoleService
-{
-    /**
-     * 根据条件分页查询角色数据
-     * 
-     * @param role 角色信息
-     * @return 角色数据集合信息
-     */
-    public List<SysRole> selectRoleList(SysRole role);
-
-    /**
-     * 根据用户ID查询角色列表
-     * 
-     * @param userId 用户ID
-     * @return 角色列表
-     */
-    public List<SysRole> selectRolesByUserId(Long userId);
-
-    /**
-     * 根据用户ID查询角色权限
-     * 
-     * @param userId 用户ID
-     * @return 权限列表
-     */
-    public Set<String> selectRolePermissionByUserId(Long userId);
-
-    /**
-     * 查询所有角色
-     * 
-     * @return 角色列表
-     */
-    public List<SysRole> selectRoleAll();
-
-    /**
-     * 根据用户ID获取角色选择框列表
-     * 
-     * @param userId 用户ID
-     * @return 选中角色ID列表
-     */
-    public List<Long> selectRoleListByUserId(Long userId);
-
-    /**
-     * 通过角色ID查询角色
-     * 
-     * @param roleId 角色ID
-     * @return 角色对象信息
-     */
-    public SysRole selectRoleById(Long roleId);
-
-    /**
-     * 校验角色名称是否唯一
-     * 
-     * @param role 角色信息
-     * @return 结果
-     */
-    public boolean checkRoleNameUnique(SysRole role);
-
-    /**
-     * 校验角色权限是否唯一
-     * 
-     * @param role 角色信息
-     * @return 结果
-     */
-    public boolean checkRoleKeyUnique(SysRole role);
-
-    /**
-     * 校验角色是否允许操作
-     * 
-     * @param role 角色信息
-     */
-    public void checkRoleAllowed(SysRole role);
-
-    /**
-     * 校验角色是否有数据权限
-     * 
-     * @param roleIds 角色id
-     */
-    public void checkRoleDataScope(Long... roleIds);
-
-    /**
-     * 通过角色ID查询角色使用数量
-     * 
-     * @param roleId 角色ID
-     * @return 结果
-     */
-    public int countUserRoleByRoleId(Long roleId);
-
-    /**
-     * 新增保存角色信息
-     * 
-     * @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);
-
-    /**
-     * 批量删除角色信息
-     * 
-     * @param roleIds 需要删除的角色ID
-     * @return 结果
-     */
-    public int deleteRoleByIds(Long[] roleIds);
-
-    /**
-     * 取消授权用户角色
-     * 
-     * @param userRole 用户和角色关联信息
-     * @return 结果
-     */
-    public int deleteAuthUser(SysUserRole userRole);
-
-    /**
-     * 批量取消授权用户角色
-     * 
-     * @param roleId 角色ID
-     * @param userIds 需要取消授权的用户数据ID
-     * @return 结果
-     */
-    public int deleteAuthUsers(Long roleId, Long[] userIds);
-
-    /**
-     * 批量选择授权用户角色
-     * 
-     * @param roleId 角色ID
-     * @param userIds 需要删除的用户数据ID
-     * @return 结果
-     */
-    public int insertAuthUsers(Long roleId, Long[] userIds);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import java.util.Set;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.system.domain.SysUserRole;
+
+/**
+ * 角色业务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysRoleService
+{
+    /**
+     * 根据条件分页查询角色数据
+     * 
+     * @param role 角色信息
+     * @return 角色数据集合信息
+     */
+    public List<SysRole> selectRoleList(SysRole role);
+
+    /**
+     * 根据用户ID查询角色列表
+     * 
+     * @param userId 用户ID
+     * @return 角色列表
+     */
+    public List<SysRole> selectRolesByUserId(Long userId);
+
+    /**
+     * 根据用户ID查询角色权限
+     * 
+     * @param userId 用户ID
+     * @return 权限列表
+     */
+    public Set<String> selectRolePermissionByUserId(Long userId);
+
+    /**
+     * 查询所有角色
+     * 
+     * @return 角色列表
+     */
+    public List<SysRole> selectRoleAll();
+
+    /**
+     * 根据用户ID获取角色选择框列表
+     * 
+     * @param userId 用户ID
+     * @return 选中角色ID列表
+     */
+    public List<Long> selectRoleListByUserId(Long userId);
+
+    /**
+     * 通过角色ID查询角色
+     * 
+     * @param roleId 角色ID
+     * @return 角色对象信息
+     */
+    public SysRole selectRoleById(Long roleId);
+
+    /**
+     * 校验角色名称是否唯一
+     * 
+     * @param role 角色信息
+     * @return 结果
+     */
+    public boolean checkRoleNameUnique(SysRole role);
+
+    /**
+     * 校验角色权限是否唯一
+     * 
+     * @param role 角色信息
+     * @return 结果
+     */
+    public boolean checkRoleKeyUnique(SysRole role);
+
+    /**
+     * 校验角色是否允许操作
+     * 
+     * @param role 角色信息
+     */
+    public void checkRoleAllowed(SysRole role);
+
+    /**
+     * 校验角色是否有数据权限
+     * 
+     * @param roleIds 角色id
+     */
+    public void checkRoleDataScope(Long... roleIds);
+
+    /**
+     * 通过角色ID查询角色使用数量
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    public int countUserRoleByRoleId(Long roleId);
+
+    /**
+     * 新增保存角色信息
+     * 
+     * @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);
+
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    public int deleteRoleByIds(Long[] roleIds);
+
+    /**
+     * 取消授权用户角色
+     * 
+     * @param userRole 用户和角色关联信息
+     * @return 结果
+     */
+    public int deleteAuthUser(SysUserRole userRole);
+
+    /**
+     * 批量取消授权用户角色
+     * 
+     * @param roleId 角色ID
+     * @param userIds 需要取消授权的用户数据ID
+     * @return 结果
+     */
+    public int deleteAuthUsers(Long roleId, Long[] userIds);
+
+    /**
+     * 批量选择授权用户角色
+     * 
+     * @param roleId 角色ID
+     * @param userIds 需要删除的用户数据ID
+     * @return 结果
+     */
+    public int insertAuthUsers(Long roleId, Long[] userIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserOnlineService.java
similarity index 84%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserOnlineService.java
index 12095ff5..31396f07 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserOnlineService.java
@@ -1,48 +1,48 @@
-package com.ruoyi.system.service;
-
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.system.domain.SysUserOnline;
-
-/**
- * 在线用户 服务层
- * 
- * @author ruoyi
- */
-public interface ISysUserOnlineService
-{
-    /**
-     * 通过登录地址查询信息
-     * 
-     * @param ipaddr 登录地址
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user);
-
-    /**
-     * 通过用户名称查询信息
-     * 
-     * @param userName 用户名称
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user);
-
-    /**
-     * 通过登录地址/用户名称查询信息
-     * 
-     * @param ipaddr 登录地址
-     * @param userName 用户名称
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user);
-
-    /**
-     * 设置在线用户信息
-     * 
-     * @param user 用户信息
-     * @return 在线用户
-     */
-    public SysUserOnline loginUserToUserOnline(LoginUser user);
-}
+package com.acupuncture.system.service;
+
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.system.domain.SysUserOnline;
+
+/**
+ * 在线用户 服务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysUserOnlineService
+{
+    /**
+     * 通过登录地址查询信息
+     * 
+     * @param ipaddr 登录地址
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user);
+
+    /**
+     * 通过用户名称查询信息
+     * 
+     * @param userName 用户名称
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user);
+
+    /**
+     * 通过登录地址/用户名称查询信息
+     * 
+     * @param ipaddr 登录地址
+     * @param userName 用户名称
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user);
+
+    /**
+     * 设置在线用户信息
+     * 
+     * @param user 用户信息
+     * @return 在线用户
+     */
+    public SysUserOnline loginUserToUserOnline(LoginUser user);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserService.java
similarity index 93%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserService.java
index e438b577..ffa85491 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/ISysUserService.java
@@ -1,206 +1,206 @@
-package com.ruoyi.system.service;
-
-import java.util.List;
-import com.ruoyi.common.core.domain.entity.SysUser;
-
-/**
- * 用户 业务层
- * 
- * @author ruoyi
- */
-public interface ISysUserService
-{
-    /**
-     * 根据条件分页查询用户列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectUserList(SysUser user);
-
-    /**
-     * 根据条件分页查询已分配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectAllocatedList(SysUser user);
-
-    /**
-     * 根据条件分页查询未分配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    public List<SysUser> selectUnallocatedList(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 user 用户信息
-     * @return 结果
-     */
-    public boolean checkUserNameUnique(SysUser user);
-
-    /**
-     * 校验手机号码是否唯一
-     *
-     * @param user 用户信息
-     * @return 结果
-     */
-    public boolean checkPhoneUnique(SysUser user);
-
-    /**
-     * 校验email是否唯一
-     *
-     * @param user 用户信息
-     * @return 结果
-     */
-    public boolean checkEmailUnique(SysUser user);
-
-    /**
-     * 校验用户是否允许操作
-     * 
-     * @param user 用户信息
-     */
-    public void checkUserAllowed(SysUser user);
-
-    /**
-     * 校验用户是否有数据权限
-     * 
-     * @param userId 用户id
-     */
-    public void checkUserDataScope(Long userId);
-
-    /**
-     * 新增用户信息
-     * 
-     * @param user 用户信息
-     * @return 结果
-     */
-    public int insertUser(SysUser user);
-
-    /**
-     * 注册用户信息
-     * 
-     * @param user 用户信息
-     * @return 结果
-     */
-    public boolean registerUser(SysUser user);
-
-    /**
-     * 修改用户信息
-     * 
-     * @param user 用户信息
-     * @return 结果
-     */
-    public int updateUser(SysUser user);
-
-    /**
-     * 用户授权角色
-     * 
-     * @param userId 用户ID
-     * @param roleIds 角色组
-     */
-    public void insertUserAuth(Long userId, Long[] roleIds);
-
-    /**
-     * 修改用户状态
-     * 
-     * @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);
-
-    /**
-     * 批量删除用户信息
-     * 
-     * @param userIds 需要删除的用户ID
-     * @return 结果
-     */
-    public int deleteUserByIds(Long[] userIds);
-
-    /**
-     * 导入用户数据
-     * 
-     * @param userList 用户数据列表
-     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
-     * @param operName 操作用户
-     * @return 结果
-     */
-    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
-}
+package com.acupuncture.system.service;
+
+import java.util.List;
+import com.acupuncture.common.core.domain.entity.SysUser;
+
+/**
+ * 用户 业务层
+ * 
+ * @author acupuncture
+ */
+public interface ISysUserService
+{
+    /**
+     * 根据条件分页查询用户列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectUserList(SysUser user);
+
+    /**
+     * 根据条件分页查询已分配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectAllocatedList(SysUser user);
+
+    /**
+     * 根据条件分页查询未分配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    public List<SysUser> selectUnallocatedList(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 user 用户信息
+     * @return 结果
+     */
+    public boolean checkUserNameUnique(SysUser user);
+
+    /**
+     * 校验手机号码是否唯一
+     *
+     * @param user 用户信息
+     * @return 结果
+     */
+    public boolean checkPhoneUnique(SysUser user);
+
+    /**
+     * 校验email是否唯一
+     *
+     * @param user 用户信息
+     * @return 结果
+     */
+    public boolean checkEmailUnique(SysUser user);
+
+    /**
+     * 校验用户是否允许操作
+     * 
+     * @param user 用户信息
+     */
+    public void checkUserAllowed(SysUser user);
+
+    /**
+     * 校验用户是否有数据权限
+     * 
+     * @param userId 用户id
+     */
+    public void checkUserDataScope(Long userId);
+
+    /**
+     * 新增用户信息
+     * 
+     * @param user 用户信息
+     * @return 结果
+     */
+    public int insertUser(SysUser user);
+
+    /**
+     * 注册用户信息
+     * 
+     * @param user 用户信息
+     * @return 结果
+     */
+    public boolean registerUser(SysUser user);
+
+    /**
+     * 修改用户信息
+     * 
+     * @param user 用户信息
+     * @return 结果
+     */
+    public int updateUser(SysUser user);
+
+    /**
+     * 用户授权角色
+     * 
+     * @param userId 用户ID
+     * @param roleIds 角色组
+     */
+    public void insertUserAuth(Long userId, Long[] roleIds);
+
+    /**
+     * 修改用户状态
+     * 
+     * @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);
+
+    /**
+     * 批量删除用户信息
+     * 
+     * @param userIds 需要删除的用户ID
+     * @return 结果
+     */
+    public int deleteUserByIds(Long[] userIds);
+
+    /**
+     * 导入用户数据
+     * 
+     * @param userList 用户数据列表
+     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
+     * @param operName 操作用户
+     * @return 结果
+     */
+    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysConfigServiceImpl.java
similarity index 87%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysConfigServiceImpl.java
index 3615b88f..dd95eb21 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysConfigServiceImpl.java
@@ -1,232 +1,232 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.Collection;
-import java.util.List;
-import javax.annotation.PostConstruct;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.annotation.DataSource;
-import com.ruoyi.common.constant.CacheConstants;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.redis.RedisCache;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.enums.DataSourceType;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysConfig;
-import com.ruoyi.system.mapper.SysConfigMapper;
-import com.ruoyi.system.service.ISysConfigService;
-
-/**
- * 参数配置 服务层实现
- * 
- * @author ruoyi
- */
-@Service
-public class SysConfigServiceImpl implements ISysConfigService
-{
-    @Autowired
-    private SysConfigMapper configMapper;
-
-    @Autowired
-    private RedisCache redisCache;
-
-    /**
-     * 项目启动时,初始化参数到缓存
-     */
-    @PostConstruct
-    public void init()
-    {
-        loadingConfigCache();
-    }
-
-    /**
-     * 查询参数配置信息
-     * 
-     * @param configId 参数配置ID
-     * @return 参数配置信息
-     */
-    @Override
-    @DataSource(DataSourceType.MASTER)
-    public SysConfig selectConfigById(Long configId)
-    {
-        SysConfig config = new SysConfig();
-        config.setConfigId(configId);
-        return configMapper.selectConfig(config);
-    }
-
-    /**
-     * 根据键名查询参数配置信息
-     * 
-     * @param configKey 参数key
-     * @return 参数键值
-     */
-    @Override
-    public String selectConfigByKey(String configKey)
-    {
-        String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
-        if (StringUtils.isNotEmpty(configValue))
-        {
-            return configValue;
-        }
-        SysConfig config = new SysConfig();
-        config.setConfigKey(configKey);
-        SysConfig retConfig = configMapper.selectConfig(config);
-        if (StringUtils.isNotNull(retConfig))
-        {
-            redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
-            return retConfig.getConfigValue();
-        }
-        return StringUtils.EMPTY;
-    }
-
-    /**
-     * 获取验证码开关
-     * 
-     * @return true开启,false关闭
-     */
-    @Override
-    public boolean selectCaptchaEnabled()
-    {
-        String captchaEnabled = selectConfigByKey("sys.account.captchaEnabled");
-        if (StringUtils.isEmpty(captchaEnabled))
-        {
-            return true;
-        }
-        return Convert.toBool(captchaEnabled);
-    }
-
-    /**
-     * 查询参数配置列表
-     * 
-     * @param config 参数配置信息
-     * @return 参数配置集合
-     */
-    @Override
-    public List<SysConfig> selectConfigList(SysConfig config)
-    {
-        return configMapper.selectConfigList(config);
-    }
-
-    /**
-     * 新增参数配置
-     * 
-     * @param config 参数配置信息
-     * @return 结果
-     */
-    @Override
-    public int insertConfig(SysConfig config)
-    {
-        int row = configMapper.insertConfig(config);
-        if (row > 0)
-        {
-            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
-        }
-        return row;
-    }
-
-    /**
-     * 修改参数配置
-     * 
-     * @param config 参数配置信息
-     * @return 结果
-     */
-    @Override
-    public int updateConfig(SysConfig config)
-    {
-        SysConfig temp = configMapper.selectConfigById(config.getConfigId());
-        if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
-        {
-            redisCache.deleteObject(getCacheKey(temp.getConfigKey()));
-        }
-
-        int row = configMapper.updateConfig(config);
-        if (row > 0)
-        {
-            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
-        }
-        return row;
-    }
-
-    /**
-     * 批量删除参数信息
-     * 
-     * @param configIds 需要删除的参数ID
-     */
-    @Override
-    public void deleteConfigByIds(Long[] configIds)
-    {
-        for (Long configId : configIds)
-        {
-            SysConfig config = selectConfigById(configId);
-            if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
-            {
-                throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
-            }
-            configMapper.deleteConfigById(configId);
-            redisCache.deleteObject(getCacheKey(config.getConfigKey()));
-        }
-    }
-
-    /**
-     * 加载参数缓存数据
-     */
-    @Override
-    public void loadingConfigCache()
-    {
-        List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
-        for (SysConfig config : configsList)
-        {
-            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
-        }
-    }
-
-    /**
-     * 清空参数缓存数据
-     */
-    @Override
-    public void clearConfigCache()
-    {
-        Collection<String> keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*");
-        redisCache.deleteObject(keys);
-    }
-
-    /**
-     * 重置参数缓存数据
-     */
-    @Override
-    public void resetConfigCache()
-    {
-        clearConfigCache();
-        loadingConfigCache();
-    }
-
-    /**
-     * 校验参数键名是否唯一
-     * 
-     * @param config 参数配置信息
-     * @return 结果
-     */
-    @Override
-    public boolean 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;
-    }
-
-    /**
-     * 设置cache key
-     * 
-     * @param configKey 参数键
-     * @return 缓存键key
-     */
-    private String getCacheKey(String configKey)
-    {
-        return CacheConstants.SYS_CONFIG_KEY + configKey;
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.common.annotation.DataSource;
+import com.acupuncture.common.constant.CacheConstants;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.redis.RedisCache;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.enums.DataSourceType;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.SysConfig;
+import com.acupuncture.system.mapper.SysConfigMapper;
+import com.acupuncture.system.service.ISysConfigService;
+
+/**
+ * 参数配置 服务层实现
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysConfigServiceImpl implements ISysConfigService
+{
+    @Autowired
+    private SysConfigMapper configMapper;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    /**
+     * 项目启动时,初始化参数到缓存
+     */
+    @PostConstruct
+    public void init()
+    {
+        loadingConfigCache();
+    }
+
+    /**
+     * 查询参数配置信息
+     * 
+     * @param configId 参数配置ID
+     * @return 参数配置信息
+     */
+    @Override
+    @DataSource(DataSourceType.MASTER)
+    public SysConfig selectConfigById(Long configId)
+    {
+        SysConfig config = new SysConfig();
+        config.setConfigId(configId);
+        return configMapper.selectConfig(config);
+    }
+
+    /**
+     * 根据键名查询参数配置信息
+     * 
+     * @param configKey 参数key
+     * @return 参数键值
+     */
+    @Override
+    public String selectConfigByKey(String configKey)
+    {
+        String configValue = Convert.toStr(redisCache.getCacheObject(getCacheKey(configKey)));
+        if (StringUtils.isNotEmpty(configValue))
+        {
+            return configValue;
+        }
+        SysConfig config = new SysConfig();
+        config.setConfigKey(configKey);
+        SysConfig retConfig = configMapper.selectConfig(config);
+        if (StringUtils.isNotNull(retConfig))
+        {
+            redisCache.setCacheObject(getCacheKey(configKey), retConfig.getConfigValue());
+            return retConfig.getConfigValue();
+        }
+        return StringUtils.EMPTY;
+    }
+
+    /**
+     * 获取验证码开关
+     * 
+     * @return true开启,false关闭
+     */
+    @Override
+    public boolean selectCaptchaEnabled()
+    {
+        String captchaEnabled = selectConfigByKey("sys.account.captchaEnabled");
+        if (StringUtils.isEmpty(captchaEnabled))
+        {
+            return true;
+        }
+        return Convert.toBool(captchaEnabled);
+    }
+
+    /**
+     * 查询参数配置列表
+     * 
+     * @param config 参数配置信息
+     * @return 参数配置集合
+     */
+    @Override
+    public List<SysConfig> selectConfigList(SysConfig config)
+    {
+        return configMapper.selectConfigList(config);
+    }
+
+    /**
+     * 新增参数配置
+     * 
+     * @param config 参数配置信息
+     * @return 结果
+     */
+    @Override
+    public int insertConfig(SysConfig config)
+    {
+        int row = configMapper.insertConfig(config);
+        if (row > 0)
+        {
+            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
+        }
+        return row;
+    }
+
+    /**
+     * 修改参数配置
+     * 
+     * @param config 参数配置信息
+     * @return 结果
+     */
+    @Override
+    public int updateConfig(SysConfig config)
+    {
+        SysConfig temp = configMapper.selectConfigById(config.getConfigId());
+        if (!StringUtils.equals(temp.getConfigKey(), config.getConfigKey()))
+        {
+            redisCache.deleteObject(getCacheKey(temp.getConfigKey()));
+        }
+
+        int row = configMapper.updateConfig(config);
+        if (row > 0)
+        {
+            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
+        }
+        return row;
+    }
+
+    /**
+     * 批量删除参数信息
+     * 
+     * @param configIds 需要删除的参数ID
+     */
+    @Override
+    public void deleteConfigByIds(Long[] configIds)
+    {
+        for (Long configId : configIds)
+        {
+            SysConfig config = selectConfigById(configId);
+            if (StringUtils.equals(UserConstants.YES, config.getConfigType()))
+            {
+                throw new ServiceException(String.format("内置参数【%1$s】不能删除 ", config.getConfigKey()));
+            }
+            configMapper.deleteConfigById(configId);
+            redisCache.deleteObject(getCacheKey(config.getConfigKey()));
+        }
+    }
+
+    /**
+     * 加载参数缓存数据
+     */
+    @Override
+    public void loadingConfigCache()
+    {
+        List<SysConfig> configsList = configMapper.selectConfigList(new SysConfig());
+        for (SysConfig config : configsList)
+        {
+            redisCache.setCacheObject(getCacheKey(config.getConfigKey()), config.getConfigValue());
+        }
+    }
+
+    /**
+     * 清空参数缓存数据
+     */
+    @Override
+    public void clearConfigCache()
+    {
+        Collection<String> keys = redisCache.keys(CacheConstants.SYS_CONFIG_KEY + "*");
+        redisCache.deleteObject(keys);
+    }
+
+    /**
+     * 重置参数缓存数据
+     */
+    @Override
+    public void resetConfigCache()
+    {
+        clearConfigCache();
+        loadingConfigCache();
+    }
+
+    /**
+     * 校验参数键名是否唯一
+     * 
+     * @param config 参数配置信息
+     * @return 结果
+     */
+    @Override
+    public boolean 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;
+    }
+
+    /**
+     * 设置cache key
+     * 
+     * @param configKey 参数键
+     * @return 缓存键key
+     */
+    private String getCacheKey(String configKey)
+    {
+        return CacheConstants.SYS_CONFIG_KEY + configKey;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDeptServiceImpl.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDeptServiceImpl.java
index 3ebcbd27..e16b4bab 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDeptServiceImpl.java
@@ -1,338 +1,338 @@
-package com.ruoyi.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.annotation.DataScope;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.TreeSelect;
-import com.ruoyi.common.core.domain.entity.SysDept;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.core.text.Convert;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.system.mapper.SysDeptMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.service.ISysDeptService;
-
-/**
- * 部门管理 服务实现
- * 
- * @author ruoyi
- */
-@Service
-public class SysDeptServiceImpl implements ISysDeptService
-{
-    @Autowired
-    private SysDeptMapper deptMapper;
-
-    @Autowired
-    private SysRoleMapper roleMapper;
-
-    /**
-     * 查询部门管理数据
-     * 
-     * @param dept 部门信息
-     * @return 部门信息集合
-     */
-    @Override
-    @DataScope(deptAlias = "d")
-    public List<SysDept> selectDeptList(SysDept dept)
-    {
-        return deptMapper.selectDeptList(dept);
-    }
-
-    /**
-     * 查询部门树结构信息
-     * 
-     * @param dept 部门信息
-     * @return 部门树信息集合
-     */
-    @Override
-    public List<TreeSelect> selectDeptTreeList(SysDept dept)
-    {
-        List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
-        return buildDeptTreeSelect(depts);
-    }
-
-    /**
-     * 构建前端所需要树结构
-     * 
-     * @param depts 部门列表
-     * @return 树结构列表
-     */
-    @Override
-    public List<SysDept> buildDeptTree(List<SysDept> depts)
-    {
-        List<SysDept> returnList = new ArrayList<SysDept>();
-        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
-        for (SysDept dept : depts)
-        {
-            // 如果是顶级节点, 遍历该父节点的所有子节点
-            if (!tempList.contains(dept.getParentId()))
-            {
-                recursionFn(depts, dept);
-                returnList.add(dept);
-            }
-        }
-        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<Long> selectDeptListByRoleId(Long roleId)
-    {
-        SysRole role = roleMapper.selectRoleById(roleId);
-        return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
-    }
-
-    /**
-     * 根据部门ID查询信息
-     * 
-     * @param deptId 部门ID
-     * @return 部门信息
-     */
-    @Override
-    public SysDept selectDeptById(Long deptId)
-    {
-        return deptMapper.selectDeptById(deptId);
-    }
-
-    /**
-     * 根据ID查询所有子部门(正常状态)
-     * 
-     * @param deptId 部门ID
-     * @return 子部门数
-     */
-    @Override
-    public int selectNormalChildrenDeptById(Long deptId)
-    {
-        return deptMapper.selectNormalChildrenDeptById(deptId);
-    }
-
-    /**
-     * 是否存在子节点
-     * 
-     * @param deptId 部门ID
-     * @return 结果
-     */
-    @Override
-    public boolean hasChildByDeptId(Long deptId)
-    {
-        int result = deptMapper.hasChildByDeptId(deptId);
-        return result > 0;
-    }
-
-    /**
-     * 查询部门是否存在用户
-     * 
-     * @param deptId 部门ID
-     * @return 结果 true 存在 false 不存在
-     */
-    @Override
-    public boolean checkDeptExistUser(Long deptId)
-    {
-        int result = deptMapper.checkDeptExistUser(deptId);
-        return result > 0;
-    }
-
-    /**
-     * 校验部门名称是否唯一
-     * 
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public boolean 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 deptId 部门id
-     */
-    @Override
-    public void checkDeptDataScope(Long deptId)
-    {
-        if (!SysUser.isAdmin(SecurityUtils.getUserId()) && StringUtils.isNotNull(deptId))
-        {
-            SysDept dept = new SysDept();
-            dept.setDeptId(deptId);
-            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
-            if (StringUtils.isEmpty(depts))
-            {
-                throw new ServiceException("没有权限访问部门数据!");
-            }
-        }
-    }
-
-    /**
-     * 新增保存部门信息
-     * 
-     * @param dept 部门信息
-     * @return 结果
-     */
-    @Override
-    public int insertDept(SysDept dept)
-    {
-        SysDept info = deptMapper.selectDeptById(dept.getParentId());
-        // 如果父节点不为正常状态,则不允许新增子节点
-        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
-        {
-            throw new ServiceException("部门停用,不允许新增");
-        }
-        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()) && StringUtils.isNotEmpty(dept.getAncestors())
-                && !StringUtils.equals("0", dept.getAncestors()))
-        {
-            // 如果该部门是启用状态,则启用该部门的所有上级部门
-            updateParentDeptStatusNormal(dept);
-        }
-        return result;
-    }
-
-    /**
-     * 修改该部门的父级部门状态
-     * 
-     * @param dept 当前部门
-     */
-    private void updateParentDeptStatusNormal(SysDept dept)
-    {
-        String ancestors = dept.getAncestors();
-        Long[] deptIds = Convert.toLongArray(ancestors);
-        deptMapper.updateDeptStatusNormal(deptIds);
-    }
-
-    /**
-     * 修改子元素关系
-     * 
-     * @param deptId 被修改的部门ID
-     * @param newAncestors 新的父ID集合
-     * @param oldAncestors 旧的父ID集合
-     */
-    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
-    {
-        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
-        for (SysDept child : children)
-        {
-            child.setAncestors(child.getAncestors().replaceFirst(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))
-            {
-                recursionFn(list, tChild);
-            }
-        }
-    }
-
-    /**
-     * 得到子节点列表
-     */
-    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 (StringUtils.isNotNull(n.getParentId()) && 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;
-    }
-}
+package com.acupuncture.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.acupuncture.common.annotation.DataScope;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.TreeSelect;
+import com.acupuncture.common.core.domain.entity.SysDept;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.core.text.Convert;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.system.mapper.SysDeptMapper;
+import com.acupuncture.system.mapper.SysRoleMapper;
+import com.acupuncture.system.service.ISysDeptService;
+
+/**
+ * 部门管理 服务实现
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysDeptServiceImpl implements ISysDeptService
+{
+    @Autowired
+    private SysDeptMapper deptMapper;
+
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    /**
+     * 查询部门管理数据
+     * 
+     * @param dept 部门信息
+     * @return 部门信息集合
+     */
+    @Override
+    @DataScope(deptAlias = "d")
+    public List<SysDept> selectDeptList(SysDept dept)
+    {
+        return deptMapper.selectDeptList(dept);
+    }
+
+    /**
+     * 查询部门树结构信息
+     * 
+     * @param dept 部门信息
+     * @return 部门树信息集合
+     */
+    @Override
+    public List<TreeSelect> selectDeptTreeList(SysDept dept)
+    {
+        List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
+        return buildDeptTreeSelect(depts);
+    }
+
+    /**
+     * 构建前端所需要树结构
+     * 
+     * @param depts 部门列表
+     * @return 树结构列表
+     */
+    @Override
+    public List<SysDept> buildDeptTree(List<SysDept> depts)
+    {
+        List<SysDept> returnList = new ArrayList<SysDept>();
+        List<Long> tempList = depts.stream().map(SysDept::getDeptId).collect(Collectors.toList());
+        for (SysDept dept : depts)
+        {
+            // 如果是顶级节点, 遍历该父节点的所有子节点
+            if (!tempList.contains(dept.getParentId()))
+            {
+                recursionFn(depts, dept);
+                returnList.add(dept);
+            }
+        }
+        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<Long> selectDeptListByRoleId(Long roleId)
+    {
+        SysRole role = roleMapper.selectRoleById(roleId);
+        return deptMapper.selectDeptListByRoleId(roleId, role.isDeptCheckStrictly());
+    }
+
+    /**
+     * 根据部门ID查询信息
+     * 
+     * @param deptId 部门ID
+     * @return 部门信息
+     */
+    @Override
+    public SysDept selectDeptById(Long deptId)
+    {
+        return deptMapper.selectDeptById(deptId);
+    }
+
+    /**
+     * 根据ID查询所有子部门(正常状态)
+     * 
+     * @param deptId 部门ID
+     * @return 子部门数
+     */
+    @Override
+    public int selectNormalChildrenDeptById(Long deptId)
+    {
+        return deptMapper.selectNormalChildrenDeptById(deptId);
+    }
+
+    /**
+     * 是否存在子节点
+     * 
+     * @param deptId 部门ID
+     * @return 结果
+     */
+    @Override
+    public boolean hasChildByDeptId(Long deptId)
+    {
+        int result = deptMapper.hasChildByDeptId(deptId);
+        return result > 0;
+    }
+
+    /**
+     * 查询部门是否存在用户
+     * 
+     * @param deptId 部门ID
+     * @return 结果 true 存在 false 不存在
+     */
+    @Override
+    public boolean checkDeptExistUser(Long deptId)
+    {
+        int result = deptMapper.checkDeptExistUser(deptId);
+        return result > 0;
+    }
+
+    /**
+     * 校验部门名称是否唯一
+     * 
+     * @param dept 部门信息
+     * @return 结果
+     */
+    @Override
+    public boolean 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 deptId 部门id
+     */
+    @Override
+    public void checkDeptDataScope(Long deptId)
+    {
+        if (!SysUser.isAdmin(SecurityUtils.getUserId()) && StringUtils.isNotNull(deptId))
+        {
+            SysDept dept = new SysDept();
+            dept.setDeptId(deptId);
+            List<SysDept> depts = SpringUtils.getAopProxy(this).selectDeptList(dept);
+            if (StringUtils.isEmpty(depts))
+            {
+                throw new ServiceException("没有权限访问部门数据!");
+            }
+        }
+    }
+
+    /**
+     * 新增保存部门信息
+     * 
+     * @param dept 部门信息
+     * @return 结果
+     */
+    @Override
+    public int insertDept(SysDept dept)
+    {
+        SysDept info = deptMapper.selectDeptById(dept.getParentId());
+        // 如果父节点不为正常状态,则不允许新增子节点
+        if (!UserConstants.DEPT_NORMAL.equals(info.getStatus()))
+        {
+            throw new ServiceException("部门停用,不允许新增");
+        }
+        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()) && StringUtils.isNotEmpty(dept.getAncestors())
+                && !StringUtils.equals("0", dept.getAncestors()))
+        {
+            // 如果该部门是启用状态,则启用该部门的所有上级部门
+            updateParentDeptStatusNormal(dept);
+        }
+        return result;
+    }
+
+    /**
+     * 修改该部门的父级部门状态
+     * 
+     * @param dept 当前部门
+     */
+    private void updateParentDeptStatusNormal(SysDept dept)
+    {
+        String ancestors = dept.getAncestors();
+        Long[] deptIds = Convert.toLongArray(ancestors);
+        deptMapper.updateDeptStatusNormal(deptIds);
+    }
+
+    /**
+     * 修改子元素关系
+     * 
+     * @param deptId 被修改的部门ID
+     * @param newAncestors 新的父ID集合
+     * @param oldAncestors 旧的父ID集合
+     */
+    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
+    {
+        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
+        for (SysDept child : children)
+        {
+            child.setAncestors(child.getAncestors().replaceFirst(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))
+            {
+                recursionFn(list, tChild);
+            }
+        }
+    }
+
+    /**
+     * 得到子节点列表
+     */
+    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 (StringUtils.isNotNull(n.getParentId()) && 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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictDataServiceImpl.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictDataServiceImpl.java
index de244f8b..44a8d304 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictDataServiceImpl.java
@@ -1,111 +1,111 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.domain.entity.SysDictData;
-import com.ruoyi.common.utils.DictUtils;
-import com.ruoyi.system.mapper.SysDictDataMapper;
-import com.ruoyi.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 字典类型
-     * @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);
-    }
-
-    /**
-     * 批量删除字典数据信息
-     * 
-     * @param dictCodes 需要删除的字典数据ID
-     */
-    @Override
-    public void deleteDictDataByIds(Long[] dictCodes)
-    {
-        for (Long dictCode : dictCodes)
-        {
-            SysDictData data = selectDictDataById(dictCode);
-            dictDataMapper.deleteDictDataById(dictCode);
-            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
-            DictUtils.setDictCache(data.getDictType(), dictDatas);
-        }
-    }
-
-    /**
-     * 新增保存字典数据信息
-     * 
-     * @param data 字典数据信息
-     * @return 结果
-     */
-    @Override
-    public int insertDictData(SysDictData data)
-    {
-        int row = dictDataMapper.insertDictData(data);
-        if (row > 0)
-        {
-            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
-            DictUtils.setDictCache(data.getDictType(), dictDatas);
-        }
-        return row;
-    }
-
-    /**
-     * 修改保存字典数据信息
-     * 
-     * @param data 字典数据信息
-     * @return 结果
-     */
-    @Override
-    public int updateDictData(SysDictData data)
-    {
-        int row = dictDataMapper.updateDictData(data);
-        if (row > 0)
-        {
-            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
-            DictUtils.setDictCache(data.getDictType(), dictDatas);
-        }
-        return row;
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+import com.acupuncture.common.utils.DictUtils;
+import com.acupuncture.system.mapper.SysDictDataMapper;
+import com.acupuncture.system.service.ISysDictDataService;
+
+/**
+ * 字典 业务层处理
+ * 
+ * @author acupuncture
+ */
+@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 字典类型
+     * @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);
+    }
+
+    /**
+     * 批量删除字典数据信息
+     * 
+     * @param dictCodes 需要删除的字典数据ID
+     */
+    @Override
+    public void deleteDictDataByIds(Long[] dictCodes)
+    {
+        for (Long dictCode : dictCodes)
+        {
+            SysDictData data = selectDictDataById(dictCode);
+            dictDataMapper.deleteDictDataById(dictCode);
+            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+            DictUtils.setDictCache(data.getDictType(), dictDatas);
+        }
+    }
+
+    /**
+     * 新增保存字典数据信息
+     * 
+     * @param data 字典数据信息
+     * @return 结果
+     */
+    @Override
+    public int insertDictData(SysDictData data)
+    {
+        int row = dictDataMapper.insertDictData(data);
+        if (row > 0)
+        {
+            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+            DictUtils.setDictCache(data.getDictType(), dictDatas);
+        }
+        return row;
+    }
+
+    /**
+     * 修改保存字典数据信息
+     * 
+     * @param data 字典数据信息
+     * @return 结果
+     */
+    @Override
+    public int updateDictData(SysDictData data)
+    {
+        int row = dictDataMapper.updateDictData(data);
+        if (row > 0)
+        {
+            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(data.getDictType());
+            DictUtils.setDictCache(data.getDictType(), dictDatas);
+        }
+        return row;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictTypeServiceImpl.java
similarity index 88%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictTypeServiceImpl.java
index b6c4c565..9f871a38 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysDictTypeServiceImpl.java
@@ -1,223 +1,223 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.Comparator;
-import java.util.List;
-import java.util.Map;
-import java.util.stream.Collectors;
-import javax.annotation.PostConstruct;
-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.core.domain.entity.SysDictData;
-import com.ruoyi.common.core.domain.entity.SysDictType;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.DictUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.mapper.SysDictDataMapper;
-import com.ruoyi.system.mapper.SysDictTypeMapper;
-import com.ruoyi.system.service.ISysDictTypeService;
-
-/**
- * 字典 业务层处理
- * 
- * @author ruoyi
- */
-@Service
-public class SysDictTypeServiceImpl implements ISysDictTypeService
-{
-    @Autowired
-    private SysDictTypeMapper dictTypeMapper;
-
-    @Autowired
-    private SysDictDataMapper dictDataMapper;
-
-    /**
-     * 项目启动时,初始化字典到缓存
-     */
-    @PostConstruct
-    public void init()
-    {
-        loadingDictCache();
-    }
-
-    /**
-     * 根据条件分页查询字典类型
-     * 
-     * @param dictType 字典类型信息
-     * @return 字典类型集合信息
-     */
-    @Override
-    public List<SysDictType> selectDictTypeList(SysDictType dictType)
-    {
-        return dictTypeMapper.selectDictTypeList(dictType);
-    }
-
-    /**
-     * 根据所有字典类型
-     * 
-     * @return 字典类型集合信息
-     */
-    @Override
-    public List<SysDictType> selectDictTypeAll()
-    {
-        return dictTypeMapper.selectDictTypeAll();
-    }
-
-    /**
-     * 根据字典类型查询字典数据
-     * 
-     * @param dictType 字典类型
-     * @return 字典数据集合信息
-     */
-    @Override
-    public List<SysDictData> selectDictDataByType(String dictType)
-    {
-        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
-        if (StringUtils.isNotEmpty(dictDatas))
-        {
-            return dictDatas;
-        }
-        dictDatas = dictDataMapper.selectDictDataByType(dictType);
-        if (StringUtils.isNotEmpty(dictDatas))
-        {
-            DictUtils.setDictCache(dictType, dictDatas);
-            return dictDatas;
-        }
-        return null;
-    }
-
-    /**
-     * 根据字典类型ID查询信息
-     * 
-     * @param dictId 字典类型ID
-     * @return 字典类型
-     */
-    @Override
-    public SysDictType selectDictTypeById(Long dictId)
-    {
-        return dictTypeMapper.selectDictTypeById(dictId);
-    }
-
-    /**
-     * 根据字典类型查询信息
-     * 
-     * @param dictType 字典类型
-     * @return 字典类型
-     */
-    @Override
-    public SysDictType selectDictTypeByType(String dictType)
-    {
-        return dictTypeMapper.selectDictTypeByType(dictType);
-    }
-
-    /**
-     * 批量删除字典类型信息
-     * 
-     * @param dictIds 需要删除的字典ID
-     */
-    @Override
-    public void deleteDictTypeByIds(Long[] dictIds)
-    {
-        for (Long dictId : dictIds)
-        {
-            SysDictType dictType = selectDictTypeById(dictId);
-            if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0)
-            {
-                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
-            }
-            dictTypeMapper.deleteDictTypeById(dictId);
-            DictUtils.removeDictCache(dictType.getDictType());
-        }
-    }
-
-    /**
-     * 加载字典缓存数据
-     */
-    @Override
-    public void loadingDictCache()
-    {
-        SysDictData dictData = new SysDictData();
-        dictData.setStatus("0");
-        Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
-        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())
-        {
-            DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
-        }
-    }
-
-    /**
-     * 清空字典缓存数据
-     */
-    @Override
-    public void clearDictCache()
-    {
-        DictUtils.clearDictCache();
-    }
-
-    /**
-     * 重置字典缓存数据
-     */
-    @Override
-    public void resetDictCache()
-    {
-        clearDictCache();
-        loadingDictCache();
-    }
-
-    /**
-     * 新增保存字典类型信息
-     * 
-     * @param dict 字典类型信息
-     * @return 结果
-     */
-    @Override
-    public int insertDictType(SysDictType dict)
-    {
-        int row = dictTypeMapper.insertDictType(dict);
-        if (row > 0)
-        {
-            DictUtils.setDictCache(dict.getDictType(), null);
-        }
-        return row;
-    }
-
-    /**
-     * 修改保存字典类型信息
-     * 
-     * @param dict 字典类型信息
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public int updateDictType(SysDictType dict)
-    {
-        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());
-        dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());
-        int row = dictTypeMapper.updateDictType(dict);
-        if (row > 0)
-        {
-            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
-            DictUtils.setDictCache(dict.getDictType(), dictDatas);
-        }
-        return row;
-    }
-
-    /**
-     * 校验字典类型称是否唯一
-     * 
-     * @param dict 字典类型
-     * @return 结果
-     */
-    @Override
-    public boolean 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;
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+import javax.annotation.PostConstruct;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysDictData;
+import com.acupuncture.common.core.domain.entity.SysDictType;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.DictUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.mapper.SysDictDataMapper;
+import com.acupuncture.system.mapper.SysDictTypeMapper;
+import com.acupuncture.system.service.ISysDictTypeService;
+
+/**
+ * 字典 业务层处理
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysDictTypeServiceImpl implements ISysDictTypeService
+{
+    @Autowired
+    private SysDictTypeMapper dictTypeMapper;
+
+    @Autowired
+    private SysDictDataMapper dictDataMapper;
+
+    /**
+     * 项目启动时,初始化字典到缓存
+     */
+    @PostConstruct
+    public void init()
+    {
+        loadingDictCache();
+    }
+
+    /**
+     * 根据条件分页查询字典类型
+     * 
+     * @param dictType 字典类型信息
+     * @return 字典类型集合信息
+     */
+    @Override
+    public List<SysDictType> selectDictTypeList(SysDictType dictType)
+    {
+        return dictTypeMapper.selectDictTypeList(dictType);
+    }
+
+    /**
+     * 根据所有字典类型
+     * 
+     * @return 字典类型集合信息
+     */
+    @Override
+    public List<SysDictType> selectDictTypeAll()
+    {
+        return dictTypeMapper.selectDictTypeAll();
+    }
+
+    /**
+     * 根据字典类型查询字典数据
+     * 
+     * @param dictType 字典类型
+     * @return 字典数据集合信息
+     */
+    @Override
+    public List<SysDictData> selectDictDataByType(String dictType)
+    {
+        List<SysDictData> dictDatas = DictUtils.getDictCache(dictType);
+        if (StringUtils.isNotEmpty(dictDatas))
+        {
+            return dictDatas;
+        }
+        dictDatas = dictDataMapper.selectDictDataByType(dictType);
+        if (StringUtils.isNotEmpty(dictDatas))
+        {
+            DictUtils.setDictCache(dictType, dictDatas);
+            return dictDatas;
+        }
+        return null;
+    }
+
+    /**
+     * 根据字典类型ID查询信息
+     * 
+     * @param dictId 字典类型ID
+     * @return 字典类型
+     */
+    @Override
+    public SysDictType selectDictTypeById(Long dictId)
+    {
+        return dictTypeMapper.selectDictTypeById(dictId);
+    }
+
+    /**
+     * 根据字典类型查询信息
+     * 
+     * @param dictType 字典类型
+     * @return 字典类型
+     */
+    @Override
+    public SysDictType selectDictTypeByType(String dictType)
+    {
+        return dictTypeMapper.selectDictTypeByType(dictType);
+    }
+
+    /**
+     * 批量删除字典类型信息
+     * 
+     * @param dictIds 需要删除的字典ID
+     */
+    @Override
+    public void deleteDictTypeByIds(Long[] dictIds)
+    {
+        for (Long dictId : dictIds)
+        {
+            SysDictType dictType = selectDictTypeById(dictId);
+            if (dictDataMapper.countDictDataByType(dictType.getDictType()) > 0)
+            {
+                throw new ServiceException(String.format("%1$s已分配,不能删除", dictType.getDictName()));
+            }
+            dictTypeMapper.deleteDictTypeById(dictId);
+            DictUtils.removeDictCache(dictType.getDictType());
+        }
+    }
+
+    /**
+     * 加载字典缓存数据
+     */
+    @Override
+    public void loadingDictCache()
+    {
+        SysDictData dictData = new SysDictData();
+        dictData.setStatus("0");
+        Map<String, List<SysDictData>> dictDataMap = dictDataMapper.selectDictDataList(dictData).stream().collect(Collectors.groupingBy(SysDictData::getDictType));
+        for (Map.Entry<String, List<SysDictData>> entry : dictDataMap.entrySet())
+        {
+            DictUtils.setDictCache(entry.getKey(), entry.getValue().stream().sorted(Comparator.comparing(SysDictData::getDictSort)).collect(Collectors.toList()));
+        }
+    }
+
+    /**
+     * 清空字典缓存数据
+     */
+    @Override
+    public void clearDictCache()
+    {
+        DictUtils.clearDictCache();
+    }
+
+    /**
+     * 重置字典缓存数据
+     */
+    @Override
+    public void resetDictCache()
+    {
+        clearDictCache();
+        loadingDictCache();
+    }
+
+    /**
+     * 新增保存字典类型信息
+     * 
+     * @param dict 字典类型信息
+     * @return 结果
+     */
+    @Override
+    public int insertDictType(SysDictType dict)
+    {
+        int row = dictTypeMapper.insertDictType(dict);
+        if (row > 0)
+        {
+            DictUtils.setDictCache(dict.getDictType(), null);
+        }
+        return row;
+    }
+
+    /**
+     * 修改保存字典类型信息
+     * 
+     * @param dict 字典类型信息
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public int updateDictType(SysDictType dict)
+    {
+        SysDictType oldDict = dictTypeMapper.selectDictTypeById(dict.getDictId());
+        dictDataMapper.updateDictDataType(oldDict.getDictType(), dict.getDictType());
+        int row = dictTypeMapper.updateDictType(dict);
+        if (row > 0)
+        {
+            List<SysDictData> dictDatas = dictDataMapper.selectDictDataByType(dict.getDictType());
+            DictUtils.setDictCache(dict.getDictType(), dictDatas);
+        }
+        return row;
+    }
+
+    /**
+     * 校验字典类型称是否唯一
+     * 
+     * @param dict 字典类型
+     * @return 结果
+     */
+    @Override
+    public boolean 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-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysLogininforServiceImpl.java
similarity index 82%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysLogininforServiceImpl.java
index a5637aee..0a045f0c 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysLogininforServiceImpl.java
@@ -1,65 +1,65 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.domain.SysLogininfor;
-import com.ruoyi.system.mapper.SysLogininforMapper;
-import com.ruoyi.system.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 infoIds 需要删除的登录日志ID
-     * @return 结果
-     */
-    @Override
-    public int deleteLogininforByIds(Long[] infoIds)
-    {
-        return logininforMapper.deleteLogininforByIds(infoIds);
-    }
-
-    /**
-     * 清空系统登录日志
-     */
-    @Override
-    public void cleanLogininfor()
-    {
-        logininforMapper.cleanLogininfor();
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.system.domain.SysLogininfor;
+import com.acupuncture.system.mapper.SysLogininforMapper;
+import com.acupuncture.system.service.ISysLogininforService;
+
+/**
+ * 系统访问日志情况信息 服务层处理
+ * 
+ * @author acupuncture
+ */
+@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 infoIds 需要删除的登录日志ID
+     * @return 结果
+     */
+    @Override
+    public int deleteLogininforByIds(Long[] infoIds)
+    {
+        return logininforMapper.deleteLogininforByIds(infoIds);
+    }
+
+    /**
+     * 清空系统登录日志
+     */
+    @Override
+    public void cleanLogininfor()
+    {
+        logininforMapper.cleanLogininfor();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysMenuServiceImpl.java
similarity index 94%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysMenuServiceImpl.java
index 78a78307..6f8b26fb 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysMenuServiceImpl.java
@@ -1,4 +1,4 @@
-package com.ruoyi.system.service.impl;
+package com.acupuncture.system.service.impl;
 
 import java.util.ArrayList;
 import java.util.Arrays;
@@ -10,25 +10,25 @@ 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.Constants;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.TreeSelect;
-import com.ruoyi.common.core.domain.entity.SysMenu;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.vo.MetaVo;
-import com.ruoyi.system.domain.vo.RouterVo;
-import com.ruoyi.system.mapper.SysMenuMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysRoleMenuMapper;
-import com.ruoyi.system.service.ISysMenuService;
+import com.acupuncture.common.constant.Constants;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.TreeSelect;
+import com.acupuncture.common.core.domain.entity.SysMenu;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.vo.MetaVo;
+import com.acupuncture.system.domain.vo.RouterVo;
+import com.acupuncture.system.mapper.SysMenuMapper;
+import com.acupuncture.system.mapper.SysRoleMapper;
+import com.acupuncture.system.mapper.SysRoleMenuMapper;
+import com.acupuncture.system.service.ISysMenuService;
 
 /**
  * 菜单 业务层处理
  * 
- * @author ruoyi
+ * @author acupuncture
  */
 @Service
 public class SysMenuServiceImpl implements ISysMenuService
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysNoticeServiceImpl.java
similarity index 85%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysNoticeServiceImpl.java
index 8bebd9c6..73c9239b 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysNoticeServiceImpl.java
@@ -1,92 +1,92 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.domain.SysNotice;
-import com.ruoyi.system.mapper.SysNoticeMapper;
-import com.ruoyi.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);
-    }
-
-    /**
-     * 批量删除公告信息
-     * 
-     * @param noticeIds 需要删除的公告ID
-     * @return 结果
-     */
-    @Override
-    public int deleteNoticeByIds(Long[] noticeIds)
-    {
-        return noticeMapper.deleteNoticeByIds(noticeIds);
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.system.domain.SysNotice;
+import com.acupuncture.system.mapper.SysNoticeMapper;
+import com.acupuncture.system.service.ISysNoticeService;
+
+/**
+ * 公告 服务层实现
+ * 
+ * @author acupuncture
+ */
+@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);
+    }
+
+    /**
+     * 批量删除公告信息
+     * 
+     * @param noticeIds 需要删除的公告ID
+     * @return 结果
+     */
+    @Override
+    public int deleteNoticeByIds(Long[] noticeIds)
+    {
+        return noticeMapper.deleteNoticeByIds(noticeIds);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysOperLogServiceImpl.java
similarity index 84%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysOperLogServiceImpl.java
index 785ee1ed..ddf8ba37 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysOperLogServiceImpl.java
@@ -1,76 +1,76 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.List;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import com.ruoyi.system.domain.SysOperLog;
-import com.ruoyi.system.mapper.SysOperLogMapper;
-import com.ruoyi.system.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 operIds 需要删除的操作日志ID
-     * @return 结果
-     */
-    @Override
-    public int deleteOperLogByIds(Long[] operIds)
-    {
-        return operLogMapper.deleteOperLogByIds(operIds);
-    }
-
-    /**
-     * 查询操作日志详细
-     * 
-     * @param operId 操作ID
-     * @return 操作日志对象
-     */
-    @Override
-    public SysOperLog selectOperLogById(Long operId)
-    {
-        return operLogMapper.selectOperLogById(operId);
-    }
-
-    /**
-     * 清空操作日志
-     */
-    @Override
-    public void cleanOperLog()
-    {
-        operLogMapper.cleanOperLog();
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.system.domain.SysOperLog;
+import com.acupuncture.system.mapper.SysOperLogMapper;
+import com.acupuncture.system.service.ISysOperLogService;
+
+/**
+ * 操作日志 服务层处理
+ * 
+ * @author acupuncture
+ */
+@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 operIds 需要删除的操作日志ID
+     * @return 结果
+     */
+    @Override
+    public int deleteOperLogByIds(Long[] operIds)
+    {
+        return operLogMapper.deleteOperLogByIds(operIds);
+    }
+
+    /**
+     * 查询操作日志详细
+     * 
+     * @param operId 操作ID
+     * @return 操作日志对象
+     */
+    @Override
+    public SysOperLog selectOperLogById(Long operId)
+    {
+        return operLogMapper.selectOperLogById(operId);
+    }
+
+    /**
+     * 清空操作日志
+     */
+    @Override
+    public void cleanOperLog()
+    {
+        operLogMapper.cleanOperLog();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysPostServiceImpl.java
similarity index 87%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysPostServiceImpl.java
index 57995eb0..a2dfc3b5 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysPostServiceImpl.java
@@ -1,178 +1,178 @@
-package com.ruoyi.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.exception.ServiceException;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.system.mapper.SysPostMapper;
-import com.ruoyi.system.mapper.SysUserPostMapper;
-import com.ruoyi.system.service.ISysPostService;
-
-/**
- * 岗位信息 服务层处理
- * 
- * @author ruoyi
- */
-@Service
-public class SysPostServiceImpl implements ISysPostService
-{
-    @Autowired
-    private SysPostMapper postMapper;
-
-    @Autowired
-    private SysUserPostMapper userPostMapper;
-
-    /**
-     * 查询岗位信息集合
-     * 
-     * @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列表
-     */
-    @Override
-    public List<Long> selectPostListByUserId(Long userId)
-    {
-        return postMapper.selectPostListByUserId(userId);
-    }
-
-    /**
-     * 校验岗位名称是否唯一
-     * 
-     * @param post 岗位信息
-     * @return 结果
-     */
-    @Override
-    public boolean 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 boolean 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;
-    }
-
-    /**
-     * 通过岗位ID查询岗位使用数量
-     * 
-     * @param postId 岗位ID
-     * @return 结果
-     */
-    @Override
-    public int countUserPostById(Long postId)
-    {
-        return userPostMapper.countUserPostById(postId);
-    }
-
-    /**
-     * 删除岗位信息
-     * 
-     * @param postId 岗位ID
-     * @return 结果
-     */
-    @Override
-    public int deletePostById(Long postId)
-    {
-        return postMapper.deletePostById(postId);
-    }
-
-    /**
-     * 批量删除岗位信息
-     * 
-     * @param postIds 需要删除的岗位ID
-     * @return 结果
-     */
-    @Override
-    public int deletePostByIds(Long[] postIds)
-    {
-        for (Long postId : postIds)
-        {
-            SysPost post = selectPostById(postId);
-            if (countUserPostById(postId) > 0)
-            {
-                throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName()));
-            }
-        }
-        return postMapper.deletePostByIds(postIds);
-    }
-
-    /**
-     * 新增保存岗位信息
-     * 
-     * @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);
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.SysPost;
+import com.acupuncture.system.mapper.SysPostMapper;
+import com.acupuncture.system.mapper.SysUserPostMapper;
+import com.acupuncture.system.service.ISysPostService;
+
+/**
+ * 岗位信息 服务层处理
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysPostServiceImpl implements ISysPostService
+{
+    @Autowired
+    private SysPostMapper postMapper;
+
+    @Autowired
+    private SysUserPostMapper userPostMapper;
+
+    /**
+     * 查询岗位信息集合
+     * 
+     * @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列表
+     */
+    @Override
+    public List<Long> selectPostListByUserId(Long userId)
+    {
+        return postMapper.selectPostListByUserId(userId);
+    }
+
+    /**
+     * 校验岗位名称是否唯一
+     * 
+     * @param post 岗位信息
+     * @return 结果
+     */
+    @Override
+    public boolean 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 boolean 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;
+    }
+
+    /**
+     * 通过岗位ID查询岗位使用数量
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    @Override
+    public int countUserPostById(Long postId)
+    {
+        return userPostMapper.countUserPostById(postId);
+    }
+
+    /**
+     * 删除岗位信息
+     * 
+     * @param postId 岗位ID
+     * @return 结果
+     */
+    @Override
+    public int deletePostById(Long postId)
+    {
+        return postMapper.deletePostById(postId);
+    }
+
+    /**
+     * 批量删除岗位信息
+     * 
+     * @param postIds 需要删除的岗位ID
+     * @return 结果
+     */
+    @Override
+    public int deletePostByIds(Long[] postIds)
+    {
+        for (Long postId : postIds)
+        {
+            SysPost post = selectPostById(postId);
+            if (countUserPostById(postId) > 0)
+            {
+                throw new ServiceException(String.format("%1$s已分配,不能删除", post.getPostName()));
+            }
+        }
+        return postMapper.deletePostByIds(postIds);
+    }
+
+    /**
+     * 新增保存岗位信息
+     * 
+     * @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-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysRoleServiceImpl.java
similarity index 89%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysRoleServiceImpl.java
index 81e1f8cc..6b935ec9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysRoleServiceImpl.java
@@ -1,427 +1,427 @@
-package com.ruoyi.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.annotation.DataScope;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.system.domain.SysRoleDept;
-import com.ruoyi.system.domain.SysRoleMenu;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.mapper.SysRoleDeptMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysRoleMenuMapper;
-import com.ruoyi.system.mapper.SysUserRoleMapper;
-import com.ruoyi.system.service.ISysRoleService;
-
-/**
- * 角色 业务层处理
- * 
- * @author ruoyi
- */
-@Service
-public class SysRoleServiceImpl implements ISysRoleService
-{
-    @Autowired
-    private SysRoleMapper roleMapper;
-
-    @Autowired
-    private SysRoleMenuMapper roleMenuMapper;
-
-    @Autowired
-    private SysUserRoleMapper userRoleMapper;
-
-    @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 List<SysRole> selectRolesByUserId(Long userId)
-    {
-        List<SysRole> userRoles = roleMapper.selectRolePermissionByUserId(userId);
-        List<SysRole> roles = selectRoleAll();
-        for (SysRole role : roles)
-        {
-            for (SysRole userRole : userRoles)
-            {
-                if (role.getRoleId().longValue() == userRole.getRoleId().longValue())
-                {
-                    role.setFlag(true);
-                    break;
-                }
-            }
-        }
-        return roles;
-    }
-
-    /**
-     * 根据用户ID查询权限
-     * 
-     * @param userId 用户ID
-     * @return 权限列表
-     */
-    @Override
-    public Set<String> selectRolePermissionByUserId(Long userId)
-    {
-        List<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 角色列表
-     */
-    @Override
-    public List<SysRole> selectRoleAll()
-    {
-        return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());
-    }
-
-    /**
-     * 根据用户ID获取角色选择框列表
-     * 
-     * @param userId 用户ID
-     * @return 选中角色ID列表
-     */
-    @Override
-    public List<Long> selectRoleListByUserId(Long userId)
-    {
-        return roleMapper.selectRoleListByUserId(userId);
-    }
-
-    /**
-     * 通过角色ID查询角色
-     * 
-     * @param roleId 角色ID
-     * @return 角色对象信息
-     */
-    @Override
-    public SysRole selectRoleById(Long roleId)
-    {
-        return roleMapper.selectRoleById(roleId);
-    }
-
-    /**
-     * 校验角色名称是否唯一
-     * 
-     * @param role 角色信息
-     * @return 结果
-     */
-    @Override
-    public boolean 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 boolean 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 角色信息
-     */
-    @Override
-    public void checkRoleAllowed(SysRole role)
-    {
-        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())
-        {
-            throw new ServiceException("不允许操作超级管理员角色");
-        }
-    }
-
-    /**
-     * 校验角色是否有数据权限
-     * 
-     * @param roleIds 角色id
-     */
-    @Override
-    public void checkRoleDataScope(Long... roleIds)
-    {
-        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
-        {
-            for (Long roleId : roleIds)
-            {
-                SysRole role = new SysRole();
-                role.setRoleId(roleId);
-                List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
-                if (StringUtils.isEmpty(roles))
-                {
-                    throw new ServiceException("没有权限访问角色数据!");
-                }
-            }
-        }
-    }
-
-    /**
-     * 通过角色ID查询角色使用数量
-     * 
-     * @param roleId 角色ID
-     * @return 结果
-     */
-    @Override
-    public int countUserRoleByRoleId(Long roleId)
-    {
-        return userRoleMapper.countUserRoleByRoleId(roleId);
-    }
-
-    /**
-     * 新增保存角色信息
-     * 
-     * @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 结果
-     */
-    @Override
-    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
-    @Transactional
-    public int deleteRoleById(Long roleId)
-    {
-        // 删除角色与菜单关联
-        roleMenuMapper.deleteRoleMenuByRoleId(roleId);
-        // 删除角色与部门关联
-        roleDeptMapper.deleteRoleDeptByRoleId(roleId);
-        return roleMapper.deleteRoleById(roleId);
-    }
-
-    /**
-     * 批量删除角色信息
-     * 
-     * @param roleIds 需要删除的角色ID
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public int deleteRoleByIds(Long[] roleIds)
-    {
-        for (Long roleId : roleIds)
-        {
-            checkRoleAllowed(new SysRole(roleId));
-            checkRoleDataScope(roleId);
-            SysRole role = selectRoleById(roleId);
-            if (countUserRoleByRoleId(roleId) > 0)
-            {
-                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
-            }
-        }
-        // 删除角色与菜单关联
-        roleMenuMapper.deleteRoleMenu(roleIds);
-        // 删除角色与部门关联
-        roleDeptMapper.deleteRoleDept(roleIds);
-        return roleMapper.deleteRoleByIds(roleIds);
-    }
-
-    /**
-     * 取消授权用户角色
-     * 
-     * @param userRole 用户和角色关联信息
-     * @return 结果
-     */
-    @Override
-    public int deleteAuthUser(SysUserRole userRole)
-    {
-        return userRoleMapper.deleteUserRoleInfo(userRole);
-    }
-
-    /**
-     * 批量取消授权用户角色
-     * 
-     * @param roleId 角色ID
-     * @param userIds 需要取消授权的用户数据ID
-     * @return 结果
-     */
-    @Override
-    public int deleteAuthUsers(Long roleId, Long[] userIds)
-    {
-        return userRoleMapper.deleteUserRoleInfos(roleId, userIds);
-    }
-
-    /**
-     * 批量选择授权用户角色
-     * 
-     * @param roleId 角色ID
-     * @param userIds 需要授权的用户数据ID
-     * @return 结果
-     */
-    @Override
-    public int insertAuthUsers(Long roleId, Long[] userIds)
-    {
-        // 新增用户与角色管理
-        List<SysUserRole> list = new ArrayList<SysUserRole>();
-        for (Long userId : userIds)
-        {
-            SysUserRole ur = new SysUserRole();
-            ur.setUserId(userId);
-            ur.setRoleId(roleId);
-            list.add(ur);
-        }
-        return userRoleMapper.batchUserRole(list);
-    }
-}
+package com.acupuncture.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.acupuncture.common.annotation.DataScope;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.system.domain.SysRoleDept;
+import com.acupuncture.system.domain.SysRoleMenu;
+import com.acupuncture.system.domain.SysUserRole;
+import com.acupuncture.system.mapper.SysRoleDeptMapper;
+import com.acupuncture.system.mapper.SysRoleMapper;
+import com.acupuncture.system.mapper.SysRoleMenuMapper;
+import com.acupuncture.system.mapper.SysUserRoleMapper;
+import com.acupuncture.system.service.ISysRoleService;
+
+/**
+ * 角色 业务层处理
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysRoleServiceImpl implements ISysRoleService
+{
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    @Autowired
+    private SysRoleMenuMapper roleMenuMapper;
+
+    @Autowired
+    private SysUserRoleMapper userRoleMapper;
+
+    @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 List<SysRole> selectRolesByUserId(Long userId)
+    {
+        List<SysRole> userRoles = roleMapper.selectRolePermissionByUserId(userId);
+        List<SysRole> roles = selectRoleAll();
+        for (SysRole role : roles)
+        {
+            for (SysRole userRole : userRoles)
+            {
+                if (role.getRoleId().longValue() == userRole.getRoleId().longValue())
+                {
+                    role.setFlag(true);
+                    break;
+                }
+            }
+        }
+        return roles;
+    }
+
+    /**
+     * 根据用户ID查询权限
+     * 
+     * @param userId 用户ID
+     * @return 权限列表
+     */
+    @Override
+    public Set<String> selectRolePermissionByUserId(Long userId)
+    {
+        List<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 角色列表
+     */
+    @Override
+    public List<SysRole> selectRoleAll()
+    {
+        return SpringUtils.getAopProxy(this).selectRoleList(new SysRole());
+    }
+
+    /**
+     * 根据用户ID获取角色选择框列表
+     * 
+     * @param userId 用户ID
+     * @return 选中角色ID列表
+     */
+    @Override
+    public List<Long> selectRoleListByUserId(Long userId)
+    {
+        return roleMapper.selectRoleListByUserId(userId);
+    }
+
+    /**
+     * 通过角色ID查询角色
+     * 
+     * @param roleId 角色ID
+     * @return 角色对象信息
+     */
+    @Override
+    public SysRole selectRoleById(Long roleId)
+    {
+        return roleMapper.selectRoleById(roleId);
+    }
+
+    /**
+     * 校验角色名称是否唯一
+     * 
+     * @param role 角色信息
+     * @return 结果
+     */
+    @Override
+    public boolean 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 boolean 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 角色信息
+     */
+    @Override
+    public void checkRoleAllowed(SysRole role)
+    {
+        if (StringUtils.isNotNull(role.getRoleId()) && role.isAdmin())
+        {
+            throw new ServiceException("不允许操作超级管理员角色");
+        }
+    }
+
+    /**
+     * 校验角色是否有数据权限
+     * 
+     * @param roleIds 角色id
+     */
+    @Override
+    public void checkRoleDataScope(Long... roleIds)
+    {
+        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
+        {
+            for (Long roleId : roleIds)
+            {
+                SysRole role = new SysRole();
+                role.setRoleId(roleId);
+                List<SysRole> roles = SpringUtils.getAopProxy(this).selectRoleList(role);
+                if (StringUtils.isEmpty(roles))
+                {
+                    throw new ServiceException("没有权限访问角色数据!");
+                }
+            }
+        }
+    }
+
+    /**
+     * 通过角色ID查询角色使用数量
+     * 
+     * @param roleId 角色ID
+     * @return 结果
+     */
+    @Override
+    public int countUserRoleByRoleId(Long roleId)
+    {
+        return userRoleMapper.countUserRoleByRoleId(roleId);
+    }
+
+    /**
+     * 新增保存角色信息
+     * 
+     * @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 结果
+     */
+    @Override
+    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
+    @Transactional
+    public int deleteRoleById(Long roleId)
+    {
+        // 删除角色与菜单关联
+        roleMenuMapper.deleteRoleMenuByRoleId(roleId);
+        // 删除角色与部门关联
+        roleDeptMapper.deleteRoleDeptByRoleId(roleId);
+        return roleMapper.deleteRoleById(roleId);
+    }
+
+    /**
+     * 批量删除角色信息
+     * 
+     * @param roleIds 需要删除的角色ID
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public int deleteRoleByIds(Long[] roleIds)
+    {
+        for (Long roleId : roleIds)
+        {
+            checkRoleAllowed(new SysRole(roleId));
+            checkRoleDataScope(roleId);
+            SysRole role = selectRoleById(roleId);
+            if (countUserRoleByRoleId(roleId) > 0)
+            {
+                throw new ServiceException(String.format("%1$s已分配,不能删除", role.getRoleName()));
+            }
+        }
+        // 删除角色与菜单关联
+        roleMenuMapper.deleteRoleMenu(roleIds);
+        // 删除角色与部门关联
+        roleDeptMapper.deleteRoleDept(roleIds);
+        return roleMapper.deleteRoleByIds(roleIds);
+    }
+
+    /**
+     * 取消授权用户角色
+     * 
+     * @param userRole 用户和角色关联信息
+     * @return 结果
+     */
+    @Override
+    public int deleteAuthUser(SysUserRole userRole)
+    {
+        return userRoleMapper.deleteUserRoleInfo(userRole);
+    }
+
+    /**
+     * 批量取消授权用户角色
+     * 
+     * @param roleId 角色ID
+     * @param userIds 需要取消授权的用户数据ID
+     * @return 结果
+     */
+    @Override
+    public int deleteAuthUsers(Long roleId, Long[] userIds)
+    {
+        return userRoleMapper.deleteUserRoleInfos(roleId, userIds);
+    }
+
+    /**
+     * 批量选择授权用户角色
+     * 
+     * @param roleId 角色ID
+     * @param userIds 需要授权的用户数据ID
+     * @return 结果
+     */
+    @Override
+    public int insertAuthUsers(Long roleId, Long[] userIds)
+    {
+        // 新增用户与角色管理
+        List<SysUserRole> list = new ArrayList<SysUserRole>();
+        for (Long userId : userIds)
+        {
+            SysUserRole ur = new SysUserRole();
+            ur.setUserId(userId);
+            ur.setRoleId(roleId);
+            list.add(ur);
+        }
+        return userRoleMapper.batchUserRole(list);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserOnlineServiceImpl.java
similarity index 87%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserOnlineServiceImpl.java
index 347837bc..89f165b9 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserOnlineServiceImpl.java
@@ -1,96 +1,96 @@
-package com.ruoyi.system.service.impl;
-
-import org.springframework.stereotype.Service;
-import com.ruoyi.common.core.domain.model.LoginUser;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.system.domain.SysUserOnline;
-import com.ruoyi.system.service.ISysUserOnlineService;
-
-/**
- * 在线用户 服务层处理
- * 
- * @author ruoyi
- */
-@Service
-public class SysUserOnlineServiceImpl implements ISysUserOnlineService
-{
-    /**
-     * 通过登录地址查询信息
-     * 
-     * @param ipaddr 登录地址
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    @Override
-    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user)
-    {
-        if (StringUtils.equals(ipaddr, user.getIpaddr()))
-        {
-            return loginUserToUserOnline(user);
-        }
-        return null;
-    }
-
-    /**
-     * 通过用户名称查询信息
-     * 
-     * @param userName 用户名称
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    @Override
-    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user)
-    {
-        if (StringUtils.equals(userName, user.getUsername()))
-        {
-            return loginUserToUserOnline(user);
-        }
-        return null;
-    }
-
-    /**
-     * 通过登录地址/用户名称查询信息
-     * 
-     * @param ipaddr 登录地址
-     * @param userName 用户名称
-     * @param user 用户信息
-     * @return 在线用户信息
-     */
-    @Override
-    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user)
-    {
-        if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
-        {
-            return loginUserToUserOnline(user);
-        }
-        return null;
-    }
-
-    /**
-     * 设置在线用户信息
-     * 
-     * @param user 用户信息
-     * @return 在线用户
-     */
-    @Override
-    public SysUserOnline loginUserToUserOnline(LoginUser user)
-    {
-        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser()))
-        {
-            return null;
-        }
-        SysUserOnline sysUserOnline = new SysUserOnline();
-        sysUserOnline.setTokenId(user.getToken());
-        sysUserOnline.setUserName(user.getUsername());
-        sysUserOnline.setIpaddr(user.getIpaddr());
-        sysUserOnline.setLoginLocation(user.getLoginLocation());
-        sysUserOnline.setBrowser(user.getBrowser());
-        sysUserOnline.setOs(user.getOs());
-        sysUserOnline.setLoginTime(user.getLoginTime());
-        if (StringUtils.isNotNull(user.getUser().getDept()))
-        {
-            sysUserOnline.setDeptName(user.getUser().getDept().getDeptName());
-        }
-        return sysUserOnline;
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import org.springframework.stereotype.Service;
+import com.acupuncture.common.core.domain.model.LoginUser;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.system.domain.SysUserOnline;
+import com.acupuncture.system.service.ISysUserOnlineService;
+
+/**
+ * 在线用户 服务层处理
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysUserOnlineServiceImpl implements ISysUserOnlineService
+{
+    /**
+     * 通过登录地址查询信息
+     * 
+     * @param ipaddr 登录地址
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    @Override
+    public SysUserOnline selectOnlineByIpaddr(String ipaddr, LoginUser user)
+    {
+        if (StringUtils.equals(ipaddr, user.getIpaddr()))
+        {
+            return loginUserToUserOnline(user);
+        }
+        return null;
+    }
+
+    /**
+     * 通过用户名称查询信息
+     * 
+     * @param userName 用户名称
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    @Override
+    public SysUserOnline selectOnlineByUserName(String userName, LoginUser user)
+    {
+        if (StringUtils.equals(userName, user.getUsername()))
+        {
+            return loginUserToUserOnline(user);
+        }
+        return null;
+    }
+
+    /**
+     * 通过登录地址/用户名称查询信息
+     * 
+     * @param ipaddr 登录地址
+     * @param userName 用户名称
+     * @param user 用户信息
+     * @return 在线用户信息
+     */
+    @Override
+    public SysUserOnline selectOnlineByInfo(String ipaddr, String userName, LoginUser user)
+    {
+        if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername()))
+        {
+            return loginUserToUserOnline(user);
+        }
+        return null;
+    }
+
+    /**
+     * 设置在线用户信息
+     * 
+     * @param user 用户信息
+     * @return 在线用户
+     */
+    @Override
+    public SysUserOnline loginUserToUserOnline(LoginUser user)
+    {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUser()))
+        {
+            return null;
+        }
+        SysUserOnline sysUserOnline = new SysUserOnline();
+        sysUserOnline.setTokenId(user.getToken());
+        sysUserOnline.setUserName(user.getUsername());
+        sysUserOnline.setIpaddr(user.getIpaddr());
+        sysUserOnline.setLoginLocation(user.getLoginLocation());
+        sysUserOnline.setBrowser(user.getBrowser());
+        sysUserOnline.setOs(user.getOs());
+        sysUserOnline.setLoginTime(user.getLoginTime());
+        if (StringUtils.isNotNull(user.getUser().getDept()))
+        {
+            sysUserOnline.setDeptName(user.getUser().getDept().getDeptName());
+        }
+        return sysUserOnline;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserServiceImpl.java
similarity index 90%
rename from ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
rename to acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserServiceImpl.java
index 3f4dba2a..d387030f 100644
--- a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
+++ b/acupuncture-system/src/main/java/com/acupuncture/system/service/impl/SysUserServiceImpl.java
@@ -1,550 +1,550 @@
-package com.ruoyi.system.service.impl;
-
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-import javax.validation.Validator;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.stereotype.Service;
-import org.springframework.transaction.annotation.Transactional;
-import org.springframework.util.CollectionUtils;
-import com.ruoyi.common.annotation.DataScope;
-import com.ruoyi.common.constant.UserConstants;
-import com.ruoyi.common.core.domain.entity.SysRole;
-import com.ruoyi.common.core.domain.entity.SysUser;
-import com.ruoyi.common.exception.ServiceException;
-import com.ruoyi.common.utils.SecurityUtils;
-import com.ruoyi.common.utils.StringUtils;
-import com.ruoyi.common.utils.bean.BeanValidators;
-import com.ruoyi.common.utils.spring.SpringUtils;
-import com.ruoyi.system.domain.SysPost;
-import com.ruoyi.system.domain.SysUserPost;
-import com.ruoyi.system.domain.SysUserRole;
-import com.ruoyi.system.mapper.SysPostMapper;
-import com.ruoyi.system.mapper.SysRoleMapper;
-import com.ruoyi.system.mapper.SysUserMapper;
-import com.ruoyi.system.mapper.SysUserPostMapper;
-import com.ruoyi.system.mapper.SysUserRoleMapper;
-import com.ruoyi.system.service.ISysConfigService;
-import com.ruoyi.system.service.ISysDeptService;
-import com.ruoyi.system.service.ISysUserService;
-
-/**
- * 用户 业务层处理
- * 
- * @author ruoyi
- */
-@Service
-public class SysUserServiceImpl implements ISysUserService
-{
-    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);
-
-    @Autowired
-    private SysUserMapper userMapper;
-
-    @Autowired
-    private SysRoleMapper roleMapper;
-
-    @Autowired
-    private SysPostMapper postMapper;
-
-    @Autowired
-    private SysUserRoleMapper userRoleMapper;
-
-    @Autowired
-    private SysUserPostMapper userPostMapper;
-
-    @Autowired
-    private ISysConfigService configService;
-
-    @Autowired
-    private ISysDeptService deptService;
-
-    @Autowired
-    protected Validator validator;
-
-    /**
-     * 根据条件分页查询用户列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    @Override
-    @DataScope(deptAlias = "d", userAlias = "u")
-    public List<SysUser> selectUserList(SysUser user)
-    {
-        return userMapper.selectUserList(user);
-    }
-
-    /**
-     * 根据条件分页查询已分配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    @Override
-    @DataScope(deptAlias = "d", userAlias = "u")
-    public List<SysUser> selectAllocatedList(SysUser user)
-    {
-        return userMapper.selectAllocatedList(user);
-    }
-
-    /**
-     * 根据条件分页查询未分配用户角色列表
-     * 
-     * @param user 用户信息
-     * @return 用户信息集合信息
-     */
-    @Override
-    @DataScope(deptAlias = "d", userAlias = "u")
-    public List<SysUser> selectUnallocatedList(SysUser user)
-    {
-        return userMapper.selectUnallocatedList(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);
-        if (CollectionUtils.isEmpty(list))
-        {
-            return StringUtils.EMPTY;
-        }
-        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
-    }
-
-    /**
-     * 查询用户所属岗位组
-     * 
-     * @param userName 用户名
-     * @return 结果
-     */
-    @Override
-    public String selectUserPostGroup(String userName)
-    {
-        List<SysPost> list = postMapper.selectPostsByUserName(userName);
-        if (CollectionUtils.isEmpty(list))
-        {
-            return StringUtils.EMPTY;
-        }
-        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
-    }
-
-    /**
-     * 校验用户名称是否唯一
-     * 
-     * @param user 用户信息
-     * @return 结果
-     */
-    @Override
-    public boolean checkUserNameUnique(SysUser user)
-    {
-        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
-        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
-        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
-        {
-            return UserConstants.NOT_UNIQUE;
-        }
-        return UserConstants.UNIQUE;
-    }
-
-    /**
-     * 校验手机号码是否唯一
-     *
-     * @param user 用户信息
-     * @return
-     */
-    @Override
-    public boolean 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 boolean 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 用户信息
-     */
-    @Override
-    public void checkUserAllowed(SysUser user)
-    {
-        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
-        {
-            throw new ServiceException("不允许操作超级管理员用户");
-        }
-    }
-
-    /**
-     * 校验用户是否有数据权限
-     * 
-     * @param userId 用户id
-     */
-    @Override
-    public void checkUserDataScope(Long userId)
-    {
-        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
-        {
-            SysUser user = new SysUser();
-            user.setUserId(userId);
-            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
-            if (StringUtils.isEmpty(users))
-            {
-                throw new ServiceException("没有权限访问用户数据!");
-            }
-        }
-    }
-
-    /**
-     * 新增保存用户信息
-     * 
-     * @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
-    public boolean registerUser(SysUser user)
-    {
-        return userMapper.insertUser(user) > 0;
-    }
-
-    /**
-     * 修改保存用户信息
-     * 
-     * @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 userId 用户ID
-     * @param roleIds 角色组
-     */
-    @Override
-    @Transactional
-    public void insertUserAuth(Long userId, Long[] roleIds)
-    {
-        userRoleMapper.deleteUserRoleByUserId(userId);
-        insertUserRole(userId, roleIds);
-    }
-
-    /**
-     * 修改用户状态
-     * 
-     * @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 userName 用户名
-     * @param avatar 头像地址
-     * @return 结果
-     */
-    @Override
-    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)
-    {
-        this.insertUserRole(user.getUserId(), user.getRoleIds());
-    }
-
-    /**
-     * 新增用户岗位信息
-     * 
-     * @param user 用户对象
-     */
-    public void insertUserPost(SysUser user)
-    {
-        Long[] posts = user.getPostIds();
-        if (StringUtils.isNotEmpty(posts))
-        {
-            // 新增用户与岗位管理
-            List<SysUserPost> list = new ArrayList<SysUserPost>(posts.length);
-            for (Long postId : posts)
-            {
-                SysUserPost up = new SysUserPost();
-                up.setUserId(user.getUserId());
-                up.setPostId(postId);
-                list.add(up);
-            }
-            userPostMapper.batchUserPost(list);
-        }
-    }
-
-    /**
-     * 新增用户角色信息
-     * 
-     * @param userId 用户ID
-     * @param roleIds 角色组
-     */
-    public void insertUserRole(Long userId, Long[] roleIds)
-    {
-        if (StringUtils.isNotEmpty(roleIds))
-        {
-            // 新增用户与角色管理
-            List<SysUserRole> list = new ArrayList<SysUserRole>(roleIds.length);
-            for (Long roleId : roleIds)
-            {
-                SysUserRole ur = new SysUserRole();
-                ur.setUserId(userId);
-                ur.setRoleId(roleId);
-                list.add(ur);
-            }
-            userRoleMapper.batchUserRole(list);
-        }
-    }
-
-    /**
-     * 通过用户ID删除用户
-     * 
-     * @param userId 用户ID
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public int deleteUserById(Long userId)
-    {
-        // 删除用户与角色关联
-        userRoleMapper.deleteUserRoleByUserId(userId);
-        // 删除用户与岗位表
-        userPostMapper.deleteUserPostByUserId(userId);
-        return userMapper.deleteUserById(userId);
-    }
-
-    /**
-     * 批量删除用户信息
-     * 
-     * @param userIds 需要删除的用户ID
-     * @return 结果
-     */
-    @Override
-    @Transactional
-    public int deleteUserByIds(Long[] userIds)
-    {
-        for (Long userId : userIds)
-        {
-            checkUserAllowed(new SysUser(userId));
-            checkUserDataScope(userId);
-        }
-        // 删除用户与角色关联
-        userRoleMapper.deleteUserRole(userIds);
-        // 删除用户与岗位关联
-        userPostMapper.deleteUserPost(userIds);
-        return userMapper.deleteUserByIds(userIds);
-    }
-
-    /**
-     * 导入用户数据
-     * 
-     * @param userList 用户数据列表
-     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
-     * @param operName 操作用户
-     * @return 结果
-     */
-    @Override
-    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)
-    {
-        if (StringUtils.isNull(userList) || userList.size() == 0)
-        {
-            throw new ServiceException("导入用户数据不能为空!");
-        }
-        int successNum = 0;
-        int failureNum = 0;
-        StringBuilder successMsg = new StringBuilder();
-        StringBuilder failureMsg = new StringBuilder();
-        for (SysUser user : userList)
-        {
-            try
-            {
-                // 验证是否存在这个用户
-                SysUser u = userMapper.selectUserByUserName(user.getUserName());
-                if (StringUtils.isNull(u))
-                {
-                    BeanValidators.validateWithException(validator, user);
-                    deptService.checkDeptDataScope(user.getDeptId());
-                    String password = configService.selectConfigByKey("sys.user.initPassword");
-                    user.setPassword(SecurityUtils.encryptPassword(password));
-                    user.setCreateBy(operName);
-                    userMapper.insertUser(user);
-                    successNum++;
-                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
-                }
-                else if (isUpdateSupport)
-                {
-                    BeanValidators.validateWithException(validator, user);
-                    checkUserAllowed(u);
-                    checkUserDataScope(u.getUserId());
-                    deptService.checkDeptDataScope(user.getDeptId());
-                    user.setUserId(u.getUserId());
-                    user.setUpdateBy(operName);
-                    userMapper.updateUser(user);
-                    successNum++;
-                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
-                }
-                else
-                {
-                    failureNum++;
-                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
-                }
-            }
-            catch (Exception e)
-            {
-                failureNum++;
-                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:";
-                failureMsg.append(msg + e.getMessage());
-                log.error(msg, e);
-            }
-        }
-        if (failureNum > 0)
-        {
-            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
-            throw new ServiceException(failureMsg.toString());
-        }
-        else
-        {
-            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
-        }
-        return successMsg.toString();
-    }
-}
+package com.acupuncture.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.validation.Validator;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.CollectionUtils;
+import com.acupuncture.common.annotation.DataScope;
+import com.acupuncture.common.constant.UserConstants;
+import com.acupuncture.common.core.domain.entity.SysRole;
+import com.acupuncture.common.core.domain.entity.SysUser;
+import com.acupuncture.common.exception.ServiceException;
+import com.acupuncture.common.utils.SecurityUtils;
+import com.acupuncture.common.utils.StringUtils;
+import com.acupuncture.common.utils.bean.BeanValidators;
+import com.acupuncture.common.utils.spring.SpringUtils;
+import com.acupuncture.system.domain.SysPost;
+import com.acupuncture.system.domain.SysUserPost;
+import com.acupuncture.system.domain.SysUserRole;
+import com.acupuncture.system.mapper.SysPostMapper;
+import com.acupuncture.system.mapper.SysRoleMapper;
+import com.acupuncture.system.mapper.SysUserMapper;
+import com.acupuncture.system.mapper.SysUserPostMapper;
+import com.acupuncture.system.mapper.SysUserRoleMapper;
+import com.acupuncture.system.service.ISysConfigService;
+import com.acupuncture.system.service.ISysDeptService;
+import com.acupuncture.system.service.ISysUserService;
+
+/**
+ * 用户 业务层处理
+ * 
+ * @author acupuncture
+ */
+@Service
+public class SysUserServiceImpl implements ISysUserService
+{
+    private static final Logger log = LoggerFactory.getLogger(SysUserServiceImpl.class);
+
+    @Autowired
+    private SysUserMapper userMapper;
+
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    @Autowired
+    private SysPostMapper postMapper;
+
+    @Autowired
+    private SysUserRoleMapper userRoleMapper;
+
+    @Autowired
+    private SysUserPostMapper userPostMapper;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @Autowired
+    protected Validator validator;
+
+    /**
+     * 根据条件分页查询用户列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<SysUser> selectUserList(SysUser user)
+    {
+        return userMapper.selectUserList(user);
+    }
+
+    /**
+     * 根据条件分页查询已分配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<SysUser> selectAllocatedList(SysUser user)
+    {
+        return userMapper.selectAllocatedList(user);
+    }
+
+    /**
+     * 根据条件分页查询未分配用户角色列表
+     * 
+     * @param user 用户信息
+     * @return 用户信息集合信息
+     */
+    @Override
+    @DataScope(deptAlias = "d", userAlias = "u")
+    public List<SysUser> selectUnallocatedList(SysUser user)
+    {
+        return userMapper.selectUnallocatedList(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);
+        if (CollectionUtils.isEmpty(list))
+        {
+            return StringUtils.EMPTY;
+        }
+        return list.stream().map(SysRole::getRoleName).collect(Collectors.joining(","));
+    }
+
+    /**
+     * 查询用户所属岗位组
+     * 
+     * @param userName 用户名
+     * @return 结果
+     */
+    @Override
+    public String selectUserPostGroup(String userName)
+    {
+        List<SysPost> list = postMapper.selectPostsByUserName(userName);
+        if (CollectionUtils.isEmpty(list))
+        {
+            return StringUtils.EMPTY;
+        }
+        return list.stream().map(SysPost::getPostName).collect(Collectors.joining(","));
+    }
+
+    /**
+     * 校验用户名称是否唯一
+     * 
+     * @param user 用户信息
+     * @return 结果
+     */
+    @Override
+    public boolean checkUserNameUnique(SysUser user)
+    {
+        Long userId = StringUtils.isNull(user.getUserId()) ? -1L : user.getUserId();
+        SysUser info = userMapper.checkUserNameUnique(user.getUserName());
+        if (StringUtils.isNotNull(info) && info.getUserId().longValue() != userId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 校验手机号码是否唯一
+     *
+     * @param user 用户信息
+     * @return
+     */
+    @Override
+    public boolean 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 boolean 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 用户信息
+     */
+    @Override
+    public void checkUserAllowed(SysUser user)
+    {
+        if (StringUtils.isNotNull(user.getUserId()) && user.isAdmin())
+        {
+            throw new ServiceException("不允许操作超级管理员用户");
+        }
+    }
+
+    /**
+     * 校验用户是否有数据权限
+     * 
+     * @param userId 用户id
+     */
+    @Override
+    public void checkUserDataScope(Long userId)
+    {
+        if (!SysUser.isAdmin(SecurityUtils.getUserId()))
+        {
+            SysUser user = new SysUser();
+            user.setUserId(userId);
+            List<SysUser> users = SpringUtils.getAopProxy(this).selectUserList(user);
+            if (StringUtils.isEmpty(users))
+            {
+                throw new ServiceException("没有权限访问用户数据!");
+            }
+        }
+    }
+
+    /**
+     * 新增保存用户信息
+     * 
+     * @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
+    public boolean registerUser(SysUser user)
+    {
+        return userMapper.insertUser(user) > 0;
+    }
+
+    /**
+     * 修改保存用户信息
+     * 
+     * @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 userId 用户ID
+     * @param roleIds 角色组
+     */
+    @Override
+    @Transactional
+    public void insertUserAuth(Long userId, Long[] roleIds)
+    {
+        userRoleMapper.deleteUserRoleByUserId(userId);
+        insertUserRole(userId, roleIds);
+    }
+
+    /**
+     * 修改用户状态
+     * 
+     * @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 userName 用户名
+     * @param avatar 头像地址
+     * @return 结果
+     */
+    @Override
+    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)
+    {
+        this.insertUserRole(user.getUserId(), user.getRoleIds());
+    }
+
+    /**
+     * 新增用户岗位信息
+     * 
+     * @param user 用户对象
+     */
+    public void insertUserPost(SysUser user)
+    {
+        Long[] posts = user.getPostIds();
+        if (StringUtils.isNotEmpty(posts))
+        {
+            // 新增用户与岗位管理
+            List<SysUserPost> list = new ArrayList<SysUserPost>(posts.length);
+            for (Long postId : posts)
+            {
+                SysUserPost up = new SysUserPost();
+                up.setUserId(user.getUserId());
+                up.setPostId(postId);
+                list.add(up);
+            }
+            userPostMapper.batchUserPost(list);
+        }
+    }
+
+    /**
+     * 新增用户角色信息
+     * 
+     * @param userId 用户ID
+     * @param roleIds 角色组
+     */
+    public void insertUserRole(Long userId, Long[] roleIds)
+    {
+        if (StringUtils.isNotEmpty(roleIds))
+        {
+            // 新增用户与角色管理
+            List<SysUserRole> list = new ArrayList<SysUserRole>(roleIds.length);
+            for (Long roleId : roleIds)
+            {
+                SysUserRole ur = new SysUserRole();
+                ur.setUserId(userId);
+                ur.setRoleId(roleId);
+                list.add(ur);
+            }
+            userRoleMapper.batchUserRole(list);
+        }
+    }
+
+    /**
+     * 通过用户ID删除用户
+     * 
+     * @param userId 用户ID
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public int deleteUserById(Long userId)
+    {
+        // 删除用户与角色关联
+        userRoleMapper.deleteUserRoleByUserId(userId);
+        // 删除用户与岗位表
+        userPostMapper.deleteUserPostByUserId(userId);
+        return userMapper.deleteUserById(userId);
+    }
+
+    /**
+     * 批量删除用户信息
+     * 
+     * @param userIds 需要删除的用户ID
+     * @return 结果
+     */
+    @Override
+    @Transactional
+    public int deleteUserByIds(Long[] userIds)
+    {
+        for (Long userId : userIds)
+        {
+            checkUserAllowed(new SysUser(userId));
+            checkUserDataScope(userId);
+        }
+        // 删除用户与角色关联
+        userRoleMapper.deleteUserRole(userIds);
+        // 删除用户与岗位关联
+        userPostMapper.deleteUserPost(userIds);
+        return userMapper.deleteUserByIds(userIds);
+    }
+
+    /**
+     * 导入用户数据
+     * 
+     * @param userList 用户数据列表
+     * @param isUpdateSupport 是否更新支持,如果已存在,则进行更新数据
+     * @param operName 操作用户
+     * @return 结果
+     */
+    @Override
+    public String importUser(List<SysUser> userList, Boolean isUpdateSupport, String operName)
+    {
+        if (StringUtils.isNull(userList) || userList.size() == 0)
+        {
+            throw new ServiceException("导入用户数据不能为空!");
+        }
+        int successNum = 0;
+        int failureNum = 0;
+        StringBuilder successMsg = new StringBuilder();
+        StringBuilder failureMsg = new StringBuilder();
+        for (SysUser user : userList)
+        {
+            try
+            {
+                // 验证是否存在这个用户
+                SysUser u = userMapper.selectUserByUserName(user.getUserName());
+                if (StringUtils.isNull(u))
+                {
+                    BeanValidators.validateWithException(validator, user);
+                    deptService.checkDeptDataScope(user.getDeptId());
+                    String password = configService.selectConfigByKey("sys.user.initPassword");
+                    user.setPassword(SecurityUtils.encryptPassword(password));
+                    user.setCreateBy(operName);
+                    userMapper.insertUser(user);
+                    successNum++;
+                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 导入成功");
+                }
+                else if (isUpdateSupport)
+                {
+                    BeanValidators.validateWithException(validator, user);
+                    checkUserAllowed(u);
+                    checkUserDataScope(u.getUserId());
+                    deptService.checkDeptDataScope(user.getDeptId());
+                    user.setUserId(u.getUserId());
+                    user.setUpdateBy(operName);
+                    userMapper.updateUser(user);
+                    successNum++;
+                    successMsg.append("<br/>" + successNum + "、账号 " + user.getUserName() + " 更新成功");
+                }
+                else
+                {
+                    failureNum++;
+                    failureMsg.append("<br/>" + failureNum + "、账号 " + user.getUserName() + " 已存在");
+                }
+            }
+            catch (Exception e)
+            {
+                failureNum++;
+                String msg = "<br/>" + failureNum + "、账号 " + user.getUserName() + " 导入失败:";
+                failureMsg.append(msg + e.getMessage());
+                log.error(msg, e);
+            }
+        }
+        if (failureNum > 0)
+        {
+            failureMsg.insert(0, "很抱歉,导入失败!共 " + failureNum + " 条数据格式不正确,错误如下:");
+            throw new ServiceException(failureMsg.toString());
+        }
+        else
+        {
+            successMsg.insert(0, "恭喜您,数据已全部导入成功!共 " + successNum + " 条,数据如下:");
+        }
+        return successMsg.toString();
+    }
+}
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysConfigMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysConfigMapper.xml
index f4295aa0..cf277b27 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysConfigMapper.xml
@@ -1,117 +1,117 @@
-<?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.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="selectConfigById" parameterType="Long" resultMap="SysConfigResult">
-        <include refid="selectConfigVo"/>
-        where config_id = #{configId}
-    </select>
-	
-    <select id="checkConfigKeyUnique" parameterType="String" resultMap="SysConfigResult">
-        <include refid="selectConfigVo"/>
-        where config_key = #{configKey} limit 1
-    </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>
-    
-    <delete id="deleteConfigByIds" parameterType="Long">
-        delete from sys_config where config_id in 
-        <foreach item="configId" collection="array" open="(" separator="," close=")">
-        	#{configId}
-        </foreach>
-    </delete>
-    
+<?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.acupuncture.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="selectConfigById" parameterType="Long" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        where config_id = #{configId}
+    </select>
+	
+    <select id="checkConfigKeyUnique" parameterType="String" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        where config_key = #{configKey} limit 1
+    </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>
+    
+    <delete id="deleteConfigByIds" parameterType="Long">
+        delete from sys_config where config_id in 
+        <foreach item="configId" collection="array" open="(" separator="," close=")">
+        	#{configId}
+        </foreach>
+    </delete>
+    
 </mapper>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysDeptMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysDeptMapper.xml
index 7a6fc158..0401beca 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -1,159 +1,159 @@
-<?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.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="deptId != null and deptId != 0">
-			AND dept_id = #{deptId}
-		</if>
-        <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>
-		<!-- 数据范围过滤 -->
-		${params.dataScope}
-		order by d.parent_id, d.order_num
-    </select>
-    
-    <select id="selectDeptListByRoleId" resultType="Long">
-		select d.dept_id
-		from sys_dept d
-            left join sys_role_dept rd on d.dept_id = rd.dept_id
-        where rd.role_id = #{roleId}
-            <if test="deptCheckStrictly">
-              and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
-            </if>
-		order by d.parent_id, d.order_num
-	</select>
-    
-    <select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
-		select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,
-			(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
-		from sys_dept d
-		where d.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} limit 1
-	</select>
-	
-	<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
-		select * from sys_dept where find_in_set(#{deptId}, ancestors)
-	</select>
-	
-	<select id="selectNormalChildrenDeptById" parameterType="Long" resultType="int">
-		select count(*) from sys_dept where status = 0 and del_flag = '0' and find_in_set(#{deptId}, ancestors)
-	</select>
-	
-	<select id="checkDeptNameUnique" resultMap="SysDeptResult">
-	    <include refid="selectDeptVo"/>
-		where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1
-	</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">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">#{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">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="updateDeptStatusNormal" parameterType="Long">
- 	    update sys_dept set status = '0' where dept_id in 
- 	    <foreach collection="array" item="deptId" open="(" separator="," close=")">
-        	#{deptId}
-        </foreach>
-	</update>
-	
-	<delete id="deleteDeptById" parameterType="Long">
-		update sys_dept set del_flag = '2' where dept_id = #{deptId}
-	</delete>
-
+<?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.acupuncture.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="deptId != null and deptId != 0">
+			AND dept_id = #{deptId}
+		</if>
+        <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>
+		<!-- 数据范围过滤 -->
+		${params.dataScope}
+		order by d.parent_id, d.order_num
+    </select>
+    
+    <select id="selectDeptListByRoleId" resultType="Long">
+		select d.dept_id
+		from sys_dept d
+            left join sys_role_dept rd on d.dept_id = rd.dept_id
+        where rd.role_id = #{roleId}
+            <if test="deptCheckStrictly">
+              and d.dept_id not in (select d.parent_id from sys_dept d inner join sys_role_dept rd on d.dept_id = rd.dept_id and rd.role_id = #{roleId})
+            </if>
+		order by d.parent_id, d.order_num
+	</select>
+    
+    <select id="selectDeptById" parameterType="Long" resultMap="SysDeptResult">
+		select d.dept_id, d.parent_id, d.ancestors, d.dept_name, d.order_num, d.leader, d.phone, d.email, d.status,
+			(select dept_name from sys_dept where dept_id = d.parent_id) parent_name
+		from sys_dept d
+		where d.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} limit 1
+	</select>
+	
+	<select id="selectChildrenDeptById" parameterType="Long" resultMap="SysDeptResult">
+		select * from sys_dept where find_in_set(#{deptId}, ancestors)
+	</select>
+	
+	<select id="selectNormalChildrenDeptById" parameterType="Long" resultType="int">
+		select count(*) from sys_dept where status = 0 and del_flag = '0' and find_in_set(#{deptId}, ancestors)
+	</select>
+	
+	<select id="checkDeptNameUnique" resultMap="SysDeptResult">
+	    <include refid="selectDeptVo"/>
+		where dept_name=#{deptName} and parent_id = #{parentId} and del_flag = '0' limit 1
+	</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">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">#{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">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="updateDeptStatusNormal" parameterType="Long">
+ 	    update sys_dept set status = '0' where dept_id in 
+ 	    <foreach collection="array" item="deptId" open="(" separator="," close=")">
+        	#{deptId}
+        </foreach>
+	</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-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysDictDataMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysDictDataMapper.xml
index c5e1da9d..5a30097c 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysDictDataMapper.xml
@@ -1,124 +1,124 @@
-<?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.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>
-		order by dict_sort asc
-	</select>
-	
-	<select id="selectDictDataByType" parameterType="String" 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>
- 	
- 	<delete id="deleteDictDataByIds" parameterType="Long">
- 		delete from sys_dict_data where dict_code in
- 		<foreach collection="array" item="dictCode" open="(" separator="," close=")">
- 			#{dictCode}
-        </foreach> 
- 	</delete>
-	
-	<update id="updateDictData" parameterType="SysDictData">
- 		update sys_dict_data
- 		<set>
- 			<if test="dictSort != null">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">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">#{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>
-	
+<?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.acupuncture.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>
+		order by dict_sort asc
+	</select>
+	
+	<select id="selectDictDataByType" parameterType="String" 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>
+ 	
+ 	<delete id="deleteDictDataByIds" parameterType="Long">
+ 		delete from sys_dict_data where dict_code in
+ 		<foreach collection="array" item="dictCode" open="(" separator="," close=")">
+ 			#{dictCode}
+        </foreach> 
+ 	</delete>
+	
+	<update id="updateDictData" parameterType="SysDictData">
+ 		update sys_dict_data
+ 		<set>
+ 			<if test="dictSort != null">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">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">#{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-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
similarity index 95%
rename from ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
index 554db544..27ed3571 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
@@ -1,105 +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.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} limit 1
-	</select>
-	
-	<delete id="deleteDictTypeById" parameterType="Long">
- 		delete from sys_dict_type where dict_id = #{dictId}
- 	</delete>
- 	
- 	<delete id="deleteDictTypeByIds" parameterType="Long">
- 		delete from sys_dict_type where dict_id in
- 		<foreach collection="array" item="dictId" open="(" separator="," close=")">
- 			#{dictId}
-        </foreach> 
- 	</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>
-	
+<?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.acupuncture.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} limit 1
+	</select>
+	
+	<delete id="deleteDictTypeById" parameterType="Long">
+ 		delete from sys_dict_type where dict_id = #{dictId}
+ 	</delete>
+ 	
+ 	<delete id="deleteDictTypeByIds" parameterType="Long">
+ 		delete from sys_dict_type where dict_id in
+ 		<foreach collection="array" item="dictId" open="(" separator="," close=")">
+ 			#{dictId}
+        </foreach> 
+ 	</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-system/src/main/resources/mapper/system/SysLogininforMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysLogininforMapper.xml
similarity index 94%
rename from ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysLogininforMapper.xml
index acfc11a9..66d0e5d4 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysLogininforMapper.xml
@@ -1,57 +1,57 @@
-<?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.system.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 login_time &gt;= #{params.beginTime}
-			</if>
-			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
-				AND login_time &lt;= #{params.endTime}
-			</if>
-		</where>
-		order by info_id desc
-	</select>
-	
-	<delete id="deleteLogininforByIds" parameterType="Long">
- 		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>
-    
+<?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.acupuncture.system.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 login_time &gt;= #{params.beginTime}
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
+				AND login_time &lt;= #{params.endTime}
+			</if>
+		</where>
+		order by info_id desc
+	</select>
+	
+	<delete id="deleteLogininforByIds" parameterType="Long">
+ 		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-system/src/main/resources/mapper/system/SysMenuMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysMenuMapper.xml
similarity index 97%
rename from ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysMenuMapper.xml
index e6be3aef..6b01b942 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -1,206 +1,206 @@
-<?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.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="query"          column="query"          />
-		<result property="routeName"      column="route_name"     />
-		<result property="isFrame"        column="is_frame"       />
-		<result property="isCache"        column="is_cache"       />
-		<result property="menuType"       column="menu_type"      />
-		<result property="visible"        column="visible"        />
-		<result property="status"         column="status"         />
-		<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, `query`, route_name, is_frame, is_cache, menu_type, visible, status, 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>
-			<if test="status != null and status != ''">
-				AND status = #{status}
-			</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.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
-		from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
-		order by m.parent_id, m.order_num
-	</select>
-	
-	<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
-		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
-		from sys_menu m
-		left join sys_role_menu rm on m.menu_id = rm.menu_id
-		left join sys_user_role ur on rm.role_id = ur.role_id
-		left join sys_role ro on ur.role_id = ro.role_id
-		where ur.user_id = #{params.userId}
-		<if test="menuName != null and menuName != ''">
-            AND m.menu_name like concat('%', #{menuName}, '%')
-		</if>
-		<if test="visible != null and visible != ''">
-            AND m.visible = #{visible}
-		</if>
-		<if test="status != null and status != ''">
-            AND m.status = #{status}
-		</if>
-		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.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
-		from sys_menu m
-			 left join sys_role_menu rm on m.menu_id = rm.menu_id
-			 left join sys_user_role 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.status = 0  AND ro.status = 0
-		order by m.parent_id, m.order_num
-	</select>
-	
-	<select id="selectMenuListByRoleId" resultType="Long">
-		select m.menu_id
-		from sys_menu m
-            left join sys_role_menu rm on m.menu_id = rm.menu_id
-        where rm.role_id = #{roleId}
-            <if test="menuCheckStrictly">
-              and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId})
-            </if>
-		order by m.parent_id, m.order_num
-	</select>
-	
-	<select id="selectMenuPerms" resultType="String">
-		select distinct m.perms
-		from sys_menu m
-			 left join sys_role_menu rm on m.menu_id = rm.menu_id
-			 left join sys_user_role 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
-			 left join sys_role r on r.role_id = ur.role_id
-		where m.status = '0' and r.status = '0' and ur.user_id = #{userId}
-	</select>
-	
-	<select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">
-		select distinct m.perms
-		from sys_menu m
-			 left join sys_role_menu rm on m.menu_id = rm.menu_id
-		where m.status = '0' and rm.role_id = #{roleId}
-	</select>
-	
-	<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} limit 1
-	</select>
-	
-	<update id="updateMenu" parameterType="SysMenu">
-		update sys_menu
-		<set>
-			<if test="menuName != null and menuName != ''">menu_name = #{menuName},</if>
-			<if test="parentId != null">parent_id = #{parentId},</if>
-			<if test="orderNum != null">order_num = #{orderNum},</if>
-			<if test="path != null and path != ''">path = #{path},</if>
-			<if test="component != null">component = #{component},</if>
-			<if test="query != null">`query` = #{query},</if>
-			<if test="routeName != null">route_name = #{routeName},</if>
-			<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
-			<if test="isCache != null and isCache != ''">is_cache = #{isCache},</if>
-			<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
-			<if test="visible != null">visible = #{visible},</if>
-			<if test="status != null">status = #{status},</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">order_num,</if>
-		<if test="path != null and path != ''">path,</if>
-		<if test="component != null and component != ''">component,</if>
-		<if test="query != null and query != ''">`query`,</if>
-		<if test="routeName != null">route_name,</if>
-		<if test="isFrame != null and isFrame != ''">is_frame,</if>
-		<if test="isCache != null and isCache != ''">is_cache,</if>
-		<if test="menuType != null and menuType != ''">menu_type,</if>
-		<if test="visible != null">visible,</if>
-		<if test="status != null">status,</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">#{orderNum},</if>
-		<if test="path != null and path != ''">#{path},</if>
-		<if test="component != null and component != ''">#{component},</if>
-		<if test="query != null and query != ''">#{query},</if>
-		<if test="routeName != null">#{routeName},</if>
-		<if test="isFrame != null and isFrame != ''">#{isFrame},</if>
-		<if test="isCache != null and isCache != ''">#{isCache},</if>
-		<if test="menuType != null and menuType != ''">#{menuType},</if>
-		<if test="visible != null">#{visible},</if>
-		<if test="status != null">#{status},</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>
-
+<?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.acupuncture.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="query"          column="query"          />
+		<result property="routeName"      column="route_name"     />
+		<result property="isFrame"        column="is_frame"       />
+		<result property="isCache"        column="is_cache"       />
+		<result property="menuType"       column="menu_type"      />
+		<result property="visible"        column="visible"        />
+		<result property="status"         column="status"         />
+		<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, `query`, route_name, is_frame, is_cache, menu_type, visible, status, 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>
+			<if test="status != null and status != ''">
+				AND status = #{status}
+			</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.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
+		from sys_menu m where m.menu_type in ('M', 'C') and m.status = 0
+		order by m.parent_id, m.order_num
+	</select>
+	
+	<select id="selectMenuListByUserId" parameterType="SysMenu" resultMap="SysMenuResult">
+		select distinct m.menu_id, m.parent_id, m.menu_name, m.path, m.component, m.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
+		from sys_menu m
+		left join sys_role_menu rm on m.menu_id = rm.menu_id
+		left join sys_user_role ur on rm.role_id = ur.role_id
+		left join sys_role ro on ur.role_id = ro.role_id
+		where ur.user_id = #{params.userId}
+		<if test="menuName != null and menuName != ''">
+            AND m.menu_name like concat('%', #{menuName}, '%')
+		</if>
+		<if test="visible != null and visible != ''">
+            AND m.visible = #{visible}
+		</if>
+		<if test="status != null and status != ''">
+            AND m.status = #{status}
+		</if>
+		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.`query`, m.route_name, m.visible, m.status, ifnull(m.perms,'') as perms, m.is_frame, m.is_cache, m.menu_type, m.icon, m.order_num, m.create_time
+		from sys_menu m
+			 left join sys_role_menu rm on m.menu_id = rm.menu_id
+			 left join sys_user_role 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.status = 0  AND ro.status = 0
+		order by m.parent_id, m.order_num
+	</select>
+	
+	<select id="selectMenuListByRoleId" resultType="Long">
+		select m.menu_id
+		from sys_menu m
+            left join sys_role_menu rm on m.menu_id = rm.menu_id
+        where rm.role_id = #{roleId}
+            <if test="menuCheckStrictly">
+              and m.menu_id not in (select m.parent_id from sys_menu m inner join sys_role_menu rm on m.menu_id = rm.menu_id and rm.role_id = #{roleId})
+            </if>
+		order by m.parent_id, m.order_num
+	</select>
+	
+	<select id="selectMenuPerms" resultType="String">
+		select distinct m.perms
+		from sys_menu m
+			 left join sys_role_menu rm on m.menu_id = rm.menu_id
+			 left join sys_user_role 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
+			 left join sys_role r on r.role_id = ur.role_id
+		where m.status = '0' and r.status = '0' and ur.user_id = #{userId}
+	</select>
+	
+	<select id="selectMenuPermsByRoleId" parameterType="Long" resultType="String">
+		select distinct m.perms
+		from sys_menu m
+			 left join sys_role_menu rm on m.menu_id = rm.menu_id
+		where m.status = '0' and rm.role_id = #{roleId}
+	</select>
+	
+	<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} limit 1
+	</select>
+	
+	<update id="updateMenu" parameterType="SysMenu">
+		update sys_menu
+		<set>
+			<if test="menuName != null and menuName != ''">menu_name = #{menuName},</if>
+			<if test="parentId != null">parent_id = #{parentId},</if>
+			<if test="orderNum != null">order_num = #{orderNum},</if>
+			<if test="path != null and path != ''">path = #{path},</if>
+			<if test="component != null">component = #{component},</if>
+			<if test="query != null">`query` = #{query},</if>
+			<if test="routeName != null">route_name = #{routeName},</if>
+			<if test="isFrame != null and isFrame != ''">is_frame = #{isFrame},</if>
+			<if test="isCache != null and isCache != ''">is_cache = #{isCache},</if>
+			<if test="menuType != null and menuType != ''">menu_type = #{menuType},</if>
+			<if test="visible != null">visible = #{visible},</if>
+			<if test="status != null">status = #{status},</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">order_num,</if>
+		<if test="path != null and path != ''">path,</if>
+		<if test="component != null and component != ''">component,</if>
+		<if test="query != null and query != ''">`query`,</if>
+		<if test="routeName != null">route_name,</if>
+		<if test="isFrame != null and isFrame != ''">is_frame,</if>
+		<if test="isCache != null and isCache != ''">is_cache,</if>
+		<if test="menuType != null and menuType != ''">menu_type,</if>
+		<if test="visible != null">visible,</if>
+		<if test="status != null">status,</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">#{orderNum},</if>
+		<if test="path != null and path != ''">#{path},</if>
+		<if test="component != null and component != ''">#{component},</if>
+		<if test="query != null and query != ''">#{query},</if>
+		<if test="routeName != null">#{routeName},</if>
+		<if test="isFrame != null and isFrame != ''">#{isFrame},</if>
+		<if test="isCache != null and isCache != ''">#{isCache},</if>
+		<if test="menuType != null and menuType != ''">#{menuType},</if>
+		<if test="visible != null">#{visible},</if>
+		<if test="status != null">#{status},</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-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysNoticeMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysNoticeMapper.xml
index 6915a148..ff2aded7 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -1,89 +1,89 @@
-<?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.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, cast(notice_content as char) as 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>
-    
-    <delete id="deleteNoticeByIds" parameterType="Long">
-        delete from sys_notice where notice_id in 
-        <foreach item="noticeId" collection="array" open="(" separator="," close=")">
-            #{noticeId}
-        </foreach>
-    </delete>
-    
+<?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.acupuncture.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, cast(notice_content as char) as 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>
+    
+    <delete id="deleteNoticeByIds" parameterType="Long">
+        delete from sys_notice where notice_id in 
+        <foreach item="noticeId" collection="array" open="(" separator="," close=")">
+            #{noticeId}
+        </foreach>
+    </delete>
+    
 </mapper>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysOperLogMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysOperLogMapper.xml
index 0c3fb691..d0362d9f 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysOperLogMapper.xml
@@ -1,87 +1,87 @@
-<?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.system.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"      />
-		<result property="costTime"       column="cost_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, cost_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, cost_time, oper_time)
-        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())
-	</insert>
-	
-	<select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
-		<include refid="selectOperLogVo"/>
-		<where>
-			<if test="operIp != null and operIp != ''">
-				AND oper_ip like concat('%', #{operIp}, '%')
-			</if>
-			<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 oper_time &gt;= #{params.beginTime}
-			</if>
-			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
-				AND oper_time &lt;= #{params.endTime}
-			</if>
-		</where>
-		order by oper_id desc
-	</select>
-	
-	<delete id="deleteOperLogByIds" parameterType="Long">
- 		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>
-
+<?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.acupuncture.system.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"      />
+		<result property="costTime"       column="cost_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, cost_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, cost_time, oper_time)
+        values (#{title}, #{businessType}, #{method}, #{requestMethod}, #{operatorType}, #{operName}, #{deptName}, #{operUrl}, #{operIp}, #{operLocation}, #{operParam}, #{jsonResult}, #{status}, #{errorMsg}, #{costTime}, sysdate())
+	</insert>
+	
+	<select id="selectOperLogList" parameterType="SysOperLog" resultMap="SysOperLogResult">
+		<include refid="selectOperLogVo"/>
+		<where>
+			<if test="operIp != null and operIp != ''">
+				AND oper_ip like concat('%', #{operIp}, '%')
+			</if>
+			<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 oper_time &gt;= #{params.beginTime}
+			</if>
+			<if test="params.endTime != null and params.endTime != ''"><!-- 结束时间检索 -->
+				AND oper_time &lt;= #{params.endTime}
+			</if>
+		</where>
+		order by oper_id desc
+	</select>
+	
+	<delete id="deleteOperLogByIds" parameterType="Long">
+ 		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-system/src/main/resources/mapper/system/SysPostMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysPostMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysPostMapper.xml
index faefb2f0..99192f84 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -1,122 +1,122 @@
-<?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.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="Long">
-		select p.post_id
-        from sys_post p
-	        left join sys_user_post up on up.post_id = p.post_id
-	        left join sys_user u on u.user_id = up.user_id
-	    where u.user_id = #{userId}
-	</select>
-	
-	<select id="selectPostsByUserName" parameterType="String" resultMap="SysPostResult">
-		select p.post_id, p.post_name, p.post_code
-		from sys_post p
-			 left join sys_user_post up on up.post_id = p.post_id
-			 left join sys_user u on u.user_id = up.user_id
-		where u.user_name = #{userName}
-	</select>
-	
-	<select id="checkPostNameUnique" parameterType="String" resultMap="SysPostResult">
-		<include refid="selectPostVo"/>
-		 where post_name=#{postName} limit 1
-	</select>
-	
-	<select id="checkPostCodeUnique" parameterType="String" resultMap="SysPostResult">
-		<include refid="selectPostVo"/>
-		 where post_code=#{postCode} limit 1
-	</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">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">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">#{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>
-	
-	<delete id="deletePostByIds" parameterType="Long">
- 		delete from sys_post where post_id in
- 		<foreach collection="array" item="postId" open="(" separator="," close=")">
- 			#{postId}
-        </foreach> 
- 	</delete>
-
+<?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.acupuncture.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="Long">
+		select p.post_id
+        from sys_post p
+	        left join sys_user_post up on up.post_id = p.post_id
+	        left join sys_user u on u.user_id = up.user_id
+	    where u.user_id = #{userId}
+	</select>
+	
+	<select id="selectPostsByUserName" parameterType="String" resultMap="SysPostResult">
+		select p.post_id, p.post_name, p.post_code
+		from sys_post p
+			 left join sys_user_post up on up.post_id = p.post_id
+			 left join sys_user u on u.user_id = up.user_id
+		where u.user_name = #{userName}
+	</select>
+	
+	<select id="checkPostNameUnique" parameterType="String" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+		 where post_name=#{postName} limit 1
+	</select>
+	
+	<select id="checkPostCodeUnique" parameterType="String" resultMap="SysPostResult">
+		<include refid="selectPostVo"/>
+		 where post_code=#{postCode} limit 1
+	</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">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">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">#{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>
+	
+	<delete id="deletePostByIds" parameterType="Long">
+ 		delete from sys_post where post_id in
+ 		<foreach collection="array" item="postId" open="(" separator="," close=")">
+ 			#{postId}
+        </foreach> 
+ 	</delete>
+
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
similarity index 91%
rename from ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
index 700671e1..e6bd84bf 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
@@ -1,34 +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.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>
-	
+<?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.acupuncture.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-system/src/main/resources/mapper/system/SysRoleMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysRoleMapper.xml
similarity index 96%
rename from ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysRoleMapper.xml
index a3b780ff..160a79e3 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -1,152 +1,152 @@
-<?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.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="menuCheckStrictly"  column="menu_check_strictly"   />
-		<result property="deptCheckStrictly"  column="dept_check_strictly"   />
-		<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.menu_check_strictly, r.dept_check_strictly,
-            r.status, r.del_flag, r.create_time, r.remark 
-        from sys_role r
-	        left join sys_user_role 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="roleId != null and roleId != 0">
-			AND r.role_id = #{roleId}
-		</if>
-		<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>
-		<!-- 数据范围过滤 -->
-		${params.dataScope}
-		order by r.role_sort
-	</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="Long">
-		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} and r.del_flag = '0' limit 1
-	</select>
-	
-	<select id="checkRoleKeyUnique" parameterType="String" resultMap="SysRoleResult">
-		<include refid="selectRoleVo"/>
-		 where r.role_key=#{roleKey} and r.del_flag = '0' limit 1
-	</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">role_sort,</if>
- 			<if test="dataScope != null and dataScope != ''">data_scope,</if>
- 			<if test="menuCheckStrictly != null">menu_check_strictly,</if>
- 			<if test="deptCheckStrictly != null">dept_check_strictly,</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">#{roleSort},</if>
- 			<if test="dataScope != null and dataScope != ''">#{dataScope},</if>
- 			<if test="menuCheckStrictly != null">#{menuCheckStrictly},</if>
- 			<if test="deptCheckStrictly != null">#{deptCheckStrictly},</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">role_sort = #{roleSort},</if>
- 			<if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if>
- 			<if test="menuCheckStrictly != null">menu_check_strictly = #{menuCheckStrictly},</if>
- 			<if test="deptCheckStrictly != null">dept_check_strictly = #{deptCheckStrictly},</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>
-	
-	<delete id="deleteRoleById" parameterType="Long">
- 		update sys_role set del_flag = '2' where role_id = #{roleId}
- 	</delete>
- 	
- 	<delete id="deleteRoleByIds" parameterType="Long">
- 	    update sys_role set del_flag = '2' where role_id in
- 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
- 			#{roleId}
-        </foreach> 
- 	</delete>
- 	
+<?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.acupuncture.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="menuCheckStrictly"  column="menu_check_strictly"   />
+		<result property="deptCheckStrictly"  column="dept_check_strictly"   />
+		<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.menu_check_strictly, r.dept_check_strictly,
+            r.status, r.del_flag, r.create_time, r.remark 
+        from sys_role r
+	        left join sys_user_role 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="roleId != null and roleId != 0">
+			AND r.role_id = #{roleId}
+		</if>
+		<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>
+		<!-- 数据范围过滤 -->
+		${params.dataScope}
+		order by r.role_sort
+	</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="Long">
+		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} and r.del_flag = '0' limit 1
+	</select>
+	
+	<select id="checkRoleKeyUnique" parameterType="String" resultMap="SysRoleResult">
+		<include refid="selectRoleVo"/>
+		 where r.role_key=#{roleKey} and r.del_flag = '0' limit 1
+	</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">role_sort,</if>
+ 			<if test="dataScope != null and dataScope != ''">data_scope,</if>
+ 			<if test="menuCheckStrictly != null">menu_check_strictly,</if>
+ 			<if test="deptCheckStrictly != null">dept_check_strictly,</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">#{roleSort},</if>
+ 			<if test="dataScope != null and dataScope != ''">#{dataScope},</if>
+ 			<if test="menuCheckStrictly != null">#{menuCheckStrictly},</if>
+ 			<if test="deptCheckStrictly != null">#{deptCheckStrictly},</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">role_sort = #{roleSort},</if>
+ 			<if test="dataScope != null and dataScope != ''">data_scope = #{dataScope},</if>
+ 			<if test="menuCheckStrictly != null">menu_check_strictly = #{menuCheckStrictly},</if>
+ 			<if test="deptCheckStrictly != null">dept_check_strictly = #{deptCheckStrictly},</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>
+	
+	<delete id="deleteRoleById" parameterType="Long">
+ 		update sys_role set del_flag = '2' where role_id = #{roleId}
+ 	</delete>
+ 	
+ 	<delete id="deleteRoleByIds" parameterType="Long">
+ 	    update sys_role set del_flag = '2' where role_id in
+ 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
+ 			#{roleId}
+        </foreach> 
+ 	</delete>
+ 	
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
similarity index 91%
rename from ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
index e75bb174..f900fc52 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -1,34 +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.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>
-	
-	<delete id="deleteRoleMenu" parameterType="Long">
- 		delete from sys_role_menu where role_id in
- 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
- 			#{roleId}
-        </foreach> 
- 	</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>
-	
+<?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.acupuncture.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>
+	
+	<delete id="deleteRoleMenu" parameterType="Long">
+ 		delete from sys_role_menu where role_id in
+ 		<foreach collection="array" item="roleId" open="(" separator="," close=")">
+ 			#{roleId}
+        </foreach> 
+ 	</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-system/src/main/resources/mapper/system/SysUserMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysUserMapper.xml
similarity index 97%
rename from ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysUserMapper.xml
index 5814cd35..3efcfb6f 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -1,221 +1,221 @@
-<?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.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"    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="ancestors" column="ancestors"   />
-        <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.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
-        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
-        from sys_user u
-		    left join sys_dept d on u.dept_id = d.dept_id
-		    left join sys_user_role 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">
-		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
-		left join sys_dept d on u.dept_id = d.dept_id
-		where u.del_flag = '0'
-		<if test="userId != null and userId != 0">
-			AND u.user_id = #{userId}
-		</if>
-		<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>
-		<!-- 数据范围过滤 -->
-		${params.dataScope}
-	</select>
-	
-	<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
-	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
-	    from sys_user u
-			 left join sys_dept d on u.dept_id = d.dept_id
-			 left join sys_user_role ur on u.user_id = ur.user_id
-			 left join sys_role r on r.role_id = ur.role_id
-	    where u.del_flag = '0' and r.role_id = #{roleId}
-	    <if test="userName != null and userName != ''">
-			AND u.user_name like concat('%', #{userName}, '%')
-		</if>
-		<if test="phonenumber != null and phonenumber != ''">
-			AND u.phonenumber like concat('%', #{phonenumber}, '%')
-		</if>
-		<!-- 数据范围过滤 -->
-		${params.dataScope}
-	</select>
-	
-	<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
-	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
-	    from sys_user u
-			 left join sys_dept d on u.dept_id = d.dept_id
-			 left join sys_user_role ur on u.user_id = ur.user_id
-			 left join sys_role r on r.role_id = ur.role_id
-	    where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)
-	    and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId})
-	    <if test="userName != null and userName != ''">
-			AND u.user_name like concat('%', #{userName}, '%')
-		</if>
-		<if test="phonenumber != null and phonenumber != ''">
-			AND u.phonenumber like concat('%', #{phonenumber}, '%')
-		</if>
-		<!-- 数据范围过滤 -->
-		${params.dataScope}
-	</select>
-	
-	<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
-	    <include refid="selectUserVo"/>
-		where u.user_name = #{userName} and u.del_flag = '0'
-	</select>
-	
-	<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
-		<include refid="selectUserVo"/>
-		where u.user_id = #{userId}
-	</select>
-	
-	<select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
-		select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1
-	</select>
-	
-	<select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
-		select user_id, phonenumber from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1
-	</select>
-	
-	<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
-		select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
-	</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 ">email = #{email},</if>
- 			<if test="phonenumber != null ">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">
- 		update sys_user set del_flag = '2' where user_id = #{userId}
- 	</delete>
- 	
- 	<delete id="deleteUserByIds" parameterType="Long">
- 		update sys_user set del_flag = '2' where user_id in
- 		<foreach collection="array" item="userId" open="(" separator="," close=")">
- 			#{userId}
-        </foreach> 
- 	</delete>
-	
+<?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.acupuncture.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"    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="ancestors" column="ancestors"   />
+        <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.ancestors, d.dept_name, d.order_num, d.leader, d.status as dept_status,
+        r.role_id, r.role_name, r.role_key, r.role_sort, r.data_scope, r.status as role_status
+        from sys_user u
+		    left join sys_dept d on u.dept_id = d.dept_id
+		    left join sys_user_role 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">
+		select u.user_id, u.dept_id, u.nick_name, u.user_name, u.email, u.avatar, u.phonenumber, u.sex, u.status, u.del_flag, u.login_ip, u.login_date, u.create_by, u.create_time, u.remark, d.dept_name, d.leader from sys_user u
+		left join sys_dept d on u.dept_id = d.dept_id
+		where u.del_flag = '0'
+		<if test="userId != null and userId != 0">
+			AND u.user_id = #{userId}
+		</if>
+		<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>
+		<!-- 数据范围过滤 -->
+		${params.dataScope}
+	</select>
+	
+	<select id="selectAllocatedList" parameterType="SysUser" resultMap="SysUserResult">
+	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+	    from sys_user u
+			 left join sys_dept d on u.dept_id = d.dept_id
+			 left join sys_user_role ur on u.user_id = ur.user_id
+			 left join sys_role r on r.role_id = ur.role_id
+	    where u.del_flag = '0' and r.role_id = #{roleId}
+	    <if test="userName != null and userName != ''">
+			AND u.user_name like concat('%', #{userName}, '%')
+		</if>
+		<if test="phonenumber != null and phonenumber != ''">
+			AND u.phonenumber like concat('%', #{phonenumber}, '%')
+		</if>
+		<!-- 数据范围过滤 -->
+		${params.dataScope}
+	</select>
+	
+	<select id="selectUnallocatedList" parameterType="SysUser" resultMap="SysUserResult">
+	    select distinct u.user_id, u.dept_id, u.user_name, u.nick_name, u.email, u.phonenumber, u.status, u.create_time
+	    from sys_user u
+			 left join sys_dept d on u.dept_id = d.dept_id
+			 left join sys_user_role ur on u.user_id = ur.user_id
+			 left join sys_role r on r.role_id = ur.role_id
+	    where u.del_flag = '0' and (r.role_id != #{roleId} or r.role_id IS NULL)
+	    and u.user_id not in (select u.user_id from sys_user u inner join sys_user_role ur on u.user_id = ur.user_id and ur.role_id = #{roleId})
+	    <if test="userName != null and userName != ''">
+			AND u.user_name like concat('%', #{userName}, '%')
+		</if>
+		<if test="phonenumber != null and phonenumber != ''">
+			AND u.phonenumber like concat('%', #{phonenumber}, '%')
+		</if>
+		<!-- 数据范围过滤 -->
+		${params.dataScope}
+	</select>
+	
+	<select id="selectUserByUserName" parameterType="String" resultMap="SysUserResult">
+	    <include refid="selectUserVo"/>
+		where u.user_name = #{userName} and u.del_flag = '0'
+	</select>
+	
+	<select id="selectUserById" parameterType="Long" resultMap="SysUserResult">
+		<include refid="selectUserVo"/>
+		where u.user_id = #{userId}
+	</select>
+	
+	<select id="checkUserNameUnique" parameterType="String" resultMap="SysUserResult">
+		select user_id, user_name from sys_user where user_name = #{userName} and del_flag = '0' limit 1
+	</select>
+	
+	<select id="checkPhoneUnique" parameterType="String" resultMap="SysUserResult">
+		select user_id, phonenumber from sys_user where phonenumber = #{phonenumber} and del_flag = '0' limit 1
+	</select>
+	
+	<select id="checkEmailUnique" parameterType="String" resultMap="SysUserResult">
+		select user_id, email from sys_user where email = #{email} and del_flag = '0' limit 1
+	</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 ">email = #{email},</if>
+ 			<if test="phonenumber != null ">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">
+ 		update sys_user set del_flag = '2' where user_id = #{userId}
+ 	</delete>
+ 	
+ 	<delete id="deleteUserByIds" parameterType="Long">
+ 		update sys_user set del_flag = '2' where user_id in
+ 		<foreach collection="array" item="userId" open="(" separator="," close=")">
+ 			#{userId}
+        </foreach> 
+ 	</delete>
+	
 </mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysUserPostMapper.xml
similarity index 91%
rename from ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysUserPostMapper.xml
index 21c40981..948d6015 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysUserPostMapper.xml
@@ -1,34 +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.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>
-	
+<?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.acupuncture.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-system/src/main/resources/mapper/system/SysUserRoleMapper.xml b/acupuncture-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
similarity index 93%
rename from ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
rename to acupuncture-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
index 95e07adb..297aebe7 100644
--- a/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
+++ b/acupuncture-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
@@ -1,44 +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.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>
+<?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.acupuncture.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
diff --git a/pom.xml b/pom.xml
index 21f8ea0f..b250a25c 100644
--- a/pom.xml
+++ b/pom.xml
@@ -4,16 +4,16 @@
          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>
+    <groupId>com.acupuncture</groupId>
+    <artifactId>acupuncture</artifactId>
     <version>3.8.9</version>
 
-    <name>ruoyi</name>
-    <url>http://www.ruoyi.vip</url>
+    <name>acupuncture</name>
+    <url>http://www.acupuncture.vip</url>
     <description>若依管理系统</description>
     
     <properties>
-        <ruoyi.version>3.8.9</ruoyi.version>
+        <acupuncture.version>3.8.9</acupuncture.version>
         <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
         <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
         <java.version>1.8</java.version>
@@ -185,49 +185,49 @@
 
             <!-- 定时任务-->
             <dependency>
-                <groupId>com.ruoyi</groupId>
-                <artifactId>ruoyi-quartz</artifactId>
-                <version>${ruoyi.version}</version>
+                <groupId>com.acupuncture</groupId>
+                <artifactId>acupuncture-quartz</artifactId>
+                <version>${acupuncture.version}</version>
             </dependency>
 
             <!-- 代码生成-->
             <dependency>
-                <groupId>com.ruoyi</groupId>
-                <artifactId>ruoyi-generator</artifactId>
-                <version>${ruoyi.version}</version>
+                <groupId>com.acupuncture</groupId>
+                <artifactId>acupuncture-generator</artifactId>
+                <version>${acupuncture.version}</version>
             </dependency>
 
             <!-- 核心模块-->
             <dependency>
-                <groupId>com.ruoyi</groupId>
-                <artifactId>ruoyi-framework</artifactId>
-                <version>${ruoyi.version}</version>
+                <groupId>com.acupuncture</groupId>
+                <artifactId>acupuncture-framework</artifactId>
+                <version>${acupuncture.version}</version>
             </dependency>
 
             <!-- 系统模块-->
             <dependency>
-                <groupId>com.ruoyi</groupId>
-                <artifactId>ruoyi-system</artifactId>
-                <version>${ruoyi.version}</version>
+                <groupId>com.acupuncture</groupId>
+                <artifactId>acupuncture-system</artifactId>
+                <version>${acupuncture.version}</version>
             </dependency>
 
             <!-- 通用工具-->
             <dependency>
-                <groupId>com.ruoyi</groupId>
-                <artifactId>ruoyi-common</artifactId>
-                <version>${ruoyi.version}</version>
+                <groupId>com.acupuncture</groupId>
+                <artifactId>acupuncture-common</artifactId>
+                <version>${acupuncture.version}</version>
             </dependency>
 
         </dependencies>
     </dependencyManagement>
 
     <modules>
-        <module>ruoyi-admin</module>
-        <module>ruoyi-framework</module>
-        <module>ruoyi-system</module>
-        <module>ruoyi-quartz</module>
-        <module>ruoyi-generator</module>
-        <module>ruoyi-common</module>
+        <module>acupuncture-admin</module>
+        <module>acupuncture-framework</module>
+        <module>acupuncture-system</module>
+        <module>acupuncture-quartz</module>
+        <module>acupuncture-generator</module>
+        <module>acupuncture-common</module>
     </modules>
     <packaging>pom</packaging>
 
diff --git a/ruoyi-ui/README.md b/ruoyi-ui/README.md
index ad24b682..e82b44f9 100644
--- a/ruoyi-ui/README.md
+++ b/ruoyi-ui/README.md
@@ -1,30 +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.npmmirror.com
-
-# 启动服务
-npm run dev
-```
-
-浏览器访问 http://localhost:80
-
-## 发布
-
-```bash
-# 构建测试环境
-npm run build:stage
-
-# 构建生产环境
-npm run build:prod
+## 开发
+
+```bash
+# 克隆项目
+git clone https://gitee.com/y_project/acupuncture-Vue
+
+# 进入项目目录
+cd acupuncture-ui
+
+# 安装依赖
+npm install
+
+# 建议不要直接使用 cnpm 安装依赖,会有各种诡异的 bug。可以通过如下操作解决 npm 下载速度慢的问题
+npm install --registry=https://registry.npmmirror.com
+
+# 启动服务
+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/package.json b/ruoyi-ui/package.json
index a46664a9..1e722ec2 100644
--- a/ruoyi-ui/package.json
+++ b/ruoyi-ui/package.json
@@ -1,91 +1,91 @@
-{
-  "name": "ruoyi",
-  "version": "3.8.9",
-  "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"
-  },
-  "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.4.0",
-    "axios": "0.28.1",
-    "clipboard": "2.0.8",
-    "core-js": "3.37.1",
-    "echarts": "5.4.0",
-    "element-ui": "2.15.14",
-    "file-saver": "2.0.5",
-    "fuse.js": "6.4.3",
-    "highlight.js": "9.18.5",
-    "js-beautify": "1.13.0",
-    "js-cookie": "3.0.1",
-    "jsencrypt": "3.0.0-rc.1",
-    "nprogress": "0.2.0",
-    "quill": "2.0.2",
-    "screenfull": "5.0.2",
-    "sortablejs": "1.10.2",
-    "splitpanes": "2.4.1",
-    "vue": "2.6.12",
-    "vue-count-to": "1.0.13",
-    "vue-cropper": "0.5.5",
-    "vue-meta": "2.4.0",
-    "vue-router": "3.4.9",
-    "vuedraggable": "2.24.3",
-    "vuex": "3.6.0"
-  },
-  "devDependencies": {
-    "@vue/cli-plugin-babel": "4.4.6",
-    "@vue/cli-plugin-eslint": "4.4.6",
-    "@vue/cli-service": "4.4.6",
-    "babel-eslint": "10.1.0",
-    "babel-plugin-dynamic-import-node": "2.3.3",
-    "chalk": "4.1.0",
-    "compression-webpack-plugin": "6.1.2",
-    "connect": "3.6.6",
-    "eslint": "7.15.0",
-    "eslint-plugin-vue": "7.2.0",
-    "lint-staged": "10.5.3",
-    "runjs": "4.4.2",
-    "sass": "1.32.13",
-    "sass-loader": "10.1.1",
-    "script-ext-html-webpack-plugin": "2.1.5",
-    "svg-sprite-loader": "5.1.1",
-    "vue-template-compiler": "2.6.12"
-  },
-  "engines": {
-    "node": ">=8.9",
-    "npm": ">= 3.0.0"
-  },
-  "browserslist": [
-    "> 1%",
-    "last 2 versions"
-  ]
-}
+{
+  "name": "acupuncture",
+  "version": "3.8.9",
+  "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"
+  },
+  "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/acupuncture-Vue.git"
+  },
+  "dependencies": {
+    "@riophae/vue-treeselect": "0.4.0",
+    "axios": "0.28.1",
+    "clipboard": "2.0.8",
+    "core-js": "3.37.1",
+    "echarts": "5.4.0",
+    "element-ui": "2.15.14",
+    "file-saver": "2.0.5",
+    "fuse.js": "6.4.3",
+    "highlight.js": "9.18.5",
+    "js-beautify": "1.13.0",
+    "js-cookie": "3.0.1",
+    "jsencrypt": "3.0.0-rc.1",
+    "nprogress": "0.2.0",
+    "quill": "2.0.2",
+    "screenfull": "5.0.2",
+    "sortablejs": "1.10.2",
+    "splitpanes": "2.4.1",
+    "vue": "2.6.12",
+    "vue-count-to": "1.0.13",
+    "vue-cropper": "0.5.5",
+    "vue-meta": "2.4.0",
+    "vue-router": "3.4.9",
+    "vuedraggable": "2.24.3",
+    "vuex": "3.6.0"
+  },
+  "devDependencies": {
+    "@vue/cli-plugin-babel": "4.4.6",
+    "@vue/cli-plugin-eslint": "4.4.6",
+    "@vue/cli-service": "4.4.6",
+    "babel-eslint": "10.1.0",
+    "babel-plugin-dynamic-import-node": "2.3.3",
+    "chalk": "4.1.0",
+    "compression-webpack-plugin": "6.1.2",
+    "connect": "3.6.6",
+    "eslint": "7.15.0",
+    "eslint-plugin-vue": "7.2.0",
+    "lint-staged": "10.5.3",
+    "runjs": "4.4.2",
+    "sass": "1.32.13",
+    "sass-loader": "10.1.1",
+    "script-ext-html-webpack-plugin": "2.1.5",
+    "svg-sprite-loader": "5.1.1",
+    "vue-template-compiler": "2.6.12"
+  },
+  "engines": {
+    "node": ">=8.9",
+    "npm": ">= 3.0.0"
+  },
+  "browserslist": [
+    "> 1%",
+    "last 2 versions"
+  ]
+}
diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js
index 2da13d48..e17c5b73 100644
--- a/ruoyi-ui/src/api/system/user.js
+++ b/ruoyi-ui/src/api/system/user.js
@@ -1,136 +1,136 @@
-import request from '@/utils/request'
-import { parseStrEmpty } from "@/utils/ruoyi";
-
-// 查询用户列表
-export function listUser(query) {
-  return request({
-    url: '/system/user/list',
-    method: 'get',
-    params: query
-  })
-}
-
-// 查询用户详细
-export function getUser(userId) {
-  return request({
-    url: '/system/user/' + parseStrEmpty(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',
-    data: data
-  })
-}
-
-// 用户头像上传
-export function uploadAvatar(data) {
-  return request({
-    url: '/system/user/profile/avatar',
-    method: 'post',
-    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
-    data: data
-  })
-}
-
-// 查询授权角色
-export function getAuthRole(userId) {
-  return request({
-    url: '/system/user/authRole/' + userId,
-    method: 'get'
-  })
-}
-
-// 保存授权角色
-export function updateAuthRole(data) {
-  return request({
-    url: '/system/user/authRole',
-    method: 'put',
-    params: data
-  })
-}
-
-// 查询部门下拉树结构
-export function deptTreeSelect() {
-  return request({
-    url: '/system/user/deptTree',
-    method: 'get'
-  })
-}
+import request from '@/utils/request'
+import { parseStrEmpty } from "@/utils/acupuncture";
+
+// 查询用户列表
+export function listUser(query) {
+  return request({
+    url: '/system/user/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 查询用户详细
+export function getUser(userId) {
+  return request({
+    url: '/system/user/' + parseStrEmpty(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',
+    data: data
+  })
+}
+
+// 用户头像上传
+export function uploadAvatar(data) {
+  return request({
+    url: '/system/user/profile/avatar',
+    method: 'post',
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+    data: data
+  })
+}
+
+// 查询授权角色
+export function getAuthRole(userId) {
+  return request({
+    url: '/system/user/authRole/' + userId,
+    method: 'get'
+  })
+}
+
+// 保存授权角色
+export function updateAuthRole(data) {
+  return request({
+    url: '/system/user/authRole',
+    method: 'put',
+    params: data
+  })
+}
+
+// 查询部门下拉树结构
+export function deptTreeSelect() {
+  return request({
+    url: '/system/user/deptTree',
+    method: 'get'
+  })
+}
diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss
index 7e44513c..4a1292ef 100644
--- a/ruoyi-ui/src/assets/styles/ruoyi.scss
+++ b/ruoyi-ui/src/assets/styles/ruoyi.scss
@@ -1,6 +1,6 @@
 /**
 * 通用css样式布局处理
-* Copyright (c) 2019 ruoyi
+* Copyright (c) 2019 acupuncture
 */
 
 /** 基础通用 **/
diff --git a/ruoyi-ui/src/components/RuoYi/Doc/index.vue b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
index cc829b24..a37b5945 100644
--- a/ruoyi-ui/src/components/RuoYi/Doc/index.vue
+++ b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
@@ -1,21 +1,21 @@
-<template>
-  <div>
-    <svg-icon icon-class="question" @click="goto" />
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RuoYiDoc',
-  data() {
-    return {
-      url: 'http://doc.ruoyi.vip/ruoyi-vue'
-    }
-  },
-  methods: {
-    goto() {
-      window.open(this.url)
-    }
-  }
-}
-</script>
\ No newline at end of file
+<template>
+  <div>
+    <svg-icon icon-class="question" @click="goto" />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'acupunctureDoc',
+  data() {
+    return {
+      url: 'http://doc.acupuncture.vip/acupuncture-vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/components/RuoYi/Git/index.vue b/ruoyi-ui/src/components/RuoYi/Git/index.vue
index 517c4486..054a8e45 100644
--- a/ruoyi-ui/src/components/RuoYi/Git/index.vue
+++ b/ruoyi-ui/src/components/RuoYi/Git/index.vue
@@ -1,21 +1,21 @@
-<template>
-  <div>
-    <svg-icon icon-class="github" @click="goto" />
-  </div>
-</template>
-
-<script>
-export default {
-  name: 'RuoYiGit',
-  data() {
-    return {
-      url: 'https://gitee.com/y_project/RuoYi-Vue'
-    }
-  },
-  methods: {
-    goto() {
-      window.open(this.url)
-    }
-  }
-}
-</script>
\ No newline at end of file
+<template>
+  <div>
+    <svg-icon icon-class="github" @click="goto" />
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'acupunctureGit',
+  data() {
+    return {
+      url: 'https://gitee.com/y_project/acupuncture-Vue'
+    }
+  },
+  methods: {
+    goto() {
+      window.open(this.url)
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/directive/dialog/drag.js b/ruoyi-ui/src/directive/dialog/drag.js
index 728f49dc..c6d98841 100644
--- a/ruoyi-ui/src/directive/dialog/drag.js
+++ b/ruoyi-ui/src/directive/dialog/drag.js
@@ -1,64 +1,64 @@
-/**
-* v-dialogDrag 弹窗拖拽
-* Copyright (c) 2019 ruoyi
-*/
-
-export default {
-  bind(el, binding, vnode, oldVnode) {
-    const value = binding.value
-    if (value == false) return
-    // 获取拖拽内容头部
-    const dialogHeaderEl = el.querySelector('.el-dialog__header');
-    const dragDom = el.querySelector('.el-dialog');
-    dialogHeaderEl.style.cursor = 'move';
-    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
-    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
-    dragDom.style.position = 'absolute';
-    dragDom.style.marginTop = 0;
-    let width = dragDom.style.width;
-    if (width.includes('%')) {
-      width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100);
-    } else {
-      width = +width.replace(/\px/g, '');
-    }
-    dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`;
-    // 鼠标按下事件
-    dialogHeaderEl.onmousedown = (e) => {
-      // 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
-      const disX = e.clientX - dialogHeaderEl.offsetLeft;
-      const disY = e.clientY - dialogHeaderEl.offsetTop;
-
-      // 获取到的值带px 正则匹配替换
-      let styL, styT;
-
-      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
-      if (sty.left.includes('%')) {
-        styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
-        styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
-      } else {
-        styL = +sty.left.replace(/\px/g, '');
-        styT = +sty.top.replace(/\px/g, '');
-      };
-
-      // 鼠标拖拽事件
-      document.onmousemove = function (e) {
-        // 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
-        const l = e.clientX - disX;
-        const t = e.clientY - disY;
-
-        let finallyL = l + styL
-        let finallyT = t + styT
-
-        // 移动当前元素
-        dragDom.style.left = `${finallyL}px`;
-        dragDom.style.top = `${finallyT}px`;
-
-      };
-
-      document.onmouseup = function (e) {
-        document.onmousemove = null;
-        document.onmouseup = null;
-      };
-    }
-  }
-};
\ No newline at end of file
+/**
+* v-dialogDrag 弹窗拖拽
+* Copyright (c) 2019 acupuncture
+*/
+
+export default {
+  bind(el, binding, vnode, oldVnode) {
+    const value = binding.value
+    if (value == false) return
+    // 获取拖拽内容头部
+    const dialogHeaderEl = el.querySelector('.el-dialog__header');
+    const dragDom = el.querySelector('.el-dialog');
+    dialogHeaderEl.style.cursor = 'move';
+    // 获取原有属性 ie dom元素.currentStyle 火狐谷歌 window.getComputedStyle(dom元素, null);
+    const sty = dragDom.currentStyle || window.getComputedStyle(dragDom, null);
+    dragDom.style.position = 'absolute';
+    dragDom.style.marginTop = 0;
+    let width = dragDom.style.width;
+    if (width.includes('%')) {
+      width = +document.body.clientWidth * (+width.replace(/\%/g, '') / 100);
+    } else {
+      width = +width.replace(/\px/g, '');
+    }
+    dragDom.style.left = `${(document.body.clientWidth - width) / 2}px`;
+    // 鼠标按下事件
+    dialogHeaderEl.onmousedown = (e) => {
+      // 鼠标按下,计算当前元素距离可视区的距离 (鼠标点击位置距离可视窗口的距离)
+      const disX = e.clientX - dialogHeaderEl.offsetLeft;
+      const disY = e.clientY - dialogHeaderEl.offsetTop;
+
+      // 获取到的值带px 正则匹配替换
+      let styL, styT;
+
+      // 注意在ie中 第一次获取到的值为组件自带50% 移动之后赋值为px
+      if (sty.left.includes('%')) {
+        styL = +document.body.clientWidth * (+sty.left.replace(/\%/g, '') / 100);
+        styT = +document.body.clientHeight * (+sty.top.replace(/\%/g, '') / 100);
+      } else {
+        styL = +sty.left.replace(/\px/g, '');
+        styT = +sty.top.replace(/\px/g, '');
+      };
+
+      // 鼠标拖拽事件
+      document.onmousemove = function (e) {
+        // 通过事件委托,计算移动的距离 (开始拖拽至结束拖拽的距离)
+        const l = e.clientX - disX;
+        const t = e.clientY - disY;
+
+        let finallyL = l + styL
+        let finallyT = t + styT
+
+        // 移动当前元素
+        dragDom.style.left = `${finallyL}px`;
+        dragDom.style.top = `${finallyT}px`;
+
+      };
+
+      document.onmouseup = function (e) {
+        document.onmousemove = null;
+        document.onmouseup = null;
+      };
+    }
+  }
+};
diff --git a/ruoyi-ui/src/directive/dialog/dragHeight.js b/ruoyi-ui/src/directive/dialog/dragHeight.js
index e805bd75..bb54be6f 100644
--- a/ruoyi-ui/src/directive/dialog/dragHeight.js
+++ b/ruoyi-ui/src/directive/dialog/dragHeight.js
@@ -1,34 +1,34 @@
-/**
- * v-dialogDragWidth 可拖动弹窗高度(右下角)
- * Copyright (c) 2019 ruoyi
- */
-
-export default {
-  bind(el) {
-    const dragDom = el.querySelector('.el-dialog');
-    const lineEl = document.createElement('div');
-    lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;';
-    lineEl.addEventListener('mousedown',
-      function(e) {
-        // 鼠标按下,计算当前元素距离可视区的距离
-        const disX = e.clientX - el.offsetLeft;
-        const disY = e.clientY - el.offsetTop;
-        // 当前宽度 高度
-        const curWidth = dragDom.offsetWidth;
-        const curHeight = dragDom.offsetHeight;
-        document.onmousemove = function(e) {
-          e.preventDefault(); // 移动时禁用默认事件
-          // 通过事件委托,计算移动的距离
-          const xl = e.clientX - disX;
-          const yl = e.clientY - disY
-          dragDom.style.width = `${curWidth + xl}px`;
-          dragDom.style.height = `${curHeight + yl}px`;
-        };
-        document.onmouseup = function(e) {
-          document.onmousemove = null;
-          document.onmouseup = null;
-        };
-      }, false);
-    dragDom.appendChild(lineEl);
-  }
-}
+/**
+ * v-dialogDragWidth 可拖动弹窗高度(右下角)
+ * Copyright (c) 2019 acupuncture
+ */
+
+export default {
+  bind(el) {
+    const dragDom = el.querySelector('.el-dialog');
+    const lineEl = document.createElement('div');
+    lineEl.style = 'width: 6px; background: inherit; height: 10px; position: absolute; right: 0; bottom: 0; margin: auto; z-index: 1; cursor: nwse-resize;';
+    lineEl.addEventListener('mousedown',
+      function(e) {
+        // 鼠标按下,计算当前元素距离可视区的距离
+        const disX = e.clientX - el.offsetLeft;
+        const disY = e.clientY - el.offsetTop;
+        // 当前宽度 高度
+        const curWidth = dragDom.offsetWidth;
+        const curHeight = dragDom.offsetHeight;
+        document.onmousemove = function(e) {
+          e.preventDefault(); // 移动时禁用默认事件
+          // 通过事件委托,计算移动的距离
+          const xl = e.clientX - disX;
+          const yl = e.clientY - disY
+          dragDom.style.width = `${curWidth + xl}px`;
+          dragDom.style.height = `${curHeight + yl}px`;
+        };
+        document.onmouseup = function(e) {
+          document.onmousemove = null;
+          document.onmouseup = null;
+        };
+      }, false);
+    dragDom.appendChild(lineEl);
+  }
+}
diff --git a/ruoyi-ui/src/directive/dialog/dragWidth.js b/ruoyi-ui/src/directive/dialog/dragWidth.js
index 96284bbf..f7266a06 100644
--- a/ruoyi-ui/src/directive/dialog/dragWidth.js
+++ b/ruoyi-ui/src/directive/dialog/dragWidth.js
@@ -1,30 +1,30 @@
-/**
- * v-dialogDragWidth 可拖动弹窗宽度(右侧边)
- * Copyright (c) 2019 ruoyi
- */
-
-export default {
-  bind(el) {
-    const dragDom = el.querySelector('.el-dialog');
-    const lineEl = document.createElement('div');
-    lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;';
-    lineEl.addEventListener('mousedown',
-      function (e) {
-        // 鼠标按下,计算当前元素距离可视区的距离
-        const disX = e.clientX - el.offsetLeft;
-        // 当前宽度
-        const curWidth = dragDom.offsetWidth;
-        document.onmousemove = function (e) {
-          e.preventDefault(); // 移动时禁用默认事件
-          // 通过事件委托,计算移动的距离
-          const l = e.clientX - disX;
-          dragDom.style.width = `${curWidth + l}px`;
-        };
-        document.onmouseup = function (e) {
-          document.onmousemove = null;
-          document.onmouseup = null;
-        };
-      }, false);
-    dragDom.appendChild(lineEl);
-  }
-}
+/**
+ * v-dialogDragWidth 可拖动弹窗宽度(右侧边)
+ * Copyright (c) 2019 acupuncture
+ */
+
+export default {
+  bind(el) {
+    const dragDom = el.querySelector('.el-dialog');
+    const lineEl = document.createElement('div');
+    lineEl.style = 'width: 5px; background: inherit; height: 80%; position: absolute; right: 0; top: 0; bottom: 0; margin: auto; z-index: 1; cursor: w-resize;';
+    lineEl.addEventListener('mousedown',
+      function (e) {
+        // 鼠标按下,计算当前元素距离可视区的距离
+        const disX = e.clientX - el.offsetLeft;
+        // 当前宽度
+        const curWidth = dragDom.offsetWidth;
+        document.onmousemove = function (e) {
+          e.preventDefault(); // 移动时禁用默认事件
+          // 通过事件委托,计算移动的距离
+          const l = e.clientX - disX;
+          dragDom.style.width = `${curWidth + l}px`;
+        };
+        document.onmouseup = function (e) {
+          document.onmousemove = null;
+          document.onmouseup = null;
+        };
+      }, false);
+    dragDom.appendChild(lineEl);
+  }
+}
diff --git a/ruoyi-ui/src/directive/module/clipboard.js b/ruoyi-ui/src/directive/module/clipboard.js
index 635315a8..9e00551c 100644
--- a/ruoyi-ui/src/directive/module/clipboard.js
+++ b/ruoyi-ui/src/directive/module/clipboard.js
@@ -1,6 +1,6 @@
 /**
 * v-clipboard 文字复制剪贴
-* Copyright (c) 2021 ruoyi
+* Copyright (c) 2021 acupuncture
 */
 
 import Clipboard from 'clipboard'
diff --git a/ruoyi-ui/src/directive/permission/hasPermi.js b/ruoyi-ui/src/directive/permission/hasPermi.js
index 6839161e..ff5f3aab 100644
--- a/ruoyi-ui/src/directive/permission/hasPermi.js
+++ b/ruoyi-ui/src/directive/permission/hasPermi.js
@@ -1,28 +1,28 @@
- /**
- * v-hasPermi 操作权限处理
- * 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(`请设置操作权限标签值`)
-    }
-  }
-}
+ /**
+ * v-hasPermi 操作权限处理
+ * Copyright (c) 2019 acupuncture
+ */
+
+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
index 9e0e0212..65a538e2 100644
--- a/ruoyi-ui/src/directive/permission/hasRole.js
+++ b/ruoyi-ui/src/directive/permission/hasRole.js
@@ -1,28 +1,28 @@
- /**
- * v-hasRole 角色权限处理
- * 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(`请设置角色权限标签值"`)
-    }
-  }
-}
+ /**
+ * v-hasRole 角色权限处理
+ * Copyright (c) 2019 acupuncture
+ */
+
+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/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
index 5c5a2489..718a982f 100644
--- a/ruoyi-ui/src/layout/components/Navbar.vue
+++ b/ruoyi-ui/src/layout/components/Navbar.vue
@@ -1,200 +1,200 @@
-<template>
-  <div class="navbar">
-    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
-
-    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
-    <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/>
-
-    <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-git id="ruoyi-git" class="right-menu-item hover-effect" />
-        </el-tooltip>
-
-        <el-tooltip content="文档地址" effect="dark" placement="bottom">
-          <ruo-yi-doc id="ruoyi-doc" 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 @click.native="setting = true">
-            <span>布局设置</span>
-          </el-dropdown-item>
-          <el-dropdown-item divided @click.native="logout">
-            <span>退出登录</span>
-          </el-dropdown-item>
-        </el-dropdown-menu>
-      </el-dropdown>
-    </div>
-  </div>
-</template>
-
-<script>
-import { mapGetters } from 'vuex'
-import Breadcrumb from '@/components/Breadcrumb'
-import TopNav from '@/components/TopNav'
-import Hamburger from '@/components/Hamburger'
-import Screenfull from '@/components/Screenfull'
-import SizeSelect from '@/components/SizeSelect'
-import Search from '@/components/HeaderSearch'
-import RuoYiGit from '@/components/RuoYi/Git'
-import RuoYiDoc from '@/components/RuoYi/Doc'
-
-export default {
-  components: {
-    Breadcrumb,
-    TopNav,
-    Hamburger,
-    Screenfull,
-    SizeSelect,
-    Search,
-    RuoYiGit,
-    RuoYiDoc
-  },
-  computed: {
-    ...mapGetters([
-      'sidebar',
-      'avatar',
-      'device'
-    ]),
-    setting: {
-      get() {
-        return this.$store.state.settings.showSettings
-      },
-      set(val) {
-        this.$store.dispatch('settings/changeSetting', {
-          key: 'showSettings',
-          value: val
-        })
-      }
-    },
-    topNav: {
-      get() {
-        return this.$store.state.settings.topNav
-      }
-    }
-  },
-  methods: {
-    toggleSideBar() {
-      this.$store.dispatch('app/toggleSideBar')
-    },
-    async logout() {
-      this.$confirm('确定注销并退出系统吗?', '提示', {
-        confirmButtonText: '确定',
-        cancelButtonText: '取消',
-        type: 'warning'
-      }).then(() => {
-        this.$store.dispatch('LogOut').then(() => {
-          location.href = '/index';
-        })
-      }).catch(() => {});
-    }
-  }
-}
-</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;
-  }
-
-  .topmenu-container {
-    position: absolute;
-    left: 50px;
-  }
-
-  .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>
+<template>
+  <div class="navbar">
+    <hamburger id="hamburger-container" :is-active="sidebar.opened" class="hamburger-container" @toggleClick="toggleSideBar" />
+
+    <breadcrumb id="breadcrumb-container" class="breadcrumb-container" v-if="!topNav"/>
+    <top-nav id="topmenu-container" class="topmenu-container" v-if="topNav"/>
+
+    <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-git id="acupuncture-git" class="right-menu-item hover-effect" />
+        </el-tooltip>
+
+        <el-tooltip content="文档地址" effect="dark" placement="bottom">
+          <ruo-yi-doc id="acupuncture-doc" 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 @click.native="setting = true">
+            <span>布局设置</span>
+          </el-dropdown-item>
+          <el-dropdown-item divided @click.native="logout">
+            <span>退出登录</span>
+          </el-dropdown-item>
+        </el-dropdown-menu>
+      </el-dropdown>
+    </div>
+  </div>
+</template>
+
+<script>
+import { mapGetters } from 'vuex'
+import Breadcrumb from '@/components/Breadcrumb'
+import TopNav from '@/components/TopNav'
+import Hamburger from '@/components/Hamburger'
+import Screenfull from '@/components/Screenfull'
+import SizeSelect from '@/components/SizeSelect'
+import Search from '@/components/HeaderSearch'
+import acupunctureGit from '@/components/acupuncture/Git'
+import acupunctureDoc from '@/components/acupuncture/Doc'
+
+export default {
+  components: {
+    Breadcrumb,
+    TopNav,
+    Hamburger,
+    Screenfull,
+    SizeSelect,
+    Search,
+    acupunctureGit,
+    acupunctureDoc
+  },
+  computed: {
+    ...mapGetters([
+      'sidebar',
+      'avatar',
+      'device'
+    ]),
+    setting: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    },
+    topNav: {
+      get() {
+        return this.$store.state.settings.topNav
+      }
+    }
+  },
+  methods: {
+    toggleSideBar() {
+      this.$store.dispatch('app/toggleSideBar')
+    },
+    async logout() {
+      this.$confirm('确定注销并退出系统吗?', '提示', {
+        confirmButtonText: '确定',
+        cancelButtonText: '取消',
+        type: 'warning'
+      }).then(() => {
+        this.$store.dispatch('LogOut').then(() => {
+          location.href = '/index';
+        })
+      }).catch(() => {});
+    }
+  }
+}
+</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;
+  }
+
+  .topmenu-container {
+    position: absolute;
+    left: 50px;
+  }
+
+  .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/main.js b/ruoyi-ui/src/main.js
index ebd94b9d..9f1c1816 100644
--- a/ruoyi-ui/src/main.js
+++ b/ruoyi-ui/src/main.js
@@ -1,86 +1,86 @@
-import Vue from 'vue'
-
-import Cookies from 'js-cookie'
-
-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 directive from './directive' // directive
-import plugins from './plugins' // plugins
-import { download } from '@/utils/request'
-
-import './assets/icons' // icon
-import './permission' // permission control
-import { getDicts } from "@/api/system/dict/data";
-import { getConfigKey } from "@/api/system/config";
-import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/ruoyi";
-// 分页组件
-import Pagination from "@/components/Pagination";
-// 自定义表格工具组件
-import RightToolbar from "@/components/RightToolbar"
-// 富文本组件
-import Editor from "@/components/Editor"
-// 文件上传组件
-import FileUpload from "@/components/FileUpload"
-// 图片上传组件
-import ImageUpload from "@/components/ImageUpload"
-// 图片预览组件
-import ImagePreview from "@/components/ImagePreview"
-// 字典标签组件
-import DictTag from '@/components/DictTag'
-// 头部标签组件
-import VueMeta from 'vue-meta'
-// 字典数据组件
-import DictData from '@/components/DictData'
-
-// 全局方法挂载
-Vue.prototype.getDicts = getDicts
-Vue.prototype.getConfigKey = getConfigKey
-Vue.prototype.parseTime = parseTime
-Vue.prototype.resetForm = resetForm
-Vue.prototype.addDateRange = addDateRange
-Vue.prototype.selectDictLabel = selectDictLabel
-Vue.prototype.selectDictLabels = selectDictLabels
-Vue.prototype.download = download
-Vue.prototype.handleTree = handleTree
-
-// 全局组件挂载
-Vue.component('DictTag', DictTag)
-Vue.component('Pagination', Pagination)
-Vue.component('RightToolbar', RightToolbar)
-Vue.component('Editor', Editor)
-Vue.component('FileUpload', FileUpload)
-Vue.component('ImageUpload', ImageUpload)
-Vue.component('ImagePreview', ImagePreview)
-
-Vue.use(directive)
-Vue.use(plugins)
-Vue.use(VueMeta)
-DictData.install()
-
-/**
- * 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)
-})
+import Vue from 'vue'
+
+import Cookies from 'js-cookie'
+
+import Element from 'element-ui'
+import './assets/styles/element-variables.scss'
+
+import '@/assets/styles/index.scss' // global css
+import '@/assets/styles/acupuncture.scss' // acupuncture css
+import App from './App'
+import store from './store'
+import router from './router'
+import directive from './directive' // directive
+import plugins from './plugins' // plugins
+import { download } from '@/utils/request'
+
+import './assets/icons' // icon
+import './permission' // permission control
+import { getDicts } from "@/api/system/dict/data";
+import { getConfigKey } from "@/api/system/config";
+import { parseTime, resetForm, addDateRange, selectDictLabel, selectDictLabels, handleTree } from "@/utils/acupuncture";
+// 分页组件
+import Pagination from "@/components/Pagination";
+// 自定义表格工具组件
+import RightToolbar from "@/components/RightToolbar"
+// 富文本组件
+import Editor from "@/components/Editor"
+// 文件上传组件
+import FileUpload from "@/components/FileUpload"
+// 图片上传组件
+import ImageUpload from "@/components/ImageUpload"
+// 图片预览组件
+import ImagePreview from "@/components/ImagePreview"
+// 字典标签组件
+import DictTag from '@/components/DictTag'
+// 头部标签组件
+import VueMeta from 'vue-meta'
+// 字典数据组件
+import DictData from '@/components/DictData'
+
+// 全局方法挂载
+Vue.prototype.getDicts = getDicts
+Vue.prototype.getConfigKey = getConfigKey
+Vue.prototype.parseTime = parseTime
+Vue.prototype.resetForm = resetForm
+Vue.prototype.addDateRange = addDateRange
+Vue.prototype.selectDictLabel = selectDictLabel
+Vue.prototype.selectDictLabels = selectDictLabels
+Vue.prototype.download = download
+Vue.prototype.handleTree = handleTree
+
+// 全局组件挂载
+Vue.component('DictTag', DictTag)
+Vue.component('Pagination', Pagination)
+Vue.component('RightToolbar', RightToolbar)
+Vue.component('Editor', Editor)
+Vue.component('FileUpload', FileUpload)
+Vue.component('ImageUpload', ImageUpload)
+Vue.component('ImagePreview', ImagePreview)
+
+Vue.use(directive)
+Vue.use(plugins)
+Vue.use(VueMeta)
+DictData.install()
+
+/**
+ * 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/plugins/download.js b/ruoyi-ui/src/plugins/download.js
index 42acd006..b53c938a 100644
--- a/ruoyi-ui/src/plugins/download.js
+++ b/ruoyi-ui/src/plugins/download.js
@@ -3,7 +3,7 @@ import {Loading, Message} from 'element-ui'
 import { saveAs } from 'file-saver'
 import { getToken } from '@/utils/auth'
 import errorCode from '@/utils/errorCode'
-import { blobValidate } from "@/utils/ruoyi";
+import { blobValidate } from "@/utils/acupuncture";
 
 const baseURL = process.env.VUE_APP_BASE_API
 let downloadLoadingInstance;
diff --git a/ruoyi-ui/src/utils/dict/Dict.js b/ruoyi-ui/src/utils/dict/Dict.js
index 22db32fe..37c635d1 100644
--- a/ruoyi-ui/src/utils/dict/Dict.js
+++ b/ruoyi-ui/src/utils/dict/Dict.js
@@ -1,82 +1,82 @@
-import Vue from 'vue'
-import { mergeRecursive } from "@/utils/ruoyi";
-import DictMeta from './DictMeta'
-import DictData from './DictData'
-
-const DEFAULT_DICT_OPTIONS = {
-  types: [],
-}
-
-/**
- * @classdesc 字典
- * @property {Object} label 标签对象,内部属性名为字典类型名称
- * @property {Object} dict 字段数组,内部属性名为字典类型名称
- * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
- */
-export default class Dict {
-  constructor() {
-    this.owner = null
-    this.label = {}
-    this.type = {}
-  }
-
-  init(options) {
-    if (options instanceof Array) {
-      options = { types: options }
-    }
-    const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
-    if (opts.types === undefined) {
-      throw new Error('need dict types')
-    }
-    const ps = []
-    this._dictMetas = opts.types.map(t => DictMeta.parse(t))
-    this._dictMetas.forEach(dictMeta => {
-      const type = dictMeta.type
-      Vue.set(this.label, type, {})
-      Vue.set(this.type, type, [])
-      if (dictMeta.lazy) {
-        return
-      }
-      ps.push(loadDict(this, dictMeta))
-    })
-    return Promise.all(ps)
-  }
-
-  /**
-   * 重新加载字典
-   * @param {String} type 字典类型
-   */
-  reloadDict(type) {
-    const dictMeta = this._dictMetas.find(e => e.type === type)
-    if (dictMeta === undefined) {
-      return Promise.reject(`the dict meta of ${type} was not found`)
-    }
-    return loadDict(this, dictMeta)
-  }
-}
-
-/**
- * 加载字典
- * @param {Dict} dict 字典
- * @param {DictMeta} dictMeta 字典元数据
- * @returns {Promise}
- */
-function loadDict(dict, dictMeta) {
-  return dictMeta.request(dictMeta)
-    .then(response => {
-      const type = dictMeta.type
-      let dicts = dictMeta.responseConverter(response, dictMeta)
-      if (!(dicts instanceof Array)) {
-        console.error('the return of responseConverter must be Array.<DictData>')
-        dicts = []
-      } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
-        console.error('the type of elements in dicts must be DictData')
-        dicts = []
-      }
-      dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
-      dicts.forEach(d => {
-        Vue.set(dict.label[type], d.value, d.label)
-      })
-      return dicts
-    })
-}
+import Vue from 'vue'
+import { mergeRecursive } from "@/utils/acupuncture";
+import DictMeta from './DictMeta'
+import DictData from './DictData'
+
+const DEFAULT_DICT_OPTIONS = {
+  types: [],
+}
+
+/**
+ * @classdesc 字典
+ * @property {Object} label 标签对象,内部属性名为字典类型名称
+ * @property {Object} dict 字段数组,内部属性名为字典类型名称
+ * @property {Array.<DictMeta>} _dictMetas 字典元数据数组
+ */
+export default class Dict {
+  constructor() {
+    this.owner = null
+    this.label = {}
+    this.type = {}
+  }
+
+  init(options) {
+    if (options instanceof Array) {
+      options = { types: options }
+    }
+    const opts = mergeRecursive(DEFAULT_DICT_OPTIONS, options)
+    if (opts.types === undefined) {
+      throw new Error('need dict types')
+    }
+    const ps = []
+    this._dictMetas = opts.types.map(t => DictMeta.parse(t))
+    this._dictMetas.forEach(dictMeta => {
+      const type = dictMeta.type
+      Vue.set(this.label, type, {})
+      Vue.set(this.type, type, [])
+      if (dictMeta.lazy) {
+        return
+      }
+      ps.push(loadDict(this, dictMeta))
+    })
+    return Promise.all(ps)
+  }
+
+  /**
+   * 重新加载字典
+   * @param {String} type 字典类型
+   */
+  reloadDict(type) {
+    const dictMeta = this._dictMetas.find(e => e.type === type)
+    if (dictMeta === undefined) {
+      return Promise.reject(`the dict meta of ${type} was not found`)
+    }
+    return loadDict(this, dictMeta)
+  }
+}
+
+/**
+ * 加载字典
+ * @param {Dict} dict 字典
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {Promise}
+ */
+function loadDict(dict, dictMeta) {
+  return dictMeta.request(dictMeta)
+    .then(response => {
+      const type = dictMeta.type
+      let dicts = dictMeta.responseConverter(response, dictMeta)
+      if (!(dicts instanceof Array)) {
+        console.error('the return of responseConverter must be Array.<DictData>')
+        dicts = []
+      } else if (dicts.filter(d => d instanceof DictData).length !== dicts.length) {
+        console.error('the type of elements in dicts must be DictData')
+        dicts = []
+      }
+      dict.type[type].splice(0, Number.MAX_SAFE_INTEGER, ...dicts)
+      dicts.forEach(d => {
+        Vue.set(dict.label[type], d.value, d.label)
+      })
+      return dicts
+    })
+}
diff --git a/ruoyi-ui/src/utils/dict/DictMeta.js b/ruoyi-ui/src/utils/dict/DictMeta.js
index 2ae08273..5c12bab4 100644
--- a/ruoyi-ui/src/utils/dict/DictMeta.js
+++ b/ruoyi-ui/src/utils/dict/DictMeta.js
@@ -1,38 +1,38 @@
-import { mergeRecursive } from "@/utils/ruoyi";
-import DictOptions from './DictOptions'
-
-/**
- * @classdesc 字典元数据
- * @property {String} type 类型
- * @property {Function} request 请求
- * @property {String} label 标签字段
- * @property {String} value 值字段
- */
-export default class DictMeta {
-  constructor(options) {
-    this.type = options.type
-    this.request = options.request
-    this.responseConverter = options.responseConverter
-    this.labelField = options.labelField
-    this.valueField = options.valueField
-    this.lazy = options.lazy === true
-  }
-}
-
-
-/**
- * 解析字典元数据
- * @param {Object} options
- * @returns {DictMeta}
- */
-DictMeta.parse= function(options) {
-  let opts = null
-  if (typeof options === 'string') {
-    opts = DictOptions.metas[options] || {}
-    opts.type = options
-  } else if (typeof options === 'object') {
-    opts = options
-  }
-  opts = mergeRecursive(DictOptions.metas['*'], opts)
-  return new DictMeta(opts)
-}
+import { mergeRecursive } from "@/utils/acupuncture";
+import DictOptions from './DictOptions'
+
+/**
+ * @classdesc 字典元数据
+ * @property {String} type 类型
+ * @property {Function} request 请求
+ * @property {String} label 标签字段
+ * @property {String} value 值字段
+ */
+export default class DictMeta {
+  constructor(options) {
+    this.type = options.type
+    this.request = options.request
+    this.responseConverter = options.responseConverter
+    this.labelField = options.labelField
+    this.valueField = options.valueField
+    this.lazy = options.lazy === true
+  }
+}
+
+
+/**
+ * 解析字典元数据
+ * @param {Object} options
+ * @returns {DictMeta}
+ */
+DictMeta.parse= function(options) {
+  let opts = null
+  if (typeof options === 'string') {
+    opts = DictOptions.metas[options] || {}
+    opts.type = options
+  } else if (typeof options === 'object') {
+    opts = options
+  }
+  opts = mergeRecursive(DictOptions.metas['*'], opts)
+  return new DictMeta(opts)
+}
diff --git a/ruoyi-ui/src/utils/dict/DictOptions.js b/ruoyi-ui/src/utils/dict/DictOptions.js
index 5e1cc41f..b6046c86 100644
--- a/ruoyi-ui/src/utils/dict/DictOptions.js
+++ b/ruoyi-ui/src/utils/dict/DictOptions.js
@@ -1,51 +1,51 @@
-import { mergeRecursive } from "@/utils/ruoyi";
-import dictConverter from './DictConverter'
-
-export const options = {
-  metas: {
-    '*': {
-      /**
-       * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
-       */
-      request: (dictMeta) => {
-        console.log(`load dict ${dictMeta.type}`)
-        return Promise.resolve([])
-      },
-      /**
-       * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
-       */
-      responseConverter,
-      labelField: 'label',
-      valueField: 'value',
-    },
-  },
-  /**
-   * 默认标签字段
-   */
-  DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
-  /**
-   * 默认值字段
-   */
-  DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
-}
-
-/**
- * 映射字典
- * @param {Object} response 字典数据
- * @param {DictMeta} dictMeta 字典元数据
- * @returns {DictData}
- */
-function responseConverter(response, dictMeta) {
-  const dicts = response.content instanceof Array ? response.content : response
-  if (dicts === undefined) {
-    console.warn(`no dict data of "${dictMeta.type}" found in the response`)
-    return []
-  }
-  return dicts.map(d => dictConverter(d, dictMeta))
-}
-
-export function mergeOptions(src) {
-  mergeRecursive(options, src)
-}
-
-export default options
+import { mergeRecursive } from "@/utils/acupuncture";
+import dictConverter from './DictConverter'
+
+export const options = {
+  metas: {
+    '*': {
+      /**
+       * 字典请求,方法签名为function(dictMeta: DictMeta): Promise
+       */
+      request: (dictMeta) => {
+        console.log(`load dict ${dictMeta.type}`)
+        return Promise.resolve([])
+      },
+      /**
+       * 字典响应数据转换器,方法签名为function(response: Object, dictMeta: DictMeta): DictData
+       */
+      responseConverter,
+      labelField: 'label',
+      valueField: 'value',
+    },
+  },
+  /**
+   * 默认标签字段
+   */
+  DEFAULT_LABEL_FIELDS: ['label', 'name', 'title'],
+  /**
+   * 默认值字段
+   */
+  DEFAULT_VALUE_FIELDS: ['value', 'id', 'uid', 'key'],
+}
+
+/**
+ * 映射字典
+ * @param {Object} response 字典数据
+ * @param {DictMeta} dictMeta 字典元数据
+ * @returns {DictData}
+ */
+function responseConverter(response, dictMeta) {
+  const dicts = response.content instanceof Array ? response.content : response
+  if (dicts === undefined) {
+    console.warn(`no dict data of "${dictMeta.type}" found in the response`)
+    return []
+  }
+  return dicts.map(d => dictConverter(d, dictMeta))
+}
+
+export function mergeOptions(src) {
+  mergeRecursive(options, src)
+}
+
+export default options
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
index 5799c05d..c79bd683 100644
--- a/ruoyi-ui/src/utils/index.js
+++ b/ruoyi-ui/src/utils/index.js
@@ -1,390 +1,390 @@
-import { parseTime } from './ruoyi'
-
-/**
- * 表格时间格式化
- */
-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 = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
-  if (!search) {
-    return {}
-  }
-  const obj = {}
-  const searchArr = search.split('&')
-  searchArr.forEach(v => {
-    const index = v.indexOf('=')
-    if (index !== -1) {
-      const name = v.substring(0, index)
-      const val = v.substring(index + 1, v.length)
-      obj[name] = val
-    }
-  })
-  return obj
-}
-
-/**
- * @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
-      // 如果设定为immediate===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, ' ')
-  }
-}
-
-export function makeMap(str, expectsLowerCase) {
-  const map = Object.create(null)
-  const list = str.split(',')
-  for (let i = 0; i < list.length; i++) {
-    map[list[i]] = true
-  }
-  return expectsLowerCase
-    ? val => map[val.toLowerCase()]
-    : val => map[val]
-}
-
-export const exportDefault = 'export default '
-
-export const beautifierConf = {
-  html: {
-    indent_size: '2',
-    indent_char: ' ',
-    max_preserve_newlines: '-1',
-    preserve_newlines: false,
-    keep_array_indentation: false,
-    break_chained_methods: false,
-    indent_scripts: 'separate',
-    brace_style: 'end-expand',
-    space_before_conditional: true,
-    unescape_strings: false,
-    jslint_happy: false,
-    end_with_newline: true,
-    wrap_line_length: '110',
-    indent_inner_html: true,
-    comma_first: false,
-    e4x: true,
-    indent_empty_lines: true
-  },
-  js: {
-    indent_size: '2',
-    indent_char: ' ',
-    max_preserve_newlines: '-1',
-    preserve_newlines: false,
-    keep_array_indentation: false,
-    break_chained_methods: false,
-    indent_scripts: 'normal',
-    brace_style: 'end-expand',
-    space_before_conditional: true,
-    unescape_strings: false,
-    jslint_happy: true,
-    end_with_newline: true,
-    wrap_line_length: '110',
-    indent_inner_html: true,
-    comma_first: false,
-    e4x: true,
-    indent_empty_lines: true
-  }
-}
-
-// 首字母大小
-export function titleCase(str) {
-  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
-}
-
-// 下划转驼峰
-export function camelCase(str) {
-  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
-}
-
-export function isNumberStr(str) {
-  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
-}
-
+import { parseTime } from './acupuncture'
+
+/**
+ * 表格时间格式化
+ */
+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 = decodeURIComponent(url.split('?')[1]).replace(/\+/g, ' ')
+  if (!search) {
+    return {}
+  }
+  const obj = {}
+  const searchArr = search.split('&')
+  searchArr.forEach(v => {
+    const index = v.indexOf('=')
+    if (index !== -1) {
+      const name = v.substring(0, index)
+      const val = v.substring(index + 1, v.length)
+      obj[name] = val
+    }
+  })
+  return obj
+}
+
+/**
+ * @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
+      // 如果设定为immediate===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, ' ')
+  }
+}
+
+export function makeMap(str, expectsLowerCase) {
+  const map = Object.create(null)
+  const list = str.split(',')
+  for (let i = 0; i < list.length; i++) {
+    map[list[i]] = true
+  }
+  return expectsLowerCase
+    ? val => map[val.toLowerCase()]
+    : val => map[val]
+}
+
+export const exportDefault = 'export default '
+
+export const beautifierConf = {
+  html: {
+    indent_size: '2',
+    indent_char: ' ',
+    max_preserve_newlines: '-1',
+    preserve_newlines: false,
+    keep_array_indentation: false,
+    break_chained_methods: false,
+    indent_scripts: 'separate',
+    brace_style: 'end-expand',
+    space_before_conditional: true,
+    unescape_strings: false,
+    jslint_happy: false,
+    end_with_newline: true,
+    wrap_line_length: '110',
+    indent_inner_html: true,
+    comma_first: false,
+    e4x: true,
+    indent_empty_lines: true
+  },
+  js: {
+    indent_size: '2',
+    indent_char: ' ',
+    max_preserve_newlines: '-1',
+    preserve_newlines: false,
+    keep_array_indentation: false,
+    break_chained_methods: false,
+    indent_scripts: 'normal',
+    brace_style: 'end-expand',
+    space_before_conditional: true,
+    unescape_strings: false,
+    jslint_happy: true,
+    end_with_newline: true,
+    wrap_line_length: '110',
+    indent_inner_html: true,
+    comma_first: false,
+    e4x: true,
+    indent_empty_lines: true
+  }
+}
+
+// 首字母大小
+export function titleCase(str) {
+  return str.replace(/( |^)[a-z]/g, L => L.toUpperCase())
+}
+
+// 下划转驼峰
+export function camelCase(str) {
+  return str.replace(/_[a-z]/g, str1 => str1.substr(-1).toUpperCase())
+}
+
+export function isNumberStr(str) {
+  return /^[+-]?(0|([1-9]\d*))(\.\d+)?$/g.test(str)
+}
+
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
index ffb0d219..ef386d29 100644
--- a/ruoyi-ui/src/utils/request.js
+++ b/ruoyi-ui/src/utils/request.js
@@ -3,7 +3,7 @@ import { Notification, MessageBox, Message, Loading } from 'element-ui'
 import store from '@/store'
 import { getToken } from '@/utils/auth'
 import errorCode from '@/utils/errorCode'
-import { tansParams, blobValidate } from "@/utils/ruoyi";
+import { tansParams, blobValidate } from "@/utils/acupuncture";
 import cache from '@/plugins/cache'
 import { saveAs } from 'file-saver'
 
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
index 44bf9c40..bd3a6f1e 100644
--- a/ruoyi-ui/src/utils/ruoyi.js
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -2,7 +2,7 @@
 
 /**
  * 通用js方法封装处理
- * Copyright (c) 2019 ruoyi
+ * Copyright (c) 2019 acupuncture
  */
 
 // 日期格式化
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
index ea46beb0..737595c6 100644
--- a/ruoyi-ui/src/views/index.vue
+++ b/ruoyi-ui/src/views/index.vue
@@ -1,1108 +1,1108 @@
-<template>
-  <div class="app-container home">
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="24">
-        <blockquote class="text-warning" style="font-size: 14px">
-          阿里云服务器折扣区<el-link href="http://aly.ruoyi.vip" type="primary" target="_blank">☛☛点我进入☚☚</el-link> &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区<el-link href="http://txy.ruoyi.vip" type="primary" target="_blank">☛☛点我进入☚☚</el-link>
-        </blockquote>
-        <hr />
-      </el-col>
-    </el-row>
-    <el-row :gutter="20">
-      <el-col :sm="24" :lg="12" style="padding-left: 20px">
-        <h2>若依后台管理框架</h2>
-        <p>
-          一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
-        </p>
-        <p>
-          <b>当前版本:</b> <span>v{{ version }}</span>
-        </p>
-        <p>
-          <el-tag type="danger">&yen;免费开源</el-tag>
-        </p>
-        <p>
-          <el-button
-            type="primary"
-            size="mini"
-            icon="el-icon-cloudy"
-            plain
-            @click="goTarget('https://gitee.com/y_project/RuoYi-Vue')"
-            >访问码云</el-button
-          >
-          <el-button
-            size="mini"
-            icon="el-icon-s-home"
-            plain
-            @click="goTarget('http://ruoyi.vip')"
-            >访问主页</el-button
-          >
-        </p>
-      </el-col>
-
-      <el-col :sm="24" :lg="12" style="padding-left: 50px">
-        <el-row>
-          <el-col :span="12">
-            <h2>技术选型</h2>
-          </el-col>
-        </el-row>
-        <el-row>
-          <el-col :span="6">
-            <h4>后端技术</h4>
-            <ul>
-              <li>SpringBoot</li>
-              <li>Spring Security</li>
-              <li>JWT</li>
-              <li>MyBatis</li>
-              <li>Druid</li>
-              <li>Fastjson</li>
-              <li>...</li>
-            </ul>
-          </el-col>
-          <el-col :span="6">
-            <h4>前端技术</h4>
-            <ul>
-              <li>Vue</li>
-              <li>Vuex</li>
-              <li>Element-ui</li>
-              <li>Axios</li>
-              <li>Sass</li>
-              <li>Quill</li>
-              <li>...</li>
-            </ul>
-          </el-col>
-        </el-row>
-      </el-col>
-    </el-row>
-    <el-divider />
-    <el-row :gutter="20">
-      <el-col :xs="24" :sm="24" :md="12" :lg="8">
-        <el-card class="update-log">
-          <div slot="header" class="clearfix">
-            <span>联系信息</span>
-          </div>
-          <div class="body">
-            <p>
-              <i class="el-icon-s-promotion"></i> 官网:<el-link
-                href="http://www.ruoyi.vip"
-                target="_blank"
-                >http://www.ruoyi.vip</el-link
-              >
-            </p>
-            <p>
-              <i class="el-icon-user-solid"></i> QQ群:<s> 满937441 </s> <s> 满887144332 </s>
-              <s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s>
-              <s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s> 
-              <s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s> 
-              <s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s> 
-              <s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
-              <s> 满287842588 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=HKz42pk2zQ1WUMbbRo50-N7tY4IDKKrj&authKey=ukBg3edmUbnmoo40xZCo6R1tYdTglYJ1nBFRW9gTHuZwLI1r8wgFT6cWUrAldwcr&noverify=0&group_code=187944233" target="_blank">187944233</a>
-            </p>
-            <p>
-              <i class="el-icon-chat-dot-round"></i> 微信:<a
-                href="javascript:;"
-                >/ *若依</a
-              >
-            </p>
-            <p>
-              <i class="el-icon-money"></i> 支付宝:<a
-                href="javascript:;"
-                class="支付宝信息"
-                >/ *若依</a
-              >
-            </p>
-          </div>
-        </el-card>
-      </el-col>
-      <el-col :xs="24" :sm="24" :md="12" :lg="8">
-        <el-card class="update-log">
-          <div slot="header" class="clearfix">
-            <span>更新日志</span>
-          </div>
-          <el-collapse accordion>
-            <el-collapse-item title="v3.8.9 - 2024-12-30">
-              <ol>
-                <li>用户管理支持分栏拖动</li>
-                <li>修改主题样式本地读取</li>
-                <li>用户头像http(s)链接支持</li>
-                <li>用户管理过滤掉已禁用部门</li>
-                <li>支持自定义显示Excel属性列</li>
-                <li>操作日志记录DELETE请求参数</li>
-                <li>白名单支持对通配符路径匹配</li>
-                <li>校检文件名是否包含特殊字符</li>
-                <li>代码生成创建表屏蔽违规的字符</li>
-                <li>菜单面包屑导航支持多层级显示</li>
-                <li>Excel注解支持wrapText是否允许内容换行</li>
-                <li>代码生成新增配置是否允许文件覆盖到本地</li>
-                <li>修复角色禁用权限不失效问题</li>
-                <li>修复代码生成上级菜单显示问题</li>
-                <li>修复导出子列表对象只能在最后的问题</li>
-                <li>修复TopNav无法正确获取active的问题</li>
-                <li>修复默认关闭Tags-Views内链页面打不开</li>
-                <li>升级oshi到最新版本6.6.5</li>
-                <li>升级tomcat到最新版本9.0.96</li>
-                <li>升级fastjson到最新版2.0.53</li>
-                <li>升级logback到最新版本1.2.13</li>
-                <li>升级spring-framework到最新版本5.3.39</li>
-                <li>升级quill到最新版本2.0.2</li>
-                <li>升级axios到最新版本0.28.1</li>
-                <li>优化身份证脱敏正则</li>
-                <li>优化权限更新后同步缓存</li>
-                <li>优化查询时间范围日期格式</li>
-                <li>优化参数键值更换为多行文本</li>
-                <li>优化导入带标题文件关闭清理</li>
-                <li>优化上传图片带域名不增加前缀</li>
-                <li>优化特殊字符密码修改失败问题</li>
-                <li>优化无用户编号不校验数据权限</li>
-                <li>优化TopNav内链菜单点击没有高亮</li>
-                <li>优化菜单管理切换Mini布局错乱问题</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.8 - 2024-06-30">
-              <ol>
-                <li>菜单管理新增路由名称</li>
-                <li>新增数据脱敏过滤注解</li>
-                <li>用户密码新增非法字符验证</li>
-                <li>限制用户操作数据权限范围</li>
-                <li>代码生成新增创建表结构功能</li>
-                <li>定时任务白名单配置范围缩小</li>
-                <li>优化代码生成主子表关联查询方式</li>
-                <li>Excel注解新增属性comboReadDict</li>
-                <li>Excel注解ColumnType类型新增文本</li>
-                <li>新增国际化资源文件配置</li>
-                <li>升级oshi到最新版本6.6.1</li>
-                <li>升级druid到最新版本1.2.23</li>
-                <li>升级core-js到最新版本3.37.1</li>
-                <li>更新HttpUtils中的User-Agent</li>
-                <li>更新compressionPlugin到6.1.2以兼容node18+</li>
-                <li>升级spring-security到安全版本,防止漏洞风险</li>
-                <li>升级spring-framework到安全版本,防止漏洞风险</li>
-                <li>优化自定义XSS注解匹配方式</li>
-                <li>优化缓存监控键名列表排序显示</li>
-                <li>优化定时任务日志默认按时间排序</li>
-                <li>优化默认文件大小超过2G无效的问题</li>
-                <li>优化查表特殊字符使用反斜杠进行转义</li>
-                <li>优化定时任务cron表达式小时配置显示错误问题</li>
-                <li>优化多个自定数据权限使用in查询,避免多次拼接</li>
-                <li>优化导入Excel时设置dictType属性重复查缓存问题</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.7 - 2023-12-08">
-              <ol>
-                <li>操作日志记录部门名称</li>
-                <li>全局数据存储用户编号</li>
-                <li>新增编程式判断资源访问权限</li>
-                <li>操作日志列表新增IP地址查询</li>
-                <li>定时任务新增页去除状态选项</li>
-                <li>代码生成支持选择前端模板类型</li>
-                <li>显隐列组件支持复选框弹出类型</li>
-                <li>通用排序属性orderBy参数限制长度</li>
-                <li>Excel自定义数据处理器增加单元格/工作簿对象</li>
-                <li>升级oshi到最新版本6.4.8</li>
-                <li>升级druid到最新版本1.2.20</li>
-                <li>升级fastjson到最新版2.0.43</li>
-                <li>升级pagehelper到最新版1.4.7</li>
-                <li>升级commons.io到最新版本2.13.0</li>
-                <li>升级element-ui到最新版本2.15.14</li>
-                <li>修复五级路由缓存无效问题</li>
-                <li>修复外链带端口出现的异常</li>
-                <li>修复树模板父级编码变量错误</li>
-                <li>修复字典表详情页面搜索问题</li>
-                <li>修复内链iframe没有传递参数问题</li>
-                <li>修复自定义字典样式不生效的问题</li>
-                <li>修复字典缓存删除方法参数错误问题</li>
-                <li>修复Excel导入数据临时文件无法删除问题</li>
-                <li>修复未登录带参数访问成功后参数丢失问题</li>
-                <li>修复HeaderSearch组件跳转query参数丢失问题</li>
-                <li>修复代码生成导入后必填项与数据库不匹配问题</li>
-                <li>修复Excels导入时无法获取到dictType字典值问题</li>
-                <li>优化下载zip方法新增遮罩层</li>
-                <li>优化头像上传参数新增文件名称</li>
-                <li>优化字典标签支持自定义分隔符</li>
-                <li>优化菜单管理类型为按钮状态可选</li>
-                <li>优化前端防重复提交数据大小限制</li>
-                <li>优化TopNav菜单没有图标svg不显示</li>
-                <li>优化数字金额大写转换精度丢失问题</li>
-                <li>优化富文本Editor组件检验图片格式</li>
-                <li>优化页签在Firefox浏览器被遮挡的问题</li>
-                <li>优化个人中心/基本资料修改时数据显示问题</li>
-                <li>优化缓存监控图表支持跟随屏幕大小自适应调整</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.6 - 2023-06-30">
-              <ol>
-                <li>支持登录IP黑名单限制</li>
-                <li>新增监控页面图标显示</li>
-                <li>操作日志新增消耗时间属性</li>
-                <li>屏蔽定时任务bean违规的字符</li>
-                <li>日志管理使用索引提升查询性能</li>
-                <li>日志注解支持排除指定的请求参数</li>
-                <li>支持自定义隐藏属性列过滤子对象</li>
-                <li>升级oshi到最新版本6.4.3</li>
-                <li>升级druid到最新版本1.2.16</li>
-                <li>升级fastjson到最新版2.0.34</li>
-                <li>升级spring-boot到最新版本2.5.15</li>
-                <li>升级element-ui到最新版本2.15.13</li>
-                <li>移除apache/commons-fileupload依赖</li>
-                <li>修复页面切换时布局错乱的问题</li>
-                <li>修复匿名注解Anonymous空指针问题</li>
-                <li>修复路由跳转被阻止时内部产生报错信息问题</li>
-                <li>修复isMatchedIp的参数判断产生空指针的问题</li>
-                <li>修复用户多角色数据权限可能出现权限抬升的情况</li>
-                <li>修复开启TopNav后一级菜单路由参数设置无效问题</li>
-                <li>修复DictTag组件value没有匹配的值时则展示value</li>
-                <li>优化文件下载出现的异常</li>
-                <li>优化选择图标组件高亮回显</li>
-                <li>优化弹窗后导航栏偏移的问题</li>
-                <li>优化修改密码日志存储明文问题</li>
-                <li>优化页签栏关闭其他出现的异常问题</li>
-                <li>优化页签关闭左侧选项排除首页选项</li>
-                <li>优化关闭当前tab页跳转最右侧tab页</li>
-                <li>优化缓存列表清除操作提示不变的问题</li>
-                <li>优化字符未使用下划线不进行驼峰式处理</li>
-                <li>优化用户导入更新时需获取用户编号问题</li>
-                <li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li>
-                <li>优化导出Excel时设置dictType属性重复查缓存问题</li>
-                <li>连接池Druid支持新的配置connectTimeout和socketTimeout</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.5 - 2023-01-01">
-              <ol>
-                <li>定时任务违规的字符</li>
-                <li>重置时取消部门选中</li>
-                <li>新增返回警告消息提示</li>
-                <li>忽略不必要的属性数据返回</li>
-                <li>修改参数键名时移除前缓存配置</li>
-                <li>导入更新用户数据前校验数据权限</li>
-                <li>兼容Excel下拉框内容过多无法显示的问题</li>
-                <li>升级echarts到最新版本5.4.0</li>
-                <li>升级core-js到最新版本3.25.3</li>
-                <li>升级oshi到最新版本6.4.0</li>
-                <li>升级kaptcha到最新版2.3.3</li>
-                <li>升级druid到最新版本1.2.15</li>
-                <li>升级fastjson到最新版2.0.20</li>
-                <li>升级pagehelper到最新版1.4.6</li>
-                <li>优化弹窗内容过多展示不全问题</li>
-                <li>优化swagger-ui静态资源使用缓存</li>
-                <li>开启TopNav没有子菜单隐藏侧边栏</li>
-                <li>删除fuse无效选项maxPatternLength</li>
-                <li>优化导出对象的子列表为空会出现[]问题</li>
-                <li>优化编辑头像时透明部分会变成黑色问题</li>
-                <li>优化小屏幕上修改头像界面布局错位的问题</li>
-                <li>修复代码生成勾选属性无效问题</li>
-                <li>修复文件上传组件格式验证问题</li>
-                <li>修复回显数据字典数组异常问题</li>
-                <li>修复sheet超出最大行数异常问题</li>
-                <li>修复Log注解GET请求记录不到参数问题</li>
-                <li>修复调度日志点击多次数据不变化的问题</li>
-                <li>修复主题颜色在Drawer组件不会加载问题</li>
-                <li>修复文件名包含特殊字符的文件无法下载问题</li>
-                <li>修复table中更多按钮切换主题色未生效修复问题</li>
-                <li>修复某些特性的环境生成代码变乱码TXT文件问题</li>
-                <li>修复代码生成图片/文件/单选时选择必填无法校验问题</li>
-                <li>修复某些特性的情况用户编辑对话框中角色和部门无法修改问题</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.4 - 2022-09-26">
-              <ol>
-                <li>数据逻辑删除不进行唯一验证</li>
-                <li>Excel注解支持导出对象的子列表方法</li>
-                <li>Excel注解支持自定义隐藏属性列</li>
-                <li>Excel注解支持backgroundColor属性设置背景色</li>
-                <li>支持配置密码最大错误次数/锁定时间</li>
-                <li>登录日志新增解锁账户功能</li>
-                <li>通用下载方法新增config配置选项</li>
-                <li>支持多权限字符匹配角色数据权限</li>
-                <li>页面内嵌iframe切换tab不刷新数据</li>
-                <li>操作日志记录支持排除敏感属性字段</li>
-                <li>修复多文件上传报错出现的异常问题</li>
-                <li>修复图片预览组件src属性为null值控制台报错问题</li>
-                <li>升级oshi到最新版本6.2.2</li>
-                <li>升级fastjson到最新版2.0.14</li>
-                <li>升级pagehelper到最新版1.4.3</li>
-                <li>升级core-js到最新版本3.25.2</li>
-                <li>升级element-ui到最新版本2.15.10</li>
-                <li>优化任务过期不执行调度</li>
-                <li>优化字典数据使用store存取</li>
-                <li>优化修改资料头像被覆盖的问题</li>
-                <li>优化修改用户登录账号重复验证</li>
-                <li>优化代码生成同步后值NULL问题</li>
-                <li>优化定时任务支持执行父类方法</li>
-                <li>优化用户个人信息接口防止修改部门</li>
-                <li>优化布局设置使用el-drawer抽屉显示</li>
-                <li>优化没有权限的用户编辑部门缺少数据</li>
-                <li>优化日志注解记录限制请求地址的长度</li>
-                <li>优化excel/scale属性导出单元格数值类型</li>
-                <li>优化日志操作中重置按钮时重复查询的问题</li>
-                <li>优化多个相同角色数据导致权限SQL重复问题</li>
-                <li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.3 - 2022-06-27">
-              <ol>
-                <li>新增缓存列表菜单功能</li>
-                <li>代码生成树表新增(展开/折叠)</li>
-                <li>Excel注解支持color字体颜色</li>
-                <li>新增Anonymous匿名访问不鉴权注解</li>
-                <li>用户头像上传限制只能为图片格式</li>
-                <li>接口使用泛型使其看到响应属性字段</li>
-                <li>检查定时任务bean所在包名是否为白名单配置</li>
-                <li>添加页签openPage支持传递参数</li>
-                <li>用户缓存信息添加部门ancestors祖级列表</li>
-                <li>升级element-ui到最新版本2.15.8</li>
-                <li>升级oshi到最新版本6.1.6</li>
-                <li>升级druid到最新版本1.2.11</li>
-                <li>升级fastjson到最新版2.0.8</li>
-                <li>升级spring-boot到最新版本2.5.14</li>
-                <li>降级jsencrypt版本兼容IE浏览器</li>
-                <li>删除多余的salt字段</li>
-                <li>新增获取不带后缀文件名称方法</li>
-                <li>新增获取配置文件中的属性值方法</li>
-                <li>新增内容编码/解码方便插件集成使用</li>
-                <li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
-                <li>优化设置分页参数默认值</li>
-                <li>优化对空字符串参数处理的过滤</li>
-                <li>优化显示顺序orderNum类型为整型</li>
-                <li>优化表单构建按钮不显示正则校验</li>
-                <li>优化字典数据回显样式下拉框显示值</li>
-                <li>优化R响应成功状态码与全局保持一致</li>
-                <li>优化druid开启wall过滤器出现的异常问题</li>
-                <li>优化用户管理左侧树型组件增加选中高亮保持</li>
-                <li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
-                <li>优化默认不启用压缩文件缓存防止node_modules过大</li>
-                <li>修复字典数据显示不全问题</li>
-                <li>修复操作日志查询类型条件为0时会查到所有数据</li>
-                <li>修复Excel注解prompt/combo同时使用不生效问题</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.2 - 2022-04-01">
-              <ol>
-                <li>前端支持设置是否需要防止数据重复提交</li>
-                <li>开启TopNav没有子菜单情况隐藏侧边栏</li>
-                <li>侧边栏菜单名称过长悬停显示标题</li>
-                <li>用户访问控制时校验数据权限,防止越权</li>
-                <li>导出Excel时屏蔽公式,防止CSV注入风险</li>
-                <li>组件ImagePreview支持多图预览显示</li>
-                <li>组件ImageUpload支持多图同时选择上传</li>
-                <li>组件FileUpload支持多文件同时选择上传</li>
-                <li>服务监控新增运行参数信息显示</li>
-                <li>定时任务目标字符串过滤特殊字符</li>
-                <li>定时任务目标字符串验证包名白名单</li>
-                <li>代码生成列表图片支持预览</li>
-                <li>代码生成编辑修改打开新页签</li>
-                <li>代码生成新增Java类型Boolean</li>
-                <li>代码生成子表支持日期/字典配置</li>
-                <li>代码生成同步保留必填/类型选项</li>
-                <li>升级oshi到最新版本6.1.2</li>
-                <li>升级fastjson到最新版1.2.80</li>
-                <li>升级pagehelper到最新版1.4.1</li>
-                <li>升级spring-boot到最新版本2.5.11</li>
-                <li>升级spring-boot-mybatis到最新版2.2.2</li>
-                <li>添加遗漏的分页参数合理化属性</li>
-                <li>修改npm即将过期的注册源地址</li>
-                <li>修复分页组件请求两次问题</li>
-                <li>修复通用文件下载接口跨域问题</li>
-                <li>修复Xss注解字段值为空时的异常问题</li>
-                <li>修复选项卡点击右键刷新丢失参数问题</li>
-                <li>修复表单清除元素位置未垂直居中问题</li>
-                <li>修复服务监控中运行参数显示条件错误</li>
-                <li>修复导入Excel时字典字段类型为Long转义为空问题</li>
-                <li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
-                <li>优化加载字典缓存数据</li>
-                <li>优化IP地址获取到多个的问题</li>
-                <li>优化任务队列满时任务拒绝策略</li>
-                <li>优化文件上传兼容Weblogic环境</li>
-                <li>优化定时任务默认保存到内存中执行</li>
-                <li>优化部门修改缩放后出现的错位问题</li>
-                <li>优化Excel格式化不同类型的日期对象</li>
-                <li>优化菜单表关键字导致的插件报错问题</li>
-                <li>优化Oracle用户头像列为空时不显示问题</li>
-                <li>优化页面若未匹配到字典标签则返回原字典值</li>
-                <li>优化修复登录失效后多次请求提示多次弹窗问题</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.1 - 2022-01-01">
-              <ol>
-                <li>新增Vue3前端代码生成模板</li>
-                <li>新增图片预览组件</li>
-                <li>新增压缩插件实现打包Gzip</li>
-                <li>自定义xss校验注解实现</li>
-                <li>自定义文字复制剪贴指令</li>
-                <li>代码生成预览支持复制内容</li>
-                <li>路由支持单独配置菜单或角色权限</li>
-                <li>用户管理部门查询选择节点后分页参数初始</li>
-                <li>修复用户分配角色属性错误</li>
-                <li>修复打包后字体图标偶现的乱码问题</li>
-                <li>修复菜单管理重置表单出现的错误</li>
-                <li>修复版本差异导致的懒加载报错问题</li>
-                <li>修复Cron组件中周回显问题</li>
-                <li>修复定时任务多参数逗号分隔的问题</li>
-                <li>修复根据ID查询列表可能出现的主键溢出问题</li>
-                <li>修复tomcat配置参数已过期问题</li>
-                <li>升级clipboard到最新版本2.0.8</li>
-                <li>升级oshi到最新版本v5.8.6</li>
-                <li>升级fastjson到最新版1.2.79</li>
-                <li>升级spring-boot到最新版本2.5.8</li>
-                <li>升级log4j2到2.17.1,防止漏洞风险</li>
-                <li>优化下载解析blob异常提示</li>
-                <li>优化代码生成字典组重复问题</li>
-                <li>优化查询用户的角色组&岗位组代码</li>
-                <li>优化定时任务cron表达式小时设置24</li>
-                <li>优化用户导入提示溢出则显示滚动条</li>
-                <li>优化防重复提交标识组合为(key+url+header)</li>
-                <li>优化分页方法设置成通用方便灵活调用</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.8.0 - 2021-12-01">
-              <ol>
-                <li>新增配套并同步的Vue3前端版本</li>
-                <li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
-                <li>优化导出数据/使用通用下载方法</li>
-                <li>Excel注解支持自定义数据处理器</li>
-                <li>Excel注解支持导入导出标题信息</li>
-                <li>Excel导入支持@Excels注解</li>
-                <li>新增组件data-dict,简化数据字典使用</li>
-                <li>新增Jaxb依赖,防止jdk8以上出现的兼容错误</li>
-                <li>生产环境使用路由懒加载提升页面响应速度</li>
-                <li>修复五级以上菜单出现的404问题</li>
-                <li>防重提交注解支持配置间隔时间/提示消息</li>
-                <li>日志注解新增是否保存响应参数</li>
-                <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
-                <li>升级SpringBoot到最新版本2.5.6</li>
-                <li>升级pagehelper到最新版1.4.0</li>
-                <li>升级spring-boot-mybatis到最新版2.2.0</li>
-                <li>升级oshi到最新版本v5.8.2</li>
-                <li>升级druid到最新版1.2.8</li>
-                <li>升级velocity到最新版本2.3</li>
-                <li>升级fastjson到最新版1.2.78</li>
-                <li>升级axios到最新版本0.24.0</li>
-                <li>升级dart-sass到版本1.32.13</li>
-                <li>升级core-js到最新版本3.19.1</li>
-                <li>升级jsencrypt到最新版本3.2.1</li>
-                <li>升级js-cookie到最新版本3.0.1</li>
-                <li>升级file-saver到最新版本2.0.5</li>
-                <li>升级sass-loader到最新版本10.1.1</li>
-                <li>升级element-ui到最新版本2.15.6</li>
-                <li>新增sendGet无参请求方法</li>
-                <li>禁用el-tag组件的渐变动画</li>
-                <li>代码生成点击预览重置激活tab</li>
-                <li>AjaxResult重写put方法,以方便链式调用</li>
-                <li>优化登录/验证码请求headers不设置token</li>
-                <li>优化用户个人信息接口防止修改用户名</li>
-                <li>优化Cron表达式生成器关闭时销毁避免缓存</li>
-                <li>优化注册成功提示消息类型success</li>
-                <li>优化aop语法,使用spring自动注入注解</li>
-                <li>优化记录登录信息,移除不必要的修改</li>
-                <li>优化mybatis全局默认的执行器</li>
-                <li>优化Excel导入图片可能出现的异常</li>
-                <li>修复代码生成模板主子表删除缺少事务</li>
-                <li>修复日志记录可能出现的转换异常</li>
-                <li>修复代码生成复选框字典遗漏问题</li>
-                <li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
-                <li>修复字符串无法被反转义问题</li>
-                <li>修复后端主子表代码模板方法名生成错误问题</li>
-                <li>修复xss过滤后格式出现的异常</li>
-                <li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.7.0 - 2021-09-13">
-              <ol>
-                <li>参数管理支持配置验证码开关</li>
-                <li>新增是否开启用户注册功能</li>
-                <li>定时任务支持在线生成cron表达式</li>
-                <li>菜单管理支持配置路由参数</li>
-                <li>支持自定义注解实现接口限流</li>
-                <li>Excel注解支持Image图片导入</li>
-                <li>自定义弹层溢出滚动样式</li>
-                <li>自定义可拖动弹窗宽度指令</li>
-                <li>自定义可拖动弹窗高度指令</li>
-                <li>修复任意账户越权问题</li>
-                <li>修改时检查用户数据权限范围</li>
-                <li>修复保存配置主题颜色失效问题</li>
-                <li>新增暗色菜单风格主题</li>
-                <li>菜单&部门新增展开/折叠功能</li>
-                <li>页签新增关闭左侧&添加图标</li>
-                <li>顶部菜单排除隐藏的默认路由</li>
-                <li>顶部菜单同步系统主题样式</li>
-                <li>跳转路由高亮相对应的菜单栏</li>
-                <li>代码生成主子表多选行数据</li>
-                <li>日期范围支持添加多组</li>
-                <li>升级element-ui到最新版本2.15.5</li>
-                <li>升级oshi到最新版本v5.8.0</li>
-                <li>升级commons.io到最新版本v2.11.0</li>
-                <li>定时任务屏蔽ldap远程调用</li>
-                <li>定时任务屏蔽http(s)远程调用</li>
-                <li>补充定时任务表字段注释</li>
-                <li>定时任务对检查异常进行事务回滚</li>
-                <li>启用父部门状态排除顶级节点</li>
-                <li>富文本新增上传文件大小限制</li>
-                <li>默认首页使用keep-alive缓存</li>
-                <li>修改代码生成字典回显样式</li>
-                <li>自定义分页合理化传入参数</li>
-                <li>修复字典组件值为整形不显示问题</li>
-                <li>修复定时任务日志执行状态显示</li>
-                <li>角色&菜单新增字段属性提示信息</li>
-                <li>修复角色分配用户页面参数类型错误提醒</li>
-                <li>优化布局设置动画特效</li>
-                <li>优化异常处理信息</li>
-                <li>优化错误token导致的解析异常</li>
-                <li>密码框新增显示切换密码图标</li>
-                <li>定时任务新增更多操作</li>
-                <li>更多操作按钮添加权限控制</li>
-                <li>导入用户样式优化</li>
-                <li>提取通用方法到基类控制器</li>
-                <li>优化使用权限工具获取用户信息</li>
-                <li>优化用户不能删除自己</li>
-                <li>优化XSS跨站脚本过滤</li>
-                <li>优化代码生成模板</li>
-                <li>验证码默认20s超时</li>
-                <li>BLOB下载时清除URL对象引用</li>
-                <li>代码生成导入表按创建时间排序</li>
-                <li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
-                <li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
-                <li>多图上传组件移除多余的api地址&验证失败导致图片删除问题&无法删除相应图片修复</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.6.0 - 2021-07-12">
-              <ol>
-                <li>角色管理新增分配用户功能</li>
-                <li>用户管理新增分配角色功能</li>
-                <li>日志列表支持排序操作</li>
-                <li>优化参数&字典缓存操作</li>
-                <li>系统布局配置支持动态标题开关</li>
-                <li>菜单路由配置支持内链访问</li>
-                <li>默认访问后端首页新增提示语</li>
-                <li>富文本默认上传返回url类型</li>
-                <li>新增自定义弹窗拖拽指令</li>
-                <li>全局注册常用通用组件</li>
-                <li>全局挂载字典标签组件</li>
-                <li>ImageUpload组件支持多图片上传</li>
-                <li>FileUpload组件支持多文件上传</li>
-                <li>文件上传组件添加数量限制属性</li>
-                <li>富文本编辑组件添加类型属性</li>
-                <li>富文本组件工具栏配置视频</li>
-                <li>封装通用iframe组件</li>
-                <li>限制超级管理员不允许操作</li>
-                <li>用户信息长度校验限制</li>
-                <li>分页组件新增pagerCount属性</li>
-                <li>添加bat脚本执行应用</li>
-                <li>升级oshi到最新版本v5.7.4</li>
-                <li>升级element-ui到最新版本2.15.2</li>
-                <li>升级pagehelper到最新版1.3.1</li>
-                <li>升级commons.io到最新版本v2.10.0</li>
-                <li>升级commons.fileupload到最新版本v1.4</li>
-                <li>升级swagger到最新版本v3.0.0</li>
-                <li>修复关闭confirm提示框控制台报错问题</li>
-                <li>修复存在的SQL注入漏洞问题</li>
-                <li>定时任务屏蔽rmi远程调用</li>
-                <li>修复用户搜索分页变量错误</li>
-                <li>修复导出角色数据范围翻译缺少仅本人</li>
-                <li>修复表单构建选择下拉选择控制台报错问题</li>
-                <li>优化图片工具类读取文件</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.5.0 - 2021-05-25">
-              <ol>
-                <li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li>
-                <li>布局设置支持保存&重置配置</li>
-                <li>修复树表数据显示不全&加载慢问题</li>
-                <li>新增IE浏览器版本过低提示页面</li>
-                <li>用户登录后记录最后登录IP&时间</li>
-                <li>页面导出按钮点击之后添加遮罩</li>
-                <li>富文本编辑器支持自定义上传地址</li>
-                <li>富文本编辑组件新增readOnly属性</li>
-                <li>页签TagsView新增关闭右侧功能</li>
-                <li>显隐列组件加载初始默认隐藏列</li>
-                <li>关闭头像上传窗口还原默认图片</li>
-                <li>个人信息添加手机&邮箱重复验证</li>
-                <li>代码生成模板导出按钮点击后添加遮罩</li>
-                <li>代码生成模板树表操作列添加新增按钮</li>
-                <li>代码生成模板修复主子表字段重名问题</li>
-                <li>升级fastjson到最新版1.2.76</li>
-                <li>升级druid到最新版本v1.2.6</li>
-                <li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>
-                <li>升级oshi到最新版本v5.6.0</li>
-                <li>velocity剔除commons-collections版本,防止3.2.1版本的反序列化漏洞</li>
-                <li>数据监控页默认账户密码防止越权访问</li>
-                <li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
-                <li>修正后端导入表权限标识</li>
-                <li>修正前端操作日志&登录日志权限标识</li>
-                <li>设置Redis配置HashKey序列化</li>
-                <li>删除操作日志记录信息</li>
-                <li>上传媒体类型添加视频格式</li>
-                <li>修复请求形参未传值记录日志异常问题</li>
-                <li>优化xss校验json请求条件</li>
-                <li>树级结构更新子节点使用replaceFirst</li>
-                <li>优化ExcelUtil空值处理</li>
-                <li>日志记录过滤BindingResult对象,防止异常</li>
-                <li>修改主题后mini类型按钮无效问题</li>
-                <li>优化通用下载完成后删除节点</li>
-                <li>通用Controller添加响应返回消息</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.4.0 - 2021-02-22">
-              <ol>
-                <li>代码生成模板支持主子表</li>
-                <li>表格右侧工具栏组件支持显隐列</li>
-                <li>图片组件添加预览&移除功能</li>
-                <li>Excel注解支持Image图片导出</li>
-                <li>操作按钮组调整为朴素按钮样式</li>
-                <li>代码生成支持文件上传组件</li>
-                <li>代码生成日期控件区分范围</li>
-                <li>代码生成数据库文本类型生成表单文本域</li>
-                <li>用户手机邮箱&菜单组件修改允许空字符串</li>
-                <li>升级SpringBoot到最新版本2.2.13 提升启动速度</li>
-                <li>升级druid到最新版本v1.2.4</li>
-                <li>升级fastjson到最新版1.2.75</li>
-                <li>升级element-ui到最新版本2.15.0</li>
-                <li>修复IE11浏览器报错问题</li>
-                <li>优化多级菜单之间切换无法缓存的问题</li>
-                <li>修复四级菜单无法显示问题</li>
-                <li>修正侧边栏静态路由丢失问题</li>
-                <li>修复角色管理-编辑角色-功能权限显示异常</li>
-                <li>配置文件新增redis数据库索引属性</li>
-                <li>权限工具类增加admin判断</li>
-                <li>角色非自定义权限范围清空选择值</li>
-                <li>修复导入数据为负浮点数时丢失精度问题</li>
-                <li>移除path-to-regexp正则匹配插件</li>
-                <li>修复生成树表代码异常</li>
-                <li>修改ip字段长度防止ipv6地址长度不够</li>
-                <li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li>
-                <li>登录后push添加catch防止出现检查错误</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.3.0 - 2020-12-14">
-              <ol>
-                <li>新增缓存监控功能</li>
-                <li>支持主题风格配置</li>
-                <li>修复多级菜单之间切换无法缓存的问题</li>
-                <li>多级菜单自动配置组件</li>
-                <li>代码生成预览支持高亮显示</li>
-                <li>支持Get请求映射Params参数</li>
-                <li>删除用户和角色解绑关联</li>
-                <li>去除用户手机邮箱部门必填验证</li>
-                <li>Excel支持注解align对齐方式</li>
-                <li>Excel支持导入Boolean型数据</li>
-                <li>优化头像样式,鼠标移入悬停遮罩</li>
-                <li>代码生成预览提供滚动机制</li>
-                <li>代码生成删除多余的数字float类型</li>
-                <li>修正转换字符串的目标字符集属性</li>
-                <li>回显数据字典防止空值报错</li>
-                <li>日志记录增加过滤多文件场景</li>
-                <li>修改缓存Set方法可能导致嵌套的问题</li>
-                <li>移除前端一些多余的依赖</li>
-                <li>防止安全扫描YUI出现的风险提示</li>
-                <li>修改node-sass为dart-sass</li>
-                <li>升级SpringBoot到最新版本2.1.18</li>
-                <li>升级poi到最新版本4.1.2</li>
-                <li>升级oshi到最新版本v5.3.6</li>
-                <li>升级bitwalker到最新版本1.21</li>
-                <li>升级axios到最新版本0.21.0</li>
-                <li>升级element-ui到最新版本2.14.1</li>
-                <li>升级vue到最新版本2.6.12</li>
-                <li>升级vuex到最新版本3.6.0</li>
-                <li>升级vue-cli到版本4.5.9</li>
-                <li>升级vue-router到最新版本3.4.9</li>
-                <li>升级vue-cli到最新版本4.4.6</li>
-                <li>升级vue-cropper到最新版本0.5.5</li>
-                <li>升级clipboard到最新版本2.0.6</li>
-                <li>升级core-js到最新版本3.8.1</li>
-                <li>升级echarts到最新版本4.9.0</li>
-                <li>升级file-saver到最新版本2.0.4</li>
-                <li>升级fuse.js到最新版本6.4.3</li>
-                <li>升级js-beautify到最新版本1.13.0</li>
-                <li>升级js-cookie到最新版本2.2.1</li>
-                <li>升级path-to-regexp到最新版本6.2.0</li>
-                <li>升级quill到最新版本1.3.7</li>
-                <li>升级screenfull到最新版本5.0.2</li>
-                <li>升级sortablejs到最新版本1.10.2</li>
-                <li>升级vuedraggable到最新版本2.24.3</li>
-                <li>升级chalk到最新版本4.1.0</li>
-                <li>升级eslint到最新版本7.15.0</li>
-                <li>升级eslint-plugin-vue到最新版本7.2.0</li>
-                <li>升级lint-staged到最新版本10.5.3</li>
-                <li>升级runjs到最新版本4.4.2</li>
-                <li>升级sass-loader到最新版本10.1.0</li>
-                <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
-                <li>升级svg-sprite-loader到最新版本5.1.1</li>
-                <li>升级vue-template-compiler到最新版本2.6.12</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.2.1 - 2020-11-18">
-              <ol>
-                <li>阻止任意文件下载漏洞</li>
-                <li>代码生成支持上传控件</li>
-                <li>新增图片上传组件</li>
-                <li>调整默认首页</li>
-                <li>升级druid到最新版本v1.2.2</li>
-                <li>mapperLocations配置支持分隔符</li>
-                <li>权限信息调整</li>
-                <li>调整sql默认时间</li>
-                <li>解决代码生成没有bit类型的问题</li>
-                <li>升级pagehelper到最新版1.3.0</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v3.2.0 - 2020-10-10">
-              <ol>
-                <li>升级springboot版本到2.1.17 提升安全性</li>
-                <li>升级oshi到最新版本v5.2.5</li>
-                <li>升级druid到最新版本v1.2.1</li>
-                <li>升级jjwt到版本0.9.1</li>
-                <li>升级fastjson到最新版1.2.74</li>
-                <li>修改sass为node-sass,避免el-icon图标乱码</li>
-                <li>代码生成支持同步数据库</li>
-                <li>代码生成支持富文本控件</li>
-                <li>代码生成页面时不忽略remark属性</li>
-                <li>代码生成添加select必填选项</li>
-                <li>Excel导出类型NUMERIC支持精度浮点类型</li>
-                <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
-                <li>Excel注解支持自动统计数据总和</li>
-                <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
-                <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
-                <li>允许用户分配到部门父节点</li>
-                <li>菜单新增是否缓存keep-alive</li>
-                <li>表格操作列间距调整</li>
-                <li>限制系统内置参数不允许删除</li>
-                <li>富文本组件优化,支持自定义高度&图片冲突问题</li>
-                <li>富文本工具栏样式对齐</li>
-                <li>导入excel整形值校验优化</li>
-                <li>修复页签关闭所有时固定标签路由不刷新问题</li>
-                <li>表单构建布局型组件新增按钮</li>
-                <li>左侧菜单文字过长显示省略号</li>
-                <li>修正根节点为子部门时,树状结构显示问题</li>
-                <li>修正调用目标字符串最大长度</li>
-                <li>修正菜单提示信息错误</li>
-                <li>修正定时任务执行一次权限标识</li>
-                <li>修正数据库字符串类型nvarchar</li>
-                <li>优化递归子节点</li>
-                <li>优化数据权限判断</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v3.1.0 - 2020-08-13">
-              <ol>
-                <li>表格工具栏右侧添加刷新&显隐查询组件</li>
-                <li>后端支持CORS跨域请求</li>
-                <li>代码生成支持选择上级菜单</li>
-                <li>代码生成支持自定义路径</li>
-                <li>代码生成支持复选框</li>
-                <li>Excel导出导入支持dictType字典类型</li>
-                <li>Excel支持分割字符串组内容</li>
-                <li>验证码类型支持(数组计算、字符验证)</li>
-                <li>升级vue-cli版本到4.4.4</li>
-                <li>修改 node-sass 为 dart-sass</li>
-                <li>表单类型为Integer/Long设置整形默认值</li>
-                <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
-                <li>优化防重复提交拦截器</li>
-                <li>优化上级菜单不能选择自己</li>
-                <li>修复角色的权限分配后,未实时生效问题</li>
-                <li>修复在线用户日志记录类型</li>
-                <li>修复富文本空格和缩进保存后不生效问题</li>
-                <li>修复在线用户判断逻辑</li>
-                <li>唯一限制条件只返回单条数据</li>
-                <li>添加获取当前的环境配置方法</li>
-                <li>超时登录后页面跳转到首页</li>
-                <li>全局异常状态汉化拦截处理</li>
-                <li>HTML过滤器改为将html转义</li>
-                <li>检查字符支持小数点&降级改成异常提醒</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v3.0.0 - 2020-07-20">
-              <ol>
-                <li>单应用调整为多模块项目</li>
-                <li>升级element-ui版本到2.13.2</li>
-                <li>删除babel,提高编译速度。</li>
-                <li>新增菜单默认主类目</li>
-                <li>编码文件名修改为uuid方式</li>
-                <li>定时任务cron表达式验证</li>
-                <li>角色权限修改时已有权限未自动勾选异常修复</li>
-                <li>防止切换权限用户后登录出现404</li>
-                <li>Excel支持sort导出排序</li>
-                <li>创建用户不允许选择超级管理员角色</li>
-                <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
-                <li>修复代码生成点击多次表修改数据不变化的问题</li>
-                <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
-                <li>修复布局为small者mini用户表单显示错位问题</li>
-                <li>修复热部署导致的强换异常问题</li>
-                <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
-                <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
-                <li>生成domain 如果是浮点型 统一用BigDecimal</li>
-                <li>定时任务调整label-width,防止部署出现错位</li>
-                <li>调整表头固定列默认样式</li>
-                <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
-                <li>代码生成字典Integer/Long使用parseInt</li>
-                <li>
-                  修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
-                </li>
-                <li>修正岗位导出权限注解</li>
-                <li>禁止加密密文返回前端</li>
-                <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
-                <li>修复首页搜索菜单外链无法点击跳转问题</li>
-                <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
-                <li>用户管理部门分支节点不可检查&显示计数</li>
-                <li>数据范围过滤属性调整</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v2.3.0 - 2020-06-01">
-              <ol>
-                <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
-                <li>dev启动默认打开浏览器</li>
-                <li>vue-cli使用默认source-map</li>
-                <li>slidebar eslint报错优化</li>
-                <li>当tags-view滚动关闭右键菜单</li>
-                <li>字典管理添加缓存读取</li>
-                <li>参数管理支持缓存操作</li>
-                <li>支持一级菜单(和主页同级)在main区域显示</li>
-                <li>限制外链地址必须以http(s)开头</li>
-                <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
-                <li>修改数据源类型优先级,先根据方法,再根据类</li>
-                <li>支持是否需要设置token属性,自定义返回码消息。</li>
-                <li>swagger请求前缀加入配置。</li>
-                <li>登录地点设置内容过长则隐藏显示</li>
-                <li>修复定时任务执行一次按钮后不提示消息问题</li>
-                <li>修改上级部门(选择项排除本身和下级)</li>
-                <li>通用http发送方法增加参数 contentType 编码类型</li>
-                <li>更换IP地址查询接口</li>
-                <li>修复页签变量undefined</li>
-                <li>添加校验部门包含未停用的子部门</li>
-                <li>修改定时任务详情下次执行时间日期显示错误</li>
-                <li>角色管理查询设置默认排序字段</li>
-                <li>swagger添加enable参数控制是否启用</li>
-                <li>只对json类型请求构建可重复读取inputStream的request</li>
-                <li>修改代码生成字典字段int类型没有自动选中问题</li>
-                <li>vuex用户名取值修正</li>
-                <li>表格树模板去掉多余的)</li>
-                <li>代码生成序号修正</li>
-                <li>全屏情况下不调整上外边距</li>
-                <li>代码生成Date字段添加默认格式</li>
-                <li>用户管理角色选择权限控制</li>
-                <li>修复路由懒加载报错问题</li>
-                <li>模板sql.vm添加菜单状态</li>
-                <li>设置用户名称不能修改</li>
-                <li>dialog添加append-to-body属性,防止ie遮罩</li>
-                <li>菜单区分状态和显示隐藏功能</li>
-                <li>升级fastjson到最新版1.2.68 修复安全加固</li>
-                <li>修复代码生成如果选择字典类型缺失逗号问题</li>
-                <li>登录请求params更换为data,防止暴露url</li>
-                <li>日志返回时间格式处理</li>
-                <li>添加handle控制允许拖动的元素</li>
-                <li>布局设置点击扩大范围</li>
-                <li>代码生成列属性排序查询</li>
-                <li>代码生成列支持拖动排序</li>
-                <li>修复时间格式不支持ios问题</li>
-                <li>表单构建添加父级class,防止冲突</li>
-                <li>定时任务并发属性修正</li>
-                <li>角色禁用&菜单隐藏不查询权限</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v2.2.0 - 2020-03-18">
-              <ol>
-                <li>系统监控新增定时任务功能</li>
-                <li>添加一个打包Web工程bat</li>
-                <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
-                <li>修复点击退出登录有时会无提示问题</li>
-                <li>修复防重复提交注解无效问题</li>
-                <li>修复通知公告批量删除异常问题</li>
-                <li>添加菜单时路由地址必填限制</li>
-                <li>代码生成字段描述可编辑</li>
-                <li>修复用户修改个人信息导致缓存不过期问题</li>
-                <li>个人信息创建时间获取正确属性值</li>
-                <li>操作日志详细显示正确类型</li>
-                <li>导入表单击行数据时选中对应的复选框</li>
-                <li>批量替换表前缀逻辑调整</li>
-                <li>固定重定向路径表达式</li>
-                <li>升级element-ui版本到2.13.0</li>
-                <li>操作日志排序调整</li>
-                <li>修复charts切换侧边栏或者缩放窗口显示bug</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v2.1.0 - 2020-02-24">
-              <ol>
-                <li>新增表单构建</li>
-                <li>代码生成支持树表结构</li>
-                <li>新增用户导入</li>
-                <li>修复动态加载路由页面刷新问题</li>
-                <li>修复地址开关无效问题</li>
-                <li>汉化错误提示页面</li>
-                <li>代码生成已知问题修改</li>
-                <li>修复多数据源下配置关闭出现异常处理</li>
-                <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
-                <li>修复上传头像控制台出现异常</li>
-                <li>修改用户管理分页不正确的问题</li>
-                <li>修复验证码记录提示错误</li>
-                <li>修复request.js缺少Message引用</li>
-                <li>修复表格时间为空出现的异常</li>
-                <li>添加Jackson日期反序列化时区配置</li>
-                <li>调整根据用户权限加载菜单数据树形结构</li>
-                <li>调整成功登录不恢复按钮,防止多次点击</li>
-                <li>修改用户个人资料同步缓存信息</li>
-                <li>修复页面同时出现el-upload和Editor不显示处理</li>
-                <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
-                <li>配置文件新增redis密码属性</li>
-                <li>设置mybatis全局的配置文件</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-
-            <el-collapse-item title="v2.0.0 - 2019-12-02">
-              <ol>
-                <li>新增代码生成</li>
-                <li>新增@RepeatSubmit注解,防止重复提交</li>
-                <li>新增菜单主目录添加/删除操作</li>
-                <li>日志记录过滤特殊对象,防止转换异常</li>
-                <li>修改代码生成路由脚本错误</li>
-                <li>用户上传头像实时同步缓存,无需重新登录</li>
-                <li>调整切换页签后不重新加载数据</li>
-                <li>添加jsencrypt实现参数的前端加密</li>
-                <li>系统退出删除用户缓存记录</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v1.1.0 - 2019-11-11">
-              <ol>
-                <li>新增在线用户管理</li>
-                <li>新增按钮组功能实现(批量删除、导出、清空)</li>
-                <li>新增查询条件重置按钮</li>
-                <li>新增Swagger全局Token配置</li>
-                <li>新增后端参数校验</li>
-                <li>修复字典管理页面的日期查询异常</li>
-                <li>修改时间函数命名防止冲突</li>
-                <li>去除菜单上级校验,默认为顶级</li>
-                <li>修复用户密码无法修改问题</li>
-                <li>修复菜单类型为按钮时不显示权限标识</li>
-                <li>其他细节优化</li>
-              </ol>
-            </el-collapse-item>
-            <el-collapse-item title="v1.0.0 - 2019-10-08">
-              <ol>
-                <li>若依前后端分离系统正式发布</li>
-              </ol>
-            </el-collapse-item>
-          </el-collapse>
-        </el-card>
-      </el-col>
-      <el-col :xs="24" :sm="24" :md="12" :lg="8">
-        <el-card class="update-log">
-          <div slot="header" class="clearfix">
-            <span>捐赠支持</span>
-          </div>
-          <div class="body">
-            <img
-              src="@/assets/images/pay.png"
-              alt="donate"
-              width="100%"
-            />
-            <span style="display: inline-block; height: 30px; line-height: 30px"
-              >你可以请作者喝杯咖啡表示鼓励</span
-            >
-          </div>
-        </el-card>
-      </el-col>
-    </el-row>
-  </div>
-</template>
-
-<script>
-export default {
-  name: "Index",
-  data() {
-    return {
-      // 版本号
-      version: "3.8.9"
-    };
-  },
-  methods: {
-    goTarget(href) {
-      window.open(href, "_blank");
-    }
-  }
-};
-</script>
-
-<style scoped lang="scss">
-.home {
-  blockquote {
-    padding: 10px 20px;
-    margin: 0 0 20px;
-    font-size: 17.5px;
-    border-left: 5px solid #eee;
-  }
-  hr {
-    margin-top: 20px;
-    margin-bottom: 20px;
-    border: 0;
-    border-top: 1px solid #eee;
-  }
-  .col-item {
-    margin-bottom: 20px;
-  }
-
-  ul {
-    padding: 0;
-    margin: 0;
-  }
-
-  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
-  font-size: 13px;
-  color: #676a6c;
-  overflow-x: hidden;
-
-  ul {
-    list-style-type: none;
-  }
-
-  h4 {
-    margin-top: 0px;
-  }
-
-  h2 {
-    margin-top: 10px;
-    font-size: 26px;
-    font-weight: 100;
-  }
-
-  p {
-    margin-top: 10px;
-
-    b {
-      font-weight: 700;
-    }
-  }
-
-  .update-log {
-    ol {
-      display: block;
-      list-style-type: decimal;
-      margin-block-start: 1em;
-      margin-block-end: 1em;
-      margin-inline-start: 0;
-      margin-inline-end: 0;
-      padding-inline-start: 40px;
-    }
-  }
-}
-</style>
-
+<template>
+  <div class="app-container home">
+    <el-row :gutter="20">
+      <el-col :sm="24" :lg="24">
+        <blockquote class="text-warning" style="font-size: 14px">
+          阿里云服务器折扣区<el-link href="http://aly.acupuncture.vip" type="primary" target="_blank">☛☛点我进入☚☚</el-link> &nbsp;&nbsp;&nbsp; 腾讯云服务器秒杀区<el-link href="http://txy.acupuncture.vip" type="primary" target="_blank">☛☛点我进入☚☚</el-link>
+        </blockquote>
+        <hr />
+      </el-col>
+    </el-row>
+    <el-row :gutter="20">
+      <el-col :sm="24" :lg="12" style="padding-left: 20px">
+        <h2>若依后台管理框架</h2>
+        <p>
+          一直想做一款后台管理系统,看了很多优秀的开源项目但是发现没有合适自己的。于是利用空闲休息时间开始自己写一套后台系统。如此有了若依管理系统,她可以用于所有的Web应用程序,如网站管理后台,网站会员中心,CMS,CRM,OA等等,当然,您也可以对她进行深度定制,以做出更强系统。所有前端后台代码封装过后十分精简易上手,出错概率低。同时支持移动客户端访问。系统会陆续更新一些实用功能。
+        </p>
+        <p>
+          <b>当前版本:</b> <span>v{{ version }}</span>
+        </p>
+        <p>
+          <el-tag type="danger">&yen;免费开源</el-tag>
+        </p>
+        <p>
+          <el-button
+            type="primary"
+            size="mini"
+            icon="el-icon-cloudy"
+            plain
+            @click="goTarget('https://gitee.com/y_project/acupuncture-Vue')"
+            >访问码云</el-button
+          >
+          <el-button
+            size="mini"
+            icon="el-icon-s-home"
+            plain
+            @click="goTarget('http://acupuncture.vip')"
+            >访问主页</el-button
+          >
+        </p>
+      </el-col>
+
+      <el-col :sm="24" :lg="12" style="padding-left: 50px">
+        <el-row>
+          <el-col :span="12">
+            <h2>技术选型</h2>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="6">
+            <h4>后端技术</h4>
+            <ul>
+              <li>SpringBoot</li>
+              <li>Spring Security</li>
+              <li>JWT</li>
+              <li>MyBatis</li>
+              <li>Druid</li>
+              <li>Fastjson</li>
+              <li>...</li>
+            </ul>
+          </el-col>
+          <el-col :span="6">
+            <h4>前端技术</h4>
+            <ul>
+              <li>Vue</li>
+              <li>Vuex</li>
+              <li>Element-ui</li>
+              <li>Axios</li>
+              <li>Sass</li>
+              <li>Quill</li>
+              <li>...</li>
+            </ul>
+          </el-col>
+        </el-row>
+      </el-col>
+    </el-row>
+    <el-divider />
+    <el-row :gutter="20">
+      <el-col :xs="24" :sm="24" :md="12" :lg="8">
+        <el-card class="update-log">
+          <div slot="header" class="clearfix">
+            <span>联系信息</span>
+          </div>
+          <div class="body">
+            <p>
+              <i class="el-icon-s-promotion"></i> 官网:<el-link
+                href="http://www.acupuncture.vip"
+                target="_blank"
+                >http://www.acupuncture.vip</el-link
+              >
+            </p>
+            <p>
+              <i class="el-icon-user-solid"></i> QQ群:<s> 满937441 </s> <s> 满887144332 </s>
+              <s> 满180251782 </s> <s> 满104180207 </s> <s> 满186866453 </s> <s> 满201396349 </s>
+              <s> 满101456076 </s> <s> 满101539465 </s> <s> 满264312783 </s> <s> 满167385320 </s>
+              <s> 满104748341 </s> <s> 满160110482 </s> <s> 满170801498 </s> <s> 满108482800 </s>
+              <s> 满101046199 </s> <s> 满136919097 </s> <s> 满143961921 </s> <s> 满174951577 </s>
+              <s> 满161281055 </s> <s> 满138988063 </s> <s> 满151450850 </s> <s> 满224622315 </s>
+              <s> 满287842588 </s> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=HKz42pk2zQ1WUMbbRo50-N7tY4IDKKrj&authKey=ukBg3edmUbnmoo40xZCo6R1tYdTglYJ1nBFRW9gTHuZwLI1r8wgFT6cWUrAldwcr&noverify=0&group_code=187944233" target="_blank">187944233</a>
+            </p>
+            <p>
+              <i class="el-icon-chat-dot-round"></i> 微信:<a
+                href="javascript:;"
+                >/ *若依</a
+              >
+            </p>
+            <p>
+              <i class="el-icon-money"></i> 支付宝:<a
+                href="javascript:;"
+                class="支付宝信息"
+                >/ *若依</a
+              >
+            </p>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :xs="24" :sm="24" :md="12" :lg="8">
+        <el-card class="update-log">
+          <div slot="header" class="clearfix">
+            <span>更新日志</span>
+          </div>
+          <el-collapse accordion>
+            <el-collapse-item title="v3.8.9 - 2024-12-30">
+              <ol>
+                <li>用户管理支持分栏拖动</li>
+                <li>修改主题样式本地读取</li>
+                <li>用户头像http(s)链接支持</li>
+                <li>用户管理过滤掉已禁用部门</li>
+                <li>支持自定义显示Excel属性列</li>
+                <li>操作日志记录DELETE请求参数</li>
+                <li>白名单支持对通配符路径匹配</li>
+                <li>校检文件名是否包含特殊字符</li>
+                <li>代码生成创建表屏蔽违规的字符</li>
+                <li>菜单面包屑导航支持多层级显示</li>
+                <li>Excel注解支持wrapText是否允许内容换行</li>
+                <li>代码生成新增配置是否允许文件覆盖到本地</li>
+                <li>修复角色禁用权限不失效问题</li>
+                <li>修复代码生成上级菜单显示问题</li>
+                <li>修复导出子列表对象只能在最后的问题</li>
+                <li>修复TopNav无法正确获取active的问题</li>
+                <li>修复默认关闭Tags-Views内链页面打不开</li>
+                <li>升级oshi到最新版本6.6.5</li>
+                <li>升级tomcat到最新版本9.0.96</li>
+                <li>升级fastjson到最新版2.0.53</li>
+                <li>升级logback到最新版本1.2.13</li>
+                <li>升级spring-framework到最新版本5.3.39</li>
+                <li>升级quill到最新版本2.0.2</li>
+                <li>升级axios到最新版本0.28.1</li>
+                <li>优化身份证脱敏正则</li>
+                <li>优化权限更新后同步缓存</li>
+                <li>优化查询时间范围日期格式</li>
+                <li>优化参数键值更换为多行文本</li>
+                <li>优化导入带标题文件关闭清理</li>
+                <li>优化上传图片带域名不增加前缀</li>
+                <li>优化特殊字符密码修改失败问题</li>
+                <li>优化无用户编号不校验数据权限</li>
+                <li>优化TopNav内链菜单点击没有高亮</li>
+                <li>优化菜单管理切换Mini布局错乱问题</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.8 - 2024-06-30">
+              <ol>
+                <li>菜单管理新增路由名称</li>
+                <li>新增数据脱敏过滤注解</li>
+                <li>用户密码新增非法字符验证</li>
+                <li>限制用户操作数据权限范围</li>
+                <li>代码生成新增创建表结构功能</li>
+                <li>定时任务白名单配置范围缩小</li>
+                <li>优化代码生成主子表关联查询方式</li>
+                <li>Excel注解新增属性comboReadDict</li>
+                <li>Excel注解ColumnType类型新增文本</li>
+                <li>新增国际化资源文件配置</li>
+                <li>升级oshi到最新版本6.6.1</li>
+                <li>升级druid到最新版本1.2.23</li>
+                <li>升级core-js到最新版本3.37.1</li>
+                <li>更新HttpUtils中的User-Agent</li>
+                <li>更新compressionPlugin到6.1.2以兼容node18+</li>
+                <li>升级spring-security到安全版本,防止漏洞风险</li>
+                <li>升级spring-framework到安全版本,防止漏洞风险</li>
+                <li>优化自定义XSS注解匹配方式</li>
+                <li>优化缓存监控键名列表排序显示</li>
+                <li>优化定时任务日志默认按时间排序</li>
+                <li>优化默认文件大小超过2G无效的问题</li>
+                <li>优化查表特殊字符使用反斜杠进行转义</li>
+                <li>优化定时任务cron表达式小时配置显示错误问题</li>
+                <li>优化多个自定数据权限使用in查询,避免多次拼接</li>
+                <li>优化导入Excel时设置dictType属性重复查缓存问题</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.7 - 2023-12-08">
+              <ol>
+                <li>操作日志记录部门名称</li>
+                <li>全局数据存储用户编号</li>
+                <li>新增编程式判断资源访问权限</li>
+                <li>操作日志列表新增IP地址查询</li>
+                <li>定时任务新增页去除状态选项</li>
+                <li>代码生成支持选择前端模板类型</li>
+                <li>显隐列组件支持复选框弹出类型</li>
+                <li>通用排序属性orderBy参数限制长度</li>
+                <li>Excel自定义数据处理器增加单元格/工作簿对象</li>
+                <li>升级oshi到最新版本6.4.8</li>
+                <li>升级druid到最新版本1.2.20</li>
+                <li>升级fastjson到最新版2.0.43</li>
+                <li>升级pagehelper到最新版1.4.7</li>
+                <li>升级commons.io到最新版本2.13.0</li>
+                <li>升级element-ui到最新版本2.15.14</li>
+                <li>修复五级路由缓存无效问题</li>
+                <li>修复外链带端口出现的异常</li>
+                <li>修复树模板父级编码变量错误</li>
+                <li>修复字典表详情页面搜索问题</li>
+                <li>修复内链iframe没有传递参数问题</li>
+                <li>修复自定义字典样式不生效的问题</li>
+                <li>修复字典缓存删除方法参数错误问题</li>
+                <li>修复Excel导入数据临时文件无法删除问题</li>
+                <li>修复未登录带参数访问成功后参数丢失问题</li>
+                <li>修复HeaderSearch组件跳转query参数丢失问题</li>
+                <li>修复代码生成导入后必填项与数据库不匹配问题</li>
+                <li>修复Excels导入时无法获取到dictType字典值问题</li>
+                <li>优化下载zip方法新增遮罩层</li>
+                <li>优化头像上传参数新增文件名称</li>
+                <li>优化字典标签支持自定义分隔符</li>
+                <li>优化菜单管理类型为按钮状态可选</li>
+                <li>优化前端防重复提交数据大小限制</li>
+                <li>优化TopNav菜单没有图标svg不显示</li>
+                <li>优化数字金额大写转换精度丢失问题</li>
+                <li>优化富文本Editor组件检验图片格式</li>
+                <li>优化页签在Firefox浏览器被遮挡的问题</li>
+                <li>优化个人中心/基本资料修改时数据显示问题</li>
+                <li>优化缓存监控图表支持跟随屏幕大小自适应调整</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.6 - 2023-06-30">
+              <ol>
+                <li>支持登录IP黑名单限制</li>
+                <li>新增监控页面图标显示</li>
+                <li>操作日志新增消耗时间属性</li>
+                <li>屏蔽定时任务bean违规的字符</li>
+                <li>日志管理使用索引提升查询性能</li>
+                <li>日志注解支持排除指定的请求参数</li>
+                <li>支持自定义隐藏属性列过滤子对象</li>
+                <li>升级oshi到最新版本6.4.3</li>
+                <li>升级druid到最新版本1.2.16</li>
+                <li>升级fastjson到最新版2.0.34</li>
+                <li>升级spring-boot到最新版本2.5.15</li>
+                <li>升级element-ui到最新版本2.15.13</li>
+                <li>移除apache/commons-fileupload依赖</li>
+                <li>修复页面切换时布局错乱的问题</li>
+                <li>修复匿名注解Anonymous空指针问题</li>
+                <li>修复路由跳转被阻止时内部产生报错信息问题</li>
+                <li>修复isMatchedIp的参数判断产生空指针的问题</li>
+                <li>修复用户多角色数据权限可能出现权限抬升的情况</li>
+                <li>修复开启TopNav后一级菜单路由参数设置无效问题</li>
+                <li>修复DictTag组件value没有匹配的值时则展示value</li>
+                <li>优化文件下载出现的异常</li>
+                <li>优化选择图标组件高亮回显</li>
+                <li>优化弹窗后导航栏偏移的问题</li>
+                <li>优化修改密码日志存储明文问题</li>
+                <li>优化页签栏关闭其他出现的异常问题</li>
+                <li>优化页签关闭左侧选项排除首页选项</li>
+                <li>优化关闭当前tab页跳转最右侧tab页</li>
+                <li>优化缓存列表清除操作提示不变的问题</li>
+                <li>优化字符未使用下划线不进行驼峰式处理</li>
+                <li>优化用户导入更新时需获取用户编号问题</li>
+                <li>优化侧边栏的平台标题与VUE_APP_TITLE保持同步</li>
+                <li>优化导出Excel时设置dictType属性重复查缓存问题</li>
+                <li>连接池Druid支持新的配置connectTimeout和socketTimeout</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.5 - 2023-01-01">
+              <ol>
+                <li>定时任务违规的字符</li>
+                <li>重置时取消部门选中</li>
+                <li>新增返回警告消息提示</li>
+                <li>忽略不必要的属性数据返回</li>
+                <li>修改参数键名时移除前缓存配置</li>
+                <li>导入更新用户数据前校验数据权限</li>
+                <li>兼容Excel下拉框内容过多无法显示的问题</li>
+                <li>升级echarts到最新版本5.4.0</li>
+                <li>升级core-js到最新版本3.25.3</li>
+                <li>升级oshi到最新版本6.4.0</li>
+                <li>升级kaptcha到最新版2.3.3</li>
+                <li>升级druid到最新版本1.2.15</li>
+                <li>升级fastjson到最新版2.0.20</li>
+                <li>升级pagehelper到最新版1.4.6</li>
+                <li>优化弹窗内容过多展示不全问题</li>
+                <li>优化swagger-ui静态资源使用缓存</li>
+                <li>开启TopNav没有子菜单隐藏侧边栏</li>
+                <li>删除fuse无效选项maxPatternLength</li>
+                <li>优化导出对象的子列表为空会出现[]问题</li>
+                <li>优化编辑头像时透明部分会变成黑色问题</li>
+                <li>优化小屏幕上修改头像界面布局错位的问题</li>
+                <li>修复代码生成勾选属性无效问题</li>
+                <li>修复文件上传组件格式验证问题</li>
+                <li>修复回显数据字典数组异常问题</li>
+                <li>修复sheet超出最大行数异常问题</li>
+                <li>修复Log注解GET请求记录不到参数问题</li>
+                <li>修复调度日志点击多次数据不变化的问题</li>
+                <li>修复主题颜色在Drawer组件不会加载问题</li>
+                <li>修复文件名包含特殊字符的文件无法下载问题</li>
+                <li>修复table中更多按钮切换主题色未生效修复问题</li>
+                <li>修复某些特性的环境生成代码变乱码TXT文件问题</li>
+                <li>修复代码生成图片/文件/单选时选择必填无法校验问题</li>
+                <li>修复某些特性的情况用户编辑对话框中角色和部门无法修改问题</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.4 - 2022-09-26">
+              <ol>
+                <li>数据逻辑删除不进行唯一验证</li>
+                <li>Excel注解支持导出对象的子列表方法</li>
+                <li>Excel注解支持自定义隐藏属性列</li>
+                <li>Excel注解支持backgroundColor属性设置背景色</li>
+                <li>支持配置密码最大错误次数/锁定时间</li>
+                <li>登录日志新增解锁账户功能</li>
+                <li>通用下载方法新增config配置选项</li>
+                <li>支持多权限字符匹配角色数据权限</li>
+                <li>页面内嵌iframe切换tab不刷新数据</li>
+                <li>操作日志记录支持排除敏感属性字段</li>
+                <li>修复多文件上传报错出现的异常问题</li>
+                <li>修复图片预览组件src属性为null值控制台报错问题</li>
+                <li>升级oshi到最新版本6.2.2</li>
+                <li>升级fastjson到最新版2.0.14</li>
+                <li>升级pagehelper到最新版1.4.3</li>
+                <li>升级core-js到最新版本3.25.2</li>
+                <li>升级element-ui到最新版本2.15.10</li>
+                <li>优化任务过期不执行调度</li>
+                <li>优化字典数据使用store存取</li>
+                <li>优化修改资料头像被覆盖的问题</li>
+                <li>优化修改用户登录账号重复验证</li>
+                <li>优化代码生成同步后值NULL问题</li>
+                <li>优化定时任务支持执行父类方法</li>
+                <li>优化用户个人信息接口防止修改部门</li>
+                <li>优化布局设置使用el-drawer抽屉显示</li>
+                <li>优化没有权限的用户编辑部门缺少数据</li>
+                <li>优化日志注解记录限制请求地址的长度</li>
+                <li>优化excel/scale属性导出单元格数值类型</li>
+                <li>优化日志操作中重置按钮时重复查询的问题</li>
+                <li>优化多个相同角色数据导致权限SQL重复问题</li>
+                <li>优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出)</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.3 - 2022-06-27">
+              <ol>
+                <li>新增缓存列表菜单功能</li>
+                <li>代码生成树表新增(展开/折叠)</li>
+                <li>Excel注解支持color字体颜色</li>
+                <li>新增Anonymous匿名访问不鉴权注解</li>
+                <li>用户头像上传限制只能为图片格式</li>
+                <li>接口使用泛型使其看到响应属性字段</li>
+                <li>检查定时任务bean所在包名是否为白名单配置</li>
+                <li>添加页签openPage支持传递参数</li>
+                <li>用户缓存信息添加部门ancestors祖级列表</li>
+                <li>升级element-ui到最新版本2.15.8</li>
+                <li>升级oshi到最新版本6.1.6</li>
+                <li>升级druid到最新版本1.2.11</li>
+                <li>升级fastjson到最新版2.0.8</li>
+                <li>升级spring-boot到最新版本2.5.14</li>
+                <li>降级jsencrypt版本兼容IE浏览器</li>
+                <li>删除多余的salt字段</li>
+                <li>新增获取不带后缀文件名称方法</li>
+                <li>新增获取配置文件中的属性值方法</li>
+                <li>新增内容编码/解码方便插件集成使用</li>
+                <li>字典类型必须以字母开头,且只能为(小写字母,数字,下滑线)</li>
+                <li>优化设置分页参数默认值</li>
+                <li>优化对空字符串参数处理的过滤</li>
+                <li>优化显示顺序orderNum类型为整型</li>
+                <li>优化表单构建按钮不显示正则校验</li>
+                <li>优化字典数据回显样式下拉框显示值</li>
+                <li>优化R响应成功状态码与全局保持一致</li>
+                <li>优化druid开启wall过滤器出现的异常问题</li>
+                <li>优化用户管理左侧树型组件增加选中高亮保持</li>
+                <li>优化新增用户与角色信息&用户与岗位信息逻辑</li>
+                <li>优化默认不启用压缩文件缓存防止node_modules过大</li>
+                <li>修复字典数据显示不全问题</li>
+                <li>修复操作日志查询类型条件为0时会查到所有数据</li>
+                <li>修复Excel注解prompt/combo同时使用不生效问题</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.2 - 2022-04-01">
+              <ol>
+                <li>前端支持设置是否需要防止数据重复提交</li>
+                <li>开启TopNav没有子菜单情况隐藏侧边栏</li>
+                <li>侧边栏菜单名称过长悬停显示标题</li>
+                <li>用户访问控制时校验数据权限,防止越权</li>
+                <li>导出Excel时屏蔽公式,防止CSV注入风险</li>
+                <li>组件ImagePreview支持多图预览显示</li>
+                <li>组件ImageUpload支持多图同时选择上传</li>
+                <li>组件FileUpload支持多文件同时选择上传</li>
+                <li>服务监控新增运行参数信息显示</li>
+                <li>定时任务目标字符串过滤特殊字符</li>
+                <li>定时任务目标字符串验证包名白名单</li>
+                <li>代码生成列表图片支持预览</li>
+                <li>代码生成编辑修改打开新页签</li>
+                <li>代码生成新增Java类型Boolean</li>
+                <li>代码生成子表支持日期/字典配置</li>
+                <li>代码生成同步保留必填/类型选项</li>
+                <li>升级oshi到最新版本6.1.2</li>
+                <li>升级fastjson到最新版1.2.80</li>
+                <li>升级pagehelper到最新版1.4.1</li>
+                <li>升级spring-boot到最新版本2.5.11</li>
+                <li>升级spring-boot-mybatis到最新版2.2.2</li>
+                <li>添加遗漏的分页参数合理化属性</li>
+                <li>修改npm即将过期的注册源地址</li>
+                <li>修复分页组件请求两次问题</li>
+                <li>修复通用文件下载接口跨域问题</li>
+                <li>修复Xss注解字段值为空时的异常问题</li>
+                <li>修复选项卡点击右键刷新丢失参数问题</li>
+                <li>修复表单清除元素位置未垂直居中问题</li>
+                <li>修复服务监控中运行参数显示条件错误</li>
+                <li>修复导入Excel时字典字段类型为Long转义为空问题</li>
+                <li>修复登录超时刷新页面跳转登录页面还提示重新登录问题</li>
+                <li>优化加载字典缓存数据</li>
+                <li>优化IP地址获取到多个的问题</li>
+                <li>优化任务队列满时任务拒绝策略</li>
+                <li>优化文件上传兼容Weblogic环境</li>
+                <li>优化定时任务默认保存到内存中执行</li>
+                <li>优化部门修改缩放后出现的错位问题</li>
+                <li>优化Excel格式化不同类型的日期对象</li>
+                <li>优化菜单表关键字导致的插件报错问题</li>
+                <li>优化Oracle用户头像列为空时不显示问题</li>
+                <li>优化页面若未匹配到字典标签则返回原字典值</li>
+                <li>优化修复登录失效后多次请求提示多次弹窗问题</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.1 - 2022-01-01">
+              <ol>
+                <li>新增Vue3前端代码生成模板</li>
+                <li>新增图片预览组件</li>
+                <li>新增压缩插件实现打包Gzip</li>
+                <li>自定义xss校验注解实现</li>
+                <li>自定义文字复制剪贴指令</li>
+                <li>代码生成预览支持复制内容</li>
+                <li>路由支持单独配置菜单或角色权限</li>
+                <li>用户管理部门查询选择节点后分页参数初始</li>
+                <li>修复用户分配角色属性错误</li>
+                <li>修复打包后字体图标偶现的乱码问题</li>
+                <li>修复菜单管理重置表单出现的错误</li>
+                <li>修复版本差异导致的懒加载报错问题</li>
+                <li>修复Cron组件中周回显问题</li>
+                <li>修复定时任务多参数逗号分隔的问题</li>
+                <li>修复根据ID查询列表可能出现的主键溢出问题</li>
+                <li>修复tomcat配置参数已过期问题</li>
+                <li>升级clipboard到最新版本2.0.8</li>
+                <li>升级oshi到最新版本v5.8.6</li>
+                <li>升级fastjson到最新版1.2.79</li>
+                <li>升级spring-boot到最新版本2.5.8</li>
+                <li>升级log4j2到2.17.1,防止漏洞风险</li>
+                <li>优化下载解析blob异常提示</li>
+                <li>优化代码生成字典组重复问题</li>
+                <li>优化查询用户的角色组&岗位组代码</li>
+                <li>优化定时任务cron表达式小时设置24</li>
+                <li>优化用户导入提示溢出则显示滚动条</li>
+                <li>优化防重复提交标识组合为(key+url+header)</li>
+                <li>优化分页方法设置成通用方便灵活调用</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.8.0 - 2021-12-01">
+              <ol>
+                <li>新增配套并同步的Vue3前端版本</li>
+                <li>新增通用方法简化模态/缓存/下载/权限/页签使用</li>
+                <li>优化导出数据/使用通用下载方法</li>
+                <li>Excel注解支持自定义数据处理器</li>
+                <li>Excel注解支持导入导出标题信息</li>
+                <li>Excel导入支持@Excels注解</li>
+                <li>新增组件data-dict,简化数据字典使用</li>
+                <li>新增Jaxb依赖,防止jdk8以上出现的兼容错误</li>
+                <li>生产环境使用路由懒加载提升页面响应速度</li>
+                <li>修复五级以上菜单出现的404问题</li>
+                <li>防重提交注解支持配置间隔时间/提示消息</li>
+                <li>日志注解新增是否保存响应参数</li>
+                <li>任务屏蔽违规字符&参数忽略双引号中的逗号</li>
+                <li>升级SpringBoot到最新版本2.5.6</li>
+                <li>升级pagehelper到最新版1.4.0</li>
+                <li>升级spring-boot-mybatis到最新版2.2.0</li>
+                <li>升级oshi到最新版本v5.8.2</li>
+                <li>升级druid到最新版1.2.8</li>
+                <li>升级velocity到最新版本2.3</li>
+                <li>升级fastjson到最新版1.2.78</li>
+                <li>升级axios到最新版本0.24.0</li>
+                <li>升级dart-sass到版本1.32.13</li>
+                <li>升级core-js到最新版本3.19.1</li>
+                <li>升级jsencrypt到最新版本3.2.1</li>
+                <li>升级js-cookie到最新版本3.0.1</li>
+                <li>升级file-saver到最新版本2.0.5</li>
+                <li>升级sass-loader到最新版本10.1.1</li>
+                <li>升级element-ui到最新版本2.15.6</li>
+                <li>新增sendGet无参请求方法</li>
+                <li>禁用el-tag组件的渐变动画</li>
+                <li>代码生成点击预览重置激活tab</li>
+                <li>AjaxResult重写put方法,以方便链式调用</li>
+                <li>优化登录/验证码请求headers不设置token</li>
+                <li>优化用户个人信息接口防止修改用户名</li>
+                <li>优化Cron表达式生成器关闭时销毁避免缓存</li>
+                <li>优化注册成功提示消息类型success</li>
+                <li>优化aop语法,使用spring自动注入注解</li>
+                <li>优化记录登录信息,移除不必要的修改</li>
+                <li>优化mybatis全局默认的执行器</li>
+                <li>优化Excel导入图片可能出现的异常</li>
+                <li>修复代码生成模板主子表删除缺少事务</li>
+                <li>修复日志记录可能出现的转换异常</li>
+                <li>修复代码生成复选框字典遗漏问题</li>
+                <li>修复关闭xss功能导致可重复读RepeatableFilter失效</li>
+                <li>修复字符串无法被反转义问题</li>
+                <li>修复后端主子表代码模板方法名生成错误问题</li>
+                <li>修复xss过滤后格式出现的异常</li>
+                <li>修复swagger没有指定dataTypeClass导致启动出现warn日志</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.7.0 - 2021-09-13">
+              <ol>
+                <li>参数管理支持配置验证码开关</li>
+                <li>新增是否开启用户注册功能</li>
+                <li>定时任务支持在线生成cron表达式</li>
+                <li>菜单管理支持配置路由参数</li>
+                <li>支持自定义注解实现接口限流</li>
+                <li>Excel注解支持Image图片导入</li>
+                <li>自定义弹层溢出滚动样式</li>
+                <li>自定义可拖动弹窗宽度指令</li>
+                <li>自定义可拖动弹窗高度指令</li>
+                <li>修复任意账户越权问题</li>
+                <li>修改时检查用户数据权限范围</li>
+                <li>修复保存配置主题颜色失效问题</li>
+                <li>新增暗色菜单风格主题</li>
+                <li>菜单&部门新增展开/折叠功能</li>
+                <li>页签新增关闭左侧&添加图标</li>
+                <li>顶部菜单排除隐藏的默认路由</li>
+                <li>顶部菜单同步系统主题样式</li>
+                <li>跳转路由高亮相对应的菜单栏</li>
+                <li>代码生成主子表多选行数据</li>
+                <li>日期范围支持添加多组</li>
+                <li>升级element-ui到最新版本2.15.5</li>
+                <li>升级oshi到最新版本v5.8.0</li>
+                <li>升级commons.io到最新版本v2.11.0</li>
+                <li>定时任务屏蔽ldap远程调用</li>
+                <li>定时任务屏蔽http(s)远程调用</li>
+                <li>补充定时任务表字段注释</li>
+                <li>定时任务对检查异常进行事务回滚</li>
+                <li>启用父部门状态排除顶级节点</li>
+                <li>富文本新增上传文件大小限制</li>
+                <li>默认首页使用keep-alive缓存</li>
+                <li>修改代码生成字典回显样式</li>
+                <li>自定义分页合理化传入参数</li>
+                <li>修复字典组件值为整形不显示问题</li>
+                <li>修复定时任务日志执行状态显示</li>
+                <li>角色&菜单新增字段属性提示信息</li>
+                <li>修复角色分配用户页面参数类型错误提醒</li>
+                <li>优化布局设置动画特效</li>
+                <li>优化异常处理信息</li>
+                <li>优化错误token导致的解析异常</li>
+                <li>密码框新增显示切换密码图标</li>
+                <li>定时任务新增更多操作</li>
+                <li>更多操作按钮添加权限控制</li>
+                <li>导入用户样式优化</li>
+                <li>提取通用方法到基类控制器</li>
+                <li>优化使用权限工具获取用户信息</li>
+                <li>优化用户不能删除自己</li>
+                <li>优化XSS跨站脚本过滤</li>
+                <li>优化代码生成模板</li>
+                <li>验证码默认20s超时</li>
+                <li>BLOB下载时清除URL对象引用</li>
+                <li>代码生成导入表按创建时间排序</li>
+                <li>修复代码生成页面数据编辑保存之后总是跳转第一页的问题</li>
+                <li>修复带safari浏览器无法格式化utc日期格式yyyy-MM-dd'T'HH:mm:ss.SSS问题</li>
+                <li>多图上传组件移除多余的api地址&验证失败导致图片删除问题&无法删除相应图片修复</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.6.0 - 2021-07-12">
+              <ol>
+                <li>角色管理新增分配用户功能</li>
+                <li>用户管理新增分配角色功能</li>
+                <li>日志列表支持排序操作</li>
+                <li>优化参数&字典缓存操作</li>
+                <li>系统布局配置支持动态标题开关</li>
+                <li>菜单路由配置支持内链访问</li>
+                <li>默认访问后端首页新增提示语</li>
+                <li>富文本默认上传返回url类型</li>
+                <li>新增自定义弹窗拖拽指令</li>
+                <li>全局注册常用通用组件</li>
+                <li>全局挂载字典标签组件</li>
+                <li>ImageUpload组件支持多图片上传</li>
+                <li>FileUpload组件支持多文件上传</li>
+                <li>文件上传组件添加数量限制属性</li>
+                <li>富文本编辑组件添加类型属性</li>
+                <li>富文本组件工具栏配置视频</li>
+                <li>封装通用iframe组件</li>
+                <li>限制超级管理员不允许操作</li>
+                <li>用户信息长度校验限制</li>
+                <li>分页组件新增pagerCount属性</li>
+                <li>添加bat脚本执行应用</li>
+                <li>升级oshi到最新版本v5.7.4</li>
+                <li>升级element-ui到最新版本2.15.2</li>
+                <li>升级pagehelper到最新版1.3.1</li>
+                <li>升级commons.io到最新版本v2.10.0</li>
+                <li>升级commons.fileupload到最新版本v1.4</li>
+                <li>升级swagger到最新版本v3.0.0</li>
+                <li>修复关闭confirm提示框控制台报错问题</li>
+                <li>修复存在的SQL注入漏洞问题</li>
+                <li>定时任务屏蔽rmi远程调用</li>
+                <li>修复用户搜索分页变量错误</li>
+                <li>修复导出角色数据范围翻译缺少仅本人</li>
+                <li>修复表单构建选择下拉选择控制台报错问题</li>
+                <li>优化图片工具类读取文件</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.5.0 - 2021-05-25">
+              <ol>
+                <li>新增菜单导航显示风格TopNav(false为左侧导航菜单,true为顶部导航菜单)</li>
+                <li>布局设置支持保存&重置配置</li>
+                <li>修复树表数据显示不全&加载慢问题</li>
+                <li>新增IE浏览器版本过低提示页面</li>
+                <li>用户登录后记录最后登录IP&时间</li>
+                <li>页面导出按钮点击之后添加遮罩</li>
+                <li>富文本编辑器支持自定义上传地址</li>
+                <li>富文本编辑组件新增readOnly属性</li>
+                <li>页签TagsView新增关闭右侧功能</li>
+                <li>显隐列组件加载初始默认隐藏列</li>
+                <li>关闭头像上传窗口还原默认图片</li>
+                <li>个人信息添加手机&邮箱重复验证</li>
+                <li>代码生成模板导出按钮点击后添加遮罩</li>
+                <li>代码生成模板树表操作列添加新增按钮</li>
+                <li>代码生成模板修复主子表字段重名问题</li>
+                <li>升级fastjson到最新版1.2.76</li>
+                <li>升级druid到最新版本v1.2.6</li>
+                <li>升级mybatis到最新版3.5.6 阻止远程代码执行漏洞</li>
+                <li>升级oshi到最新版本v5.6.0</li>
+                <li>velocity剔除commons-collections版本,防止3.2.1版本的反序列化漏洞</li>
+                <li>数据监控页默认账户密码防止越权访问</li>
+                <li>修复firefox下表单构建拖拽会新打卡一个选项卡</li>
+                <li>修正后端导入表权限标识</li>
+                <li>修正前端操作日志&登录日志权限标识</li>
+                <li>设置Redis配置HashKey序列化</li>
+                <li>删除操作日志记录信息</li>
+                <li>上传媒体类型添加视频格式</li>
+                <li>修复请求形参未传值记录日志异常问题</li>
+                <li>优化xss校验json请求条件</li>
+                <li>树级结构更新子节点使用replaceFirst</li>
+                <li>优化ExcelUtil空值处理</li>
+                <li>日志记录过滤BindingResult对象,防止异常</li>
+                <li>修改主题后mini类型按钮无效问题</li>
+                <li>优化通用下载完成后删除节点</li>
+                <li>通用Controller添加响应返回消息</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.4.0 - 2021-02-22">
+              <ol>
+                <li>代码生成模板支持主子表</li>
+                <li>表格右侧工具栏组件支持显隐列</li>
+                <li>图片组件添加预览&移除功能</li>
+                <li>Excel注解支持Image图片导出</li>
+                <li>操作按钮组调整为朴素按钮样式</li>
+                <li>代码生成支持文件上传组件</li>
+                <li>代码生成日期控件区分范围</li>
+                <li>代码生成数据库文本类型生成表单文本域</li>
+                <li>用户手机邮箱&菜单组件修改允许空字符串</li>
+                <li>升级SpringBoot到最新版本2.2.13 提升启动速度</li>
+                <li>升级druid到最新版本v1.2.4</li>
+                <li>升级fastjson到最新版1.2.75</li>
+                <li>升级element-ui到最新版本2.15.0</li>
+                <li>修复IE11浏览器报错问题</li>
+                <li>优化多级菜单之间切换无法缓存的问题</li>
+                <li>修复四级菜单无法显示问题</li>
+                <li>修正侧边栏静态路由丢失问题</li>
+                <li>修复角色管理-编辑角色-功能权限显示异常</li>
+                <li>配置文件新增redis数据库索引属性</li>
+                <li>权限工具类增加admin判断</li>
+                <li>角色非自定义权限范围清空选择值</li>
+                <li>修复导入数据为负浮点数时丢失精度问题</li>
+                <li>移除path-to-regexp正则匹配插件</li>
+                <li>修复生成树表代码异常</li>
+                <li>修改ip字段长度防止ipv6地址长度不够</li>
+                <li>防止get请求参数值为false或0等特殊值会导致无法正确的传参</li>
+                <li>登录后push添加catch防止出现检查错误</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.3.0 - 2020-12-14">
+              <ol>
+                <li>新增缓存监控功能</li>
+                <li>支持主题风格配置</li>
+                <li>修复多级菜单之间切换无法缓存的问题</li>
+                <li>多级菜单自动配置组件</li>
+                <li>代码生成预览支持高亮显示</li>
+                <li>支持Get请求映射Params参数</li>
+                <li>删除用户和角色解绑关联</li>
+                <li>去除用户手机邮箱部门必填验证</li>
+                <li>Excel支持注解align对齐方式</li>
+                <li>Excel支持导入Boolean型数据</li>
+                <li>优化头像样式,鼠标移入悬停遮罩</li>
+                <li>代码生成预览提供滚动机制</li>
+                <li>代码生成删除多余的数字float类型</li>
+                <li>修正转换字符串的目标字符集属性</li>
+                <li>回显数据字典防止空值报错</li>
+                <li>日志记录增加过滤多文件场景</li>
+                <li>修改缓存Set方法可能导致嵌套的问题</li>
+                <li>移除前端一些多余的依赖</li>
+                <li>防止安全扫描YUI出现的风险提示</li>
+                <li>修改node-sass为dart-sass</li>
+                <li>升级SpringBoot到最新版本2.1.18</li>
+                <li>升级poi到最新版本4.1.2</li>
+                <li>升级oshi到最新版本v5.3.6</li>
+                <li>升级bitwalker到最新版本1.21</li>
+                <li>升级axios到最新版本0.21.0</li>
+                <li>升级element-ui到最新版本2.14.1</li>
+                <li>升级vue到最新版本2.6.12</li>
+                <li>升级vuex到最新版本3.6.0</li>
+                <li>升级vue-cli到版本4.5.9</li>
+                <li>升级vue-router到最新版本3.4.9</li>
+                <li>升级vue-cli到最新版本4.4.6</li>
+                <li>升级vue-cropper到最新版本0.5.5</li>
+                <li>升级clipboard到最新版本2.0.6</li>
+                <li>升级core-js到最新版本3.8.1</li>
+                <li>升级echarts到最新版本4.9.0</li>
+                <li>升级file-saver到最新版本2.0.4</li>
+                <li>升级fuse.js到最新版本6.4.3</li>
+                <li>升级js-beautify到最新版本1.13.0</li>
+                <li>升级js-cookie到最新版本2.2.1</li>
+                <li>升级path-to-regexp到最新版本6.2.0</li>
+                <li>升级quill到最新版本1.3.7</li>
+                <li>升级screenfull到最新版本5.0.2</li>
+                <li>升级sortablejs到最新版本1.10.2</li>
+                <li>升级vuedraggable到最新版本2.24.3</li>
+                <li>升级chalk到最新版本4.1.0</li>
+                <li>升级eslint到最新版本7.15.0</li>
+                <li>升级eslint-plugin-vue到最新版本7.2.0</li>
+                <li>升级lint-staged到最新版本10.5.3</li>
+                <li>升级runjs到最新版本4.4.2</li>
+                <li>升级sass-loader到最新版本10.1.0</li>
+                <li>升级script-ext-html-webpack-plugin到最新版本2.1.5</li>
+                <li>升级svg-sprite-loader到最新版本5.1.1</li>
+                <li>升级vue-template-compiler到最新版本2.6.12</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.2.1 - 2020-11-18">
+              <ol>
+                <li>阻止任意文件下载漏洞</li>
+                <li>代码生成支持上传控件</li>
+                <li>新增图片上传组件</li>
+                <li>调整默认首页</li>
+                <li>升级druid到最新版本v1.2.2</li>
+                <li>mapperLocations配置支持分隔符</li>
+                <li>权限信息调整</li>
+                <li>调整sql默认时间</li>
+                <li>解决代码生成没有bit类型的问题</li>
+                <li>升级pagehelper到最新版1.3.0</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.2.0 - 2020-10-10">
+              <ol>
+                <li>升级springboot版本到2.1.17 提升安全性</li>
+                <li>升级oshi到最新版本v5.2.5</li>
+                <li>升级druid到最新版本v1.2.1</li>
+                <li>升级jjwt到版本0.9.1</li>
+                <li>升级fastjson到最新版1.2.74</li>
+                <li>修改sass为node-sass,避免el-icon图标乱码</li>
+                <li>代码生成支持同步数据库</li>
+                <li>代码生成支持富文本控件</li>
+                <li>代码生成页面时不忽略remark属性</li>
+                <li>代码生成添加select必填选项</li>
+                <li>Excel导出类型NUMERIC支持精度浮点类型</li>
+                <li>Excel导出targetAttr优化获取值,防止get方法不规范</li>
+                <li>Excel注解支持自动统计数据总和</li>
+                <li>Excel注解支持设置BigDecimal精度&舍入规则</li>
+                <li>菜单&数据权限新增(展开/折叠 全选/全不选 父子联动)</li>
+                <li>允许用户分配到部门父节点</li>
+                <li>菜单新增是否缓存keep-alive</li>
+                <li>表格操作列间距调整</li>
+                <li>限制系统内置参数不允许删除</li>
+                <li>富文本组件优化,支持自定义高度&图片冲突问题</li>
+                <li>富文本工具栏样式对齐</li>
+                <li>导入excel整形值校验优化</li>
+                <li>修复页签关闭所有时固定标签路由不刷新问题</li>
+                <li>表单构建布局型组件新增按钮</li>
+                <li>左侧菜单文字过长显示省略号</li>
+                <li>修正根节点为子部门时,树状结构显示问题</li>
+                <li>修正调用目标字符串最大长度</li>
+                <li>修正菜单提示信息错误</li>
+                <li>修正定时任务执行一次权限标识</li>
+                <li>修正数据库字符串类型nvarchar</li>
+                <li>优化递归子节点</li>
+                <li>优化数据权限判断</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v3.1.0 - 2020-08-13">
+              <ol>
+                <li>表格工具栏右侧添加刷新&显隐查询组件</li>
+                <li>后端支持CORS跨域请求</li>
+                <li>代码生成支持选择上级菜单</li>
+                <li>代码生成支持自定义路径</li>
+                <li>代码生成支持复选框</li>
+                <li>Excel导出导入支持dictType字典类型</li>
+                <li>Excel支持分割字符串组内容</li>
+                <li>验证码类型支持(数组计算、字符验证)</li>
+                <li>升级vue-cli版本到4.4.4</li>
+                <li>修改 node-sass 为 dart-sass</li>
+                <li>表单类型为Integer/Long设置整形默认值</li>
+                <li>代码生成器默认mapper路径与默认mapperScan路径不一致</li>
+                <li>优化防重复提交拦截器</li>
+                <li>优化上级菜单不能选择自己</li>
+                <li>修复角色的权限分配后,未实时生效问题</li>
+                <li>修复在线用户日志记录类型</li>
+                <li>修复富文本空格和缩进保存后不生效问题</li>
+                <li>修复在线用户判断逻辑</li>
+                <li>唯一限制条件只返回单条数据</li>
+                <li>添加获取当前的环境配置方法</li>
+                <li>超时登录后页面跳转到首页</li>
+                <li>全局异常状态汉化拦截处理</li>
+                <li>HTML过滤器改为将html转义</li>
+                <li>检查字符支持小数点&降级改成异常提醒</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v3.0.0 - 2020-07-20">
+              <ol>
+                <li>单应用调整为多模块项目</li>
+                <li>升级element-ui版本到2.13.2</li>
+                <li>删除babel,提高编译速度。</li>
+                <li>新增菜单默认主类目</li>
+                <li>编码文件名修改为uuid方式</li>
+                <li>定时任务cron表达式验证</li>
+                <li>角色权限修改时已有权限未自动勾选异常修复</li>
+                <li>防止切换权限用户后登录出现404</li>
+                <li>Excel支持sort导出排序</li>
+                <li>创建用户不允许选择超级管理员角色</li>
+                <li>修复代码生成导入表结构出现异常页面不提醒问题</li>
+                <li>修复代码生成点击多次表修改数据不变化的问题</li>
+                <li>修复头像上传成功二次打开无法改变裁剪框大小和位置问题</li>
+                <li>修复布局为small者mini用户表单显示错位问题</li>
+                <li>修复热部署导致的强换异常问题</li>
+                <li>修改用户管理复选框宽度,防止部分浏览器出现省略号</li>
+                <li>IpUtils工具,清除Xss特殊字符,防止Xff注入攻击</li>
+                <li>生成domain 如果是浮点型 统一用BigDecimal</li>
+                <li>定时任务调整label-width,防止部署出现错位</li>
+                <li>调整表头固定列默认样式</li>
+                <li>代码生成模板调整,字段为String并且必填则加空串条件</li>
+                <li>代码生成字典Integer/Long使用parseInt</li>
+                <li>
+                  修复dict_sort不可update为0的问题&查询返回增加dict_sort升序排序
+                </li>
+                <li>修正岗位导出权限注解</li>
+                <li>禁止加密密文返回前端</li>
+                <li>修复代码生成页面中的查询条件创建时间未生效的问题</li>
+                <li>修复首页搜索菜单外链无法点击跳转问题</li>
+                <li>修复菜单管理选择图标,backspace删除时不过滤数据</li>
+                <li>用户管理部门分支节点不可检查&显示计数</li>
+                <li>数据范围过滤属性调整</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v2.3.0 - 2020-06-01">
+              <ol>
+                <li>升级fastjson到最新版1.2.70 修复高危安全漏洞</li>
+                <li>dev启动默认打开浏览器</li>
+                <li>vue-cli使用默认source-map</li>
+                <li>slidebar eslint报错优化</li>
+                <li>当tags-view滚动关闭右键菜单</li>
+                <li>字典管理添加缓存读取</li>
+                <li>参数管理支持缓存操作</li>
+                <li>支持一级菜单(和主页同级)在main区域显示</li>
+                <li>限制外链地址必须以http(s)开头</li>
+                <li>tagview & sidebar 主题颜色与element ui(全局)同步</li>
+                <li>修改数据源类型优先级,先根据方法,再根据类</li>
+                <li>支持是否需要设置token属性,自定义返回码消息。</li>
+                <li>swagger请求前缀加入配置。</li>
+                <li>登录地点设置内容过长则隐藏显示</li>
+                <li>修复定时任务执行一次按钮后不提示消息问题</li>
+                <li>修改上级部门(选择项排除本身和下级)</li>
+                <li>通用http发送方法增加参数 contentType 编码类型</li>
+                <li>更换IP地址查询接口</li>
+                <li>修复页签变量undefined</li>
+                <li>添加校验部门包含未停用的子部门</li>
+                <li>修改定时任务详情下次执行时间日期显示错误</li>
+                <li>角色管理查询设置默认排序字段</li>
+                <li>swagger添加enable参数控制是否启用</li>
+                <li>只对json类型请求构建可重复读取inputStream的request</li>
+                <li>修改代码生成字典字段int类型没有自动选中问题</li>
+                <li>vuex用户名取值修正</li>
+                <li>表格树模板去掉多余的)</li>
+                <li>代码生成序号修正</li>
+                <li>全屏情况下不调整上外边距</li>
+                <li>代码生成Date字段添加默认格式</li>
+                <li>用户管理角色选择权限控制</li>
+                <li>修复路由懒加载报错问题</li>
+                <li>模板sql.vm添加菜单状态</li>
+                <li>设置用户名称不能修改</li>
+                <li>dialog添加append-to-body属性,防止ie遮罩</li>
+                <li>菜单区分状态和显示隐藏功能</li>
+                <li>升级fastjson到最新版1.2.68 修复安全加固</li>
+                <li>修复代码生成如果选择字典类型缺失逗号问题</li>
+                <li>登录请求params更换为data,防止暴露url</li>
+                <li>日志返回时间格式处理</li>
+                <li>添加handle控制允许拖动的元素</li>
+                <li>布局设置点击扩大范围</li>
+                <li>代码生成列属性排序查询</li>
+                <li>代码生成列支持拖动排序</li>
+                <li>修复时间格式不支持ios问题</li>
+                <li>表单构建添加父级class,防止冲突</li>
+                <li>定时任务并发属性修正</li>
+                <li>角色禁用&菜单隐藏不查询权限</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v2.2.0 - 2020-03-18">
+              <ol>
+                <li>系统监控新增定时任务功能</li>
+                <li>添加一个打包Web工程bat</li>
+                <li>修复页签鼠标滚轮按下的时候,可以关闭不可关闭的tag</li>
+                <li>修复点击退出登录有时会无提示问题</li>
+                <li>修复防重复提交注解无效问题</li>
+                <li>修复通知公告批量删除异常问题</li>
+                <li>添加菜单时路由地址必填限制</li>
+                <li>代码生成字段描述可编辑</li>
+                <li>修复用户修改个人信息导致缓存不过期问题</li>
+                <li>个人信息创建时间获取正确属性值</li>
+                <li>操作日志详细显示正确类型</li>
+                <li>导入表单击行数据时选中对应的复选框</li>
+                <li>批量替换表前缀逻辑调整</li>
+                <li>固定重定向路径表达式</li>
+                <li>升级element-ui版本到2.13.0</li>
+                <li>操作日志排序调整</li>
+                <li>修复charts切换侧边栏或者缩放窗口显示bug</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v2.1.0 - 2020-02-24">
+              <ol>
+                <li>新增表单构建</li>
+                <li>代码生成支持树表结构</li>
+                <li>新增用户导入</li>
+                <li>修复动态加载路由页面刷新问题</li>
+                <li>修复地址开关无效问题</li>
+                <li>汉化错误提示页面</li>
+                <li>代码生成已知问题修改</li>
+                <li>修复多数据源下配置关闭出现异常处理</li>
+                <li>添加HTML过滤器,用于去除XSS漏洞隐患</li>
+                <li>修复上传头像控制台出现异常</li>
+                <li>修改用户管理分页不正确的问题</li>
+                <li>修复验证码记录提示错误</li>
+                <li>修复request.js缺少Message引用</li>
+                <li>修复表格时间为空出现的异常</li>
+                <li>添加Jackson日期反序列化时区配置</li>
+                <li>调整根据用户权限加载菜单数据树形结构</li>
+                <li>调整成功登录不恢复按钮,防止多次点击</li>
+                <li>修改用户个人资料同步缓存信息</li>
+                <li>修复页面同时出现el-upload和Editor不显示处理</li>
+                <li>修复在角色管理页修改菜单权限偶尔未选中问题</li>
+                <li>配置文件新增redis密码属性</li>
+                <li>设置mybatis全局的配置文件</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v2.0.0 - 2019-12-02">
+              <ol>
+                <li>新增代码生成</li>
+                <li>新增@RepeatSubmit注解,防止重复提交</li>
+                <li>新增菜单主目录添加/删除操作</li>
+                <li>日志记录过滤特殊对象,防止转换异常</li>
+                <li>修改代码生成路由脚本错误</li>
+                <li>用户上传头像实时同步缓存,无需重新登录</li>
+                <li>调整切换页签后不重新加载数据</li>
+                <li>添加jsencrypt实现参数的前端加密</li>
+                <li>系统退出删除用户缓存记录</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v1.1.0 - 2019-11-11">
+              <ol>
+                <li>新增在线用户管理</li>
+                <li>新增按钮组功能实现(批量删除、导出、清空)</li>
+                <li>新增查询条件重置按钮</li>
+                <li>新增Swagger全局Token配置</li>
+                <li>新增后端参数校验</li>
+                <li>修复字典管理页面的日期查询异常</li>
+                <li>修改时间函数命名防止冲突</li>
+                <li>去除菜单上级校验,默认为顶级</li>
+                <li>修复用户密码无法修改问题</li>
+                <li>修复菜单类型为按钮时不显示权限标识</li>
+                <li>其他细节优化</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v1.0.0 - 2019-10-08">
+              <ol>
+                <li>若依前后端分离系统正式发布</li>
+              </ol>
+            </el-collapse-item>
+          </el-collapse>
+        </el-card>
+      </el-col>
+      <el-col :xs="24" :sm="24" :md="12" :lg="8">
+        <el-card class="update-log">
+          <div slot="header" class="clearfix">
+            <span>捐赠支持</span>
+          </div>
+          <div class="body">
+            <img
+              src="@/assets/images/pay.png"
+              alt="donate"
+              width="100%"
+            />
+            <span style="display: inline-block; height: 30px; line-height: 30px"
+              >你可以请作者喝杯咖啡表示鼓励</span
+            >
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "Index",
+  data() {
+    return {
+      // 版本号
+      version: "3.8.9"
+    };
+  },
+  methods: {
+    goTarget(href) {
+      window.open(href, "_blank");
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.home {
+  blockquote {
+    padding: 10px 20px;
+    margin: 0 0 20px;
+    font-size: 17.5px;
+    border-left: 5px solid #eee;
+  }
+  hr {
+    margin-top: 20px;
+    margin-bottom: 20px;
+    border: 0;
+    border-top: 1px solid #eee;
+  }
+  .col-item {
+    margin-bottom: 20px;
+  }
+
+  ul {
+    padding: 0;
+    margin: 0;
+  }
+
+  font-family: "open sans", "Helvetica Neue", Helvetica, Arial, sans-serif;
+  font-size: 13px;
+  color: #676a6c;
+  overflow-x: hidden;
+
+  ul {
+    list-style-type: none;
+  }
+
+  h4 {
+    margin-top: 0px;
+  }
+
+  h2 {
+    margin-top: 10px;
+    font-size: 26px;
+    font-weight: 100;
+  }
+
+  p {
+    margin-top: 10px;
+
+    b {
+      font-weight: 700;
+    }
+  }
+
+  .update-log {
+    ol {
+      display: block;
+      list-style-type: decimal;
+      margin-block-start: 1em;
+      margin-block-end: 1em;
+      margin-inline-start: 0;
+      margin-inline-end: 0;
+      padding-inline-start: 40px;
+    }
+  }
+}
+</style>
+
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
index 2f962b75..efb63de7 100644
--- a/ruoyi-ui/src/views/login.vue
+++ b/ruoyi-ui/src/views/login.vue
@@ -1,219 +1,219 @@
-<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" v-if="captchaEnabled">
-        <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" class="login-code-img"/>
-        </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>
-        <div style="float: right;" v-if="register">
-          <router-link class="link-type" :to="'/register'">立即注册</router-link>
-        </div>
-      </el-form-item>
-    </el-form>
-    <!--  底部  -->
-    <div class="el-login-footer">
-      <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
-    </div>
-  </div>
-</template>
-
-<script>
-import { getCodeImg } from "@/api/login";
-import Cookies from "js-cookie";
-import { encrypt, decrypt } from '@/utils/jsencrypt'
-
-export default {
-  name: "Login",
-  data() {
-    return {
-      codeUrl: "",
-      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,
-      // 验证码开关
-      captchaEnabled: true,
-      // 注册开关
-      register: 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.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
-        if (this.captchaEnabled) {
-          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 : decrypt(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", encrypt(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.$router.push({ path: this.redirect || "/" }).catch(()=>{});
-          }).catch(() => {
-            this.loading = false;
-            if (this.captchaEnabled) {
-              this.getCode();
-            }
-          });
-        }
-      });
-    }
-  }
-};
-</script>
-
-<style rel="stylesheet/scss" lang="scss">
-.login {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  height: 100%;
-  background-image: url("../assets/images/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;
-}
-.login-code-img {
-  height: 38px;
-}
-</style>
+<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" v-if="captchaEnabled">
+        <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" class="login-code-img"/>
+        </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>
+        <div style="float: right;" v-if="register">
+          <router-link class="link-type" :to="'/register'">立即注册</router-link>
+        </div>
+      </el-form-item>
+    </el-form>
+    <!--  底部  -->
+    <div class="el-login-footer">
+      <span>Copyright © 2018-2025 acupuncture.vip All Rights Reserved.</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getCodeImg } from "@/api/login";
+import Cookies from "js-cookie";
+import { encrypt, decrypt } from '@/utils/jsencrypt'
+
+export default {
+  name: "Login",
+  data() {
+    return {
+      codeUrl: "",
+      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,
+      // 验证码开关
+      captchaEnabled: true,
+      // 注册开关
+      register: 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.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
+        if (this.captchaEnabled) {
+          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 : decrypt(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", encrypt(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.$router.push({ path: this.redirect || "/" }).catch(()=>{});
+          }).catch(() => {
+            this.loading = false;
+            if (this.captchaEnabled) {
+              this.getCode();
+            }
+          });
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.login {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background-image: url("../assets/images/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;
+}
+.login-code-img {
+  height: 38px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
index 892c7275..d9e43757 100644
--- a/ruoyi-ui/src/views/monitor/job/index.vue
+++ b/ruoyi-ui/src/views/monitor/job/index.vue
@@ -179,7 +179,7 @@
                 <el-tooltip placement="top">
                   <div slot="content">
                     Bean调用示例:ryTask.ryParams('ry')
-                    <br />Class类调用示例:com.ruoyi.quartz.task.RyTask.ryParams('ry')
+                    <br />Class类调用示例:com.acupuncture.quartz.task.RyTask.ryParams('ry')
                     <br />参数说明:支持字符串,布尔类型,长整型,浮点型,整型
                   </div>
                   <i class="el-icon-question"></i>
diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue
index b00f576c..f2d24bcf 100644
--- a/ruoyi-ui/src/views/register.vue
+++ b/ruoyi-ui/src/views/register.vue
@@ -1,210 +1,210 @@
-<template>
-  <div class="register">
-    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
-      <h3 class="title">若依后台管理系统</h3>
-      <el-form-item prop="username">
-        <el-input v-model="registerForm.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="registerForm.password"
-          type="password"
-          auto-complete="off"
-          placeholder="密码"
-          @keyup.enter.native="handleRegister"
-        >
-          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
-        </el-input>
-      </el-form-item>
-      <el-form-item prop="confirmPassword">
-        <el-input
-          v-model="registerForm.confirmPassword"
-          type="password"
-          auto-complete="off"
-          placeholder="确认密码"
-          @keyup.enter.native="handleRegister"
-        >
-          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
-        </el-input>
-      </el-form-item>
-      <el-form-item prop="code" v-if="captchaEnabled">
-        <el-input
-          v-model="registerForm.code"
-          auto-complete="off"
-          placeholder="验证码"
-          style="width: 63%"
-          @keyup.enter.native="handleRegister"
-        >
-          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
-        </el-input>
-        <div class="register-code">
-          <img :src="codeUrl" @click="getCode" class="register-code-img"/>
-        </div>
-      </el-form-item>
-      <el-form-item style="width:100%;">
-        <el-button
-          :loading="loading"
-          size="medium"
-          type="primary"
-          style="width:100%;"
-          @click.native.prevent="handleRegister"
-        >
-          <span v-if="!loading">注 册</span>
-          <span v-else>注 册 中...</span>
-        </el-button>
-        <div style="float: right;">
-          <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
-        </div>
-      </el-form-item>
-    </el-form>
-    <!--  底部  -->
-    <div class="el-register-footer">
-      <span>Copyright © 2018-2025 ruoyi.vip All Rights Reserved.</span>
-    </div>
-  </div>
-</template>
-
-<script>
-import { getCodeImg, register } from "@/api/login";
-
-export default {
-  name: "Register",
-  data() {
-    const equalToPassword = (rule, value, callback) => {
-      if (this.registerForm.password !== value) {
-        callback(new Error("两次输入的密码不一致"));
-      } else {
-        callback();
-      }
-    };
-    return {
-      codeUrl: "",
-      registerForm: {
-        username: "",
-        password: "",
-        confirmPassword: "",
-        code: "",
-        uuid: ""
-      },
-      registerRules: {
-        username: [
-          { required: true, trigger: "blur", message: "请输入您的账号" },
-          { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
-        ],
-        password: [
-          { required: true, trigger: "blur", message: "请输入您的密码" },
-          { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
-          { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
-        ],
-        confirmPassword: [
-          { required: true, trigger: "blur", message: "请再次输入您的密码" },
-          { required: true, validator: equalToPassword, trigger: "blur" }
-        ],
-        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
-      },
-      loading: false,
-      captchaEnabled: true
-    };
-  },
-  created() {
-    this.getCode();
-  },
-  methods: {
-    getCode() {
-      getCodeImg().then(res => {
-        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
-        if (this.captchaEnabled) {
-          this.codeUrl = "data:image/gif;base64," + res.img;
-          this.registerForm.uuid = res.uuid;
-        }
-      });
-    },
-    handleRegister() {
-      this.$refs.registerForm.validate(valid => {
-        if (valid) {
-          this.loading = true;
-          register(this.registerForm).then(res => {
-            const username = this.registerForm.username;
-            this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
-              dangerouslyUseHTMLString: true,
-              type: 'success'
-            }).then(() => {
-              this.$router.push("/login");
-            }).catch(() => {});
-          }).catch(() => {
-            this.loading = false;
-            if (this.captchaEnabled) {
-              this.getCode();
-            }
-          })
-        }
-      });
-    }
-  }
-};
-</script>
-
-<style rel="stylesheet/scss" lang="scss">
-.register {
-  display: flex;
-  justify-content: center;
-  align-items: center;
-  height: 100%;
-  background-image: url("../assets/images/login-background.jpg");
-  background-size: cover;
-}
-.title {
-  margin: 0px auto 30px auto;
-  text-align: center;
-  color: #707070;
-}
-
-.register-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;
-  }
-}
-.register-tip {
-  font-size: 13px;
-  text-align: center;
-  color: #bfbfbf;
-}
-.register-code {
-  width: 33%;
-  height: 38px;
-  float: right;
-  img {
-    cursor: pointer;
-    vertical-align: middle;
-  }
-}
-.el-register-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;
-}
-.register-code-img {
-  height: 38px;
-}
-</style>
+<template>
+  <div class="register">
+    <el-form ref="registerForm" :model="registerForm" :rules="registerRules" class="register-form">
+      <h3 class="title">若依后台管理系统</h3>
+      <el-form-item prop="username">
+        <el-input v-model="registerForm.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="registerForm.password"
+          type="password"
+          auto-complete="off"
+          placeholder="密码"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="confirmPassword">
+        <el-input
+          v-model="registerForm.confirmPassword"
+          type="password"
+          auto-complete="off"
+          placeholder="确认密码"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="password" class="el-input__icon input-icon" />
+        </el-input>
+      </el-form-item>
+      <el-form-item prop="code" v-if="captchaEnabled">
+        <el-input
+          v-model="registerForm.code"
+          auto-complete="off"
+          placeholder="验证码"
+          style="width: 63%"
+          @keyup.enter.native="handleRegister"
+        >
+          <svg-icon slot="prefix" icon-class="validCode" class="el-input__icon input-icon" />
+        </el-input>
+        <div class="register-code">
+          <img :src="codeUrl" @click="getCode" class="register-code-img"/>
+        </div>
+      </el-form-item>
+      <el-form-item style="width:100%;">
+        <el-button
+          :loading="loading"
+          size="medium"
+          type="primary"
+          style="width:100%;"
+          @click.native.prevent="handleRegister"
+        >
+          <span v-if="!loading">注 册</span>
+          <span v-else>注 册 中...</span>
+        </el-button>
+        <div style="float: right;">
+          <router-link class="link-type" :to="'/login'">使用已有账户登录</router-link>
+        </div>
+      </el-form-item>
+    </el-form>
+    <!--  底部  -->
+    <div class="el-register-footer">
+      <span>Copyright © 2018-2025 acupuncture.vip All Rights Reserved.</span>
+    </div>
+  </div>
+</template>
+
+<script>
+import { getCodeImg, register } from "@/api/login";
+
+export default {
+  name: "Register",
+  data() {
+    const equalToPassword = (rule, value, callback) => {
+      if (this.registerForm.password !== value) {
+        callback(new Error("两次输入的密码不一致"));
+      } else {
+        callback();
+      }
+    };
+    return {
+      codeUrl: "",
+      registerForm: {
+        username: "",
+        password: "",
+        confirmPassword: "",
+        code: "",
+        uuid: ""
+      },
+      registerRules: {
+        username: [
+          { required: true, trigger: "blur", message: "请输入您的账号" },
+          { min: 2, max: 20, message: '用户账号长度必须介于 2 和 20 之间', trigger: 'blur' }
+        ],
+        password: [
+          { required: true, trigger: "blur", message: "请输入您的密码" },
+          { min: 5, max: 20, message: "用户密码长度必须介于 5 和 20 之间", trigger: "blur" },
+          { pattern: /^[^<>"'|\\]+$/, message: "不能包含非法字符:< > \" ' \\\ |", trigger: "blur" }
+        ],
+        confirmPassword: [
+          { required: true, trigger: "blur", message: "请再次输入您的密码" },
+          { required: true, validator: equalToPassword, trigger: "blur" }
+        ],
+        code: [{ required: true, trigger: "change", message: "请输入验证码" }]
+      },
+      loading: false,
+      captchaEnabled: true
+    };
+  },
+  created() {
+    this.getCode();
+  },
+  methods: {
+    getCode() {
+      getCodeImg().then(res => {
+        this.captchaEnabled = res.captchaEnabled === undefined ? true : res.captchaEnabled;
+        if (this.captchaEnabled) {
+          this.codeUrl = "data:image/gif;base64," + res.img;
+          this.registerForm.uuid = res.uuid;
+        }
+      });
+    },
+    handleRegister() {
+      this.$refs.registerForm.validate(valid => {
+        if (valid) {
+          this.loading = true;
+          register(this.registerForm).then(res => {
+            const username = this.registerForm.username;
+            this.$alert("<font color='red'>恭喜你,您的账号 " + username + " 注册成功!</font>", '系统提示', {
+              dangerouslyUseHTMLString: true,
+              type: 'success'
+            }).then(() => {
+              this.$router.push("/login");
+            }).catch(() => {});
+          }).catch(() => {
+            this.loading = false;
+            if (this.captchaEnabled) {
+              this.getCode();
+            }
+          })
+        }
+      });
+    }
+  }
+};
+</script>
+
+<style rel="stylesheet/scss" lang="scss">
+.register {
+  display: flex;
+  justify-content: center;
+  align-items: center;
+  height: 100%;
+  background-image: url("../assets/images/login-background.jpg");
+  background-size: cover;
+}
+.title {
+  margin: 0px auto 30px auto;
+  text-align: center;
+  color: #707070;
+}
+
+.register-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;
+  }
+}
+.register-tip {
+  font-size: 13px;
+  text-align: center;
+  color: #bfbfbf;
+}
+.register-code {
+  width: 33%;
+  height: 38px;
+  float: right;
+  img {
+    cursor: pointer;
+    vertical-align: middle;
+  }
+}
+.el-register-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;
+}
+.register-code-img {
+  height: 38px;
+}
+</style>
diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
index a15e0734..d4cd72af 100644
--- a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
+++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
@@ -1,312 +1,312 @@
-<template>
-  <el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
-    <el-row>
-      <el-col :span="12">
-        <el-form-item prop="tplCategory">
-          <span slot="label">生成模板</span>
-          <el-select v-model="info.tplCategory" @change="tplSelectChange">
-            <el-option label="单表(增删改查)" value="crud" />
-            <el-option label="树表(增删改查)" value="tree" />
-            <el-option label="主子表(增删改查)" value="sub" />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item prop="tplWebType">
-          <span slot="label">前端类型</span>
-          <el-select v-model="info.tplWebType">
-            <el-option label="Vue2 Element UI 模版" value="element-ui" />
-            <el-option label="Vue3 Element Plus 模版" value="element-plus" />
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item prop="packageName">
-          <span slot="label">
-            生成包路径
-            <el-tooltip content="生成在哪个java包下,例如 com.ruoyi.system" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.packageName" />
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="12">
-        <el-form-item prop="moduleName">
-          <span slot="label">
-            生成模块名
-            <el-tooltip content="可理解为子系统名,例如 system" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.moduleName" />
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="12">
-        <el-form-item prop="businessName">
-          <span slot="label">
-            生成业务名
-            <el-tooltip content="可理解为功能英文名,例如 user" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.businessName" />
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="12">
-        <el-form-item prop="functionName">
-          <span slot="label">
-            生成功能名
-            <el-tooltip content="用作类描述,例如 用户" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.functionName" />
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="12">
-        <el-form-item prop="genType">
-          <span slot="label">
-            生成代码方式
-            <el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
-          <el-radio v-model="info.genType" label="1">自定义路径</el-radio>
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            上级菜单
-            <el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <treeselect
-            :append-to-body="true"
-            v-model="info.parentMenuId"
-            :options="menus"
-            :normalizer="normalizer"
-            :show-count="true"
-            placeholder="请选择系统菜单"
-          />
-        </el-form-item>
-      </el-col>
-
-      <el-col :span="24" v-if="info.genType == '1'">
-        <el-form-item prop="genPath">
-          <span slot="label">
-            自定义路径
-            <el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-input v-model="info.genPath">
-            <el-dropdown slot="append">
-              <el-button type="primary">
-                最近路径快速选择
-                <i class="el-icon-arrow-down el-icon--right"></i>
-              </el-button>
-              <el-dropdown-menu slot="dropdown">
-                <el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
-              </el-dropdown-menu>
-            </el-dropdown>
-          </el-input>
-        </el-form-item>
-      </el-col>
-    </el-row>
-
-    <el-row v-show="info.tplCategory == 'tree'">
-      <h4 class="form-header">其他信息</h4>
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            树编码字段
-            <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-select v-model="info.treeCode" placeholder="请选择">
-            <el-option
-              v-for="(column, index) in info.columns"
-              :key="index"
-              :label="column.columnName + ':' + column.columnComment"
-              :value="column.columnName"
-            ></el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            树父编码字段
-            <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-select v-model="info.treeParentCode" placeholder="请选择">
-            <el-option
-              v-for="(column, index) in info.columns"
-              :key="index"
-              :label="column.columnName + ':' + column.columnComment"
-              :value="column.columnName"
-            ></el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            树名称字段
-            <el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-select v-model="info.treeName" placeholder="请选择">
-            <el-option
-              v-for="(column, index) in info.columns"
-              :key="index"
-              :label="column.columnName + ':' + column.columnComment"
-              :value="column.columnName"
-            ></el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-    </el-row>
-    <el-row v-show="info.tplCategory == 'sub'">
-      <h4 class="form-header">关联信息</h4>
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            关联子表的表名
-            <el-tooltip content="关联子表的表名, 如:sys_user" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
-            <el-option
-              v-for="(table, index) in tables"
-              :key="index"
-              :label="table.tableName + ':' + table.tableComment"
-              :value="table.tableName"
-            ></el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-      <el-col :span="12">
-        <el-form-item>
-          <span slot="label">
-            子表关联的外键名
-            <el-tooltip content="子表关联的外键名, 如:user_id" placement="top">
-              <i class="el-icon-question"></i>
-            </el-tooltip>
-          </span>
-          <el-select v-model="info.subTableFkName" placeholder="请选择">
-            <el-option
-              v-for="(column, index) in subColumns"
-              :key="index"
-              :label="column.columnName + ':' + column.columnComment"
-              :value="column.columnName"
-            ></el-option>
-          </el-select>
-        </el-form-item>
-      </el-col>
-    </el-row>
-  </el-form>
-</template>
-
-<script>
-import Treeselect from "@riophae/vue-treeselect";
-import "@riophae/vue-treeselect/dist/vue-treeselect.css";
-
-export default {
-  components: { Treeselect },
-  props: {
-    info: {
-      type: Object,
-      default: null
-    },
-    tables: {
-      type: Array,
-      default: null
-    },
-    menus: {
-      type: Array,
-      default: []
-    },
-  },
-  data() {
-    return {
-      subColumns: [],
-      rules: {
-        tplCategory: [
-          { required: true, message: "请选择生成模板", trigger: "blur" }
-        ],
-        packageName: [
-          { required: true, message: "请输入生成包路径", trigger: "blur" }
-        ],
-        moduleName: [
-          { required: true, message: "请输入生成模块名", trigger: "blur" }
-        ],
-        businessName: [
-          { required: true, message: "请输入生成业务名", trigger: "blur" }
-        ],
-        functionName: [
-          { required: true, message: "请输入生成功能名", trigger: "blur" }
-        ],
-      }
-    };
-  },
-  watch: {
-    'info.subTableName': function(val) {
-      this.setSubTableColumns(val);
-    },
-    'info.tplWebType': function(val) {
-      if (val === '') {
-        this.info.tplWebType = "element-ui";
-      }
-    }
-  },
-  methods: {
-    /** 转换菜单数据结构 */
-    normalizer(node) {
-      if (node.children && !node.children.length) {
-        delete node.children;
-      }
-      return {
-        id: node.menuId,
-        label: node.menuName,
-        children: node.children
-      };
-    },
-    /** 选择子表名触发 */
-    subSelectChange(value) {
-      this.info.subTableFkName = '';
-    },
-    /** 选择生成模板触发 */
-    tplSelectChange(value) {
-      if(value !== 'sub') {
-        this.info.subTableName = '';
-        this.info.subTableFkName = '';
-      }
-    },
-    /** 设置关联外键 */
-    setSubTableColumns(value) {
-      for (var item in this.tables) {
-        const name = this.tables[item].tableName;
-        if (value === name) {
-          this.subColumns = this.tables[item].columns;
-          break;
-        }
-      }
-    }
-  }
-};
-</script>
+<template>
+  <el-form ref="genInfoForm" :model="info" :rules="rules" label-width="150px">
+    <el-row>
+      <el-col :span="12">
+        <el-form-item prop="tplCategory">
+          <span slot="label">生成模板</span>
+          <el-select v-model="info.tplCategory" @change="tplSelectChange">
+            <el-option label="单表(增删改查)" value="crud" />
+            <el-option label="树表(增删改查)" value="tree" />
+            <el-option label="主子表(增删改查)" value="sub" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item prop="tplWebType">
+          <span slot="label">前端类型</span>
+          <el-select v-model="info.tplWebType">
+            <el-option label="Vue2 Element UI 模版" value="element-ui" />
+            <el-option label="Vue3 Element Plus 模版" value="element-plus" />
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item prop="packageName">
+          <span slot="label">
+            生成包路径
+            <el-tooltip content="生成在哪个java包下,例如 com.acupuncture.system" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-input v-model="info.packageName" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
+        <el-form-item prop="moduleName">
+          <span slot="label">
+            生成模块名
+            <el-tooltip content="可理解为子系统名,例如 system" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-input v-model="info.moduleName" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
+        <el-form-item prop="businessName">
+          <span slot="label">
+            生成业务名
+            <el-tooltip content="可理解为功能英文名,例如 user" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-input v-model="info.businessName" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
+        <el-form-item prop="functionName">
+          <span slot="label">
+            生成功能名
+            <el-tooltip content="用作类描述,例如 用户" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-input v-model="info.functionName" />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
+        <el-form-item prop="genType">
+          <span slot="label">
+            生成代码方式
+            <el-tooltip content="默认为zip压缩包下载,也可以自定义生成路径" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-radio v-model="info.genType" label="0">zip压缩包</el-radio>
+          <el-radio v-model="info.genType" label="1">自定义路径</el-radio>
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            上级菜单
+            <el-tooltip content="分配到指定菜单下,例如 系统管理" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <treeselect
+            :append-to-body="true"
+            v-model="info.parentMenuId"
+            :options="menus"
+            :normalizer="normalizer"
+            :show-count="true"
+            placeholder="请选择系统菜单"
+          />
+        </el-form-item>
+      </el-col>
+
+      <el-col :span="24" v-if="info.genType == '1'">
+        <el-form-item prop="genPath">
+          <span slot="label">
+            自定义路径
+            <el-tooltip content="填写磁盘绝对路径,若不填写,则生成到当前Web项目下" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-input v-model="info.genPath">
+            <el-dropdown slot="append">
+              <el-button type="primary">
+                最近路径快速选择
+                <i class="el-icon-arrow-down el-icon--right"></i>
+              </el-button>
+              <el-dropdown-menu slot="dropdown">
+                <el-dropdown-item @click.native="info.genPath = '/'">恢复默认的生成基础路径</el-dropdown-item>
+              </el-dropdown-menu>
+            </el-dropdown>
+          </el-input>
+        </el-form-item>
+      </el-col>
+    </el-row>
+
+    <el-row v-show="info.tplCategory == 'tree'">
+      <h4 class="form-header">其他信息</h4>
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            树编码字段
+            <el-tooltip content="树显示的编码字段名, 如:dept_id" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-select v-model="info.treeCode" placeholder="请选择">
+            <el-option
+              v-for="(column, index) in info.columns"
+              :key="index"
+              :label="column.columnName + ':' + column.columnComment"
+              :value="column.columnName"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            树父编码字段
+            <el-tooltip content="树显示的父编码字段名, 如:parent_Id" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-select v-model="info.treeParentCode" placeholder="请选择">
+            <el-option
+              v-for="(column, index) in info.columns"
+              :key="index"
+              :label="column.columnName + ':' + column.columnComment"
+              :value="column.columnName"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            树名称字段
+            <el-tooltip content="树节点的显示名称字段名, 如:dept_name" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-select v-model="info.treeName" placeholder="请选择">
+            <el-option
+              v-for="(column, index) in info.columns"
+              :key="index"
+              :label="column.columnName + ':' + column.columnComment"
+              :value="column.columnName"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+    </el-row>
+    <el-row v-show="info.tplCategory == 'sub'">
+      <h4 class="form-header">关联信息</h4>
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            关联子表的表名
+            <el-tooltip content="关联子表的表名, 如:sys_user" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-select v-model="info.subTableName" placeholder="请选择" @change="subSelectChange">
+            <el-option
+              v-for="(table, index) in tables"
+              :key="index"
+              :label="table.tableName + ':' + table.tableComment"
+              :value="table.tableName"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item>
+          <span slot="label">
+            子表关联的外键名
+            <el-tooltip content="子表关联的外键名, 如:user_id" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+          </span>
+          <el-select v-model="info.subTableFkName" placeholder="请选择">
+            <el-option
+              v-for="(column, index) in subColumns"
+              :key="index"
+              :label="column.columnName + ':' + column.columnComment"
+              :value="column.columnName"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+      </el-col>
+    </el-row>
+  </el-form>
+</template>
+
+<script>
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  components: { Treeselect },
+  props: {
+    info: {
+      type: Object,
+      default: null
+    },
+    tables: {
+      type: Array,
+      default: null
+    },
+    menus: {
+      type: Array,
+      default: []
+    },
+  },
+  data() {
+    return {
+      subColumns: [],
+      rules: {
+        tplCategory: [
+          { required: true, message: "请选择生成模板", trigger: "blur" }
+        ],
+        packageName: [
+          { required: true, message: "请输入生成包路径", trigger: "blur" }
+        ],
+        moduleName: [
+          { required: true, message: "请输入生成模块名", trigger: "blur" }
+        ],
+        businessName: [
+          { required: true, message: "请输入生成业务名", trigger: "blur" }
+        ],
+        functionName: [
+          { required: true, message: "请输入生成功能名", trigger: "blur" }
+        ],
+      }
+    };
+  },
+  watch: {
+    'info.subTableName': function(val) {
+      this.setSubTableColumns(val);
+    },
+    'info.tplWebType': function(val) {
+      if (val === '') {
+        this.info.tplWebType = "element-ui";
+      }
+    }
+  },
+  methods: {
+    /** 转换菜单数据结构 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.menuId,
+        label: node.menuName,
+        children: node.children
+      };
+    },
+    /** 选择子表名触发 */
+    subSelectChange(value) {
+      this.info.subTableFkName = '';
+    },
+    /** 选择生成模板触发 */
+    tplSelectChange(value) {
+      if(value !== 'sub') {
+        this.info.subTableName = '';
+        this.info.subTableFkName = '';
+      }
+    },
+    /** 设置关联外键 */
+    setSubTableColumns(value) {
+      for (var item in this.tables) {
+        const name = this.tables[item].tableName;
+        if (value === name) {
+          this.subColumns = this.tables[item].columns;
+          break;
+        }
+      }
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue
index 9237c302..f8528e21 100644
--- a/ruoyi-ui/src/views/tool/gen/index.vue
+++ b/ruoyi-ui/src/views/tool/gen/index.vue
@@ -280,7 +280,7 @@ export default {
           this.$modal.msgSuccess("成功生成到自定义路径:" + row.genPath);
         });
       } else {
-        this.$download.zip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi.zip");
+        this.$download.zip("/tool/gen/batchGenCode?tables=" + tableNames, "acupuncture.zip");
       }
     },
     /** 同步数据库操作 */
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
index fa67f51b..1eb35617 100644
--- a/ruoyi-ui/vue.config.js
+++ b/ruoyi-ui/vue.config.js
@@ -1,131 +1,131 @@
-'use strict'
-const path = require('path')
-
-function resolve(dir) {
-  return path.join(__dirname, dir)
-}
-
-const CompressionPlugin = require('compression-webpack-plugin')
-
-const name = process.env.VUE_APP_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 = {
-  // 部署生产环境和开发环境下的URL。
-  // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
-  // 例如 https://www.ruoyi.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.ruoyi.vip/admin/,则设置 baseUrl 为 /admin/。
-  publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
-  // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
-  outputDir: 'dist',
-  // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
-  assetsDir: 'static',
-  // 是否开启eslint保存检测,有效值:ture | false | 'error'
-  lintOnSave: process.env.NODE_ENV === 'development',
-  // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
-  productionSourceMap: false,
-  transpileDependencies: ['quill'],
-  // webpack-dev-server 相关配置
-  devServer: {
-    host: '0.0.0.0',
-    port: port,
-    open: true,
-    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
-  },
-  css: {
-    loaderOptions: {
-      sass: {
-        sassOptions: { outputStyle: "expanded" }
-      }
-    }
-  },
-  configureWebpack: {
-    name: name,
-    resolve: {
-      alias: {
-        '@': resolve('src')
-      }
-    },
-    plugins: [
-      // http://doc.ruoyi.vip/ruoyi-vue/other/faq.html#使用gzip解压缩静态文件
-      new CompressionPlugin({
-        cache: false,                                  // 不启用文件缓存
-        test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i,  // 压缩文件格式
-        filename: '[path][base].gz[query]',            // 压缩后的文件名
-        algorithm: 'gzip',                             // 使用gzip压缩
-        minRatio: 0.8,                                 // 压缩比例,小于 80% 的文件不会被压缩
-        deleteOriginalAssets: false                    // 压缩后删除原文件
-      })
-    ],
-  },
-  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()
-
-    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
-                test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
-                priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
-              },
-              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')
-    })
-  }
-}
+'use strict'
+const path = require('path')
+
+function resolve(dir) {
+  return path.join(__dirname, dir)
+}
+
+const CompressionPlugin = require('compression-webpack-plugin')
+
+const name = process.env.VUE_APP_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 = {
+  // 部署生产环境和开发环境下的URL。
+  // 默认情况下,Vue CLI 会假设你的应用是被部署在一个域名的根路径上
+  // 例如 https://www.acupuncture.vip/。如果应用被部署在一个子路径上,你就需要用这个选项指定这个子路径。例如,如果你的应用被部署在 https://www.acupuncture.vip/admin/,则设置 baseUrl 为 /admin/。
+  publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
+  // 在npm run build 或 yarn build 时 ,生成文件的目录名称(要和baseUrl的生产环境路径一致)(默认dist)
+  outputDir: 'dist',
+  // 用于放置生成的静态资源 (js、css、img、fonts) 的;(项目打包之后,静态资源会放在这个文件夹下)
+  assetsDir: 'static',
+  // 是否开启eslint保存检测,有效值:ture | false | 'error'
+  lintOnSave: process.env.NODE_ENV === 'development',
+  // 如果你不需要生产环境的 source map,可以将其设置为 false 以加速生产环境构建。
+  productionSourceMap: false,
+  transpileDependencies: ['quill'],
+  // webpack-dev-server 相关配置
+  devServer: {
+    host: '0.0.0.0',
+    port: port,
+    open: true,
+    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
+  },
+  css: {
+    loaderOptions: {
+      sass: {
+        sassOptions: { outputStyle: "expanded" }
+      }
+    }
+  },
+  configureWebpack: {
+    name: name,
+    resolve: {
+      alias: {
+        '@': resolve('src')
+      }
+    },
+    plugins: [
+      // http://doc.acupuncture.vip/acupuncture-vue/other/faq.html#使用gzip解压缩静态文件
+      new CompressionPlugin({
+        cache: false,                                  // 不启用文件缓存
+        test: /\.(js|css|html|jpe?g|png|gif|svg)?$/i,  // 压缩文件格式
+        filename: '[path][base].gz[query]',            // 压缩后的文件名
+        algorithm: 'gzip',                             // 使用gzip压缩
+        minRatio: 0.8,                                 // 压缩比例,小于 80% 的文件不会被压缩
+        deleteOriginalAssets: false                    // 压缩后删除原文件
+      })
+    ],
+  },
+  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()
+
+    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
+                test: /[\\/]node_modules[\\/]_?element-ui(.*)/, // in order to adapt to cnpm
+                priority: 20 // the weight needs to be larger than libs and app or it will be packaged into libs or app
+              },
+              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/ry.sh b/ry.sh
index d6a9cf33..c2b209b3 100644
--- a/ry.sh
+++ b/ry.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
 # ./ry.sh start 启动 stop 停止 restart 重启 status 状态
-AppName=ruoyi-admin.jar
+AppName=acupuncture-admin.jar
 
 # JVM参数
 JVM_OPTS="-Dname=$AppName  -Duser.timezone=Asia/Shanghai -Xms512m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps  -XX:+PrintGCDetails -XX:NewRatio=1 -XX:SurvivorRatio=30 -XX:+UseParallelGC -XX:+UseParallelOldGC"
diff --git a/sql/ry_20240629.sql b/sql/ry_20240629.sql
index a8647d21..58f11e32 100644
--- a/sql/ry_20240629.sql
+++ b/sql/ry_20240629.sql
@@ -161,7 +161,7 @@ create table sys_menu (
 insert into sys_menu values('1', '系统管理', '0', '1', 'system',           null, '', '', 1, 0, 'M', '0', '0', '', 'system',   'admin', sysdate(), '', null, '系统管理目录');
 insert into sys_menu values('2', '系统监控', '0', '2', 'monitor',          null, '', '', 1, 0, 'M', '0', '0', '', 'monitor',  'admin', sysdate(), '', null, '系统监控目录');
 insert into sys_menu values('3', '系统工具', '0', '3', 'tool',             null, '', '', 1, 0, 'M', '0', '0', '', 'tool',     'admin', sysdate(), '', null, '系统工具目录');
-insert into sys_menu values('4', '若依官网', '0', '4', 'http://ruoyi.vip', null, '', '', 0, 0, 'M', '0', '0', '', 'guide',    'admin', sysdate(), '', null, '若依官网地址');
+insert into sys_menu values('4', '若依官网', '0', '4', 'http://acupuncture.vip', null, '', '', 0, 0, 'M', '0', '0', '', 'guide',    'admin', sysdate(), '', null, '若依官网地址');
 -- 二级菜单
 insert into sys_menu values('100',  '用户管理', '1',   '1', 'user',       'system/user/index',        '', '', 1, 0, 'C', '0', '0', 'system:user:list',        'user',          'admin', sysdate(), '', null, '用户管理菜单');
 insert into sys_menu values('101',  '角色管理', '1',   '2', 'role',       'system/role/index',        '', '', 1, 0, 'C', '0', '0', 'system:role:list',        'peoples',       'admin', sysdate(), '', null, '角色管理菜单');