From 6708810c4de34dfb9513061432d656f91d56ee3a Mon Sep 17 00:00:00 2001
From: 13693261870 <252740454@qq.com>
Date: 星期三, 02 七月 2025 14:48:15 +0800
Subject: [PATCH] 重新/批量提交代码至git库

---
 ruoyi-ui/.eslintignore                                                                                |   10 
 ruoyi-ui/src/components/ThemePicker/index.vue                                                         |  170 
 ruoyi-ui/src/utils/scroll-to.js                                                                       |   58 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpWharfController.java                      |  101 
 ruoyi-ui/src/assets/icons/svg/druid.svg                                                               |    1 
 ruoyi-ui/bin/build.bat                                                                                |   12 
 ruoyi-ui/src/assets/icons/svg/eye.svg                                                                 |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterAnalyseServiceImpl.java          |   20 
 ruoyi-ui/src/views/monitor/cache/list.vue                                                             |  241 
 ruoyi-ui/package.json                                                                                 |   91 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java                                |  570 
 ruoyi-ui/src/assets/icons/svg/tree.svg                                                                |    1 
 ruoyi-buss/src/main/resources/templates/buss/harbor/edit.html                                         |  162 
 ruoyi-ui/src/assets/icons/svg/bug.svg                                                                 |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/ModbusElectricityUtils.java       |  281 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java       |   73 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java                                      |  484 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValue.java                           |  119 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueFinalMapper.java                  |   18 
 ruoyi-ui/src/views/system/dept/index.vue                                                              |  340 
 ruoyi-generator/pom.xml                                                                               |   40 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpBerthController.java                      |  142 
 ruoyi-ui/build/index.js                                                                               |   35 
 ruoyi-ui/src/assets/icons/svg/monitor.svg                                                             |    2 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java                               |   77 
 ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java                       |  130 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmAnalyseServiceImpl.java            |   21 
 ruoyi-quartz/ruoyi-quartz.iml                                                                         |    8 
 ruoyi-ui/src/utils/jsencrypt.js                                                                       |   30 
 ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml                                     |  117 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java                       |  106 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskTimeController.java                          |  560 
 ruoyi-ui/src/api/monitor/cache.js                                                                     |   57 
 ruoyi-ui/src/components/Editor/index.vue                                                              |  274 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmHarbor2.java                                         |  321 
 ruoyi-ui/src/store/index.js                                                                           |   25 
 ruoyi-ui/src/views/system/menu/index.vue                                                              |  466 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java                         |   18 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmHarbor2Service.java                                |   69 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java                              |   99 
 ruoyi-ui/src/assets/icons/svg/guide.svg                                                               |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java                            |   89 
 sql/ry_20240629.sql                                                                                   |  701 
 ruoyi-ui/src/assets/404_images/404.png                                                                |    0 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpBerthMapper.java                                 |   26 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskQueryParam.java                                |   48 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSelectRuleService.java                     |   16 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java                              |   43 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/enums/DataTypeEnum.java                                   |   76 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidTaskMapper.java                              |   24 
 ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml                                     |   89 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java                                     |   30 
 ruoyi-ui/src/components/Screenfull/index.vue                                                          |   57 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java                      |  145 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DemoController.java                                |   44 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskList2Mapper.java                                 |  140 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidTaskService.java                            |   18 
 ruoyi-ui/src/assets/icons/svg/tree-table.svg                                                          |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicApp.java                                 |   19 
 ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java                       |  180 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java                              |  144 
 ruoyi-ui/src/assets/icons/svg/cascader.svg                                                            |    1 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java                      |   89 
 ruoyi-ui/src/assets/icons/svg/edit.svg                                                                |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java                                |  268 
 ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java              |   68 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipDeviceServiceImpl.java                 |   80 
 ruoyi-ui/src/assets/styles/element-variables.scss                                                     |   31 
 ruoyi-ui/src/utils/dict/DictMeta.js                                                                   |   38 
 ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java                                             |   38 
 ruoyi-ui/public/robots.txt                                                                            |    2 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilAnalyseService.java                     |   16 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmHarbor.java                                      |  456 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueServiceImpl.java            |   20 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilAnalyseMapper.xml                                    |    5 
 ruoyi-ui/src/store/modules/tagsView.js                                                                |  228 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterAnalyseService.java                   |   16 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpWharfServiceImpl.java                      |   35 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskDetailController.java                        |  117 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java                             |   44 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskServiceImpl.java                           |  110 
 ruoyi-generator/src/main/resources/vm/java/service.java.vm                                            |   61 
 ruoyi-ui/src/directive/index.js                                                                       |   23 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueFinalMapper.java                    |   22 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityInfoServiceImpl.java       |   91 
 ruoyi-ui/src/layout/components/Sidebar/Logo.vue                                                       |   93 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java                               |  216 
 ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessHisMapper.xml                                 |  154 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarRuleServiceImpl.java               |   20 
 ruoyi-ui/src/components/DictData/index.js                                                             |   49 
 ruoyi-ui/src/api/system/menu.js                                                                       |   60 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java                          |  130 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java                                     |  106 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueService.java                     |   16 
 ruoyi-ui/src/assets/icons/svg/theme.svg                                                               |    1 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DmHarborMapper.java                                |   66 
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java                             |  408 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java                      |  178 
 ruoyi-ui/src/assets/icons/svg/radio.svg                                                               |    1 
 ruoyi-ui/src/assets/icons/svgo.yml                                                                    |   22 
 ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml                                   |  105 
 ruoyi-generator/src/main/resources/vm/java/domain.java.vm                                             |  105 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmBerth.java                                       |  266 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveModuleInfo.java                             |  176 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java                             |   44 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsMatDispatch2.java                                    |  120 
 ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml                                     |   94 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValueFinal.java                          |  165 
 ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml                                    |  113 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java                         |   73 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterInfoMapper.xml                                     |   26 
 ruoyi-ui/src/components/Hamburger/index.vue                                                           |   44 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlace.java                                      |  317 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidVehicle.java                                 |  268 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveModuleInfoServiceImpl.java            |  296 
 ruoyi-buss/src/main/resources/templates/buss/harbor/harbor.html                                       |  237 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java           |  145 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java                          |  101 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java                           |   83 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilAnalyseMapper.java                       |   18 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java       |   27 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipsServiceImpl.java                      |  193 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java                                |   56 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java                        |   48 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/Crc16Utils.java                           |   70 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java                       |  261 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java                |   96 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessHisMapper.java                           |   69 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DmHarborServiceImpl.java                     |  108 
 ruoyi-ui/src/assets/icons/svg/redis.svg                                                               |    1 
 ruoyi-ui/src/plugins/index.js                                                                         |   20 
 ruoyi-ui/src/assets/styles/btn.scss                                                                   |   99 
 ruoyi-ui/src/api/monitor/server.js                                                                    |    9 
 ruoyi-ui/src/assets/icons/svg/documentation.svg                                                       |    1 
 ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml                                       |  152 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpBerthService.java                               |   19 
 ruoyi-ui/src/assets/icons/svg/code.svg                                                                |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueMapper.java                     |   19 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherAnalyseService.java                 |   17 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessService.java                           |   69 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java                            |   24 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicBeanRegistrar.java                      |   20 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/RfidUtil.java                                          |  149 
 ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java                                |   62 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssess.java                                     |   28 
 ruoyi-ui/src/plugins/modal.js                                                                         |   83 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/HikService.java                                   |   30 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdBerthGroupController.java                        |  802 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskMapper.java                                      |   76 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java                  |  111 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/FloatInverseWaterParser.java            |   61 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueFinalService.java                |   35 
 ruoyi-ui/src/api/tool/gen.js                                                                          |   85 
 ruoyi-ui/src/components/RuoYi/Doc/index.vue                                                           |   21 
 ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java                                              |   27 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityInfoMapper.java                  |   18 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/StringToHexUtil.java                         |   50 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueMapper.xml                                      |   25 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatisTime.java                             |   47 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java                            |   58 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusHexToFloat.java                     |   35 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompilerException.java                   |   74 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java                       |   11 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DsTaskListServiceImpl.java                   |   43 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveCarValueFinalController.java         |   70 
 ruoyi-ui/src/layout/components/Settings/index.vue                                                     |  260 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipDeviceService.java                          |   37 
 ruoyi-ui/.editorconfig                                                                                |   22 
 ruoyi-ui/src/store/getters.js                                                                         |   19 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValue.java                             |  200 
 ruoyi-ui/src/utils/errorCode.js                                                                       |    6 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java                                   |  173 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java                             |  126 
 ruoyi-buss/src/main/ruoyi-buss.iml                                                                    |   11 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java                        |   63 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueFinalMapper.java                |   19 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java                              |  124 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueServiceImpl.java              |   20 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueMapper.java                         |   18 
 ruoyi-ui/src/assets/icons/svg/logininfor.svg                                                          |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java                                     |  382 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/HikController.java                          |  193 
 ruoyi-ui/src/assets/logo/logo.png                                                                     |    0 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java   |   28 
 ruoyi-buss/src/main/resources/templates/buss/detail/add.html                                          |  327 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/FileReadUtils.java                           |   67 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueMapper.xml                                      |    6 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipParkingMapper.java                           |   22 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessMapper.java                              |   61 
 ruoyi-buss/src/main/resources/mapper/buss/DmHarbor2Mapper.xml                                         |  175 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jUtils.java                                  |  154 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java                             |   63 
 ruoyi-buss/src/main/resources/templates/buss/config/add.html                                          |   57 
 ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm                                           |  505 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/IDmHarborService.java                             |   65 
 ruoyi-ui/src/components/SvgIcon/index.vue                                                             |   61 
 ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml                                |  210 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java                          |   15 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java                           |  277 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueFinalService.java              |   37 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherAnalyseMapper.java                   |   19 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityAnalyseServiceImpl.java    |   20 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/ElectricityAnalyseTask.java                          |  146 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java                               |  119 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpWharf.java                                       |   63 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadRtuUtils.java                             |  163 
 ruoyi-ui/src/views/system/user/index.vue                                                              |  553 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmBerth2Service.java                                 |   85 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketOilServer.java                         |  304 
 ruoyi-ui/src/views/system/user/authRole.vue                                                           |  117 
 ruoyi-buss/src/main/resources/templates/buss/harbor/add.html                                          |  161 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/OpenWZ.java                                        |   58 
 ruoyi-ui/src/assets/icons/svg/clipboard.svg                                                           |    1 
 ruoyi-ui/src/views/tool/gen/editTable.vue                                                             |  234 
 ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java                               |   87 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEquipmentTypeServiceImpl.java              |   35 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/HikServiceImpl.java                          |  333 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java                           |   42 
 ruoyi-ui/src/components/IconSelect/requireIcons.js                                                    |   11 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValue.java                               |  307 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/PackageInternalsFinder.java                     |  189 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java                        |   40 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueFinalServiceImpl.java     |   83 
 ruoyi-ui/vue.config.js                                                                                |  131 
 ruoyi-admin/src/main/resources/banner.txt                                                             |   11 
 ruoyi-ui/src/directive/module/clipboard.js                                                            |   54 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadUdpUtils.java                             |  167 
 ruoyi-ui/src/assets/styles/mixin.scss                                                                 |   66 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DemoApp.java                                    |   32 
 ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java                               |   92 
 ruoyi-ui/src/layout/index.vue                                                                         |  111 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java                                          |  114 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityInfoMapper.xml                               |    6 
 ruoyi-ui/src/assets/icons/svg/message.svg                                                             |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherInfoServiceImpl.java           |   82 
 ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java      |   45 
 ruoyi-ui/bin/run-web.bat                                                                              |   12 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java                               |  107 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/Tree.java                                       |   74 
 ruoyi-ui/src/store/modules/settings.js                                                                |   42 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskRecordList.java                                |   63 
 ruoyi-ui/README.md                                                                                    |   30 
 ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js                                                   |   25 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterInfoServiceImpl.java             |  163 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java                   |  122 
 ruoyi-manage/src/main/resources/mapper/DpShipParkingMapper.xml                                        |   31 
 ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessListMapper.xml                                |  149 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityInfo.java                        |  177 
 ruoyi-ui/src/settings.js                                                                              |   44 
 ruoyi-ui/src/views/index_v1.vue                                                                       |   98 
 ruoyi-ui/src/views/monitor/server/index.vue                                                           |  207 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueFinalService.java          |   36 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java                                    |  684 
 ruoyi-ui/src/utils/dict/index.js                                                                      |   33 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueMapper.java                 |   18 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmInfoMapper.xml                                       |   27 
 ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml                                       |  122 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipTypeService.java                            |   17 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java                  |  146 
 ruoyi-buss/src/main/resources/templates/buss/list/list.html                                           |  365 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java                             |   70 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java |   16 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java                  |   87 
 ruoyi-buss/src/main/resources/templates/buss/berth/berth.html                                         |  173 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java                      |  427 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEffectAssessListServiceImpl.java           |   39 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/SysFileManageVO.java                            |   33 
 ruoyi-buss/src/main/resources/templates/buss/warship/warship.html                                     |  189 
 ruoyi-ui/src/utils/generator/js.js                                                                    |  235 
 ruoyi-buss/src/main/java/com/ruoyi/buss/GeneticFleetAssignment.java                                   |  151 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicClassLoader.java                         |   70 
 ruoyi-ui/src/views/monitor/cache/index.vue                                                            |  148 
 ruoyi-ui/src/utils/generator/render.js                                                                |  126 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueFinalMapper.xml                               |   29 
 ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java                       |  263 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java                                   |  218 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/DpEquipmentVO.java                              |  250 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpWharfService.java                               |   17 
 ruoyi-ui/src/views/dashboard/LineChart.vue                                                            |  135 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueFinalMapper.xml                             |   22 
 ruoyi-quartz/pom.xml                                                                                  |   44 
 ruoyi-ui/src/views/system/dict/index.vue                                                              |  347 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java                                |  167 
 ruoyi-ui/src/views/system/user/profile/index.vue                                                      |   91 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueMapper.java                         |   18 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java               |   86 
 ruoyi-generator/src/main/resources/vm/java/controller.java.vm                                         |  115 
 ruoyi-ui/src/api/system/dept.js                                                                       |   52 
 ruoyi-ui/src/assets/icons/svg/time.svg                                                                |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/EquipmentService.java                             |   34 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherAnalyseMapper.xml                                |   20 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdSupplyPlanDTO.java                               |   35 
 ruoyi-buss/src/main/resources/templates/buss/berth/add.html                                           |   89 
 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java            |   56 
 ruoyi-ui/src/assets/icons/svg/number.svg                                                              |    1 
 ruoyi-ui/src/assets/styles/sidebar.scss                                                               |  227 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidVehicleServiceImpl.java                |   72 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValueFinal.java                          |  321 
 ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java                   |   26 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/MyMetaObjectHandler.java                           |   22 
 ruoyi-ui/src/api/system/post.js                                                                       |   44 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/QueryAnalysisVO.java                            |   79 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmHarbor2Controller.java                           |  112 
 ruoyi-ui/src/utils/generator/icon.json                                                                |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java                                 |  357 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java                          |   84 
 ruoyi-ui/src/assets/icons/svg/excel.svg                                                               |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java                                 |  113 
 ruoyi-ui/src/assets/401_images/401.gif                                                                |    0 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessServiceImpl.java                   |  118 
 ruoyi-ui/src/components/PanThumb/index.vue                                                            |  142 
 ruoyi-ui/src/utils/index.js                                                                           |  390 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEffectAssessListController.java           |   89 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessListServiceImpl.java               |   97 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java                      |  338 
 ruoyi-ui/src/assets/icons/svg/link.svg                                                                |    1 
 ruoyi-buss/src/main/resources/mapper/buss/DsTaskDetailMapper.xml                                      |  304 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java                               |  102 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java                                    |  272 
 ruoyi-ui/src/assets/icons/svg/people.svg                                                              |    1 
 ruoyi-ui/src/api/login.js                                                                             |   60 
 ruoyi-ui/src/assets/icons/svg/log.svg                                                                 |    1 
 ruoyi-buss/src/main/resources/templates/buss/config/edit.html                                         |   58 
 ruoyi-ui/src/assets/icons/svg/nested.svg                                                              |    1 
 ruoyi-ui/src/assets/icons/svg/switch.svg                                                              |    1 
 ruoyi-buss/src/main/resources/templates/buss/assess/add.html                                          |   65 
 ruoyi-ui/src/views/tool/gen/basicInfoForm.vue                                                         |   60 
 ruoyi-ui/src/views/monitor/druid/index.vue                                                            |   15 
 ruoyi-framework/pom.xml                                                                               |   64 
 ruoyi-ui/src/assets/icons/svg/chart.svg                                                               |    1 
 ruoyi-buss/ruoyi-buss.iml                                                                             |    8 
 ruoyi-buss/src/main/resources/mapper/buss/DmDdConfigMapper.xml                                        |   73 
 ruoyi-ui/src/views/login.vue                                                                          |  219 
 ruoyi-ui/src/views/redirect.vue                                                                       |   12 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsMatDispatch2Service.java                           |   64 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java                              |   19 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarRuleMapper.java                          |   18 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmHarbor2ServiceImpl.java                        |  103 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpUnitSupplyTimeServiceImpl.java             |   35 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java  |   16 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilInfoMapper.xml                                       |   25 
 ruoyi-ui/src/views/error/404.vue                                                                      |  233 
 ruoyi-ui/src/main.js                                                                                  |   86 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java                       |   72 
 ruoyi-ui/src/assets/404_images/404_cloud.png                                                          |    0 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/EquipmentServiceImpl.java                    |   81 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java                           |  324 
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java                                  |  257 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipDeviceMapper.java                            |   39 
 ruoyi-ui/src/router/index.js                                                                          |  183 
 ruoyi-ui/src/assets/styles/transition.scss                                                            |   49 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmInfoService.java                        |   23 
 ruoyi-ui/public/index.html                                                                            |  208 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarRule.java                                |  138 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidTaskController.java                   |   78 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanList.java                                   |   10 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java                                       |   63 
 ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml                                   |   44 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java                                 |   99 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java                               |   81 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmWarshipMapper.java                                   |   61 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueServiceImpl.java      |   20 
 ruoyi-ui/src/assets/icons/svg/table.svg                                                               |    1 
 .gitignore                                                                                            |   25 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueMapper.xml                                  |   20 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java              |   89 
 ruoyi-system/ruoyi-system.iml                                                                         |    8 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java                           |   62 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java                              |   52 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java                                  |  178 
 ruoyi-ui/src/assets/icons/svg/redis-list.svg                                                          |    2 
 ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml                                       |  159 
 ruoyi-ui/src/components/Crontab/week.vue                                                              |  202 
 ruoyi-ui/src/assets/icons/svg/tool.svg                                                                |    1 
 ruoyi-ui/src/components/ImagePreview/index.vue                                                        |   90 
 ruoyi-ui/src/views/dashboard/PanelGroup.vue                                                           |  181 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java                      |  259 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueMapper.java                         |   19 
 ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java                               |   56 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java                          |   34 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmDdConfigService.java                               |   61 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueService.java                   |   23 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java                             |  158 
 ruoyi-ui/src/plugins/auth.js                                                                          |   60 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessHis.java                                 |  258 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java                                     |   36 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidTaskServiceImpl.java                   |   36 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserLittleUtil.java          |   69 
 ruoyi-buss/src/main/resources/mapper/buss/DsTaskMapper.xml                                            |  117 
 ruoyi-fuzhou/src/main/resources/mapper/EquipmentMapper.xml                                            |  128 
 ruoyi-ui/src/assets/styles/variables.scss                                                             |   54 
 ruoyi-ui/src/components/ParentView/index.vue                                                          |    3 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidVehicleController.java                |  113 
 ruoyi-ui/src/assets/icons/svg/skill.svg                                                               |    1 
 ruoyi-ui/src/components/FileUpload/index.vue                                                          |  221 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/DsTaskDetailVO.java                                 |  492 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java                              |  254 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/TreeVO.java                                     |   45 
 ruoyi-fuzhou/pom.xml                                                                                  |   92 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueMapper.xml                              |    6 
 ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm                                        |  169 
 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java                           |   55 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipType.java                                    |   83 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java                                        |  115 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmInfo.java                                |  180 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java   |   34 
 ruoyi-ui/src/assets/icons/svg/dashboard.svg                                                           |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java                                  |   39 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java                  |  223 
 ruoyi-ui/src/assets/icons/svg/size.svg                                                                |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/ReceiveValueListVo.java                         |   86 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveSlmValueFinalController.java         |   73 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipDevice.java                                  |  104 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java                                 |  107 
 ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java            |   67 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueServiceImpl.java              |   20 
 ruoyi-ui/src/directive/permission/hasRole.js                                                          |   28 
 ruoyi-manage/src/main/resources/mapper/DpBerthMapper.xml                                              |   55 
 ruoyi-ui/src/views/system/role/authUser.vue                                                           |  199 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEffectAssessListMapper.java                      |   24 
 ruoyi-generator/src/main/resources/vm/vue/index.vue.vm                                                |  602 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipsMapper.java                                 |   32 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmAnalyseMapper.java                       |   18 
 ruoyi-ui/src/utils/permission.js                                                                      |   47 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSelectRuleMapper.java                       |   18 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java                            |   56 
 ruoyi-ui/src/assets/images/profile.jpg                                                                |    0 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java                           |  410 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java                      |  114 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java                            |   60 
 ruoyi-ui/src/utils/auth.js                                                                            |   15 
 ruoyi-ui/src/components/Pagination/index.vue                                                          |  114 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityAnalyse.java                     |  285 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java                                 |  291 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java                |   65 
 ruoyi-ui/src/assets/images/pay.png                                                                    |    0 
 ruoyi-ui/src/assets/icons/svg/zip.svg                                                                 |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterAnalyseMapper.java                     |   18 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValueFinal.java                        |  213 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherAnalyse.java                         |  119 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java                     |   31 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthReqDTO.java                              |   53 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmDdConfig.java                                        |   99 
 ruoyi-ui/src/utils/validate.js                                                                        |  114 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmWarshipServiceImpl.java                        |   97 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/SysFileMapper.java                                 |   18 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java                               |   60 
 ruoyi-ui/src/views/system/role/selectUser.vue                                                         |  136 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java                                |   55 
 ruoyi-system/pom.xml                                                                                  |   24 
 ruoyi-ui/src/api/monitor/operlog.js                                                                   |   26 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueMapper.xml                                      |   32 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmAnalyseService.java                     |   16 
 ruoyi-fuzhou/src/main/resources/mapper/HikEventMapper.xml                                             |   36 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpUnitSupplyTimeService.java                      |   19 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java                                          |  514 
 ruoyi-admin/src/test/java/com/ruoyi/web/MybatisPlusGeneraotr.java                                     |   72 
 ruoyi-ui/src/assets/icons/svg/textarea.svg                                                            |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsMatDispatch2ServiceImpl.java                   |   65 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidVehicleMapper.java                           |   27 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentTypeController.java              |   73 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipTypeMapper.java                              |   26 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmHarbor2Mapper.java                                   |   70 
 ruoyi-ui/src/api/monitor/jobLog.js                                                                    |   26 
 ruoyi-ui/src/layout/components/Sidebar/Item.vue                                                       |   33 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWaterValueFinalController.java       |   69 
 ruoyi-ui/src/utils/dict/DictData.js                                                                   |   13 
 ruoyi-ui/src/api/monitor/logininfor.js                                                                |   34 
 ruoyi-ui/src/assets/icons/svg/time-range.svg                                                          |    1 
 ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml                                   |  124 
 ruoyi-ui/src/directive/permission/hasPermi.js                                                         |   28 
 ruoyi-ui/src/layout/components/InnerLink/index.vue                                                    |   47 
 ruoyi-buss/src/main/resources/templates/buss/detail/edit.html                                         |  328 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java                                      |  239 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java   |   44 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmInfoMapper.java                          |   19 
 ruoyi-ui/public/html/ie.html                                                                          |   46 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpUnitSupplyTime.java                              |   57 
 ruoyi-ui/src/assets/icons/svg/swagger.svg                                                             |    1 
 ruoyi-ui/src/components/Crontab/result.vue                                                            |  559 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValueFinal.java                          |  308 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveModuleInfoMapper.xml                                    |    5 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipParkingController.java                |   74 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilAnalyse.java                             |  309 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicJavaFileManager.java                     |  124 
 ruoyi-ui/src/utils/generator/config.js                                                                |  438 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityAnalyseMapper.xml                            |    5 
 ruoyi-ui/src/views/system/notice/index.vue                                                            |  312 
 ruoyi-ui/.eslintrc.js                                                                                 |  199 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java                               |   64 
 ruoyi-ui/src/views/monitor/job/index.vue                                                              |  513 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java                                      |   81 
 ruoyi-ui/src/components/RightToolbar/index.vue                                                        |  129 
 ruoyi-ui/src/views/system/config/index.vue                                                            |  343 
 ruoyi-ui/src/assets/icons/svg/peoples.svg                                                             |    1 
 ruoyi-ui/src/assets/images/light.svg                                                                  |   39 
 ruoyi-admin/src/main/resources/i18n/messages.properties                                               |   38 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java                   |  143 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWeatherValueFinalController.java     |   71 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityAnalyseService.java             |   16 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java                                  |   67 
 ruoyi-ui/src/api/monitor/online.js                                                                    |   18 
 ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java                          |   91 
 ruoyi-ui/src/assets/icons/svg/search.svg                                                              |    1 
 ruoyi-ui/src/assets/icons/svg/language.svg                                                            |    1 
 ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml                                   |   34 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java                                      |   20 
 ruoyi-ui/src/assets/icons/svg/upload.svg                                                              |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmAnalyse.java                             |  153 
 ruoyi-ui/src/directive/dialog/dragWidth.js                                                            |   30 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java                      |   29 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskController.java                              |  130 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskList2Controller.java                         |  141 
 ruoyi-ui/src/assets/icons/svg/list.svg                                                                |    1 
 ruoyi-ui/src/api/system/role.js                                                                       |  119 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java                          |  157 
 ruoyi-ui/src/views/system/user/profile/resetPwd.vue                                                   |   69 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueFinalMapper.java                    |   18 
 ruoyi-ui/src/App.vue                                                                                  |   28 
 ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java                                     |   39 
 sql/dameng/ry_20240629.sql                                                                            | 1201 
 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java                   |  102 
 ruoyi-manage/src/main/resources/mapper/SysFileMapper.xml                                              |   22 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java                              |   26 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java                      |   76 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShips.java                                       |  131 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/SysFileServiceImpl.java                      |  118 
 ruoyi-ui/src/layout/components/index.js                                                               |    5 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java                      |   16 
 ruoyi-ui/src/assets/icons/svg/international.svg                                                       |    1 
 ruoyi-manage/src/main/resources/mapper/DpShipDeviceMapper.xml                                         |   97 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java                             |   76 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmInfoServiceImpl.java               |   82 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java         |   16 
 ruoyi-ui/src/assets/styles/index.scss                                                                 |  182 
 ruoyi-ui/src/views/register.vue                                                                       |  210 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueFinalServiceImpl.java         |   81 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssessHis.java                                  |   29 
 ruoyi-ui/src/api/system/dict/type.js                                                                  |   60 
 ruoyi-ui/src/assets/icons/svg/system.svg                                                              |    2 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilInfoMapper.java                          |   18 
 ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue                                                |   94 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java                                     |   75 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilInfo.java                                |  184 
 ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm                                             |  590 
 ruoyi-ui/src/assets/icons/svg/pdf.svg                                                                 |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicCompiler.java                           |   41 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueFinalServiceImpl.java         |   85 
 ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm                                         |   76 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpWharfMapper.java                                 |   18 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java                                   |   64 
 ruoyi-admin/src/main/resources/application-prod.yml                                                   |   64 
 ruoyi-ui/.env.development                                                                             |   11 
 ruoyi-buss/src/main/resources/mapper/buss/DsTaskList2Mapper.xml                                       |  352 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterInfo.java                              |  181 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RS485TCPServer.java                                 |   44 
 ruoyi-ui/src/assets/icons/svg/job.svg                                                                 |    1 
 ruoyi-ui/src/assets/icons/svg/github.svg                                                              |    1 
 ruoyi-ui/src/store/modules/user.js                                                                    |  106 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java                       |  163 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsMatDispatchMapper2.java                              |   68 
 ruoyi-ui/src/assets/icons/svg/date.svg                                                                |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskListStatis.java                                 |   40 
 pom.xml                                                                                               |  307 
 ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java                              |   85 
 ruoyi-ui/src/api/system/user.js                                                                       |  136 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmBerth2.java                                          |  179 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/MemoryByteCode.java                             |   55 
 ruoyi-ui/src/views/tool/build/RightPanel.vue                                                          |  946 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java                          |   61 
 ruoyi-ui/src/assets/icons/svg/validCode.svg                                                           |    1 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEffectAssessList.java                            |   89 
 ruoyi-ui/src/assets/icons/svg/lock.svg                                                                |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadTcpUtils.java                             |  176 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java                               |   49 
 ruoyi-ui/src/api/menu.js                                                                              |    9 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java                                      |  191 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarRuleMapper.xml                                       |    6 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipsService.java                               |   35 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java                                    |   18 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpBerthServiceImpl.java                      |   36 
 ruoyi-ui/src/assets/icons/svg/user.svg                                                                |    1 
 sql/quartz.sql                                                                                        |  174 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java                                 |  144 
 ruoyi-ui/src/views/tool/gen/createTable.vue                                                           |   45 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueMapper.xml                                    |    5 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java                                |   28 
 ruoyi-ui/src/components/Crontab/index.vue                                                             |  430 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessHisServiceImpl.java                |  120 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java                      |   89 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ShipGroupDTO.java                                  |   33 
 ruoyi-ui/src/views/tool/gen/genInfoForm.vue                                                           |  312 
 ruoyi-generator/src/main/resources/vm/sql/sql.vm                                                      |   22 
 ruoyi-ui/src/assets/icons/svg/checkbox.svg                                                            |    1 
 ruoyi-ui/src/assets/icons/svg/form.svg                                                                |    1 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java                       |  125 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmWarship.java                                         |  193 
 ruoyi-fuzhou/src/main/resources/mapper/DpRfidVehicleMapper.xml                                        |   44 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/ModbusWaterUtils.java                   |  296 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java                    |   87 
 ruoyi-buss/pom.xml                                                                                    |   61 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessListService.java                       |   61 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueFinalService.java                  |   36 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java                     |  112 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DsTaskListMapper.java                              |   27 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java             |   80 
 ruoyi-ui/src/views/system/user/profile/userInfo.vue                                                   |   88 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpEquipment.java                                   |  306 
 ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java                       |   34 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterAnalyseMapper.xml                                  |    6 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/RfIdVo.java                                         |   43 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/HikConfig.java                                     |   28 
 ruoyi-ui/src/layout/components/Sidebar/index.vue                                                      |   57 
 ruoyi-buss/src/main/resources/templates/buss/detail/detail.html                                       |  305 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueService.java                       |   16 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java                                        |  171 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java                                   |  141 
 ruoyi-ui/src/assets/icons/svg/drag.svg                                                                |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java                                 |   20 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java                                   |   46 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java                         |   19 
 ruoyi-ui/bin/package.bat                                                                              |   12 
 ruoyi-ui/src/layout/components/Navbar.vue                                                             |  200 
 ruoyi-admin/src/main/java/com/ruoyi/web/webSocket/WebSocketEquServer.java                             |  345 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/RfidVehicleVO.java                              |   33 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompiler.java                            |  224 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java                   |   61 
 ruoyi-buss/src/main/resources/templates/buss/task/edit.html                                           |   58 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java                                   |   46 
 ruoyi-ui/src/components/RightPanel/index.vue                                                          |  106 
 ruoyi-ui/src/utils/generator/html.js                                                                  |  359 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidTask.java                                    |  232 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataSender.java                              |   18 
 ruoyi-ui/src/views/monitor/online/index.vue                                                           |  122 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java                                |  117 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java                                       |   18 
 ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java                        |  184 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/MatReqVO.java                                       |   11 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueFinalService.java                  |   38 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java                              |   31 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserUtil.java                |   55 
 ruoyi-buss/src/main/resources/templates/buss/warship/add.html                                         |  105 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java                                |   57 
 ruoyi-ui/src/store/modules/permission.js                                                              |  137 
 ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java        |  110 
 ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue                                                      |  106 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java                                   |   46 
 ruoyi-ui/src/components/ImageUpload/index.vue                                                         |  231 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmWarshipController.java                           |  117 
 ruoyi-manage/src/main/resources/mapper/DsTaskListMapper.xml                                           |   91 
 ruoyi-manage/src/main/resources/mapper/DpShipTypeMapper.xml                                           |   29 
 ruoyi-ui/.gitignore                                                                                   |   23 
 ruoyi-ui/src/assets/icons/svg/input.svg                                                               |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTask.java                                            |  114 
 ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java       |   53 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipParkingService.java                         |   23 
 ruoyi-ui/src/store/modules/dict.js                                                                    |   50 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java               |   99 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java                                        |   99 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java                                   |  148 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueService.java               |   16 
 ruoyi-ui/src/assets/icons/svg/eye-open.svg                                                            |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/AnalyseUtils.java                                   |   74 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessHisService.java                        |   78 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmBerth2Controller.java                            |  113 
 ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml                          |  127 
 ruoyi-manage/pom.xml                                                                                  |   59 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipTypeServiceImpl.java                   |   35 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssess.java                                    |  118 
 ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm                                               |  140 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java                                 |  127 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java                           |  241 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmDdConfigController.java                          |  117 
 ruoyi-ui/src/assets/icons/index.js                                                                    |    9 
 ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml                                 |   57 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusWeatherServerUtils.java                       |  506 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/SysFileService.java                               |   43 
 ruoyi-buss/src/main/resources/templates/buss/warship/edit.html                                        |  106 
 ruoyi-buss/src/main/resources/mapper/buss/DmWarshipMapper.xml                                         |  125 
 ruoyi-ui/src/utils/dict/DictConverter.js                                                              |   17 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilInfoService.java                        |   27 
 ruoyi-buss/src/main/resources/templates/buss/list/edit.html                                           |  294 
 ruoyi-ui/src/assets/images/dark.svg                                                                   |   39 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueFinalMapper.java                    |   19 
 ruoyi-ui/src/views/tool/build/index.vue                                                               |  768 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java                       |  231 
 ruoyi-buss/src/main/resources/templates/buss/assess/assess.html                                       |  137 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskList2Service.java                              |  151 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/ShipTypeVO.java                                 |   33 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/WebSocketConfig.java                               |   23 
 ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml                                       |  221 
 ruoyi-ui/src/components/RuoYi/Git/index.vue                                                           |   21 
 ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java                                 |   86 
 ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfiguration.java                         |   33 
 ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue                                                      |  149 
 ruoyi-ui/src/assets/icons/svg/phone.svg                                                               |    1 
 ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java                          |  373 
 ruoyi-ui/src/views/tool/swagger/index.vue                                                             |   15 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java                           |   74 
 ruoyi-ui/src/assets/icons/svg/qq.svg                                                                  |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSelectRuleServiceImpl.java            |   20 
 ruoyi-ui/src/views/system/user/profile/userAvatar.vue                                                 |  184 
 ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java                        |   39 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherInfoMapper.xml                                   |   27 
 sql/dameng/dameng.sql                                                                                 |   11 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java                             |   95 
 ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml                                   |   34 
 ruoyi-ui/src/utils/request.js                                                                         |  152 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/waterdept/ModbusWaterDeptUtils.java                 |  128 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java                               |   79 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java                      |  132 
 ruoyi-common/ruoyi-common.iml                                                                         |    8 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java                                |   98 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SysFileController.java                      |  152 
 ruoyi-fuzhou/ruoyi-fuzhou.iml                                                                         |    8 
 ruoyi-ui/src/assets/icons/svg/row.svg                                                                 |    1 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java                                   |  182 
 ruoyi-ui/src/layout/components/IframeToggle/index.vue                                                 |   33 
 ruoyi-manage/src/main/resources/mapper/DmHarborMapper.xml                                             |  187 
 ruoyi-buss/src/main/resources/templates/buss/list/add.html                                            |  293 
 ruoyi-ui/src/store/modules/app.js                                                                     |   66 
 ruoyi-ui/src/views/dashboard/RaddarChart.vue                                                          |  116 
 ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java                                |  385 
 ruoyi-ui/src/assets/icons/svg/online.svg                                                              |    1 
 ruoyi-ui/src/views/tool/build/IconsDialog.vue                                                         |  123 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityInfoService.java                |   21 
 ruoyi-manage/src/main/resources/mapper/DpUnitSupplyTimeMapper.xml                                     |   28 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java                                  |   67 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueFinalMapper.xml                                 |   26 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java                                    |   70 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java                       |   39 
 ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java                                 |  101 
 ruoyi-ui/src/assets/icons/svg/component.svg                                                           |    1 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpUnitSupplyTimeMapper.java                        |   24 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdSupplyPlanController.java                        |  621 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java                    |  210 
 ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue                                                |   99 
 ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm                                        |  474 
 ruoyi-ui/src/views/tool/gen/importTable.vue                                                           |  120 
 ruoyi-generator/src/main/resources/generator.yml                                                      |   12 
 ruoyi-ui/src/assets/icons/svg/server.svg                                                              |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortWrapperImpl.java                      |  189 
 ruoyi-generator/src/main/resources/vm/js/api.js.vm                                                    |   44 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEvent.java                                      |  200 
 ruoyi-buss/src/main/resources/mapper/buss/DsMatDispatchMapper.xml                                     |  136 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/MemoryJavaFileManager.java                     |   53 
 ruoyi-ui/src/plugins/download.js                                                                      |   79 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataReceiver.java                            |   38 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java                           |   50 
 ruoyi-ui/src/views/monitor/job/log.vue                                                                |  295 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java                              |   44 
 ruoyi-ui/src/views/dashboard/PieChart.vue                                                             |   79 
 ruoyi-ui/src/views/error/401.vue                                                                      |   88 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentController.java                  | 1003 
 ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java                                    | 1010 
 ruoyi-ui/src/components/TopNav/index.vue                                                              |  193 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/NumberUtils.java                                       |   29 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java                    |  181 
 ruoyi-ui/src/layout/components/Sidebar/Link.vue                                                       |   43 
 ruoyi-ui/src/assets/icons/svg/star.svg                                                                |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java                      |  543 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmBerthService2Impl.java                         |  119 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueService.java                       |   16 
 ruoyi-ui/src/views/system/dict/data.vue                                                               |  402 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/SysFileManage.java                                 |   57 
 ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEquipmentTypeMapper.java                         |   24 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatis.java                                 |   49 
 ruoyi-ui/public/favicon.ico                                                                           |    0 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveInfo.java                                   |   82 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java                       |   28 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java                      |  265 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java                      |   68 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueFinalServiceImpl.java         |   82 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java                               |   59 
 ruoyi-ui/src/assets/styles/element-ui.scss                                                            |   92 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValue.java                       |  283 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveModuleInfoService.java                     |   28 
 ruoyi-ui/src/views/dashboard/mixins/resize.js                                                         |   56 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DsTaskList.java                                    |  605 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuSlaveUtils.java                                  |   86 
 ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java                                      |   18 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java                                 |  110 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipTypeController.java                   |   72 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java                           |  203 
 ruoyi-ui/src/assets/icons/svg/build.svg                                                               |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java                                 |   33 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java                  |  111 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/ClassUriWrapper.java                            |   25 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueFinalMapper.xml                                 |   39 
 ruoyi-ui/src/assets/icons/svg/icon.svg                                                                |    1 
 ruoyi-ui/src/layout/components/TagsView/index.vue                                                     |  328 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/Subdata.java                                       |  212 
 ruoyi-ui/src/assets/icons/svg/example.svg                                                             |    1 
 ruoyi-ui/src/views/system/post/index.vue                                                              |  309 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java                                 |   19 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessList.java                                |  254 
 ruoyi-ui/src/components/IconSelect/index.vue                                                          |  104 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java                        |   24 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/HexStringToInt.java               |   70 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueFinalServiceImpl.java       |   80 
 ruoyi-ui/src/assets/icons/svg/slider.svg                                                              |    1 
 sql/dameng/quartz.sql                                                                                 |  328 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueFinalMapper.xml                                 |   37 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java                    |   16 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/ProtocolDataEncoder.java                     |   30 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskList2ServiceImpl.java                      |  180 
 ruoyi-admin/src/main/resources/application-dev.yml                                                    |   63 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValue.java                               |  165 
 ruoyi-ui/src/assets/icons/svg/email.svg                                                               |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarRuleService.java                        |   16 
 ruoyi-manage/src/main/resources/mapper/DpEquipmentTypeMapper.xml                                      |   32 
 ruoyi-ui/src/views/system/role/index.vue                                                              |  605 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterInfoMapper.java                        |   18 
 ruoyi-ui/src/components/Crontab/hour.vue                                                              |  120 
 ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java                    |  531 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java                  |  124 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdGroupDTO.java                                    |   45 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java                                       |   86 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java                                  | 1900 +
 ruoyi-manage/src/main/resources/mapper/DpWharfMapper.xml                                              |   22 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherAnalyseServiceImpl.java        |   21 
 ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java                                  |   94 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterAnalyse.java                           |  201 
 ruoyi-ui/src/permission.js                                                                            |   63 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueFinalServiceImpl.java |   80 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipDeviceController.java                 |   93 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueServiceImpl.java              |   21 
 ruoyi-ui/src/components/DictTag/index.vue                                                             |   89 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSelectRule.java                             |   83 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVO.java                               |   60 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValueFinal.java                  |  297 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherInfoService.java                    |   23 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java            |   52 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmDdConfigMapper.java                                  |   61 
 ruoyi-ui/src/api/system/config.js                                                                     |   60 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java                              |  173 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java                      |  550 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValueFinal.java                      |  119 
 ruoyi-ui/src/utils/dict/DictOptions.js                                                                |   51 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java                      |  135 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuMasterUtils.java                                 |  116 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityAnalyseMapper.java               |   18 
 ruoyi-ui/src/views/tool/build/DraggableItem.vue                                                       |  100 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/MyProcessImageListener.java                     |   20 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortUtils.java                            |   61 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsMatDispatch2Controller.java                      |  228 
 ruoyi-buss/src/main/resources/templates/buss/task/add.html                                            |   57 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskDetail.java                                      |  553 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEquipmentTypeService.java                       |   17 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherInfoMapper.java                      |   19 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilAnalyseServiceImpl.java            |   20 
 ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java                                   |  145 
 ruoyi-admin/ruoyi-admin.iml                                                                           |    8 
 ruoyi-ui/.env.production                                                                              |    8 
 ruoyi-ui/.env.staging                                                                                 |   12 
 ruoyi-ui/src/assets/icons/svg/select.svg                                                              |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java        |   16 
 ruoyi-ui/src/utils/dict/Dict.js                                                                       |   82 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocationReqDTO.java                              |   42 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEventObj.java                                   |   40 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueServiceImpl.java          |   21 
 ruoyi-ui/src/assets/icons/svg/education.svg                                                           |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskAQController.java                            |  285 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthTimeReqDTO.java                          |   42 
 ruoyi-ui/src/components/iFrame/index.vue                                                              |   36 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java                            |   58 
 ruoyi-ui/src/directive/dialog/drag.js                                                                 |   64 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java                 |  115 
 ruoyi-ui/src/assets/images/login-background.jpg                                                       |    0 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java             |   66 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java                          |  143 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/CustomJavaFileObject.java                       |   84 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DmHarborController.java                     |  288 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueFinalMapper.java            |   18 
 ruoyi-ui/src/assets/icons/svg/date-range.svg                                                          |    1 
 ruoyi-ui/src/layout/mixin/ResizeHandler.js                                                            |   45 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/DateUtils.java                                         |  115 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/DsTaskQueryParam.java                              |   75 
 ruoyi-ui/src/components/SizeSelect/index.vue                                                          |   56 
 ruoyi-ui/src/layout/components/AppMain.vue                                                            |   91 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java                       |  176 
 ruoyi-ui/src/directive/dialog/dragHeight.js                                                           |   34 
 ruoyi-generator/ruoyi-generator.iml                                                                   |    8 
 ruoyi-buss/src/main/resources/templates/buss/config/config.html                                       |  113 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java                              |  206 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveModuleInfoMapper.java                       |   18 
 ts.txt                                                                                                |   29 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/AssessUtil.java                                        |  251 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValue.java                               |  295 
 ruoyi-ui/src/plugins/cache.js                                                                         |   79 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java                                     |  155 
 ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml                                             |   20 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdEffectEstimateController.java                    |  893 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java                             |   44 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipsController.java                      |  102 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEquipmentType.java                               |   58 
 ruoyi-ui/src/assets/icons/svg/money.svg                                                               |    1 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java                  |  159 
 ruoyi-ui/src/api/monitor/job.js                                                                       |   71 
 ruoyi-ui/src/components/Breadcrumb/index.vue                                                          |  103 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java                                   |   26 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/EquipmentMapper.java                               |   35 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java                                   |   49 
 ruoyi-ui/public/styles/theme-chalk/index.css                                                          |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueService.java                       |   17 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java                    |   94 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java                                 |  118 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java                       |   96 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketServer.java                            |  132 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskDetailServiceImpl.java                     |  132 
 ruoyi-ui/src/assets/icons/svg/tab.svg                                                                 |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskDetailMapper.java                                |   94 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java                                     |  111 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoController.java                  |  182 
 ruoyi-manage/src/main/resources/mapper/DpShipsMapper.xml                                              |   60 
 ruoyi-ui/src/assets/icons/svg/password.svg                                                            |    1 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java                                   |   24 
 ruoyi-ui/src/assets/icons/svg/wechat.svg                                                              |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java                                     |  102 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskService.java                                   |   76 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusYdkfmjUtils.java                              |  157 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueFinalMapper.xml                         |   36 
 ruoyi-manage/src/main/resources/mapper/DpEffectAssessListMapper.xml                                   |   43 
 ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java               |   21 
 ruoyi-ui/src/assets/icons/svg/shopping.svg                                                            |    1 
 ruoyi-ui/src/utils/ruoyi.js                                                                           |  233 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/HikEventMapper.java                                |   24 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessListController.java                  |  116 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java                                    |  291 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java                 |   86 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmDdConfigServiceImpl.java                       |   94 
 ruoyi-admin/src/main/resources/application.yml                                                        |  147 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/StringSource.java                               |   23 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveElectricityValueFinalController.java |   69 
 ruoyi-ui/src/assets/icons/svg/dict.svg                                                                |    1 
 ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java                    |   92 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveOilValueFinalController.java         |   71 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java                           |  274 
 ruoyi-ui/src/views/tool/gen/index.vue                                                                 |  354 
 ruoyi-ui/src/views/dashboard/BarChart.vue                                                             |  102 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java                              |  240 
 ruoyi-ui/src/api/system/notice.js                                                                     |   44 
 ruoyi-ui/src/views/index.vue                                                                          | 1107 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DsTaskListController.java                   |  178 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java                |   16 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java                               |   40 
 ruoyi-ui/src/assets/icons/svg/404.svg                                                                 |    1 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusSlmServerUtils.java                           |  550 
 ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml                                        |  111 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoFinalController.java             |  284 
 ruoyi-ui/src/plugins/tab.js                                                                           |   71 
 ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg                                                     |    1 
 ruoyi-framework/ruoyi-framework.iml                                                                   |    8 
 ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java                                      |   32 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusOilServerUtils.java                 |  423 
 ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java                                 |   19 
 ruoyi-fuzhou/src/main/resources/mapper/DpRfidTaskMapper.xml                                           |   14 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java                               |   93 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveSelectRuleMapper.xml                                    |    6 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java                             |   62 
 ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml                                   |   34 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java                         |   97 
 ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties                                    |    1 
 ruoyi-ui/src/assets/icons/svg/color.svg                                                               |    1 
 ruoyi-ui/src/assets/styles/ruoyi.scss                                                                 |  296 
 ruoyi-ui/src/views/monitor/operlog/index.vue                                                          |  323 
 ruoyi-generator/src/main/resources/vm/java/mapper.java.vm                                             |   91 
 ruoyi-ui/src/components/Crontab/day.vue                                                               |  161 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java                                 |   24 
 ruoyi-ui/src/utils/generator/css.js                                                                   |   18 
 ruoyi-ui/src/utils/generator/drawingDefault.js                                                        |   29 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java                                   |   46 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskDetailService.java                             |  102 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java                          |  266 
 ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java                          |   69 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEffectAssessListService.java                    |   18 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterInfoService.java                      |   25 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessListMapper.java                          |   61 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/CameraPTZ.java                                     |   62 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilInfoServiceImpl.java               |  130 
 ruoyi-ui/src/assets/icons/svg/button.svg                                                              |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmBerth2Mapper.java                                    |   87 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherInfo.java                            |  182 
 ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessMapper.xml                                    |  104 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java                             |   83 
 ruoyi-ui/src/assets/icons/svg/fullscreen.svg                                                          |    1 
 ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java                            |   32 
 ruoyi-ui/src/assets/icons/svg/post.svg                                                                |    1 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMAssessController.java                            |  562 
 ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskList2.java                                       |  631 
 ruoyi-ui/src/components/Crontab/month.vue                                                             |  114 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/Main.java                                    |   22 
 ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java                |   16 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jWriteUtils.java                             |  173 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java                    |  136 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/DsTaskListService.java                            |   20 
 ruoyi-ui/src/assets/icons/svg/rate.svg                                                                |    1 
 ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipParkingServiceImpl.java                |   57 
 ruoyi-ui/src/components/Crontab/min.vue                                                               |  116 
 ruoyi-admin/src/main/resources/logback.xml                                                            |   93 
 ruoyi-ui/src/components/Crontab/year.vue                                                              |  131 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java                          |   60 
 ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml                                       |  206 
 ruoyi-ui/src/api/system/dict/data.js                                                                  |   52 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java                                 |  126 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessController.java                      |  116 
 ruoyi-buss/src/main/resources/mapper/buss/DmBerth2Mapper.xml                                          |  145 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueMapper.java                       |   18 
 ruoyi-buss/src/main/java/com/ruoyi/buss/common/Normalization.java                                     |   49 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java                                     |  197 
 ruoyi-buss/src/main/resources/templates/buss/assess/edit.html                                         |   66 
 ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java                                       |   51 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipParking.java                                 |   72 
 ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java                          |   98 
 ruoyi-buss/src/main/resources/templates/buss/task/task.html                                           |  141 
 ruoyi-ui/babel.config.js                                                                              |   13 
 ruoyi-ui/src/views/monitor/logininfor/index.vue                                                       |  246 
 ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmWarshipService.java                                |   61 
 ruoyi-ui/src/assets/icons/svg/download.svg                                                            |    1 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpUnitSupplyTimeController.java             |   95 
 ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmAnalyseMapper.xml                                    |   25 
 ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java                    |   60 
 ruoyi-ui/src/assets/icons/svg/question.svg                                                            |    1 
 ruoyi-admin/pom.xml                                                                                   |  140 
 ruoyi-buss/src/main/resources/templates/buss/berth/edit.html                                          |   90 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueFinalService.java                  |   37 
 ruoyi-ui/src/components/HeaderSearch/index.vue                                                        |  196 
 ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidVehicleService.java                         |   26 
 ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java                 |   44 
 ruoyi-ui/src/components/Crontab/second.vue                                                            |  117 
 ruoyi-common/pom.xml                                                                                  |  135 
 ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskController.java                              |  624 
 ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java                  |   40 
 ruoyi-manage/ruoyi-manage.iml                                                                         |    8 
 ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java               |   88 
 ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java                      |   24 
 ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java                              |   59 
 ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpBerth.java                                       |   70 
 ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java                                       |  124 
 1,039 files changed, 113,744 insertions(+), 10 deletions(-)

diff --git a/.gitignore b/.gitignore
index 32858aa..377881c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,12 +1,17 @@
-*.class
+.idea
+.idea/*
+target
+target/*
+*/target/*
 
-# Mobile Tools for Java (J2ME)
-.mtj.tmp/
+ruoyi-admin/target/*
 
-# Package Files #
-*.jar
-*.war
-*.ear
-
-# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
-hs_err_pid*
+/ruoyi-admin/target
+/ruoyi-buss/target
+/ruoyi-common/target
+/ruoyi-framework/target
+/ruoyi-fuzhou/target
+/ruoyi-generator/target
+/ruoyi-manage/target
+/ruoyi-quartz/target
+/ruoyi-system/target
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..461ff36
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,307 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.ruoyi</groupId>
+    <artifactId>ruoyi</artifactId>
+    <version>3.8.9</version>
+
+    <name>ruoyi</name>
+    <url>http://www.ruoyi.vip</url>
+    <description>鑻ヤ緷绠$悊绯荤粺</description>
+
+    <properties>
+        <ruoyi.version>3.8.9</ruoyi.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>17</java.version>
+        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+        <mybatis-spring-boot.version>3.0.3</mybatis-spring-boot.version>
+        <druid.version>1.2.23</druid.version>
+        <bitwalker.version>1.21</bitwalker.version>
+        <swagger.version>3.0.0</swagger.version>
+        <kaptcha.version>2.3.3</kaptcha.version>
+        <pagehelper.boot.version>2.1.0</pagehelper.boot.version>
+        <fastjson.version>2.0.53</fastjson.version>
+        <oshi.version>6.6.5</oshi.version>
+        <commons.io.version>2.13.0</commons.io.version>
+        <poi.version>4.1.2</poi.version>
+        <velocity.version>2.3</velocity.version>
+        <jwt.version>0.9.1</jwt.version>
+        <mysql.version>8.2.0</mysql.version>
+        <jaxb-api.version>2.3.1</jaxb-api.version>
+        <jakarta.version>6.0.0</jakarta.version>
+        <springdoc.version>2.6.0</springdoc.version>
+        <dameng.version>8.1.3.140</dameng.version>
+    </properties>
+
+    <!-- 渚濊禆澹版槑 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringBoot鐨勪緷璧栭厤缃�-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>3.2.0</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- 闃块噷鏁版嵁搴撹繛鎺ユ睜 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-3-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <!-- 瑙f瀽瀹㈡埛绔搷浣滅郴缁熴�佹祻瑙堝櫒绛� -->
+            <dependency>
+                <groupId>eu.bitwalker</groupId>
+                <artifactId>UserAgentUtils</artifactId>
+                <version>${bitwalker.version}</version>
+            </dependency>
+
+<!--            <dependency>-->
+<!--                <groupId>org.mybatis.spring.boot</groupId>-->
+<!--                <artifactId>mybatis-spring-boot-starter</artifactId>-->
+<!--                <version>${mybatis-spring-boot.version}</version>-->
+<!--            </dependency>-->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>3.5.4.1</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>mybatis-spring</artifactId>
+                        <groupId>org.mybatis</groupId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+            <dependency>
+                <groupId>org.mybatis</groupId>
+                <artifactId>mybatis-spring</artifactId>
+                <version>3.0.3</version>
+            </dependency>
+            <!-- pagehelper 鍒嗛〉鎻掍欢 -->
+<!--            <dependency>-->
+<!--                <groupId>com.github.pagehelper</groupId>-->
+<!--                <artifactId>pagehelper-spring-boot-starter</artifactId>-->
+<!--                <version>${pagehelper.boot.version}</version>-->
+<!--                <exclusions>-->
+<!--                    <exclusion>-->
+<!--                        <artifactId>mybatis-spring</artifactId>-->
+<!--                        <groupId>org.mybatis</groupId>-->
+<!--                    </exclusion>-->
+<!--                    <exclusion>-->
+<!--                        <artifactId>mybatis</artifactId>-->
+<!--                        <groupId>org.mybatis</groupId>-->
+<!--                    </exclusion>-->
+<!--                </exclusions>-->
+<!--            </dependency>-->
+            <dependency>
+                <groupId>com.mysql</groupId>
+                <artifactId>mysql-connector-j</artifactId>
+                <version>${mysql.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>javax.xml.bind</groupId>
+                <artifactId>jaxb-api</artifactId>
+                <version>${jaxb-api.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>jakarta.servlet</groupId>
+                <artifactId>jakarta.servlet-api</artifactId>
+                <version>${jakarta.version}</version>
+            </dependency>
+
+            <!-- 鑾峰彇绯荤粺淇℃伅 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
+
+            <!-- spring-doc -->
+            <dependency>
+                <groupId>org.springdoc</groupId>
+                <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+                <version>${springdoc.version}</version>
+            </dependency>
+
+            <!-- io甯哥敤宸ュ叿绫� -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+
+            <!-- excel宸ュ叿 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- 闃块噷JSON瑙f瀽鍣� -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+
+            <!-- Token鐢熸垚涓庤В鏋�-->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${jwt.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-boot-starter</artifactId>
+                <version>3.0.0</version>
+            </dependency>
+
+            <!-- 楠岃瘉鐮� -->
+            <dependency>
+                <groupId>pro.fessional</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!-- 瀹氭椂浠诲姟-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-quartz</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 浠g爜鐢熸垚-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-generator</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 鏍稿績妯″潡-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-framework</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 绯荤粺妯″潡-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-system</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 閫氱敤宸ュ叿-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-common</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 閫氱敤宸ュ叿-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-fuzhou</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <!-- 澶у睆涓氬姟妯″潡-->
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-manage</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.ruoyi</groupId>
+                <artifactId>ruoyi-manage</artifactId>
+                <version>${ruoyi.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.dameng</groupId>
+                <artifactId>DmJdbcDriver18</artifactId>
+                <version>${dameng.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>ruoyi-fuzhou</module>
+        <module>ruoyi-manage</module>
+        <module>ruoyi-buss</module>
+    </modules>
+    <packaging>pom</packaging>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+<!--                <version>3.13.0</version>-->
+                <configuration>
+                    <parameters>true</parameters>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>3.3.0</version>
+            </plugin>
+        </plugins>
+    </build>
+
+    <repositories>
+        <repository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+        </repository>
+    </repositories>
+
+    <pluginRepositories>
+        <pluginRepository>
+            <id>public</id>
+            <name>aliyun nexus</name>
+            <url>https://maven.aliyun.com/repository/public</url>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+        </pluginRepository>
+    </pluginRepositories>
+
+</project>
diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml
new file mode 100644
index 0000000..fbef0ec
--- /dev/null
+++ b/ruoyi-admin/pom.xml
@@ -0,0 +1,140 @@
+<?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>
+
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
+            <version>4.4.0</version>
+        </dependency>
+
+<!--        <dependency>-->
+<!--            <groupId>org.springdoc</groupId>-->
+<!--            <artifactId>springdoc-openapi-ui</artifactId>-->
+<!--            <version>1.8.0</version> &lt;!&ndash; 璇蜂娇鐢ㄦ渶鏂扮増鏈� &ndash;&gt;-->
+<!--        </dependency>-->
+
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+            <version>2.6.0</version>  <!-- 鐗堟湰鍙疯鏍规嵁浣犵殑Spring Boot鐗堟湰鍖归厤 -->
+        </dependency>
+
+         <!-- Mysql椹卞姩鍖� -->
+        <dependency>
+            <groupId>com.mysql</groupId>
+            <artifactId>mysql-connector-j</artifactId>
+        </dependency>
+
+        <!-- 杈炬ⅵ鏁版嵁搴撻┍鍔ㄥ寘 -->
+        <dependency>
+            <groupId>com.dameng</groupId>
+            <artifactId>DmJdbcDriver18</artifactId>
+        </dependency>
+
+        <!-- 鏍稿績妯″潡-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-framework</artifactId>
+        </dependency>
+
+        <!-- 瀹氭椂浠诲姟-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-quartz</artifactId>
+        </dependency>
+
+        <!-- 浠g爜鐢熸垚-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-generator</artifactId>
+        </dependency>
+
+        <!-- 浠g爜鐢熸垚-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-fuzhou</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-manage</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-buss</artifactId>
+            <version>3.8.9</version>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.5.2</version>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-manage</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>
diff --git a/ruoyi-admin/ruoyi-admin.iml b/ruoyi-admin/ruoyi-admin.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-admin/ruoyi-admin.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
new file mode 100644
index 0000000..c36ffd9
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiApplication.java
@@ -0,0 +1,38 @@
+package com.ruoyi;
+
+import com.ruoyi.common.utils.ip.IpUtils;
+import lombok.extern.slf4j.Slf4j;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.Bean;
+import org.springframework.web.socket.config.annotation.EnableWebSocket;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+/**
+ * 鍚姩绋嬪簭
+ *
+ * @author ruoyi
+ */
+@Slf4j
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@MapperScan("com.ruoyi.**.mapper")
+@EnableWebSocket
+public class RuoYiApplication {
+
+    private static String serverPort;
+
+    @Value("${server.port}")
+    public void setServerPort(String serverPort) {
+        RuoYiApplication.serverPort = serverPort;
+    }
+
+    public static void main(String[] args) {
+        //http://127.0.0.1:8080/swagger-ui/index.html#/
+        SpringApplication.run(RuoYiApplication.class, args);
+        log.info("API鏂囨。鍦板潃:http://{}:{}/doc.html", IpUtils.getHostIp(), serverPort);
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
new file mode 100644
index 0000000..6de67dc
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/RuoYiServletInitializer.java
@@ -0,0 +1,18 @@
+package com.ruoyi;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web瀹瑰櫒涓繘琛岄儴缃�
+ * 
+ * @author ruoyi
+ */
+public class RuoYiServletInitializer extends SpringBootServletInitializer
+{
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application)
+    {
+        return application.sources(RuoYiApplication.class);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
new file mode 100644
index 0000000..d0f9318
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CaptchaController.java
@@ -0,0 +1,89 @@
+package com.ruoyi.web.controller.common;
+
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+import jakarta.annotation.Resource;
+
+import javax.imageio.ImageIO;
+
+import jakarta.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;
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
new file mode 100644
index 0000000..b7fad0c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/CommonController.java
@@ -0,0 +1,163 @@
+package com.ruoyi.web.controller.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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);
+        }
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SysFileController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SysFileController.java
new file mode 100644
index 0000000..2fabfc8
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/common/SysFileController.java
@@ -0,0 +1,152 @@
+package com.ruoyi.web.controller.common;
+
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.file.FileUtils;
+import com.ruoyi.manage.domain.SysFileManage;
+import com.ruoyi.manage.domain.vo.SysFileManageVO;
+import com.ruoyi.manage.service.SysFileService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.FileSystemResource;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 鏂囦欢绠$悊琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@RestController
+@RequestMapping("/dp/sysFile")
+@Tag(name = "澶у睆--鏂囦欢绠$悊")
+public class SysFileController {
+    @Autowired
+    SysFileService sysFileService;
+    @Autowired
+    RuoYiConfig ruoYiConfig;
+
+    /**
+     * 鏌ヨ鏂囦欢绠$悊鍒楄〃
+     */
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鏂囦欢绠$悊鍒楄〃")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(sysFileService.listAll());
+    }
+
+    /**
+     * 鍗曚釜涓婁紶鏂囦欢
+     */
+    @PostMapping("/uploadFile")
+    @Operation(summary = "鍗曚釜涓婁紶鏂囦欢")
+    public AjaxResult uploadFile(MultipartFile file,String name,String type,
+                                 @RequestParam(value = "remark",required = false) String remark) {
+        SysFileManage sysFileManage = new SysFileManage();
+        sysFileManage.setName(name);
+        sysFileManage.setType(type);
+        sysFileManage.setRemark(remark);
+        try {
+            int res = sysFileService.saveFile(file,sysFileManage);
+            return AjaxResult.success(res);
+        }
+        catch (Exception e)
+        {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢
+     */
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎鏂囦欢")
+    public AjaxResult deleteBatch(@RequestBody List<String> ids)
+    {
+        List<String> res = sysFileService.deleteBatch(ids);
+        if(res.size()==0){
+            return AjaxResult.success("鍒犻櫎鎴愬姛");
+        }
+        return AjaxResult.success(res);
+    }
+
+    @PostMapping("/download")
+    @Operation(summary = "涓嬭浇鏂囦欢")
+    public ResponseEntity<FileSystemResource> resourceDownload(String id){
+        try {
+            SysFileManage sysFileManage = sysFileService.getById(id);
+            String filePath = sysFileManage.getFilePath();
+            String name = sysFileManage.getName();
+            String realFilePath = filePath.replaceFirst("/profile",RuoYiConfig.getProfile());
+            String ext = sysFileManage.getExt();
+            if(ext!=null && !ext.isEmpty()){
+                if(ext.equals("json")){
+                    realFilePath = filePath.replaceFirst("/profile",ruoYiConfig.getJson());
+                }
+            }
+            String realFileName = name + realFilePath.substring(realFilePath.indexOf("_") + 1);
+
+            File file = new File(realFilePath);
+            if(!file.exists()){
+                return ResponseEntity.notFound().build();
+            }
+            FileSystemResource resource = new FileSystemResource(file);
+
+            return ResponseEntity.ok()
+                    .header("Content-Disposition","attachment;filename=" + realFileName)
+                    .body(resource);
+
+        }catch (Exception e){
+            e.printStackTrace();
+            return ResponseEntity.status(500).build();
+        }
+    }
+
+    @GetMapping("/getCount")
+    @Operation(summary = "鏌ヨ鎬绘潯鏁�")
+    public AjaxResult getCount(){
+        return AjaxResult.success(sysFileService.queryCount());
+    }
+
+
+    /**
+     * 鍒嗛〉鏌ヨ鏂囦欢绠$悊鍒楄〃
+     */
+    @PostMapping("/getPageList")
+    @Operation(summary = "鍒嗛〉鏌ヨ鏂囦欢绠$悊鍒楄〃")
+    public TableDataInfo getPageList(@Validated @RequestBody SysFileManageVO vo) {
+        List<SysFileManage> list = sysFileService.queryData(vo);
+        return paginate(list, vo.getPageNum(), vo.getPageSize());
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveCarValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveCarValueFinalController.java
new file mode 100644
index 0000000..cd146ef
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveCarValueFinalController.java
@@ -0,0 +1,70 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.service.ReceiveCarValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/receiveCarValueFinal")
+@Tag(name = "澶у睆--宸ュ喌鏁版嵁澶勭悊缁撴灉")
+public class ReceiveCarValueFinalController {
+    @Autowired
+    private ReceiveCarValueFinalService receiveCarValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveCarValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "宸ュ喌鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveCarValueFinal> carValueFinals)
+    {
+        return AjaxResult.success(receiveCarValueFinalService.saveBatch(carValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "宸ュ喌鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveCarValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "宸ュ喌鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveCarValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "宸ュ喌鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveCarValueFinal receiveCarValueFinal)
+    {
+        return AjaxResult.success(receiveCarValueFinalService.updateDate(receiveCarValueFinal));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveElectricityValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveElectricityValueFinalController.java
new file mode 100644
index 0000000..7f1f031
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveElectricityValueFinalController.java
@@ -0,0 +1,69 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.service.ReceiveElectricityValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/receiveElectricityValueFinal")
+@Tag(name = "澶у睆--鐢垫暟鎹鐞嗙粨鏋�")
+public class ReceiveElectricityValueFinalController {
+    @Autowired
+    private ReceiveElectricityValueFinalService receiveElectricityValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveElectricityValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "鐢佃〃鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveElectricityValueFinal> electricityValueFinals)
+    {
+        return AjaxResult.success(receiveElectricityValueFinalService.saveBatch(electricityValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "鐢佃〃鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveElectricityValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "鐢佃〃鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveElectricityValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "鐢佃〃鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveElectricityValueFinal receiveElectricityValueFinal)
+    {
+        return AjaxResult.success(receiveElectricityValueFinalService.updateDate(receiveElectricityValueFinal));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoController.java
new file mode 100644
index 0000000..e31c287
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoController.java
@@ -0,0 +1,182 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 鏁版嵁鎺ユ敹淇℃伅 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-10
+ */
+@Tag(name = "璁惧鏁版嵁绠$悊")
+@RestController
+@RequestMapping("/dp/receiveInfo")
+public class ReceiveInfoController {
+
+    @Resource
+    private EquipmentService equipmentService;
+
+    @Resource
+    private ReceiveOilValueService receiveOilValueService;
+
+    @Resource
+    private ReceiveWaterValueService receiveWaterValueService;
+
+    @Resource
+    private ReceiveWaterInfoService receiveWaterInfoService;
+
+    @Resource
+    private ReceiveOilInfoService receiveOilInfoService;
+
+    @Resource
+    private ReceiveElectricityInfoService receiveElectricityInfoService;
+    @Resource
+    private ReceiveWeatherInfoService receiveWeatherInfoService;
+    @Resource
+    private ReceiveWeatherValueService receiveWeatherValueService;
+
+    @Resource
+    private ReceiveSlmInfoService receiveSlmInfoService;
+
+    @Resource
+    private ReceiveSlmValueService receiveSlmValueService;
+
+    @Resource
+    private ReceiveElectricityValueService receiveElectricityValueService;
+
+    @Resource
+    private ReceiveCarRuleService receiveCarRuleService;
+
+    @Resource
+    private ReceiveCarValueService receiveCarValueService;
+
+    @Operation(summary = "璁惧鍒楄〃鍒楄〃")
+    @GetMapping("/list")
+    public R<List<DpEquipment>> list(@RequestParam(value = "deviceType", required = false) Integer deviceType) {
+        return R.ok(equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().eq(DpEquipment::getEquipmentTypeId, deviceType);
+        }}));
+    }
+
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁")
+    @PostMapping("/dataList")
+    public R<List> dataList(@Validated @RequestBody ReceiveValueListVo vo) {
+        DpEquipment receiveInfo = equipmentService.getById(vo.getId());
+        if (receiveInfo == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.NIGDETUIYOU.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveOilValueService.list(new LambdaQueryWrapper<ReceiveOilValue>() {{
+                or().eq(ReceiveOilValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .ge(vo.getStartTime() != null, ReceiveOilValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveOilValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveOilValue::getCreateTime);
+            }}));
+        } else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWaterValueService.list(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+                or().eq(ReceiveWaterValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .ge(vo.getStartTime() != null, ReceiveWaterValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveWaterValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveWaterValue::getCreateTime);
+            }}));
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveElectricityValueService.list(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+                or().eq(ReceiveElectricityValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .ge(vo.getStartTime() != null, ReceiveElectricityValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveElectricityValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveElectricityValue::getCreateTime);
+            }}));
+        } else if (DataTypeEnum.GONGKUANG.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveCarValueService.list(new LambdaQueryWrapper<ReceiveCarValue>() {{
+                or().eq(ReceiveCarValue::getVin, receiveInfo.getEquCode())
+                        .ge(vo.getStartTime() != null, ReceiveCarValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveCarValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveCarValue::getCreateTime);
+            }}));
+        }else if (DataTypeEnum.WEATHER.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWeatherValueService.list(new LambdaQueryWrapper<ReceiveWeatherValue>() {{
+                or().eq(ReceiveWeatherValue::getDeviceName, receiveInfo.getId())
+                        .ge(vo.getStartTime() != null, ReceiveWeatherValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveWeatherValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveWeatherValue::getCreateTime);
+            }}));
+        }else if (DataTypeEnum.SLM.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveSlmValueService.list(new LambdaQueryWrapper<ReceiveSlmValue>() {{
+                or().eq(ReceiveSlmValue::getDeviceName, receiveInfo.getId())
+                        .ge(vo.getStartTime() != null, ReceiveSlmValue::getCreateTime, vo.getStartTime())
+                        .lt(vo.getEndTime() != null, ReceiveSlmValue::getCreateTime, vo.getEndTime())
+                        .orderByDesc(ReceiveSlmValue::getCreateTime);
+            }}));
+        }
+        return R.ok(new ArrayList());
+    }
+
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁琛ㄥご")
+    @GetMapping("/tableList")
+    public R<List> tableList(@RequestParam("id") Long id) {
+        DpEquipment receiveInfo = equipmentService.getById(id);
+        if (receiveInfo == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.NIGDETUIYOU.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                or().select(ReceiveOilInfo::getParam, ReceiveOilInfo::getParamCode, ReceiveOilInfo::getUnit).eq(ReceiveOilInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                or().select(ReceiveWaterInfo::getParam, ReceiveWaterInfo::getParamCode, ReceiveWaterInfo::getUnit).eq(ReceiveWaterInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveElectricityInfoService.list(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                or().select(ReceiveElectricityInfo::getParam, ReceiveElectricityInfo::getParamCode, ReceiveElectricityInfo::getUnit).eq(ReceiveElectricityInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.GONGKUANG.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            List<ReceiveElectricityInfo> receiveElectricityInfos = new ArrayList<>();
+            List<ReceiveCarRule> list = receiveCarRuleService.list();
+            ReceiveElectricityInfo electricityInfo;
+            for (ReceiveCarRule rule : list
+            ) {
+                electricityInfo = new ReceiveElectricityInfo();
+                electricityInfo.setUnit(rule.getUnit());
+                electricityInfo.setParamCode(rule.getCarCode());
+                electricityInfo.setParam(rule.getDataName());
+                receiveElectricityInfos.add(electricityInfo);
+            }
+            return R.ok(receiveElectricityInfos);
+        } else if (DataTypeEnum.WEATHER.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWeatherInfoService.list(new LambdaQueryWrapper<ReceiveWeatherInfo>() {{
+                or().select(ReceiveWeatherInfo::getParam, ReceiveWeatherInfo::getParamCode, ReceiveWeatherInfo::getUnit).eq(ReceiveWeatherInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.SLM.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveSlmInfoService.list(new LambdaQueryWrapper<ReceiveSlmInfo>() {{
+                or().select(ReceiveSlmInfo::getParam, ReceiveSlmInfo::getParamCode, ReceiveSlmInfo::getUnit).eq(ReceiveSlmInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        }
+        return R.ok(new ArrayList());
+    }
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoFinalController.java
new file mode 100644
index 0000000..8f2df84
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveInfoFinalController.java
@@ -0,0 +1,284 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import com.ruoyi.system.domain.SysOperLog;
+import com.ruoyi.system.domain.vo.SysOperLogVO;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.apache.poi.ss.formula.functions.T;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.system.service.ISysOperLogService;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@Tag(name = "澶у睆--璁惧鏁版嵁澶勭悊缁撴灉")
+@RestController
+@RequestMapping("/dp/receiveInfoFinal")
+public class ReceiveInfoFinalController {
+    @Autowired
+    private EquipmentService equipmentService;
+
+    @Autowired
+    private ReceiveWaterInfoService receiveWaterInfoService;
+
+    @Autowired
+    private ReceiveOilInfoService receiveOilInfoService;
+
+    @Autowired
+    private ReceiveElectricityInfoService receiveElectricityInfoService;
+
+    @Autowired
+    private ReceiveCarRuleService receiveCarRuleService;
+
+    @Autowired
+    private ReceiveOilValueFinalService receiveOilValueFinalService;
+    @Autowired
+    private ReceiveCarValueFinalService receiveCarValueFinalService;
+    @Autowired
+    private ReceiveElectricityValueFinalService receiveElectricityValueFinalService;
+    @Autowired
+    private ReceiveWaterValueFinalService receiveWaterValueFinalService;
+    @Autowired
+    private  ISysOperLogService sysOperLogService;
+
+    @Autowired
+    private ReceiveOilValueService oilValueService;
+    @Autowired
+    private ReceiveCarValueService carValueService;
+    @Autowired
+    private ReceiveElectricityValueService electricityValueService;
+    @Autowired
+    private ReceiveWaterValueService waterValueService;
+
+    @Autowired
+    private ReceiveWeatherValueFinalService receiveWeatherValueFinalService;
+    @Autowired
+    private ReceiveWeatherInfoService receiveWeatherInfoService;
+
+
+    @Autowired
+    private ReceiveSlmValueFinalService receiveSlmValueFinalService;
+    @Autowired
+    private ReceiveSlmInfoService receiveSlmInfoService;
+
+
+
+
+    @Operation(summary = "璁惧鏁版嵁鍒楄〃")
+    @GetMapping("/list")
+    public R<List<DpEquipment>> list(@RequestParam(value = "deviceType", required = false) Integer deviceType) {
+        return R.ok(equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().eq(DpEquipment::getEquipmentTypeId, deviceType);
+        }}));
+    }
+
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁")
+    @PostMapping("/dataList")
+    public R<List> dataList(@Validated @RequestBody ReceiveValueListVo vo) {
+        DpEquipment receiveInfo = equipmentService.getById(vo.getId());
+        if (receiveInfo == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.NIGDETUIYOU.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveOilValueFinalService.queryData(vo));
+        }
+        else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWaterValueFinalService.queryData(vo));
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveElectricityValueFinalService.queryData(vo));
+        } else if (DataTypeEnum.GONGKUANG.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveCarValueFinalService.queryData(vo));
+        }else if (DataTypeEnum.WEATHER.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWeatherValueFinalService.queryData(vo));
+        }else if (DataTypeEnum.SLM.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveSlmValueFinalService.queryData(vo));
+        }
+        return R.ok(new ArrayList());
+    }
+
+    @Operation(summary = "鏌ヨ鏃堕棿娈靛唴姣忓ぉ鐨勭粺璁℃暟鎹�")
+    @GetMapping("/selectDailyData")
+    public AjaxResult selectDailyData(@RequestParam(value = "startTime") String startTime,
+                                @RequestParam(value = "endTime") String endTime,
+                                @RequestParam(value = "title") String title) {
+        JSONArray jsonArray = new JSONArray();
+        SysOperLogVO insertLog = new SysOperLogVO();
+        insertLog.setTitle(title);
+        insertLog.setStartTime(startTime);
+        insertLog.setEndTime(endTime);
+        Map<String,List<SysOperLog>> map = sysOperLogService.queryByDate(insertLog);
+        for (Map.Entry<String,List<SysOperLog>> entry : map.entrySet()){
+            int insertCount = 0;
+            int updateCount = 0;
+            int deleteCount = 0;
+            String date = entry.getKey();
+            List<SysOperLog> logList = entry.getValue();
+            JSONObject jsonObject = new JSONObject();
+            if(logList.size()>0){
+                for (SysOperLog operLog : logList){
+                    if(operLog.getBusinessType()==1){
+                        insertCount++;
+                    }else if(operLog.getBusinessType()==2){
+                        updateCount++;
+                    }else if(operLog.getBusinessType()==3){
+                        deleteCount++;
+                    }
+                }
+            }
+            jsonObject.put("dateTime",date);
+            jsonObject.put("insertCount",insertCount);
+            jsonObject.put("updateCount",updateCount);
+            jsonObject.put("deleteCount",deleteCount);
+            jsonArray.add(jsonObject);
+        }
+        return AjaxResult.success(jsonArray);
+    }
+
+    @Operation(summary = "鏁伴噺缁熻")
+    @GetMapping("/queryCount")
+    public AjaxResult queryCount(@RequestParam(value = "title") String title){
+        JSONObject jsonObject = new JSONObject();
+        if(title.equals("娌硅〃鏁版嵁")){
+            jsonObject.put("processedData",receiveOilValueFinalService.queryCount());
+            jsonObject.put("rawCount",oilValueService.count());
+        }else if(title.equals("姘磋〃鏁版嵁")){
+            jsonObject.put("processedData",receiveWaterValueFinalService.queryCount());
+            jsonObject.put("rawCount",waterValueService.count());
+        }else if(title.equals("鐢佃〃鏁版嵁")){
+            jsonObject.put("processedData",receiveElectricityValueFinalService.queryCount());
+            jsonObject.put("rawCount",electricityValueService.count());
+        }else if(title.equals("宸ュ喌鏁版嵁")){
+            jsonObject.put("processedData",receiveCarValueFinalService.queryCount());
+            jsonObject.put("rawCount",carValueService.count());
+        }
+        return AjaxResult.success(jsonObject);
+    }
+
+    @Operation(summary = "鏍规嵁title鏌ヨ缁熻鏁版嵁(鍒嗛〉)")
+    @PostMapping("/selectData")
+    public AjaxResult selectData(@Validated @RequestBody SysOperLogVO sysOperLogVO) {
+        List<SysOperLog> logList = sysOperLogService.queryDataByTitle(sysOperLogVO);
+        TableDataInfo dataInfo = paginate(logList,sysOperLogVO.getPageNum(),sysOperLogVO.getPageSize());
+        return AjaxResult.success(dataInfo);
+    }
+
+
+    @Operation(summary = "鍒ゆ柇瀵瑰簲璇锋眰璺緞")
+    @GetMapping("/getUrl")
+    public R<String> getUrl(@RequestParam("equId") String equId) {
+        DpEquipment receiveInfo = equipmentService.getById(equId);
+        if (receiveInfo == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.NIGDETUIYOU.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("oilValueFinal");
+        }
+        else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("receiveWaterValueFinal");
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("receiveElectricityValueFinal");
+        } else if (DataTypeEnum.GONGKUANG.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("receiveCarValueFinal");
+        } else if (DataTypeEnum.WEATHER.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("receiveWeatherValueFinal");
+        } else if (DataTypeEnum.SLM.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok("receiveSlmValueFinal");
+        }
+        return R.ok(null);
+    }
+
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁琛ㄥご")
+    @GetMapping("/tableList")
+    public R<List> tableList(@RequestParam("id") Long id) {
+        DpEquipment receiveInfo = equipmentService.getById(id);
+        if (receiveInfo == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.NIGDETUIYOU.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                or().select(ReceiveOilInfo::getParam, ReceiveOilInfo::getParamCode, ReceiveOilInfo::getUnit).eq(ReceiveOilInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        }
+        else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                or().select(ReceiveWaterInfo::getParam, ReceiveWaterInfo::getParamCode, ReceiveWaterInfo::getUnit).eq(ReceiveWaterInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveElectricityInfoService.list(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                or().select(ReceiveElectricityInfo::getParam, ReceiveElectricityInfo::getParamCode, ReceiveElectricityInfo::getUnit).eq(ReceiveElectricityInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.GONGKUANG.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            List<ReceiveElectricityInfo> receiveElectricityInfos = new ArrayList<>();
+            List<ReceiveCarRule> list = receiveCarRuleService.list();
+            ReceiveElectricityInfo electricityInfo;
+            for (ReceiveCarRule rule : list
+            ) {
+                electricityInfo = new ReceiveElectricityInfo();
+                electricityInfo.setUnit(rule.getUnit());
+                electricityInfo.setParamCode(rule.getCarCode());
+                electricityInfo.setParam(rule.getDataName());
+                receiveElectricityInfos.add(electricityInfo);
+            }
+            return R.ok(receiveElectricityInfos);
+        } else if (DataTypeEnum.WEATHER.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveWeatherInfoService.list(new LambdaQueryWrapper<ReceiveWeatherInfo>() {{
+                or().select(ReceiveWeatherInfo::getParam, ReceiveWeatherInfo::getParamCode, ReceiveWeatherInfo::getUnit).eq(ReceiveWeatherInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        } else if (DataTypeEnum.SLM.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return R.ok(receiveSlmInfoService.list(new LambdaQueryWrapper<ReceiveSlmInfo>() {{
+                or().select(ReceiveSlmInfo::getParam, ReceiveSlmInfo::getParamCode, ReceiveSlmInfo::getUnit).eq(ReceiveSlmInfo::getDeviceName, String.valueOf(receiveInfo.getId()));
+            }}));
+        }
+        return R.ok(new ArrayList());
+    }
+
+    //鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)
+    @PostMapping("/getPageListByIdRuoyi")
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)")
+    public AjaxResult getPageListByIdRuoyi(@Validated @RequestBody ReceiveValueListVo vo) {
+        List dataList = dataList(vo).getData();
+        List tableList = tableList(vo.getId()).getData();
+
+        TableDataInfo dataInfo = paginate(dataList, vo.getPageNum(), vo.getPageSize());
+        JSONObject object = new JSONObject();
+        object.put("dataList", dataInfo);
+        object.put("tableList", tableList);
+        return AjaxResult.success(object);
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveOilValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveOilValueFinalController.java
new file mode 100644
index 0000000..11970de
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveOilValueFinalController.java
@@ -0,0 +1,71 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveOilValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.service.ReceiveOilValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/oilValueFinal")
+@Tag(name = "澶у睆--娌规暟鎹鐞嗙粨鏋�")
+public class ReceiveOilValueFinalController {
+
+    @Autowired
+    private ReceiveOilValueFinalService receiveOilValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveOilValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "娌硅〃鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveOilValueFinal> oilValueFinals)
+    {
+        return AjaxResult.success(receiveOilValueFinalService.saveBatch(oilValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "娌硅〃鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveOilValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "娌硅〃鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveOilValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "娌硅〃鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveOilValueFinal receiveOilValueFinal)
+    {
+        return AjaxResult.success(receiveOilValueFinalService.updateDate(receiveOilValueFinal));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveSlmValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveSlmValueFinalController.java
new file mode 100644
index 0000000..96374d8
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveSlmValueFinalController.java
@@ -0,0 +1,73 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.service.ReceiveSlmValueFinalService;
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/receiveSlmValueFinal")
+@Tag(name = "澶у睆--姘存暟鎹鐞嗙粨鏋�")
+public class ReceiveSlmValueFinalController {
+
+    @Autowired
+    private ReceiveSlmValueFinalService receiveSlmValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveSlmValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "姘磋〃鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveSlmValueFinal> waterValueFinals)
+    {
+        return AjaxResult.success(receiveSlmValueFinalService.saveBatchNew(waterValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "姘磋〃鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveSlmValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "姘磋〃鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveSlmValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "姘磋〃鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveSlmValueFinal ReceiveSlmValueFinal)
+    {
+        return AjaxResult.success(receiveSlmValueFinalService.updateDate(ReceiveSlmValueFinal));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWaterValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWaterValueFinalController.java
new file mode 100644
index 0000000..18c5b82
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWaterValueFinalController.java
@@ -0,0 +1,69 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.service.ReceiveWaterValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/receiveWaterValueFinal")
+@Tag(name = "澶у睆--姘存暟鎹鐞嗙粨鏋�")
+public class ReceiveWaterValueFinalController {
+    @Autowired
+    private ReceiveWaterValueFinalService receiveWaterValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveWaterValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "姘磋〃鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveWaterValueFinal> waterValueFinals)
+    {
+        return AjaxResult.success(receiveWaterValueFinalService.saveBatch(waterValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "姘磋〃鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveWaterValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "姘磋〃鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveWaterValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "姘磋〃鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveWaterValueFinal receiveWaterValueFinal)
+    {
+        return AjaxResult.success(receiveWaterValueFinalService.updateDate(receiveWaterValueFinal));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWeatherValueFinalController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWeatherValueFinalController.java
new file mode 100644
index 0000000..ada087a
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/fuzhou/ReceiveWeatherValueFinalController.java
@@ -0,0 +1,71 @@
+package com.ruoyi.web.controller.fuzhou;
+
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueFinalService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@RestController
+@RequestMapping("/dp/receiveWeatherValueFinal")
+@Tag(name = "澶у睆--姘存暟鎹鐞嗙粨鏋�")
+public class ReceiveWeatherValueFinalController {
+    @Autowired
+    private ReceiveWeatherValueFinalService receiveWeatherValueFinalService;
+
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋暟鎹垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(receiveWeatherValueFinalService.listAll());
+    }
+
+    @PostMapping("/saveBatch")
+    @Operation(summary = "鎵归噺鎻掑叆")
+    @Log(title = "姘磋〃鏁版嵁鏂板", businessType = BusinessType.INSERT)
+    public AjaxResult saveBatch(@RequestBody List<ReceiveWeatherValueFinal> waterValueFinals)
+    {
+        return AjaxResult.success(receiveWeatherValueFinalService.saveBatchNew(waterValueFinals));
+    }
+
+    @PostMapping("/queryData")
+    @Operation(summary = "鏉′欢鏌ヨ")
+    @Log(title = "姘磋〃鏁版嵁鏌ヨ", businessType = BusinessType.SELECT)
+    public AjaxResult queryData(@RequestBody ReceiveValueListVo vo)
+    {
+        return AjaxResult.success(receiveWeatherValueFinalService.queryData(vo));
+    }
+
+    @PostMapping("/deleteBatch")
+    @Operation(summary = "鎵归噺鍒犻櫎")
+    @Log(title = "姘磋〃鏁版嵁鍒犻櫎", businessType = BusinessType.DELETE)
+    public AjaxResult deleteBatch(@RequestBody List<Long> ids)
+    {
+        return AjaxResult.success(receiveWeatherValueFinalService.deleteBatch(ids));
+    }
+
+    @PostMapping("/updateDate")
+    @Operation(summary = "淇敼鏇存柊")
+    @Log(title = "姘磋〃鏁版嵁淇敼", businessType = BusinessType.UPDATE)
+    public AjaxResult updateDate(@RequestBody ReceiveWeatherValueFinal receiveWeatherValueFinal)
+    {
+        return AjaxResult.success(receiveWeatherValueFinalService.updateDate(receiveWeatherValueFinal));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DmHarborController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DmHarborController.java
new file mode 100644
index 0000000..7e66ae6
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DmHarborController.java
@@ -0,0 +1,288 @@
+package com.ruoyi.web.controller.manage;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.*;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.domain.model.LoginUser;
+import com.ruoyi.common.utils.SecurityUtils;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+import com.ruoyi.fuzhou.domain.vo.DpEquipmentVO;
+import com.ruoyi.fuzhou.service.EquipmentService;
+import com.ruoyi.fuzhou.service.ReceiveWaterValueService;
+import com.ruoyi.manage.domain.DmBerth;
+import com.ruoyi.manage.service.DpBerthService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+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.ruoyi.manage.domain.DmHarbor;
+import com.ruoyi.manage.service.IDmHarborService;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 娓彛淇℃伅Controller
+ * 
+ * @author ruoyi
+ * @date 2025-03-17
+ */
+@RestController
+@RequestMapping("/dp/harbor")
+@Tag(name = "澶у睆--娓彛绠$悊")
+public class DmHarborController extends BaseController
+{
+    @Autowired
+    private IDmHarborService dmHarborService;
+    @Autowired
+    private DpBerthService dpBerthService;
+    @Resource
+    private EquipmentService dpEquipmentService;
+    @Resource
+    private ReceiveWaterValueService receiveWaterValueService;
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     */
+    @GetMapping("/list")
+    @Operation(summary = "鏌ヨ娓彛淇℃伅鍒楄〃")
+    public TableDataInfo list(DmHarbor dmHarbor)
+    {
+
+       return dmHarborService.getList(dmHarbor);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夋腐鍙d俊鎭垪琛�
+     */
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋腐鍙d俊鎭垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(dmHarborService.list());
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夋腐鍙d俊鎭垪琛�
+     */
+    @GetMapping("/getListAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋腐鍙d俊鎭�")
+    public AjaxResult getListAll()
+    {
+        //鑾峰彇鐢ㄦ埛淇℃伅鏍规嵁閮ㄩ棬ID鏌ヨ娓彛淇℃伅
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long deptId = loginUser.getDeptId();
+        if(deptId.equals(100L)){
+            return AjaxResult.success(dmHarborService.list());
+        }
+        if(deptId.equals(4001L)){
+            deptId = 101L;
+        }
+        if(deptId.equals(4002L)){
+            deptId = 4000L;
+        }
+        QueryWrapper<DmHarbor> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("DEPT_ID",deptId);
+        return AjaxResult.success(dmHarborService.list(queryWrapper));
+    }
+
+    /**
+     * 鏌ヨ娓彛鍙婂叾娉婁綅璇︽儏
+     */
+    @GetMapping("/getHarborBerth")
+    @Operation(summary = "鏌ヨ娓彛鍙婂叾娉婁綅璇︽儏")
+    public AjaxResult getHarborBerth()
+    {
+        //鑾峰彇鐢ㄦ埛淇℃伅鏍规嵁閮ㄩ棬ID鏌ヨ娓彛淇℃伅
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long deptId = loginUser.getDeptId();
+        List<DmHarbor> reslist = new ArrayList<>();
+        if(deptId.equals(100L)){
+            List<DmHarbor> list = dmHarborService.list();
+            for (DmHarbor dmHarbor : list){
+                LambdaQueryWrapper<DmBerth> berthQueryWrapper = new LambdaQueryWrapper<>();
+                berthQueryWrapper.eq(DmBerth::getHarborId,dmHarbor.getPkId()).notIn(DmBerth::getName,"鍥尯").orderByAsc(DmBerth::getOrderNum);
+                List<DmBerth> dmBerths = dpBerthService.list(berthQueryWrapper);
+                dmHarbor.setDmBerthList(dmBerths);
+                reslist.add(dmHarbor);
+            }
+            return AjaxResult.success(reslist);
+        }else {
+            if(deptId.equals(4001L)){
+                deptId = 101L;
+            }
+            QueryWrapper<DmHarbor> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("DEPT_ID",deptId);
+            List<DmHarbor> list = dmHarborService.list(queryWrapper);
+            for (DmHarbor dmHarbor : list){
+                LambdaQueryWrapper<DmBerth> QueryWrapper = new LambdaQueryWrapper<>();
+                QueryWrapper.eq(DmBerth::getHarborId,dmHarbor.getPkId()).notIn(DmBerth::getName,"鍥尯").orderByAsc(DmBerth::getOrderNum);
+                List<DmBerth> dmBerths = dpBerthService.list(QueryWrapper);
+                dmHarbor.setDmBerthList(dmBerths);
+                reslist.add(dmHarbor);
+            }
+            return AjaxResult.success(reslist);
+        }
+    }
+
+    /**
+     * 鏌ヨ娓彛姘存繁鏁版嵁鍒楄〃
+     */
+    @GetMapping("/getWaterDepthList")
+    @Operation(summary = "鏌ヨ娓彛姘存繁鏁版嵁鍒楄〃")
+    public AjaxResult getWaterDepthList() {
+        //鑾峰彇鐢ㄦ埛淇℃伅鏍规嵁閮ㄩ棬ID鏌ヨ娓彛淇℃伅
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long deptId = loginUser.getDeptId();
+        List<DpEquipmentVO> resList = new ArrayList<>();
+        if(deptId.equals(100L)){
+            List<DmHarbor> list = dmHarborService.list();
+            return AjaxResult.success(getWaterDepth(list));
+        }else {
+            if(deptId.equals(4001L)){
+                deptId = 101L;
+            }
+            QueryWrapper<DmHarbor> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("DEPT_ID",deptId);
+            List<DmHarbor> list = dmHarborService.list(queryWrapper);
+            return AjaxResult.success(getWaterDepth(list));
+        }
+    }
+
+    /**
+     * 鏌ヨ娓彛姘存繁鏁版嵁鍒楄〃
+     */
+    @GetMapping("/getWaterListByIds")
+    @Operation(summary = "閫氳繃璁惧id鏌ヨ姘存繁鏁版嵁鍒楄〃")
+    public AjaxResult getWaterListByIds(String ids) {
+
+        LocalDate today=LocalDate.now();
+        LocalDateTime startOfDay=today.atStartOfDay();
+        LocalDateTime endOfDay=today.plusDays(1).atStartOfDay().minusSeconds(1);
+
+
+        List<ReceiveWaterValue> result=receiveWaterValueService.list(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+            in(ReceiveWaterValue::getDeviceName,ids.split(","))
+            .ge(ReceiveWaterValue::getCreateTime,startOfDay)
+            .le(ReceiveWaterValue::getCreateTime,endOfDay);
+        }});
+
+        List<Map<String,Object>>res=new ArrayList<>();
+        String[] idArray=ids.split(",");
+        for (int i = 0; i < idArray.length; i++){
+            Map<String,Object> map=new HashMap<>();
+            map.put("id",idArray[i]);
+            List<ReceiveWaterValue> ds=new ArrayList<>();
+            for (int k = 0; k < result.size(); k++) {
+                ReceiveWaterValue data=result.get(k);
+                if(data.getDeviceName().equals(idArray[i])){
+                    ds.add(data);
+                }
+            }
+            map.put("data",ds);
+            res.add(map);
+        }
+
+        return AjaxResult.success(res);
+    }
+
+    private JSONArray getWaterDepth(List<DmHarbor> list){
+        List<DpEquipmentVO> resList = new ArrayList<>();
+        for (DmHarbor dmHarbor : list){
+            List<DpEquipmentVO> dpEquipmentVOS = dpEquipmentService.getListByWhId(dmHarbor.getPkId().intValue());
+            for (DpEquipmentVO dpEquipmentVO : dpEquipmentVOS){
+                if(dpEquipmentVO.getEquipmentTypeId()==7){
+                    ReceiveWaterValue waterValue = receiveWaterValueService.getOne(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+                        eq(ReceiveWaterValue::getDeviceName, String.valueOf(dpEquipmentVO.getId()))
+                                .orderByDesc(ReceiveWaterValue::getCreateTime).last("LIMIT 1");
+                    }});
+                    if(waterValue!=null){
+                        dpEquipmentVO.setFieldName(waterValue.getWaterDeep());
+                        resList.add(dpEquipmentVO);
+                    }
+                }
+            }
+        }
+        JSONArray jsonArray = new JSONArray();
+        for (DpEquipmentVO dpEquipmentVO : resList){
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("equName",dpEquipmentVO.getEquName());
+            jsonObject.put("waterDeep",dpEquipmentVO.getFieldName());
+            jsonArray.add(jsonObject);
+        }
+        return jsonArray;
+    }
+
+
+    /**
+     * 瀵煎嚭娓彛淇℃伅鍒楄〃
+     */
+//    @PreAuthorize("@ss.hasPermi('system:harbor:export')")
+//    @Log(title = "娓彛淇℃伅", businessType = BusinessType.EXPORT)
+//    @PostMapping("/export")
+//    public void export(HttpServletResponse response, DmHarbor2 dmHarbor)
+//    {
+//        List<DmHarbor2> list = dmHarborService.selectDmHarborList(dmHarbor);
+//        ExcelUtil<DmHarbor2> util = new ExcelUtil<DmHarbor2>(DmHarbor2.class);
+//        util.exportExcel(response, list, "娓彛淇℃伅鏁版嵁");
+//    }
+
+    /**
+     * 鑾峰彇娓彛淇℃伅璇︾粏淇℃伅
+     */
+    @GetMapping("/{pkId}")
+    @Operation(summary = "鑾峰彇娓彛淇℃伅璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("pkId") Long pkId)
+    {
+        return success(dmHarborService.getById(pkId));
+    }
+
+    /**
+     * 鏂板娓彛淇℃伅
+     */
+    @Operation(summary = "鏂板娓彛淇℃伅")
+    @PostMapping
+    public AjaxResult add(@RequestBody DmHarbor dmHarbor)
+    {
+        return toAjax(dmHarborService.save(dmHarbor));
+    }
+
+    /**
+     * 淇敼娓彛淇℃伅
+     */
+    @Operation(summary = "淇敼娓彛淇℃伅")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DmHarbor dmHarbor)
+    {
+        return toAjax(dmHarborService.updateById(dmHarbor));
+    }
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎娓彛淇℃伅")
+    @DeleteMapping("/{pkId}")
+    public AjaxResult remove(@PathVariable Long pkId)
+    {
+        return toAjax(dmHarborService.removeById(pkId));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpBerthController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpBerthController.java
new file mode 100644
index 0000000..99c85e5
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpBerthController.java
@@ -0,0 +1,142 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DmBerth;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.domain.DmHarbor;
+import com.ruoyi.manage.service.DpBerthService;
+import com.ruoyi.manage.service.DpShipParkingService;
+import com.ruoyi.manage.service.DpShipsService;
+import com.ruoyi.manage.service.IDmHarborService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@RestController
+@RequestMapping("/dp/dpBerth")
+@Tag(name = "澶у睆--娉婁綅绠$悊")
+public class DpBerthController extends BaseController {
+    @Autowired
+    private DpBerthService dpBerthService;
+    @Autowired
+    private DpShipParkingService dpShipParkingService;
+    @Autowired
+    private DpShipsService dpShipsService;
+    @Autowired
+    private IDmHarborService dmHarborService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰彇娉婁綅鍒楄〃")
+    public AjaxResult getList(Integer whId){
+        LambdaQueryWrapper<DmBerth> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(DmBerth::getHarborId,whId);
+        return AjaxResult.success(dpBerthService.list(queryWrapper));
+    }
+
+    @GetMapping("/getBerthList")
+    @Operation(summary = "鑾峰彇娉婁綅璇︽儏鍒楄〃")
+    public AjaxResult getBerthList(Integer whId){
+        LambdaQueryWrapper<DmBerth> queryWrapper = new LambdaQueryWrapper<>();
+        queryWrapper.eq(DmBerth::getHarborId,whId);
+        List<DmBerth> dpBerthList = dpBerthService.list(queryWrapper);
+        List<DmBerth> berthList = new ArrayList<>();
+        for (DmBerth dmBerth : dpBerthList){
+//            List<DpShipParking> parkingList = dpShipParkingService.getByWhBeId(whId,dmBerth.getPkid().intValue(),dmBerth.getShipsNum());
+            List<DpShips> shipsList = dpShipsService.getByWhIdBeId(whId,dmBerth.getPkid().intValue());
+            DmHarbor dmHarbor = dmHarborService.selectDmHarborByPkId(whId.longValue());
+            dmBerth.setHarborName(dmHarbor.getHarborName());
+            dmBerth.setShipsParking(shipsList);
+            berthList.add(dmBerth);
+        }
+        return AjaxResult.success(berthList);
+    }
+
+    @GetMapping("/pageList")
+    @Operation(summary = "娉婁綅鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DmBerth dpBerth) {
+        return dpBerthService.getPageList(dpBerth);
+    }
+
+    @GetMapping("/exitName")
+    @Operation(summary = "楠岃瘉娉婁綅鍚嶇О鏄惁瀛樺湪")
+    public Boolean exitName(@RequestParam Integer whId,@RequestParam String name) {
+        QueryWrapper<DmBerth> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("HARBOR_ID",whId)
+                .eq("NAME",name);
+        return dpBerthService.exists(queryWrapper);
+    }
+
+    /**
+     * 鑾峰彇鐮佸ご-娉婁綅璇︾粏淇℃伅
+     */
+    @GetMapping(value = "/{beId}")
+    @Operation(summary = "鑾峰彇娉婁綅璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("beId") Long beId)
+    {
+        return success(dpBerthService.getById(beId));
+    }
+
+    /**
+     * 鏂板鐮佸ご-娉婁綅
+     */
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DmBerth dpBerth)
+    {
+        QueryWrapper<DmBerth> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("HARBOR_ID",dpBerth.getHarborId())
+                .eq("NAME",dpBerth.getName());
+        if(!dpBerthService.exists(queryWrapper)){
+            return toAjax(dpBerthService.save(dpBerth));
+        }else {
+            return AjaxResult.error("娉婁綅鍚嶇О宸插瓨鍦�");
+        }
+    }
+
+    /**
+     * 淇敼鐮佸ご-娉婁綅
+     */
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DmBerth dpBerth)
+    {
+        return toAjax(dpBerthService.updateById(dpBerth));
+//        QueryWrapper<DmBerth> queryWrapper = new QueryWrapper<>();
+//        queryWrapper.eq("HARBOR_ID",dpBerth.getHarborId())
+//                .eq("NAME",dpBerth.getName());
+//        if(!dpBerthService.exists(queryWrapper)){
+//            return toAjax(dpBerthService.updateById(dpBerth));
+//        }else {
+//            return AjaxResult.error("娉婁綅鍚嶇О宸插瓨鍦�");
+//        }
+    }
+
+    /**
+     * 鍒犻櫎鐮佸ご-娉婁綅
+     */
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{beId}")
+    public AjaxResult remove(@PathVariable Integer beId)
+    {
+        return toAjax(dpBerthService.removeById(beId));
+    }
+
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEffectAssessListController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEffectAssessListController.java
new file mode 100644
index 0000000..9c3d452
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEffectAssessListController.java
@@ -0,0 +1,89 @@
+package com.ruoyi.web.controller.manage;
+
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpEffectAssessList;
+import com.ruoyi.manage.service.DpEffectAssessListService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ *  鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@RestController
+@RequestMapping("/dp/dpEffectAssessList")
+@Tag(name = "澶у睆--鏁堣兘璇勪及鎸囨爣绠$悊")
+public class DpEffectAssessListController extends BaseController {
+    @Autowired
+    private DpEffectAssessListService dpEffectAssessListService;
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     */
+    @PostMapping("/list")
+    @Operation(summary = "鏌ヨ鏁堣兘璇勪及鎸囨爣淇℃伅鍒楄〃锛堝垎椤碉級")
+    public TableDataInfo list(@RequestBody DpEffectAssessList dpEffectAssessList)
+    {
+
+        return dpEffectAssessListService.getList(dpEffectAssessList);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夋腐鍙d俊鎭垪琛�
+     */
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋晥鑳借瘎浼版寚鏍囧垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(dpEffectAssessListService.list());
+    }
+
+    /**
+     * 鑾峰彇娓彛淇℃伅璇︾粏淇℃伅
+     */
+    @GetMapping("/{pkId}")
+    @Operation(summary = "鑾峰彇鏁堣兘璇勪及鎸囨爣淇℃伅")
+    public AjaxResult getInfo(@PathVariable("pkId") Long pkId)
+    {
+        return success(dpEffectAssessListService.getById(pkId));
+    }
+
+    /**
+     * 鏂板娓彛淇℃伅
+     */
+    @Operation(summary = "鏂板鏁堣兘璇勪及鎸囨爣")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpEffectAssessList dpEffectAssessList)
+    {
+        return toAjax(dpEffectAssessListService.save(dpEffectAssessList));
+    }
+
+    /**
+     * 淇敼娓彛淇℃伅
+     */
+    @Operation(summary = "淇敼鏁堣兘璇勪及鎸囨爣")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpEffectAssessList dpEffectAssessList)
+    {
+        return toAjax(dpEffectAssessListService.updateById(dpEffectAssessList));
+    }
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎鏁堣兘璇勪及鎸囨爣")
+    @DeleteMapping("/{pkId}")
+    public AjaxResult remove(@PathVariable Long pkId)
+    {
+        return toAjax(dpEffectAssessListService.removeById(pkId));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentController.java
new file mode 100644
index 0000000..1540577
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentController.java
@@ -0,0 +1,1003 @@
+package com.ruoyi.web.controller.manage;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+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.R;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+import com.ruoyi.fuzhou.domain.vo.DpEquipmentVO;
+import com.ruoyi.fuzhou.domain.vo.QueryAnalysisVO;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import com.ruoyi.manage.domain.DpEquipmentType;
+import com.ruoyi.manage.domain.DsTaskList;
+import com.ruoyi.manage.domain.SysFileManage;
+import com.ruoyi.manage.domain.vo.Tree;
+import com.ruoyi.manage.service.DpEquipmentTypeService;
+import com.ruoyi.manage.service.SysFileService;
+import com.ruoyi.system.service.ISysDictDataService;
+import com.ruoyi.web.controller.fuzhou.ReceiveInfoController;
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.text.SimpleDateFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@RestController
+@RequestMapping("/dp/dpEquipment")
+@Tag(name = "澶у睆--璁惧绠$悊")
+public class DpEquipmentController extends BaseController {
+    @Resource
+    private EquipmentService dpEquipmentService;
+
+    @Resource
+    private ReceiveInfoController receiveInfoController;
+
+    @Resource
+    private ISysDictDataService iSysDictDataService;
+
+    @Resource
+    ReceiveModuleInfoService receiveModuleInfoService;
+
+    @Resource
+    DsTaskListController dsTaskListController;
+
+    @Resource
+    private ReceiveOilValueService receiveOilValueService;
+
+    @Resource
+    private ReceiveWaterValueService receiveWaterValueService;
+
+    @Resource
+    private ReceiveElectricityValueService receiveElectricityValueService;
+
+    @Resource
+    private HikService hikService;
+
+    @Resource
+    private DpEquipmentTypeService dpEquipmentTypeService;
+
+    @Autowired
+    SysFileService sysFileService;
+    @Autowired
+    RuoYiConfig ruoYiConfig;
+
+
+    @GetMapping("/list")
+    @Operation(summary = "璁惧鍒楄〃")
+    public AjaxResult getList(Integer beId) {
+        List<Tree> treeList = new ArrayList<>();
+        if (null != beId) {
+            List<DpEquipmentVO> list = dpEquipmentService.getListByBeId(beId);
+            if (null != list) {
+                Map<String, List<DpEquipmentVO>> result = list.stream().collect(Collectors.groupingBy(DpEquipmentVO::getEqutype));
+                treeList = buildTree(result);
+            }
+        }
+        return AjaxResult.success(treeList);
+    }
+
+    private List<Tree> buildTree(Map<String, List<DpEquipmentVO>> result) {
+        // 鏋勫缓鏍戣妭鐐�
+        List<Tree> tree = new ArrayList<>();
+        for (Map.Entry<String, List<DpEquipmentVO>> entry : result.entrySet()) {
+            Tree typeNode = new Tree();
+            typeNode.setId(generateId());
+            typeNode.setLabel(entry.getKey());
+            typeNode.setChildren(entry.getValue().stream()
+                    .map(equipment -> {
+                        Tree equipmentNode = new Tree();
+                        equipmentNode.setLabel(equipment.getEquName());
+                        equipmentNode.setId(equipment.getId());
+                        equipmentNode.setIntervalTime(equipment.getIntervalTime());
+                        equipmentNode.setPeriodTime(equipment.getPeriodTime());
+                        equipmentNode.setIcon(equipment.getIcon());
+                        return equipmentNode;
+                    })
+                    .collect(Collectors.toList()));
+            typeNode.setDisabled(true);
+            tree.add(typeNode);
+        }
+
+        return tree;
+
+    }
+
+    //鐢熸垚涓嶉噸澶岻D
+    private int generateId() {
+        UUID uuid = UUID.randomUUID();
+        long hash = uuid.hashCode();
+        return (int) (hash & Integer.MAX_VALUE);
+    }
+
+    @GetMapping("/pageList")
+    @Operation(summary = "娉婁綅璁惧鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpEquipment dpEquipmentVO) {
+        return dpEquipmentService.getPageList(dpEquipmentVO);
+    }
+
+    @Operation(summary = "璁惧璇︽儏")
+    @GetMapping("/{id}")
+    public AjaxResult getById(@PathVariable Integer id) {
+        DpEquipmentVO dpEquipmentVO = dpEquipmentService.selectById(id);
+        DpEquipment dpEquipment1 = receiveModuleInfoService.getIp(String.valueOf(dpEquipmentVO.getId()), dpEquipmentVO.getEquipmentTypeId());
+        dpEquipmentVO.setIp(dpEquipment1.getIp());
+        dpEquipmentVO.setPort(dpEquipment1.getPort());
+        dpEquipmentVO.setDeviceAddress(dpEquipment1.getDeviceAddress());
+        return AjaxResult.success(dpEquipmentVO);
+    }
+
+    @GetMapping("/getListByWhId")
+    @Operation(summary = "鏍规嵁鐮佸ごID鑾峰彇璁惧鏍�")
+    public AjaxResult getListByWhId(Integer whId) {
+        List<Tree> treeList = new ArrayList<>();
+        List<DpEquipmentVO> list = dpEquipmentService.getListByWhId(whId);
+        if (null != list) {
+            Map<String, List<DpEquipmentVO>> result = list.stream().collect(Collectors.groupingBy(DpEquipmentVO::getEqutype));
+            treeList = buildTree(result);
+        }
+        //鏍规嵁绯荤粺瀛楀吀鎺掑簭
+        SysDictData sysDictData = new SysDictData();
+        sysDictData.setDictType("dp_equipment_type");
+        List<SysDictData> dictDataList = iSysDictDataService.selectDictDataList(sysDictData);
+        Map<String, Integer> dictSortMap = new HashMap<>();
+        for (SysDictData dictData : dictDataList) {
+            dictSortMap.put(dictData.getDictLabel(), dictData.getDictSort().intValue());
+        }
+        treeList.sort(Comparator.comparingInt(tree -> dictSortMap.getOrDefault(tree.getLabel(), Integer.MAX_VALUE)));
+
+        return AjaxResult.success(treeList);
+    }
+
+    @GetMapping("/getEquipmentsByWhId")
+    @Operation(summary = "鏍规嵁鐮佸ごID鑾峰彇璁惧璇︽儏鍒楄〃")
+    public AjaxResult getEquipmentsByWhId(Integer whId) {
+        List<DpEquipmentVO> list = dpEquipmentService.getListByWhId(whId);
+        List<DpEquipmentVO> resList = new ArrayList<>();
+        resList = equipmentStatusHandling(list);
+
+        return AjaxResult.success(resList);
+    }
+
+    @GetMapping("/getEquipmentsCount")
+    @Operation(summary = "璁惧鐘舵�佹暟閲忕粺璁�")
+    public AjaxResult getEquipmentsCount(Integer whId) {
+        List<DpEquipmentVO> list = dpEquipmentService.getListByWhId(whId);
+        List<DpEquipmentVO> resList = new ArrayList<>();
+        resList = equipmentStatusHandling(list);
+
+        LambdaQueryWrapper<DpEquipmentType> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.orderByAsc(DpEquipmentType::getId);
+        List<DpEquipmentType> typeList = dpEquipmentTypeService.list(lambdaQueryWrapper);
+
+        Map<Integer, List<DpEquipmentVO>> groupMap = resList.stream().collect(Collectors.groupingBy(DpEquipmentVO::getEquipmentTypeId));
+        JSONArray jsonArray = new JSONArray();
+        List<Integer> typeIds = Arrays.asList(1, 2, 3, 4);
+
+        for (Map.Entry<Integer, List<DpEquipmentVO>> entry : groupMap.entrySet()) {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("name", entry.getValue().get(0).getEqutype());
+            Long online = (long) entry.getValue().size();
+            if (typeIds.contains(entry.getKey())) {
+                online = entry.getValue().stream().filter(e -> e.getStatus() == 1).count();
+            }
+            jsonObject.put("online", online);
+            jsonObject.put("total", entry.getValue().size());
+            jsonObject.put("typeId", entry.getKey());
+            jsonArray.add(jsonObject);
+        }
+
+        Set<Integer> typeIDs = groupMap.keySet();
+        for (DpEquipmentType dpEquipmentType : typeList) {
+            if (!typeIDs.contains(dpEquipmentType.getId())) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("name", dpEquipmentType.getTypeName());
+                jsonObject.put("online", 0);
+                jsonObject.put("total", 0);
+                jsonObject.put("typeId", dpEquipmentType.getId());
+                jsonArray.add(jsonObject);
+            }
+        }
+
+        List<JSONObject> objects = jsonArray.toList(JSONObject.class);
+        objects.sort(Comparator.comparingInt(o -> o.getIntValue("typeId")));
+
+        jsonArray.clear();
+        jsonArray.addAll(objects);
+
+        return AjaxResult.success(jsonArray);
+    }
+
+
+    @GetMapping("/getEquipmentsByBeId")
+    @Operation(summary = "鏍规嵁娉婁綅ID鑾峰彇璁惧宸ュ喌淇℃伅")
+    @Hidden
+    public AjaxResult getEquipmentsByBeId(@RequestParam Integer beId, @RequestParam String startTime) {
+        List<DpEquipmentVO> list = dpEquipmentService.getListByBeId(beId);
+        return AjaxResult.success(list);
+    }
+
+    @GetMapping("/getListByBeIdTypeId")
+    @Operation(summary = "鏍规嵁娉婁綅ID鍜岃澶囩被鍨婭D鑾峰彇璁惧淇℃伅鍒楄〃")
+    public AjaxResult getListByBeIdTypeId(@RequestParam Integer beId, @RequestParam Integer typeId) {
+        R<DsTaskList> res = dsTaskListController.getByBeId(beId);
+        DsTaskList dsTaskList = res.getData();
+        Date psTime = dsTaskList.getPsTime();
+        List<Integer> typeIds = new ArrayList<>();
+        if (typeId == 1) {
+            typeIds.add(1);
+            typeIds.add(12);
+            typeIds.add(13);
+            typeIds.add(14);
+        } else {
+            typeIds.add(typeId);
+        }
+        List<DpEquipmentVO> equList = dpEquipmentService.getListByBeIdTypeId(beId, typeIds);
+        List<DpEquipmentVO> voList = new ArrayList<>();
+        for (DpEquipmentVO dpEquipmentVO : equList) {
+            ReceiveValueListVo voEL = new ReceiveValueListVo();
+            voEL.setId(dpEquipmentVO.getId().longValue());
+            voEL.setEndTime(psTime);
+            List dataList = receiveInfoController.dataList(voEL).getData();
+            if (!dataList.isEmpty()) {
+                dpEquipmentVO.setDataHis(dataList.get(0));
+            }
+            voList.add(dpEquipmentVO);
+        }
+        List<DpEquipmentVO> resList = equipmentStatusHandling(voList);
+
+        JSONObject object = new JSONObject();
+        if (!equList.isEmpty()) {
+            ReceiveValueListVo vo = new ReceiveValueListVo();
+            ReceiveValueListVo voNew = new ReceiveValueListVo();
+            vo.setId(equList.get(0).getId().longValue());
+            vo.setEndTime(psTime);
+            voNew.setId(equList.get(0).getId().longValue());
+            List dataList = receiveInfoController.dataList(vo).getData();
+            List dataListNew = receiveInfoController.dataList(voNew).getData();
+            List tableList = receiveInfoController.tableList(vo.getId()).getData();
+            object.put("equList", resList);
+            if (!dataListNew.isEmpty()) {
+                object.put("dataOne", dataListNew.get(0));
+            } else {
+                object.put("dataOne", "");
+            }
+            if (!dataList.isEmpty()) {
+                object.put("dataHis", dataList.get(0));
+            } else {
+                object.put("dataHis", "");
+            }
+            object.put("tableList", tableList);
+        }
+        return AjaxResult.success(object);
+    }
+
+    @GetMapping("/getDataOneById")
+    @Operation(summary = "鏍规嵁ID鑾峰彇鏈�鏂颁竴鏉℃暟鎹�")
+    public AjaxResult getDataOneById(Integer id) {
+        DpEquipmentVO dpEquipmentVO = dpEquipmentService.selectById(id);
+        R<DsTaskList> res = dsTaskListController.getByBeId(dpEquipmentVO.getBeId());
+        DsTaskList dsTaskList = res.getData();
+        Date psTime = dsTaskList.getPsTime();
+        Date peTime = dsTaskList.getPeTime();
+        Integer equTypeId = dpEquipmentVO.getEquipmentTypeId();
+
+        ReceiveValueListVo vo = new ReceiveValueListVo();
+        vo.setId(id.longValue());
+        vo.setStartTime(psTime);
+        vo.setEndTime(peTime);
+        JSONObject object = new JSONObject();
+        List dataList = receiveInfoController.dataList(vo).getData();
+        List tableList = receiveInfoController.tableList(vo.getId()).getData();
+        if (dataList.size() > 0) {
+            object.put("dataOne", dataList.get(0));
+            object.put("equUpTime", getEquUptime(dataList, equTypeId));
+        } else {
+            object.put("dataOne", new JSONObject());
+            object.put("equUpTime", null);
+        }
+        object.put("tableList", tableList);
+        return AjaxResult.success(object);
+    }
+
+    private List<DpEquipmentVO> equipmentStatusHandling(List<DpEquipmentVO> list) {
+
+        List<DpEquipmentVO> resList = new ArrayList<>();
+        Map<String, Integer> onlineMap = new LinkedHashMap<>();
+        ArrayList<String> arrayList = new ArrayList<>();
+
+        for (DpEquipmentVO equipmentVO : list) {
+            Integer typeId = equipmentVO.getEquipmentTypeId();
+            if (typeId == 4 && equipmentVO.getFieldName() != null && !equipmentVO.getFieldName().isEmpty()) {
+                arrayList.add(equipmentVO.getFieldName());
+            }
+        }
+        String[] indexCodes = arrayList.toArray(new String[arrayList.size()]);
+        onlineMap = hikService.getCameraOnline(indexCodes);
+        for (DpEquipmentVO dpEquipmentVO : list) {
+            Integer typeId = dpEquipmentVO.getEquipmentTypeId();
+            Integer id = dpEquipmentVO.getId();
+            if (DataTypeEnum.LIJIUOIL.getCode().equals(typeId) || DataTypeEnum.OIL.getCode().equals(typeId) ||
+                    DataTypeEnum.LIJIUJUN.getCode().equals(typeId)) {
+                ReceiveOilValue receiveOilValue = receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+                    or().eq(ReceiveOilValue::getDeviceName, String.valueOf(id))
+                            .orderByDesc(ReceiveOilValue::getCreateTime).last("LIMIT 1");
+                }});
+                if (receiveOilValue != null && receiveOilValue.getOilTimeFlow() != null) {
+                    if (Double.parseDouble(receiveOilValue.getOilTimeFlow()) != 0.0) {
+                        dpEquipmentVO.setStatus(1);
+                    }
+                }
+
+            } else if (DataTypeEnum.WATER_FLOW.getCode().equals(typeId) || DataTypeEnum.WATER_YA.getCode().equals(typeId)
+                    || DataTypeEnum.WATER_DEPT.getCode().equals(typeId)) {
+                ReceiveWaterValue receiveWaterValue = receiveWaterValueService.getOne(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+                    or().eq(ReceiveWaterValue::getDeviceName, String.valueOf(id))
+                            .orderByDesc(ReceiveWaterValue::getCreateTime).last("LIMIT 1");
+                }});
+                if (receiveWaterValue != null && receiveWaterValue.getTimeFlow() != null) {
+                    if (Double.parseDouble(receiveWaterValue.getTimeFlow()) != 0.0) {
+                        dpEquipmentVO.setStatus(1);
+                    }
+                }
+
+            } else if (DataTypeEnum.ELECTRICITY.getCode().equals(typeId)) {
+                ReceiveElectricityValue receiveElectricityValue = receiveElectricityValueService.getOne(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+                    or().eq(ReceiveElectricityValue::getDeviceName, String.valueOf(id))
+                            .orderByDesc(ReceiveElectricityValue::getCreateTime).last("LIMIT 1");
+                }});
+                if (receiveElectricityValue != null && receiveElectricityValue.getCurrentA() != null
+                        && receiveElectricityValue.getCurrentB() != null && receiveElectricityValue.getCurrentC() != null) {
+                    if (Double.parseDouble(receiveElectricityValue.getCurrentA()) != 0.0 || Double.parseDouble(receiveElectricityValue.getCurrentB()) != 0.0
+                            || Double.parseDouble(receiveElectricityValue.getCurrentC()) != 0.0) {
+                        dpEquipmentVO.setStatus(1);
+                    }
+                }
+
+            } else if (typeId == 4) {
+                Integer status = onlineMap.getOrDefault(dpEquipmentVO.getFieldName(), 0);
+                dpEquipmentVO.setStatus(status);
+            }
+            resList.add(dpEquipmentVO);
+        }
+        return resList;
+    }
+
+    private String getEquUptime(List dataList, Integer equTypeId) {
+        Integer size = dataList.size();
+        if (equTypeId == 1 || equTypeId == 12 || equTypeId == 13 || equTypeId == 14) {
+            for (int i = size - 1; i >= 0; i--) {
+                ReceiveOilValue receiveOilValue = (ReceiveOilValue) dataList.get(i);
+                if (receiveOilValue.getOilTimeFlow() != null
+                        && Double.parseDouble(receiveOilValue.getOilTimeFlow()) != 0.0) {
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    String timeStr = sdf.format(receiveOilValue.getCreateTime());
+                    return timeCalculator(timeStr);
+                }
+            }
+        } else if (equTypeId == 2) {
+            for (int k = size - 1; k >= 0; k--) {
+                ReceiveWaterValue receiveWaterValue = (ReceiveWaterValue) dataList.get(k);
+                if (receiveWaterValue.getTimeFlow() != null
+                        && Double.parseDouble(receiveWaterValue.getTimeFlow()) != 0.0) {
+                    SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+                    String timeStr = sdf.format(receiveWaterValue.getCreateTime());
+                    return timeCalculator(timeStr);
+                }
+            }
+        }
+        return null;
+    }
+
+    private String timeCalculator(String timeStr) {
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDateTime dateTime = LocalDateTime.parse(timeStr, formatter);
+        LocalDateTime now = LocalDateTime.now();
+        Duration duration = Duration.between(dateTime, now);
+        long total = Math.abs(duration.toMinutes());
+        long hour = total / 60;
+        long minutes = total % 60;
+        return hour + "灏忔椂" + minutes + "鍒嗛挓";
+    }
+
+    @GetMapping("/getXyzById")
+    @Operation(summary = "鏍规嵁ID鑾峰彇璁惧璇︽儏")
+    public AjaxResult getXyzById(Integer id) {
+        DpEquipment dpEquipment = dpEquipmentService.getById(id);
+        DpEquipment dpEquipment1 = receiveModuleInfoService.getIp(String.valueOf(dpEquipment.getId()), dpEquipment.getEquipmentTypeId());
+        dpEquipment.setIp(dpEquipment1.getIp());
+        dpEquipment.setPort(dpEquipment1.getPort());
+        dpEquipment.setDeviceAddress(dpEquipment1.getDeviceAddress());
+        return AjaxResult.success(dpEquipment);
+    }
+
+    //鑾峰彇璁惧鏁版嵁涓庤〃澶�
+    @PostMapping("/getDataById")
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁涓庤〃澶�")
+    public AjaxResult getDataById(@Validated @RequestBody ReceiveValueListVo vo) {
+        List dataList = receiveInfoController.dataList(vo).getData();
+        List tableList = receiveInfoController.tableList(vo.getId()).getData();
+        JSONObject object = new JSONObject();
+        object.put("dataList", dataList);
+        object.put("tableList", tableList);
+        return AjaxResult.success(object);
+    }
+
+    //鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)
+    @PostMapping("/getPageListById")
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)")
+    public AjaxResult getPageListById(@Validated @RequestBody ReceiveValueListVo vo) {
+        List dataList = receiveInfoController.dataList(vo).getData();
+        List tableList = receiveInfoController.tableList(vo.getId()).getData();
+
+        List sampledList = new ArrayList();
+        for (int i = 0; i < dataList.size(); i++) {
+            if (i % 5 == 0) {
+                sampledList.add(dataList.get(i));
+            }
+        }
+        TableDataInfo dataInfo = paginate(sampledList, vo.getPageNum(), vo.getPageSize());
+
+//        TableDataInfo dataInfo = paginate(dataList, vo.getPageNum(), vo.getPageSize());
+        JSONObject object = new JSONObject();
+        object.put("dataList", dataInfo);
+        object.put("tableList", tableList);
+        return AjaxResult.success(object);
+    }
+
+    //鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)
+    @PostMapping("/getPageListByIdRuoyi")
+    @Operation(summary = "鑾峰彇璁惧鏁版嵁涓庤〃澶�(鍒嗛〉)")
+    public AjaxResult getPageListByIdRuoyi(@Validated @RequestBody ReceiveValueListVo vo) {
+        List dataList = receiveInfoController.dataList(vo).getData();
+        List tableList = receiveInfoController.tableList(vo.getId()).getData();
+
+        TableDataInfo dataInfo = paginate(dataList, vo.getPageNum(), vo.getPageSize());
+        JSONObject object = new JSONObject();
+        object.put("dataList", dataInfo);
+        object.put("tableList", tableList);
+        return AjaxResult.success(object);
+    }
+
+
+    /**
+     * 鏂板娉婁綅--璁惧
+     */
+    @Operation(summary = "鏂板")
+    @PostMapping
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult add(@RequestBody DpEquipment dpEquipment) {
+        dpEquipment.setEquSeType(dpEquipment.getEquipmentTypeId());
+        dpEquipmentService.save(dpEquipment);
+        receiveModuleInfoService.saveByModule(String.valueOf(dpEquipment.getId()), dpEquipment.getIp(), dpEquipment.getPort(), dpEquipment.getDeviceAddress(), dpEquipment.getEquipmentTypeId());
+        return toAjax(true);
+    }
+
+    /**
+     * 淇敼娉婁綅--璁惧
+     */
+    @Operation(summary = "淇敼")
+    @PutMapping
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult edit(@RequestBody DpEquipment dpEquipment) {
+        DpEquipment equipment = dpEquipmentService.getById(dpEquipment.getId());
+        if (equipment == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        receiveModuleInfoService.removeByModule(String.valueOf(equipment.getId()), equipment.getEquipmentTypeId());
+        dpEquipment.setEquSeType(dpEquipment.getEquipmentTypeId());
+        dpEquipmentService.updateById(dpEquipment);
+        receiveModuleInfoService.saveByModule(String.valueOf(dpEquipment.getId()), dpEquipment.getIp(), dpEquipment.getPort(), dpEquipment.getDeviceAddress(), dpEquipment.getEquipmentTypeId());
+        return toAjax(true);
+    }
+
+    /**
+     * 鍒犻櫎娉婁綅--璁惧
+     */
+    @Operation(summary = "鍒犻櫎")
+    @Transactional(rollbackFor = Exception.class)
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id) {
+        DpEquipment equipment = dpEquipmentService.getById(id);
+        if (equipment == null) {
+            throw new ServiceException("璁惧涓嶅瓨鍦紒");
+        }
+        receiveModuleInfoService.removeByModule(String.valueOf(equipment), equipment.getEquipmentTypeId());
+        return toAjax(dpEquipmentService.removeById(id));
+    }
+
+    //澶氭潯浠舵煡璇㈣澶囧垪琛�
+    public List<DpEquipmentVO> queryDpEquipmentList(Integer beId, Integer typeId) {
+        List<Integer> typeIds = new ArrayList<>();
+        if (typeId == 1) {
+            typeIds.add(1);
+            typeIds.add(12);
+            typeIds.add(13);
+            typeIds.add(14);
+        } else {
+            typeIds.add(typeId);
+        }
+        List<DpEquipmentVO> equList = dpEquipmentService.getListByBeIdTypeId(beId, typeIds);
+        return equList;
+    }
+
+    //澶氭潯浠舵煡璇㈡按娣辨�佸娍鍒嗘瀽鏁版嵁
+    @PostMapping("/queryWaterDeepAnalysis")
+    @Operation(summary = "澶氭潯浠舵煡璇㈡按娣辨�佸娍鍒嗘瀽鏁版嵁")
+    public AjaxResult queryWaterDeepAnalysis(@Validated @RequestBody QueryAnalysisVO queryAnalysisVO) {
+        List<String> ids = new ArrayList<>();
+        Integer beId = queryAnalysisVO.getBeId();
+        List<DpEquipmentVO> equList = queryDpEquipmentList(beId, 7);
+
+        JSONArray jsonArray = new JSONArray();
+        if (equList.size() > 0) {
+            for (DpEquipmentVO dpEquipmentVO : equList) {
+                ids.add(String.valueOf(dpEquipmentVO.getId()));
+            }
+
+            LambdaQueryWrapper<ReceiveWaterValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+            Date startTime = queryAnalysisVO.getStartTime();
+            Date endTime = queryAnalysisVO.getEndTime();
+            Integer interval = queryAnalysisVO.getInterval();
+
+            Map<String, Date> timeMap = new LinkedHashMap<>();
+            LocalDate endDate = LocalDate.now();
+            LocalDate startDate = LocalDate.now().minusDays(interval);
+
+            if (startTime != null && endTime != null) {
+                timeMap = convertStartEndTime(startTime, endTime);
+                startDate = convertDate(timeMap.get("start")).toLocalDate();
+                endDate = convertDate(timeMap.get("end")).toLocalDate();
+            } else {
+                timeMap = getStartEndTime(interval);
+            }
+
+            lambdaQueryWrapper.in(ReceiveWaterValue::getDeviceName, ids)
+                    .ge(ReceiveWaterValue::getCreateTime, timeMap.get("start"))
+                    .lt(ReceiveWaterValue::getCreateTime, timeMap.get("end"))
+                    .orderByDesc(ReceiveWaterValue::getCreateTime);
+            List<ReceiveWaterValue> waterValues = receiveWaterValueService.list(lambdaQueryWrapper);
+
+            List<LocalDate> dateRange = startDate.datesUntil(endDate.plusDays(1)).collect(Collectors.toList());
+
+            Map<LocalDate, List<ReceiveWaterValue>> groups = new LinkedHashMap<>();
+            for (LocalDate localDate : dateRange) {
+                groups.put(localDate, new ArrayList<>());
+            }
+            for (ReceiveWaterValue receiveWaterValue : waterValues) {
+                LocalDateTime localDateTime = convertDate(receiveWaterValue.getCreateTime());
+                LocalDate localDate = localDateTime.toLocalDate();
+                groups.computeIfPresent(localDate, (key, list) -> {
+                    list.add(receiveWaterValue);
+                    return list;
+                });
+            }
+
+            for (Map.Entry<LocalDate, List<ReceiveWaterValue>> entry : groups.entrySet()) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("date", entry.getKey());
+                jsonObject.put("avg", "0.0");
+                jsonObject.put("dif", "0.0");
+                if (entry.getValue().size() > 0) {
+                    Map<String, Double> map = waterDeepMaxMin(entry.getValue());
+                    Double max = map.get("max");
+                    Double min = map.get("min");
+                    jsonObject.put("avg", String.format("%.3f", (max + min) / 2));
+                    jsonObject.put("dif", String.format("%.3f", (max - min)));
+                }
+                jsonArray.add(jsonObject);
+            }
+        }
+        return AjaxResult.success(jsonArray);
+    }
+
+    private LocalDateTime convertDate(Date date) {
+        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDateTime();
+    }
+
+    private Map<String, Date> convertStartEndTime(Date startTime, Date endTime) {
+        SimpleDateFormat timeSDF = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        SimpleDateFormat dateSDF = new SimpleDateFormat("yyyy-MM-dd");
+
+        String dateStartStr = dateSDF.format(startTime);
+        String dateEndStr = dateSDF.format(endTime);
+
+        String startTimeStr = " 00:00:00";
+        String endTimeStr = " 23:59:59";
+
+        String newStartStr = dateStartStr + startTimeStr;
+        String newEndStr = dateEndStr + endTimeStr;
+
+        Map<String, Date> map = new LinkedHashMap<>();
+        try {
+            Date start = timeSDF.parse(newStartStr);
+            Date end = timeSDF.parse(newEndStr);
+            map.put("start", start);
+            map.put("end", end);
+        } catch (Exception e) {
+            System.out.println(e.getMessage());
+        }
+
+        return map;
+    }
+
+    private Map<String, Date> getStartEndTime(Integer interval) {
+        LocalDate endDate = LocalDate.now();
+        LocalDate startDate = LocalDate.now().minusDays(interval);
+        String startTime = " 00:00:00";
+        String endTime = " 23:59:59";
+        DateTimeFormatter formatterDate = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter formatterTime = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        String startStr = startDate.format(formatterDate) + startTime;
+        String endStr = endDate.format(formatterDate) + endTime;
+        LocalDateTime localDateTimeStart = LocalDateTime.parse(startStr, formatterTime);
+        LocalDateTime localDateTimeEnd = LocalDateTime.parse(endStr, formatterTime);
+        Instant instantStart = localDateTimeStart.atZone(ZoneId.systemDefault()).toInstant();
+        Instant instantEnd = localDateTimeEnd.atZone(ZoneId.systemDefault()).toInstant();
+        Date start = Date.from(instantStart);
+        Date end = Date.from(instantEnd);
+
+        Map<String, Date> map = new HashMap<>();
+        map.put("start", start);
+        map.put("end", end);
+        return map;
+    }
+
+    private Map<String, Double> waterDeepMaxMin(List<ReceiveWaterValue> list) {
+        OptionalDouble max = list.stream()
+                .mapToDouble(e -> Double.parseDouble(e.getWaterDeep()))
+                .max();
+        OptionalDouble min = list.stream()
+                .mapToDouble(e -> Double.parseDouble(e.getWaterDeep()))
+                .min();
+        Map<String, Double> map = new HashMap<>();
+        map.put("max", max.orElse(0.0));
+        map.put("min", min.orElse(0.0));
+        return map;
+    }
+
+    private Double convertString(String str) {
+        if (str == null || str.trim().isEmpty()) {
+            return 0.0;
+        }
+        if (str.matches(".*[eE].*")) {
+            return 0.0;
+        }
+        try {
+            double value = Double.parseDouble(str);
+            return Math.abs(value);
+        } catch (Exception e) {
+            return 0.0;
+        }
+    }
+
+    //澶氭潯浠舵煡璇㈢數琛ㄦ�佸娍鍒嗘瀽鏁版嵁
+    @PostMapping("/queryElectricityAnalysis")
+    @Operation(summary = "澶氭潯浠舵煡璇㈢數琛ㄦ�佸娍鍒嗘瀽鏁版嵁")
+    public AjaxResult queryElectricityAnalysis(@Validated @RequestBody QueryAnalysisVO queryAnalysisVO) {
+        List<String> ids = new ArrayList<>();
+        Integer beId = queryAnalysisVO.getBeId();
+        List<DpEquipmentVO> equList = queryDpEquipmentList(beId, 3);
+
+        JSONArray jsonArray = new JSONArray();
+        if (equList.size() > 0) {
+            for (DpEquipmentVO dpEquipmentVO : equList) {
+                ids.add(String.valueOf(dpEquipmentVO.getId()));
+            }
+
+            LambdaQueryWrapper<ReceiveElectricityValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+            Date startTime = queryAnalysisVO.getStartTime();
+            Date endTime = queryAnalysisVO.getEndTime();
+            Integer interval = queryAnalysisVO.getInterval();
+
+            Map<String, Date> timeMap = new LinkedHashMap<>();
+            LocalDate endDate = LocalDate.now();
+            LocalDate startDate = LocalDate.now().minusDays(interval);
+
+            if (startTime != null && endTime != null) {
+                timeMap = convertStartEndTime(startTime, endTime);
+                startDate = convertDate(timeMap.get("start")).toLocalDate();
+                endDate = convertDate(timeMap.get("end")).toLocalDate();
+            } else {
+                timeMap = getStartEndTime(interval);
+            }
+
+            lambdaQueryWrapper.in(ReceiveElectricityValue::getDeviceName, ids)
+                    .ge(ReceiveElectricityValue::getCreateTime, timeMap.get("start"))
+                    .lt(ReceiveElectricityValue::getCreateTime, timeMap.get("end"))
+                    .orderByDesc(ReceiveElectricityValue::getCreateTime);
+            List<ReceiveElectricityValue> electricityValues = receiveElectricityValueService.list(lambdaQueryWrapper);
+
+            List<LocalDate> dateRange = startDate.datesUntil(endDate.plusDays(1)).collect(Collectors.toList());
+
+            Map<LocalDate, List<ReceiveElectricityValue>> groups = new LinkedHashMap<>();
+            for (LocalDate localDate : dateRange) {
+                groups.put(localDate, new ArrayList<>());
+            }
+            for (ReceiveElectricityValue receiveElectricityValue : electricityValues) {
+                LocalDateTime localDateTime = convertDate(receiveElectricityValue.getCreateTime());
+                LocalDate localDate = localDateTime.toLocalDate();
+                groups.computeIfPresent(localDate, (key, list) -> {
+                    list.add(receiveElectricityValue);
+                    return list;
+                });
+            }
+
+            for (Map.Entry<LocalDate, List<ReceiveElectricityValue>> entry : groups.entrySet()) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("date", entry.getKey());
+                jsonObject.put("avg", "0.0");
+                if (entry.getValue().size() > 0) {
+                    List<ReceiveElectricityValue> valueList = entry.getValue();
+                    Integer size = valueList.size();
+                    Double total = 0.0;
+                    for (ReceiveElectricityValue receiveElectricityValue : valueList) {
+                        Double zhengValue = convertString(receiveElectricityValue.getZhengPower());
+                        total = total + zhengValue;
+                    }
+                    jsonObject.put("avg", String.format("%.3f", total / size));
+                }
+                jsonArray.add(jsonObject);
+            }
+        }
+        return AjaxResult.success(jsonArray);
+    }
+
+
+    //澶氭潯浠舵煡璇㈡补琛ㄦ�佸娍鍒嗘瀽鏁版嵁
+    @PostMapping("/queryOilAnalysis")
+    @Operation(summary = "澶氭潯浠舵煡璇㈡补琛ㄦ�佸娍鍒嗘瀽鏁版嵁")
+    public AjaxResult queryOilAnalysis(@Validated @RequestBody QueryAnalysisVO queryAnalysisVO) {
+        List<String> ids = new ArrayList<>();
+        Integer beId = queryAnalysisVO.getBeId();
+        List<DpEquipmentVO> equList = queryDpEquipmentList(beId, 1);
+
+        JSONArray jsonArray = new JSONArray();
+        if (equList.size() > 0) {
+            for (DpEquipmentVO dpEquipmentVO : equList) {
+                ids.add(String.valueOf(dpEquipmentVO.getId()));
+            }
+
+            LambdaQueryWrapper<ReceiveOilValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+            Date startTime = queryAnalysisVO.getStartTime();
+            Date endTime = queryAnalysisVO.getEndTime();
+            Integer interval = queryAnalysisVO.getInterval();
+
+            Map<String, Date> timeMap = new LinkedHashMap<>();
+            LocalDate endDate = LocalDate.now();
+            LocalDate startDate = LocalDate.now().minusDays(interval);
+
+            if (startTime != null && endTime != null) {
+                timeMap = convertStartEndTime(startTime, endTime);
+                startDate = convertDate(timeMap.get("start")).toLocalDate();
+                endDate = convertDate(timeMap.get("end")).toLocalDate();
+            } else {
+                timeMap = getStartEndTime(interval);
+            }
+
+            lambdaQueryWrapper.in(ReceiveOilValue::getDeviceName, ids)
+                    .ge(ReceiveOilValue::getCreateTime, timeMap.get("start"))
+                    .lt(ReceiveOilValue::getCreateTime, timeMap.get("end"))
+                    .orderByDesc(ReceiveOilValue::getCreateTime);
+            List<ReceiveOilValue> oilValues = receiveOilValueService.list(lambdaQueryWrapper);
+
+            List<LocalDate> dateRange = startDate.datesUntil(endDate.plusDays(1)).collect(Collectors.toList());
+
+            Map<LocalDate, List<ReceiveOilValue>> groups = new LinkedHashMap<>();
+            for (LocalDate localDate : dateRange) {
+                groups.put(localDate, new ArrayList<>());
+            }
+            for (ReceiveOilValue receiveOilValue : oilValues) {
+                LocalDateTime localDateTime = convertDate(receiveOilValue.getCreateTime());
+                LocalDate localDate = localDateTime.toLocalDate();
+                groups.computeIfPresent(localDate, (key, list) -> {
+                    list.add(receiveOilValue);
+                    return list;
+                });
+            }
+
+            for (Map.Entry<LocalDate, List<ReceiveOilValue>> entry : groups.entrySet()) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("date", entry.getKey());
+                jsonObject.put("avg", "0.0");
+                if (entry.getValue().size() > 0) {
+                    List<ReceiveOilValue> valueList = entry.getValue();
+                    Integer size = valueList.size();
+                    Double total = 0.0;
+                    for (ReceiveOilValue receiveOilValue : valueList) {
+                        Double flowTotalValue = convertString(receiveOilValue.getFlowTotal());
+                        total = total + flowTotalValue;
+                    }
+                    jsonObject.put("avg", String.format("%.3f", total / size));
+                }
+                jsonArray.add(jsonObject);
+            }
+        }
+
+        return AjaxResult.success(jsonArray);
+    }
+
+    //澶氭潯浠舵煡璇㈡按琛ㄦ�佸娍鍒嗘瀽鏁版嵁
+    @PostMapping("/queryWaterAnalysis")
+    @Operation(summary = "澶氭潯浠舵煡璇㈡按琛ㄦ�佸娍鍒嗘瀽鏁版嵁")
+    public AjaxResult queryWaterAnalysis(@Validated @RequestBody QueryAnalysisVO queryAnalysisVO) {
+        List<String> ids = new ArrayList<>();
+        Integer beId = queryAnalysisVO.getBeId();
+        List<DpEquipmentVO> equList = queryDpEquipmentList(beId, 2);
+
+        JSONArray jsonArray = new JSONArray();
+        if (equList.size() > 0) {
+            for (DpEquipmentVO dpEquipmentVO : equList) {
+                ids.add(String.valueOf(dpEquipmentVO.getId()));
+            }
+
+            LambdaQueryWrapper<ReceiveWaterValue> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+            Date startTime = queryAnalysisVO.getStartTime();
+            Date endTime = queryAnalysisVO.getEndTime();
+            Integer interval = queryAnalysisVO.getInterval();
+
+            Map<String, Date> timeMap = new LinkedHashMap<>();
+            LocalDate endDate = LocalDate.now();
+            LocalDate startDate = LocalDate.now().minusDays(interval);
+
+            if (startTime != null && endTime != null) {
+                timeMap = convertStartEndTime(startTime, endTime);
+                startDate = convertDate(timeMap.get("start")).toLocalDate();
+                endDate = convertDate(timeMap.get("end")).toLocalDate();
+            } else {
+                timeMap = getStartEndTime(interval);
+            }
+
+            lambdaQueryWrapper.in(ReceiveWaterValue::getDeviceName, ids)
+                    .ge(ReceiveWaterValue::getCreateTime, timeMap.get("start"))
+                    .lt(ReceiveWaterValue::getCreateTime, timeMap.get("end"))
+                    .orderByDesc(ReceiveWaterValue::getCreateTime);
+            List<ReceiveWaterValue> waterValues = receiveWaterValueService.list(lambdaQueryWrapper);
+
+            List<LocalDate> dateRange = startDate.datesUntil(endDate.plusDays(1)).collect(Collectors.toList());
+
+            Map<LocalDate, List<ReceiveWaterValue>> groups = new LinkedHashMap<>();
+            for (LocalDate localDate : dateRange) {
+                groups.put(localDate, new ArrayList<>());
+            }
+            for (ReceiveWaterValue receiveWaterValue : waterValues) {
+                LocalDateTime localDateTime = convertDate(receiveWaterValue.getCreateTime());
+                LocalDate localDate = localDateTime.toLocalDate();
+                groups.computeIfPresent(localDate, (key, list) -> {
+                    list.add(receiveWaterValue);
+                    return list;
+                });
+            }
+
+            for (Map.Entry<LocalDate, List<ReceiveWaterValue>> entry : groups.entrySet()) {
+                JSONObject jsonObject = new JSONObject();
+                jsonObject.put("date", entry.getKey());
+                jsonObject.put("avg", "0.0");
+                if (entry.getValue().size() > 0) {
+                    List<ReceiveWaterValue> valueList = entry.getValue();
+                    Integer size = valueList.size();
+                    Double total = 0.0;
+                    for (ReceiveWaterValue receiveWaterValue : valueList) {
+                        Double zhengTotalValue = convertString(receiveWaterValue.getZhengTotal());
+                        total = total + zhengTotalValue;
+                    }
+                    jsonObject.put("avg", String.format("%.3f", total / size));
+                }
+                jsonArray.add(jsonObject);
+            }
+        }
+
+        return AjaxResult.success(jsonArray);
+    }
+
+    /**
+     * 涓嬪彂json鏂囦欢
+     */
+    @PostMapping("/uploadFile")
+    @Operation(summary = "涓嬪彂json鏂囦欢")
+    public AjaxResult uploadFile(@RequestBody JSONArray json,
+                                 @RequestParam(value = "name") String name) {
+        SysFileManage sysFileManage = new SysFileManage();
+        sysFileManage.setName(name + "_" + System.currentTimeMillis());
+        sysFileManage.setType("json");
+        sysFileManage.setExt("json");
+        String filePath = ruoYiConfig.getJson() + "/" + sysFileManage.getName() + ".json";
+        String path = "/profile/" + sysFileManage.getName() + ".json";
+        sysFileManage.setFilePath(path);
+        try {
+            File file = new File(filePath);
+            file.createNewFile();
+            String jsonStr = JSON.toJSONString(json);
+
+            Writer writer = new OutputStreamWriter(new FileOutputStream(file), "UTF-8");
+            writer.write(jsonStr);
+            writer.flush();
+            writer.close();
+
+            return AjaxResult.success(sysFileService.saveData(sysFileManage));
+        } catch (Exception e) {
+            return AjaxResult.error(e.getMessage());
+        }
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+
+
+    @GetMapping("/getYdkfm")
+    @Operation(summary = "鑾峰彇娌圭數鎺ч榾闂�")
+    public AjaxResult getYdkfm(Integer id) throws Exception {
+        if (null == id || id < 0L) return AjaxResult.error("id涓虹┖");
+        DpEquipmentVO dpEquipmentVO = dpEquipmentService.selectById(id);
+        DpEquipment dp = receiveModuleInfoService.getIp(String.valueOf(dpEquipmentVO.getId()), dpEquipmentVO.getEquipmentTypeId());
+
+        DpEquipment eq = dpEquipmentService.getEpByField(String.valueOf(dp.getPort()));
+        if (null == eq || null == eq.getId()) return AjaxResult.error("鎵句笉鍒版补鐢垫帶闃�闂�");
+
+        Map<String, Object> map = receiveModuleInfoService.getYdkfmStatus(String.valueOf(eq.getId()));
+        return success(map);
+    }
+
+    @GetMapping("/ctrlYdkfm")
+    @Operation(summary = "鎺у埗娌圭數鎺ч榾闂�")
+    public AjaxResult ctrlYdkfm(Integer id, Boolean flag) throws Exception {
+        if (null == id || id < 0L) return AjaxResult.error("id涓虹┖");
+        if (null == flag) return AjaxResult.error("flag涓虹┖");
+
+        DpEquipmentVO dpEquipmentVO = dpEquipmentService.selectById(id);
+        DpEquipment dp = receiveModuleInfoService.getIp(String.valueOf(dpEquipmentVO.getId()), dpEquipmentVO.getEquipmentTypeId());
+
+        DpEquipment eq = dpEquipmentService.getEpByField(String.valueOf(dp.getPort()));
+        if (null == eq || null == eq.getId()) return AjaxResult.error("鎵句笉鍒版补鐢垫帶闃�闂�");
+
+        Map<String, Object> map = receiveModuleInfoService.ctrlYdkfm(String.valueOf(eq.getId()), flag);
+        return success(map);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentTypeController.java
new file mode 100644
index 0000000..cc031b0
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpEquipmentTypeController.java
@@ -0,0 +1,73 @@
+package com.ruoyi.web.controller.manage;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpEquipmentType;
+import com.ruoyi.manage.service.DpEquipmentTypeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 璁惧绫诲瀷琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@RestController
+@RequestMapping("/dp/dpEquipmentType")
+@Tag(name = "澶у睆--璁惧绫诲瀷绠$悊")
+public class DpEquipmentTypeController {
+    @Autowired
+    private DpEquipmentTypeService dpEquipmentTypeService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰彇璁惧绫诲瀷鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpEquipmentTypeService.list());
+    }
+
+
+
+    @GetMapping("/pageList")
+    @Operation(summary = "璁惧绫诲瀷鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpEquipmentType dpEquipmentType) {
+        return dpEquipmentTypeService.getPageList(dpEquipmentType);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇璁惧绫诲瀷璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpEquipmentTypeService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpEquipmentType dpEquipmentType)
+    {
+        return AjaxResult.success(dpEquipmentTypeService.save(dpEquipmentType));
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpEquipmentType dpEquipmentType)
+    {
+        return AjaxResult.success(dpEquipmentTypeService.updateById(dpEquipmentType));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpEquipmentTypeService.removeById(id));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidTaskController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidTaskController.java
new file mode 100644
index 0000000..fa0cf91
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidTaskController.java
@@ -0,0 +1,78 @@
+package com.ruoyi.web.controller.manage;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidTask;
+import com.ruoyi.fuzhou.domain.OpenWZ;
+import com.ruoyi.fuzhou.service.DpRfidTaskService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID浠诲姟琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-25
+ */
+@RestController
+@RequestMapping("/dp/dpRfidTask")
+@Tag(name = "澶у睆--RFID浠诲姟鏁版嵁")
+public class DpRfidTaskController {
+    @Autowired
+    private DpRfidTaskService dpRfidTaskService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰彇RFID浠诲姟鏁版嵁鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpRfidTaskService.list());
+    }
+
+    @Operation(summary = "RFID浠诲姟鏁版嵁鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpRfidTask dpRfidTask) {
+        return dpRfidTaskService.getPageList(dpRfidTask);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇RFID浠诲姟鏁版嵁璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpRfidTaskService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpRfidTask dpRfidTask)
+    {
+        List<OpenWZ> openWZS = dpRfidTask.getWzData();
+        dpRfidTask.setWzDataStr(JSON.toJSONString(openWZS));
+        dpRfidTask.setWzData(null);
+        return AjaxResult.success(dpRfidTaskService.save(dpRfidTask));
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpRfidTask dpRfidTask)
+    {
+        return AjaxResult.success(dpRfidTaskService.updateById(dpRfidTask));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpRfidTaskService.removeById(id));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidVehicleController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidVehicleController.java
new file mode 100644
index 0000000..075e4b2
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpRfidVehicleController.java
@@ -0,0 +1,113 @@
+package com.ruoyi.web.controller.manage;
+
+import com.alibaba.fastjson2.JSON;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidVehicle;
+import com.ruoyi.fuzhou.domain.OpenWZ;
+import com.ruoyi.fuzhou.domain.vo.RfidVehicleVO;
+import com.ruoyi.fuzhou.service.DpRfidVehicleService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID杞﹁締璁板綍琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-21
+ */
+@RestController
+@RequestMapping("/dp/dpRfidVehicle")
+@Tag(name = "澶у睆--杞﹁締RFID鏁版嵁")
+public class DpRfidVehicleController {
+    @Autowired
+    private DpRfidVehicleService dpRfidVehicleService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰彇杞﹁締RFID鏁版嵁鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpRfidVehicleService.list());
+    }
+
+    @GetMapping("/selectByTime")
+    @Operation(summary = "鏍规嵁鏃堕棿娈垫煡璇㈡暟鎹�")
+    public AjaxResult selectByTime(@RequestParam String startTime,@RequestParam String endTime){
+        LambdaQueryWrapper<DpRfidVehicle> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.ge(DpRfidVehicle::getPassTime,startTime)
+                .le(DpRfidVehicle::getPassTime,endTime)
+                .orderByDesc(DpRfidVehicle::getPassTime);
+        return AjaxResult.success(
+                dpRfidVehicleService.list(lambdaQueryWrapper));
+    }
+
+    @GetMapping("/selectByNodeNum")
+    @Operation(summary = "鏍规嵁缁堢ID鏌ヨ鏁版嵁")
+    public AjaxResult selectByNodeNum(@RequestParam String nodeNum){
+        LambdaQueryWrapper<DpRfidVehicle> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(DpRfidVehicle::getSn,nodeNum)
+                .orderByDesc(DpRfidVehicle::getPassTime);
+        return AjaxResult.success(dpRfidVehicleService.list(lambdaQueryWrapper));
+    }
+
+    @PostMapping("/selectRfidVehicle")
+    @Operation(summary = "鏉′欢鏌ヨRFID杞﹁締鏁版嵁")
+    public AjaxResult selectRfidVehicle(@RequestBody RfidVehicleVO rfidVehicleVO){
+        return AjaxResult.success(dpRfidVehicleService.selectRfidVehicle(rfidVehicleVO));
+    }
+
+    @GetMapping("/QueryVehicleByTask/{task}")
+    @Operation(summary = "鏍规嵁rfid浠诲姟鏌ヨRFID杞﹁締鏁版嵁")
+    public AjaxResult QueryVehicleByTask(@PathVariable("task") String task){
+        return AjaxResult.success(dpRfidVehicleService.QueryVehicleByTask(task));
+    }
+
+
+    @Operation(summary = "杞﹁締RFID鏁版嵁鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpRfidVehicle dpRfidVehicle) {
+        return dpRfidVehicleService.getPageList(dpRfidVehicle);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇杞﹁締RFID鏁版嵁璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpRfidVehicleService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpRfidVehicle dpRfidVehicle)
+    {
+        List<OpenWZ> openWZS = dpRfidVehicle.getWzData();
+        dpRfidVehicle.setWzDataStr(JSON.toJSONString(openWZS));
+        dpRfidVehicle.setWzData(null);
+        return AjaxResult.success(dpRfidVehicleService.save(dpRfidVehicle));
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpRfidVehicle dpRfidVehicle)
+    {
+        return AjaxResult.success(dpRfidVehicleService.updateById(dpRfidVehicle));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpRfidVehicleService.removeById(id));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipDeviceController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipDeviceController.java
new file mode 100644
index 0000000..a6a7951
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipDeviceController.java
@@ -0,0 +1,93 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipDevice;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.service.DpShipDeviceService;
+import com.ruoyi.manage.service.DpShipsService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌墖璁惧琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-12
+ */
+@Tag(name = "澶у睆--鑸拌埞璁惧绠$悊")
+@RestController
+@RequestMapping("/dp/dpShipDevice")
+public class DpShipDeviceController {
+    @Resource
+    private DpShipDeviceService dpShipDeviceService;
+    @Resource
+    private DpShipsService dpShipsService;
+
+    @Operation(summary = "鏂板鑸拌埞璁惧鏁版嵁")
+    @PostMapping("/insertDpShipDevice")
+    public R<Boolean> insertDpShipDevice(@RequestBody DpShipDevice dpShipDevice) {
+        QueryWrapper<DpShipDevice> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("DEVICE_NAME",dpShipDevice.getDeviceName());
+        if(!dpShipDeviceService.exists(queryWrapper)){
+            return R.ok(dpShipDeviceService.save(dpShipDevice));
+        }else {
+            return R.fail("鍚嶇О宸插瓨鍦�");
+        }
+
+    }
+
+    @Operation(summary = "鏇存柊鑸拌埞璁惧鏁版嵁")
+    @PostMapping("/updateDpShipDevice")
+    public R<Boolean> updateDpShipDevice(@RequestBody DpShipDevice dpShipDevice) {
+        return R.ok(dpShipDeviceService.updateById(dpShipDevice));
+    }
+
+    @Operation(summary = "鍒犻櫎鑸拌埞璁惧鏁版嵁")
+    @GetMapping("/deleteDpShipDevice")
+    public R<Boolean> deleteDpShipDevice( String id) {
+        return R.ok(dpShipDeviceService.removeById(id));
+    }
+
+    @Operation(summary = "鏍规嵁ID鑾峰彇鑸拌埞璁惧鏁版嵁")
+    @GetMapping ("/getDpShipDeviceByID")
+    public R<DpShipDevice> getDpShipDeviceByID( String id) {
+        DpShipDevice dpShipDevice = dpShipDeviceService.selectDpShipDevice(id);
+        return R.ok(dpShipDevice);
+    }
+
+    @Operation(summary = "鏍规嵁鍚嶇О鑾峰彇鑸拌埞璁惧鏁版嵁")
+    @GetMapping ("/getDpShipDeviceByName")
+    public R<DpShipDevice> getDpShipDeviceByName(String name) {
+        DpShipDevice dpShipDevice = dpShipDeviceService.selectDpShipDeviceByName(name);
+        return R.ok(dpShipDevice);
+    }
+
+    @Operation(summary = "鑾峰彇鑸拌埞璁惧鏁版嵁鍒楄〃")
+    @GetMapping ("/getDpShipDevices")
+    public R<List<DpShipDevice>> getDpShipDevices() {
+        return R.ok(dpShipDeviceService.getDpShipDevices());
+    }
+
+    @Operation(summary = "鑾峰彇鑸拌埞璁惧鍒嗛〉鍒楄〃")
+    @GetMapping ("/getDpShipDevicesPage")
+    public TableDataInfo getDpShipDevicesPage(DpShipDevice shipDevice) {
+        return dpShipDeviceService.getDpShipDevicesPage(shipDevice);
+    }
+
+    @Operation(summary = "鏍规嵁鑸拌埞缂栧彿鏌ヨ璁惧鍒楄〃")
+    @GetMapping("/selectDpShipDeviceByShipId")
+    public R<List<DpShipDevice>> selectDpShipDeviceByShipId( String deviceShipId) {
+        return R.ok(dpShipDeviceService.selectDpShipDeviceByShipId(deviceShipId));
+    }
+
+
+}
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipParkingController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipParkingController.java
new file mode 100644
index 0000000..a314efa
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipParkingController.java
@@ -0,0 +1,74 @@
+package com.ruoyi.web.controller.manage;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipParking;
+import com.ruoyi.manage.service.DpShipParkingService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 娉婁綅鍋滆埞淇℃伅琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-22
+ */
+@RestController
+@RequestMapping("/dp/dpShipParking")
+@Tag(name = "澶у睆--娉婁綅鍋滄硦鑸拌墖")
+public class DpShipParkingController {
+
+    @Autowired
+    private DpShipParkingService dpShipParkingService;
+
+    @GetMapping("/list")
+    @Operation(summary = "娉婁綅鍋滄硦鑸拌墖鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpShipParkingService.list());
+    }
+
+
+
+    @GetMapping("/pageList")
+    @Operation(summary = "娉婁綅鍋滄硦鑸拌墖鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpShipParking dpShipParking) {
+        return dpShipParkingService.getPageList(dpShipParking);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇娉婁綅鍋滄硦鑸拌墖璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpShipParkingService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpShipParking dpShipParking)
+    {
+        return AjaxResult.success(dpShipParkingService.save(dpShipParking));
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpShipParking dpShipParking)
+    {
+        return AjaxResult.success(dpShipParkingService.updateById(dpShipParking));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpShipParkingService.removeById(id));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipTypeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipTypeController.java
new file mode 100644
index 0000000..a62265e
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipTypeController.java
@@ -0,0 +1,72 @@
+package com.ruoyi.web.controller.manage;
+
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipType;
+import com.ruoyi.manage.service.DpShipTypeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 鑸拌埞绫诲瀷琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@RestController
+@RequestMapping("/dp/dpShipType")
+@Tag(name = "澶у睆--鑸拌埞绫诲瀷绠$悊")
+public class DpShipTypeController {
+    @Autowired
+    private DpShipTypeService dpShipTypeService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鑾峰彇鑸拌埞绫诲瀷鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpShipTypeService.list());
+    }
+
+
+
+    @GetMapping("/pageList")
+    @Operation(summary = "鑸拌埞绫诲瀷鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpShipType dpShipType) {
+        return dpShipTypeService.getPageList(dpShipType);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇鑸拌埞绫诲瀷璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpShipTypeService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpShipType dpShipType)
+    {
+        return AjaxResult.success(dpShipTypeService.save(dpShipType));
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpShipType dpShipType)
+    {
+        return AjaxResult.success(dpShipTypeService.updateById(dpShipType));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpShipTypeService.removeById(id));
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipsController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipsController.java
new file mode 100644
index 0000000..60bc4ff
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpShipsController.java
@@ -0,0 +1,102 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.domain.vo.ShipTypeVO;
+import com.ruoyi.manage.domain.vo.Tree;
+import com.ruoyi.manage.service.DpShipsService;
+import io.swagger.v3.oas.annotations.Hidden;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 鑸拌埞琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Tag(name = "澶у睆--鑸拌埞鏁版嵁绠$悊")
+@RestController
+@RequestMapping("/dp/dpShips")
+public class DpShipsController {
+
+    @Resource
+    private DpShipsService dpShipsService;
+
+    @Operation(summary = "鏂板鑸拌埞鏁版嵁")
+    @PostMapping("/insertDpShip")
+    public R<Boolean> insertDpShip(@RequestBody DpShips dpShips) {
+        return R.ok(dpShipsService.save(dpShips));
+    }
+
+    @Operation(summary = "鏇存柊鑸拌埞鏁版嵁")
+    @PostMapping("/updateDpShip")
+    public R<Boolean> updateDpShip(@RequestBody DpShips dpShips) {
+        return R.ok(dpShipsService.updateById(dpShips));
+    }
+
+    @Operation(summary = "鍒犻櫎鑸拌埞鏁版嵁")
+    @GetMapping("/deleteDpShip")
+    public R<Boolean> deleteDpShip( String id) {
+        return R.ok(dpShipsService.removeById(id));
+    }
+
+
+    @Operation(summary = "鑾峰彇鑸拌埞ById")
+    @GetMapping("/{id}")
+    public R<DpShips> getDpShipsById(@PathVariable String id) {
+        return R.ok(dpShipsService.getDpShipsById(id));
+    }
+
+    @Operation(summary = "鑾峰彇鑸拌埞鏁版嵁鍒楄〃")
+    @GetMapping("/getDpShips")
+    public R<List<DpShips>> getDpShips() {
+        return R.ok(dpShipsService.list());
+    }
+
+    @Operation(summary = "鑾峰彇鑸拌埞鍒嗛〉鎹垪琛�")
+    @GetMapping("/list")
+    public TableDataInfo list(DpShips ships) {
+        return dpShipsService.getPageList(ships);
+    }
+
+
+    @Operation(summary = "鏍规嵁鐮佸ごID鏌ヨ鑸硅埌绫诲瀷")
+    @PostMapping("/getDpShipTypeByWhId")
+    public R<List<ShipTypeVO>> getDpShipTypeByWhId(@Parameter(description = "鐮佸ごID", required = true) Integer whId) {
+        return R.ok(dpShipsService.getDpShipTypeByWhId(whId));
+    }
+
+    @Operation(summary = "(鏂�)鏍规嵁鐮佸ごID鏌ヨ鑸硅埌绫诲瀷")
+    @PostMapping("/getDpShipTypeByWhIdNEW")
+    public R<List<ShipTypeVO>> getDpShipTypeByWhIdNEW(@Parameter(description = "鐮佸ごID", required = true) Integer whId) {
+        return R.ok(dpShipsService.getDpShipTypeByWhIdNEW(whId));
+    }
+
+    @Operation(summary = "鏍规嵁鐮佸ごID鍜岃埌鑸圭被鍨嬫煡璇㈣埌鑸瑰垪琛�")
+    @PostMapping("/getDpShipsByWhIdType")
+    public AjaxResult getDpShipsByWhIdType(@Parameter(description = "鐮佸ごID", required = true) Integer whId,
+                                           @Parameter(description = "鑸硅埌绫诲瀷ID", required = true) String shipType) {
+        return AjaxResult.success(dpShipsService.getDpShipsByWhIdType(whId,shipType));
+    }
+
+    @Operation(summary = "(鏂�)鏍规嵁鐮佸ごID鍜岃埌鑸圭被鍨嬫暟缁勬煡璇㈠垪琛�")
+    @PostMapping("/getDpShipsByWhIdTypeNEW")
+    public AjaxResult getDpShipsByWhIdTypeNEW(@Parameter(description = "鐮佸ごID", required = true) Integer whId,
+                                              @RequestBody List<Integer> shipTypes) {
+        return AjaxResult.success(dpShipsService.getDpShipsByWhIdTypeNEW(whId,shipTypes));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpUnitSupplyTimeController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpUnitSupplyTimeController.java
new file mode 100644
index 0000000..3efcc96
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpUnitSupplyTimeController.java
@@ -0,0 +1,95 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpUnitSupplyTime;
+import com.ruoyi.manage.service.DpUnitSupplyTimeService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+/**
+ * <p>
+ * 鍗曚綅琛ョ粰鏃堕棿琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-20
+ */
+@RestController
+@RequestMapping("/dp/dpUnitSupplyTime")
+@Tag(name = "澶у睆--鍗曚綅琛ョ粰鏃堕棿")
+public class DpUnitSupplyTimeController {
+    @Autowired
+    private DpUnitSupplyTimeService dpUnitSupplyTimeService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鍗曚綅琛ョ粰鏃堕棿鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dpUnitSupplyTimeService.list());
+    }
+
+
+
+    @GetMapping("/pageList")
+    @Operation(summary = "鍗曚綅琛ョ粰鏃堕棿鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpUnitSupplyTime dpUnitSupplyTime) {
+        return dpUnitSupplyTimeService.getPageList(dpUnitSupplyTime);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇鍗曚綅琛ョ粰鏃堕棿璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer id)
+    {
+        return AjaxResult.success(dpUnitSupplyTimeService.getById(id));
+    }
+
+
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpUnitSupplyTime dpUnitSupplyTime)
+    {
+        QueryWrapper<DpUnitSupplyTime> queryWrapperDesign = new QueryWrapper<>();
+        queryWrapperDesign.eq("SHIP_DESIGN",dpUnitSupplyTime.getShipDesign());
+        QueryWrapper<DpUnitSupplyTime> queryWrapperCategory = new QueryWrapper<>();
+        queryWrapperCategory.eq("CATEGORY",dpUnitSupplyTime.getCategory());
+        if(dpUnitSupplyTimeService.exists(queryWrapperDesign)){
+           return AjaxResult.error("鑸拌埞鍨嬪彿宸插瓨鍦�");
+        }else if(dpUnitSupplyTimeService.exists(queryWrapperCategory)){
+            return AjaxResult.error("琛ョ粰绉嶇被宸插瓨鍦�");
+        }else {
+            return AjaxResult.success(dpUnitSupplyTimeService.save(dpUnitSupplyTime));
+        }
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpUnitSupplyTime dpUnitSupplyTime)
+    {
+        QueryWrapper<DpUnitSupplyTime> queryWrapperDesign = new QueryWrapper<>();
+        queryWrapperDesign.eq("SHIP_DESIGN",dpUnitSupplyTime.getShipDesign());
+        QueryWrapper<DpUnitSupplyTime> queryWrapperCategory = new QueryWrapper<>();
+        queryWrapperCategory.eq("CATEGORY",dpUnitSupplyTime.getCategory());
+        if(dpUnitSupplyTimeService.exists(queryWrapperDesign)){
+            return AjaxResult.error("鑸拌埞鍨嬪彿宸插瓨鍦�");
+        }else if(dpUnitSupplyTimeService.exists(queryWrapperCategory)){
+            return AjaxResult.error("琛ョ粰绉嶇被宸插瓨鍦�");
+        }else {
+            return AjaxResult.success(dpUnitSupplyTimeService.updateById(dpUnitSupplyTime));
+        }
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{id}")
+    public AjaxResult remove(@PathVariable Integer id)
+    {
+        return AjaxResult.success(dpUnitSupplyTimeService.removeById(id));
+    }
+
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpWharfController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpWharfController.java
new file mode 100644
index 0000000..ced4afb
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DpWharfController.java
@@ -0,0 +1,101 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpWharf;
+import com.ruoyi.manage.service.DpWharfService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.annotation.Resource;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.transaction.interceptor.TransactionAspectSupport;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鐮佸ご 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@RestController
+@RequestMapping("/dp/dpWharf")
+@Tag(name = "澶у睆--鐮佸ご绠$悊")
+public class DpWharfController extends BaseController {
+    @Resource
+    private DpWharfService dpWharfService;
+
+    @GetMapping("/list")
+    @Operation(summary = "鐮佸ご鍒楄〃")
+    public AjaxResult getList(){
+       return AjaxResult.success(dpWharfService.list());
+    }
+
+    @GetMapping("/pageList")
+    @Operation(summary = "鐮佸ご鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DpWharf wharf) {
+
+        // 鍒涘缓鍒嗛〉瀵硅薄锛堝綋鍓嶉〉锛屾瘡椤靛ぇ灏忥級
+        Page<DpWharf> page = new Page<>(wharf.getPageNum(), wharf.getPageSize());
+        QueryWrapper<DpWharf> queryWrapper = new QueryWrapper<>();
+        if (null!=wharf.getName()){
+            queryWrapper.like("name", wharf.getName());
+        }
+        IPage<DpWharf> result = dpWharfService.page(page, queryWrapper);
+        List<DpWharf> records = result.getRecords();
+        long total = result.getTotal();
+        return new TableDataInfo(records,Integer.parseInt(String.valueOf(total)));
+    }
+
+    /**
+     * 鑾峰彇鐮佸ご璇︾粏淇℃伅
+     */
+    @Operation(summary = "鑾峰彇鐮佸ご璇︾粏淇℃伅")
+    @GetMapping(value = "/{whId}")
+    public AjaxResult getInfo(@PathVariable("whId") Long whId) {
+        return success(dpWharfService.getById(whId));
+    }
+
+    /**
+     * 鏂板鐮佸ご
+     */
+    @Operation(summary = "鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DpWharf dpWharf) {
+        return toAjax(dpWharfService.save(dpWharf));
+    }
+
+    /**
+     * 淇敼鐮佸ご
+     */
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DpWharf dpWharf) {
+        return toAjax(dpWharfService.updateById(dpWharf));
+    }
+
+    /**
+     * 鍒犻櫎鐮佸ご
+     */
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{whId}")
+    @Transactional(rollbackFor = Exception.class)
+    public AjaxResult remove(@PathVariable Integer whId) {
+        try {
+            dpWharfService.deleteWhraf(whId);
+        }catch (Exception e){
+            TransactionAspectSupport.currentTransactionStatus().setRollbackOnly();
+            e.printStackTrace();
+            return AjaxResult.error("鍒犻櫎澶辫触");
+        }
+
+        return AjaxResult.success("鍒犻櫎鎴愬姛");
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DsTaskListController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DsTaskListController.java
new file mode 100644
index 0000000..fa644d3
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/DsTaskListController.java
@@ -0,0 +1,178 @@
+package com.ruoyi.web.controller.manage;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.buss.common.RfidUtil;
+import com.ruoyi.buss.domain.vo.RfIdVo;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.domain.R;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.*;
+import com.ruoyi.manage.service.DpBerthService;
+import com.ruoyi.manage.service.DpShipTypeService;
+import com.ruoyi.manage.service.DpShipsService;
+import com.ruoyi.manage.service.DsTaskListService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 浠诲姟鍒嗛厤璇︽儏琛� 鍓嶇鎺у埗鍣�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-24
+ */
+@RestController
+@RequestMapping("/dp/dsTaskList")
+@Tag(name = "澶у睆--浠诲姟鍒嗛厤璇︽儏")
+public class DsTaskListController {
+    @Autowired
+    private DsTaskListService dsTaskListService;
+    @Autowired
+    private DpShipsService dpShipsService;
+    @Autowired
+    private DpShipTypeService dpShipTypeService;
+    @Autowired
+    private DpBerthService dpBerthService;
+    @Autowired
+    private RuoYiConfig ruoYiConfig;
+
+
+    @GetMapping("/list")
+    @Operation(summary = "浠诲姟鍒嗛厤璇︽儏鍒楄〃")
+    public AjaxResult getList(){
+        return AjaxResult.success(dsTaskListService.list());
+    }
+
+
+
+    @GetMapping("/pageList")
+    @Operation(summary = "浠诲姟鍒嗛厤璇︽儏鍒嗛〉鍒楄〃")
+    public TableDataInfo getPageList(DsTaskList dsTaskList) {
+        return dsTaskListService.getPageList(dsTaskList);
+    }
+
+    @GetMapping("/pageListDaily")
+    @Operation(summary = "鏃ュ父浠诲姟鍒嗛厤璇︽儏鍒嗛〉鍒楄〃")
+    public TableDataInfo pageListDaily(DsTaskList dsTaskList) {
+        return dsTaskListService.getPageListDaily(dsTaskList);
+    }
+
+
+    @GetMapping(value = "/{id}")
+    @Operation(summary = "鑾峰彇浠诲姟鍒嗛厤璇︽儏璇︾粏淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") Integer pkid)
+    {
+        return AjaxResult.success(dsTaskListService.getById(pkid));
+    }
+
+
+    @Operation(summary = "缇ょ粍鏂板")
+    @PostMapping
+    public AjaxResult add(@RequestBody DsTaskList dsTaskList)
+    {
+        return AjaxResult.success(dsTaskListService.save(dsTaskList));
+    }
+
+    @Operation(summary = "鏃ュ父鏂板")
+    @PostMapping(value = "/dailyAdd")
+    public AjaxResult dailyAdd(@RequestBody DsTaskList dsTaskList,
+                               @RequestParam(value = "lon") Double lon,
+                               @RequestParam(value = "lat") Double lat,
+                               @RequestParam(value = "alt") Double alt,
+                               @RequestParam(value = "heading") Double heading)
+    {
+        String shipType = dsTaskList.getShipType();
+        LambdaQueryWrapper<DpShipType> shipTypeWrapper = new LambdaQueryWrapper<>();
+        shipTypeWrapper.eq(DpShipType::getShipDesign,shipType);
+        DpShipType dpShipType = dpShipTypeService.getOne(shipTypeWrapper);
+        Integer shipTypeId = dpShipType.getId();
+        Integer whId = dsTaskList.getHarborId().intValue();
+        Integer beId = dsTaskList.getBerthId().intValue();
+        String shipId = dsTaskList.getShipNo();
+
+        DpShips dpShip = new DpShips();
+        dpShip.setShipTypeId(shipTypeId);
+        dpShip.setWhId(whId);
+        dpShip.setBeId(beId);
+        dpShip.setShipId(shipId);
+        dpShip.setShipName(shipId);
+        dpShip.setLon(lon);
+        dpShip.setLat(lat);
+        dpShip.setAlt(alt);
+        dpShip.setHeading(heading);
+
+        DmBerth dmBerth =dpBerthService.getById(beId);
+        String path = dmBerth.getPath();
+
+        boolean taskListRes = dsTaskListService.save(dsTaskList);
+        if(taskListRes){
+            List<RfIdVo> list = new ArrayList<>();
+            RfIdVo rfIdVo = new RfIdVo();
+            rfIdVo.setId((999+Integer.parseInt(shipId)));
+            rfIdVo.setName(String.valueOf(999+Integer.parseInt(shipId)));
+            rfIdVo.setPath(path);
+            list.add(rfIdVo);
+            RfidUtil.sendJsonPost(ruoYiConfig.getBussRfidUrl(),list.toString());
+        }
+        boolean shipRes = dpShipsService.save(dpShip);
+        if(taskListRes && shipRes){
+            return AjaxResult.success();
+        }else {
+            return AjaxResult.error();
+        }
+
+    }
+
+
+    @Operation(summary = "淇敼")
+    @PutMapping
+    public AjaxResult edit(@RequestBody DsTaskList dsTaskList)
+    {
+        return AjaxResult.success(dsTaskListService.updateById(dsTaskList));
+    }
+
+
+    @Operation(summary = "鍒犻櫎")
+    @DeleteMapping("/{pkid}")
+    public AjaxResult remove(@PathVariable Integer pkid)
+    {
+        return AjaxResult.success(dsTaskListService.removeById(pkid));
+    }
+
+    @Operation(summary = "鏃ュ父浠诲姟鍒犻櫎")
+    @DeleteMapping("/deleteDaily/{pkid}")
+    public AjaxResult deleteDaily(@PathVariable Integer pkid)
+    {
+        DsTaskList dsTaskList = dsTaskListService.getById(pkid);
+        LambdaQueryWrapper<DpShips> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(DpShips::getShipId,dsTaskList.getShipNo());
+        boolean shipRes = dpShipsService.remove(lambdaQueryWrapper);
+        boolean taskRes = dsTaskListService.removeById(pkid);
+        if(shipRes && taskRes){
+            return AjaxResult.success();
+        }else {
+            return AjaxResult.error();
+        }
+
+    }
+
+    @GetMapping(value = "/getByBeId")
+    @Operation(summary = "鏍规嵁娉婁綅ID鑾峰彇浠诲姟鍒嗛厤璇︽儏")
+    public R<DsTaskList> getByBeId(@RequestParam("beId") Integer beId)
+    {
+        LambdaQueryWrapper<DsTaskList> lambdaQueryWrapper = new LambdaQueryWrapper();
+        lambdaQueryWrapper.eq(DsTaskList::getBerthId,beId)
+                .eq(DsTaskList::getTaskId,999)
+                .orderByDesc(DsTaskList::getCreateTime)
+                .last("LIMIT 1");
+        return R.ok(dsTaskListService.getOne(lambdaQueryWrapper));
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/HikController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/HikController.java
new file mode 100644
index 0000000..18d0538
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/manage/HikController.java
@@ -0,0 +1,193 @@
+package com.ruoyi.web.controller.manage;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.CameraPTZ;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.HikEvent;
+import com.ruoyi.fuzhou.domain.HikEventObj;
+import com.ruoyi.fuzhou.service.EquipmentService;
+import com.ruoyi.fuzhou.service.HikService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.time.OffsetDateTime;
+import java.util.Date;
+
+@RestController
+@RequestMapping("/dp/hik")
+@Tag(name = "澶у睆--娴峰悍瑙嗛")
+public class HikController extends BaseController {
+    @Autowired
+    private HikService hikService;
+    @Autowired
+    private EquipmentService dpEquipmentService;
+
+    @GetMapping("/getCameraPreviewURL/{cameraName}")
+    @Operation(summary = "鏍规嵁name鏌ヨ瑙嗛鎾斁URL")
+    public AjaxResult getCameraPreviewURL(@PathVariable("cameraName") String cameraName) throws Exception {
+        return AjaxResult.success(hikService.getCameraPreviewURL(cameraName));
+    }
+
+    @GetMapping("/getCameraURL/{cameraIndexCode}")
+    @Operation(summary = "鏍规嵁indexcode鏌ヨ瑙嗛鎾斁URL")
+    public AjaxResult getCameraURL(@PathVariable("cameraIndexCode") String cameraIndexCode) throws Exception {
+        return AjaxResult.success(hikService.getCameraURL(cameraIndexCode));
+    }
+
+    @GetMapping("/getCameraOnline/{indexCodes}")
+    @Operation(summary = "鏍规嵁indexCodes鏁扮粍鏌ヨ鐩戞帶鐘舵��")
+    public AjaxResult getCameraOnline(@PathVariable("indexCodes") String[] indexCodes) throws Exception {
+        return AjaxResult.success(hikService.getCameraOnline(indexCodes));
+    }
+
+    @Operation(summary = "浜戝彴鎿嶄綔")
+    @PostMapping("/cameraCommand")
+    public AjaxResult cameraCommand(@RequestBody CameraPTZ cameraPTZ) throws Exception{
+        return AjaxResult.success(hikService.cameraCommand(cameraPTZ));
+    }
+
+    @Operation(summary = "鏍规嵁浜嬩欢绫诲瀷璁㈤槄浜嬩欢")
+    @PostMapping("/subByEventTypes")
+    public JSONObject subByEventTypes(@RequestBody HikEventObj hikEventObj) throws Exception{
+        return hikService.subByEventTypes(hikEventObj);
+    }
+
+    @Operation(summary = "鏍规嵁浜嬩欢绫诲瀷鍙栨秷璁㈤槄浜嬩欢")
+    @PostMapping("/unSubByEventTypes")
+    public JSONObject unSubByEventTypes(@RequestBody HikEventObj hikEventObj) throws Exception{
+        return hikService.unSubByEventTypes(hikEventObj);
+    }
+
+    @Operation(summary = "鏌ヨ璁㈤槄浜嬩欢淇℃伅")
+    @PostMapping("/eventView")
+    public JSONObject eventView() throws Exception{
+        return hikService.eventView();
+    }
+
+    @Operation(summary = "鎺ユ敹娴峰悍浜嬩欢淇℃伅")
+    @PostMapping("/eventRcv")
+    public JSONObject eventRcv(@RequestBody JSONObject jsonObject) throws Exception{
+        String method = null;
+        JSONObject params = new JSONObject();
+        JSONArray events = new JSONArray();
+        JSONObject res = new JSONObject();
+        String sendTime = null;
+        if(jsonObject.containsKey("method")){
+            method = jsonObject.getString("method");
+        }
+        if (jsonObject.containsKey("params")) {
+            params = jsonObject.getJSONObject("params");
+            if(params.containsKey("sendTime")){
+                sendTime = params.getString("sendTime");
+            }
+            if (params.containsKey("events")) {
+                events = params.getJSONArray("events");
+                if(events.size()>0){
+                    for (int i=0;i<events.size();i++){
+                        JSONObject event = events.getJSONObject(i);
+
+                        HikEvent hikEvent = new HikEvent();
+                        hikEvent.setSendTime(convertTime(sendTime));
+                        if(event.containsKey("srcIndex")){
+                            String srcIndex = event.getString("srcIndex");
+                            hikEvent.setSrcIndex(srcIndex);
+                        }
+                        if(event.containsKey("srcType")){
+                            String srcType = event.getString("srcType");
+                            hikEvent.setSrcType(srcType);
+                        }
+                        if(event.containsKey("srcName")){
+                            String srcName = event.getString("srcName");
+                            hikEvent.setSrcName(srcName);
+                        }
+                        if(event.containsKey("eventType")){
+                            Integer eventType = event.getIntValue("eventType");
+                            hikEvent.setEventType(eventType);
+                        }
+                        if(event.containsKey("happenTime")){
+                            String happenTime = event.getString("happenTime");
+                            hikEvent.setHappenTime(convertTime(happenTime));
+                        }
+                        boolean reaIns = hikService.saveInsert(hikEvent);
+                        if(reaIns){
+                            res.put("code","0");
+                            res.put("msg","success");
+                        }
+
+                        if(event.containsKey("data")){
+                            JSONObject data = event.getJSONObject("data");
+                            if(data.containsKey("regionEntrance")){
+                                JSONArray regionEntrance = data.getJSONArray("regionEntrance");
+                                if(regionEntrance.size()>0){
+                                    for (int k=0;k<regionEntrance.size();k++){
+                                        JSONObject region = regionEntrance.getJSONObject(k);
+                                        if(region.containsKey("targetAttrs")){
+                                            JSONObject targetAttrs = region.getJSONObject("targetAttrs");
+                                            if(targetAttrs.containsKey("cameraAddress")){
+                                                String cameraAddress = targetAttrs.getString("cameraAddress");
+                                            }
+                                            if(targetAttrs.containsKey("cameraIndexCode")){
+                                                String cameraIndexCode = targetAttrs.getString("cameraIndexCode");
+                                            }
+                                            if(targetAttrs.containsKey("deviceIndexCode")){
+                                                String deviceIndexCode = targetAttrs.getString("deviceIndexCode");
+                                            }
+                                            if(targetAttrs.containsKey("imageServerCode")){
+                                                String imageServerCode = targetAttrs.getString("imageServerCode");
+                                            }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        return res;
+    }
+
+    /**
+     * 鏌ヨ娴峰悍浜嬩欢鍒楄〃
+     */
+    @PostMapping("/list")
+    @Operation(summary = "鏌ヨ娴峰悍浜嬩欢鍒楄〃锛堝垎椤碉級")
+    public TableDataInfo list(@RequestBody HikEvent hikEvent)
+    {
+        return hikService.getList(hikEvent);
+    }
+
+    /**
+     * 鏌ヨ鎵�鏈夋捣搴蜂簨浠跺垪琛�
+     */
+    @GetMapping("/listAll")
+    @Operation(summary = "鏌ヨ鎵�鏈夋捣搴蜂簨浠跺垪琛�")
+    public AjaxResult listAll()
+    {
+        return AjaxResult.success(hikService.list());
+    }
+
+    /**
+     * 鑾峰彇娓彛淇℃伅璇︾粏淇℃伅
+     */
+    @GetMapping("/{id}")
+    @Operation(summary = "鑾峰彇娴峰悍浜嬩欢淇℃伅")
+    public AjaxResult getInfo(@PathVariable("id") String id)
+    {
+        return success(hikService.getById(id));
+    }
+
+    private Date convertTime(String time){
+        OffsetDateTime offsetDateTime = OffsetDateTime.parse(time);
+        Date date = Date.from(offsetDateTime.toInstant());
+        return date;
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
new file mode 100644
index 0000000..66e870c
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/CacheController.java
@@ -0,0 +1,125 @@
+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 io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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, "瀵嗙爜閿欒娆℃暟"));
+    }
+
+    @SuppressWarnings("deprecation")
+    @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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
new file mode 100644
index 0000000..9cdd39e
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/ServerController.java
@@ -0,0 +1,29 @@
+package com.ruoyi.web.controller.monitor;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
new file mode 100644
index 0000000..62660ef
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysLogininforController.java
@@ -0,0 +1,99 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+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")
+@Hidden
+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,
+                              @RequestParam(value = "pageNum", required = false)Integer pageNum,
+                              @RequestParam(value = "pageSize", required = false)Integer pageSize)
+    {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+//        return getDataTable(list);
+        return paginate(list,pageNum,pageSize);
+    }
+
+    @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 = "璐︽埛瑙i攣", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public AjaxResult unlock(@PathVariable("userName") String userName)
+    {
+        passwordService.clearLoginRecordCache(userName);
+        return success();
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
new file mode 100644
index 0000000..2c6af9d
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysOperlogController.java
@@ -0,0 +1,87 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+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")
+@Hidden
+public class SysOperlogController extends BaseController
+{
+    @Autowired
+    private ISysOperLogService operLogService;
+
+    @PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog,
+                              @RequestParam(value = "pageNum", required = false)Integer pageNum,
+                              @RequestParam(value = "pageSize", required = false)Integer pageSize)
+    {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+//        return getDataTable(list);
+        return paginate(list,pageNum,pageSize);
+    }
+
+    @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();
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
new file mode 100644
index 0000000..fdbde2d
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/monitor/SysUserOnlineController.java
@@ -0,0 +1,86 @@
+package com.ruoyi.web.controller.monitor;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
new file mode 100644
index 0000000..6498188
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysConfigController.java
@@ -0,0 +1,136 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
new file mode 100644
index 0000000..1acc000
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDeptController.java
@@ -0,0 +1,135 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
new file mode 100644
index 0000000..7131935
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictDataController.java
@@ -0,0 +1,124 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
new file mode 100644
index 0000000..0d48ed0
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysDictTypeController.java
@@ -0,0 +1,146 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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.*;
+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")
+@Hidden
+public class SysDictTypeController extends BaseController
+{
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictType dictType,
+                              @RequestParam(value = "pageNum", required = false)Integer pageNum,
+                              @RequestParam(value = "pageSize", required = false)Integer pageSize)
+    {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+//        return getDataTable(list);
+        return paginate(list,pageNum,pageSize);
+    }
+
+    @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);
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
new file mode 100644
index 0000000..8915fba
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysIndexController.java
@@ -0,0 +1,31 @@
+package com.ruoyi.web.controller.system;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
new file mode 100644
index 0000000..4cb1ead
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysLoginController.java
@@ -0,0 +1,112 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import java.util.Set;
+
+import com.ruoyi.common.core.domain.R;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.bind.annotation.*;
+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
+@Tag(name = "鐢ㄦ埛鐧诲綍")
+public class SysLoginController
+{
+    @Autowired
+    private SysLoginService loginService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 鐧诲綍鏂规硶
+     * 
+     * @param loginBody 鐧诲綍淇℃伅
+     * @return 缁撴灉
+     */
+    @PostMapping("/login")
+    @Operation(summary = "鐧诲綍")
+    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")
+    @Operation(summary = "鐢ㄦ埛淇℃伅")
+    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;
+    }
+
+    @DeleteMapping("logout")
+    @Operation(summary = "鐢ㄦ埛鐧诲嚭")
+    public AjaxResult logout(HttpServletRequest request){
+        String userName = SecurityUtils.getUsername();
+        SecurityContextHolder.clearContext();
+        request.getSession().invalidate();
+        return AjaxResult.success(userName+"鐧诲嚭鎴愬姛");
+    }
+
+    /**
+     * 鑾峰彇璺敱淇℃伅
+     * 
+     * @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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
new file mode 100644
index 0000000..ef6c7fd
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysMenuController.java
@@ -0,0 +1,145 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(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() + "'澶辫触锛屽湴鍧�蹇呴』浠ttp(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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
new file mode 100644
index 0000000..c54afbc
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysNoticeController.java
@@ -0,0 +1,94 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
new file mode 100644
index 0000000..4b64e22
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysPostController.java
@@ -0,0 +1,132 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
new file mode 100644
index 0000000..ea8c2ca
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysProfileController.java
@@ -0,0 +1,143 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.Map;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
new file mode 100644
index 0000000..c0e8e64
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRegisterController.java
@@ -0,0 +1,40 @@
+package com.ruoyi.web.controller.system;
+
+import io.swagger.v3.oas.annotations.Hidden;
+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
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
new file mode 100644
index 0000000..c6374c1
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysRoleController.java
@@ -0,0 +1,265 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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")
+@Hidden
+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/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
new file mode 100644
index 0000000..44b3c5f
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/system/SysUserController.java
@@ -0,0 +1,259 @@
+package com.ruoyi.web.controller.system;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+import io.swagger.v3.oas.annotations.Hidden;
+import jakarta.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")
+@Hidden
+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/core/config/SwaggerConfig.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
new file mode 100644
index 0000000..61e91ee
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfig.java
@@ -0,0 +1,62 @@
+//package com.ruoyi.web.core.config;
+//
+//import org.springframework.beans.factory.annotation.Autowired;
+//import org.springframework.context.annotation.Bean;
+//import org.springframework.context.annotation.Configuration;
+//import com.ruoyi.common.config.RuoYiConfig;
+//import io.swagger.v3.oas.models.Components;
+//import io.swagger.v3.oas.models.OpenAPI;
+//import io.swagger.v3.oas.models.info.Contact;
+//import io.swagger.v3.oas.models.info.Info;
+//import io.swagger.v3.oas.models.security.SecurityRequirement;
+//import io.swagger.v3.oas.models.security.SecurityScheme;
+//
+///**
+// * Swagger2鐨勬帴鍙i厤缃�
+// *
+// * @author ruoyi
+// */
+//@Configuration
+//public class SwaggerConfig {
+//    /**
+//     * 绯荤粺鍩虹閰嶇疆
+//     */
+//    @Autowired
+//    private RuoYiConfig ruoyiConfig;
+//
+//    /**
+//     * 鑷畾涔夌殑 OpenAPI 瀵硅薄
+//     */
+//    @Bean
+//    public OpenAPI customOpenApi() {
+//        return new OpenAPI().components(new Components()
+//                        // 璁剧疆璁よ瘉鐨勮姹傚ご
+//                        .addSecuritySchemes("apikey", securityScheme()))
+//                .addSecurityItem(new SecurityRequirement().addList("apikey"))
+//                .info(getApiInfo());
+//    }
+//
+//    @Bean
+//    public SecurityScheme securityScheme() {
+//        return new SecurityScheme()
+//                .type(SecurityScheme.Type.APIKEY)
+//                .name("Authorization")
+//                .in(SecurityScheme.In.HEADER)
+//                .scheme("Bearer");
+//    }
+//
+//    /**
+//     * 娣诲姞鎽樿淇℃伅
+//     */
+//    public Info getApiInfo() {
+//        return new Info()
+//                // 璁剧疆鏍囬
+//                .title("鏍囬锛氭櫤鎱ф腐鍙鎺ュ彛鏂囨。")
+//                // 鎻忚堪
+//                .description("鎻忚堪锛氭櫤鎱ф腐鍙�")
+//                // 浣滆�呬俊鎭�
+//                .contact(new Contact().name(ruoyiConfig.getName()))
+//                // 鐗堟湰
+//                .version("鐗堟湰鍙�:" + ruoyiConfig.getVersion());
+//    }
+//}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfiguration.java b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfiguration.java
new file mode 100644
index 0000000..af179d1
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/core/config/SwaggerConfiguration.java
@@ -0,0 +1,33 @@
+package com.ruoyi.web.core.config;
+
+import com.github.xiaoymin.knife4j.spring.configuration.Knife4jProperties;
+import org.springdoc.core.models.GroupedOpenApi;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class SwaggerConfiguration {
+
+    /**
+     * 閰嶇疆 OpenAPI Group
+     * @return GroupedOpenApi
+     */
+    @Bean
+    public GroupedOpenApi publicApi() {
+        return GroupedOpenApi.builder()
+                .group("public") // 瀹氫箟鍒嗙粍鍚嶇О
+                .packagesToScan("com.ruoyi.web.controller", "com.ruoyi.buss.controller") // 鎵弿鎺у埗鍣ㄦ墍鍦ㄧ殑鍖�
+                .build();
+    }
+
+    /**
+     * 閰嶇疆 Knife4j
+     * @return Knife4jProperties
+     */
+//    @Bean
+//    public Knife4jProperties knife4jProperties() {
+//        Knife4jProperties knife4jProperties = new Knife4jProperties();
+//        knife4jProperties.setEnable(true); // 鍚敤 Knife4j
+//        return knife4jProperties;
+//    }
+}
diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/webSocket/WebSocketEquServer.java b/ruoyi-admin/src/main/java/com/ruoyi/web/webSocket/WebSocketEquServer.java
new file mode 100644
index 0000000..aa30f96
--- /dev/null
+++ b/ruoyi-admin/src/main/java/com/ruoyi/web/webSocket/WebSocketEquServer.java
@@ -0,0 +1,345 @@
+package com.ruoyi.web.webSocket;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import com.ruoyi.manage.domain.DsTaskList;
+import com.ruoyi.manage.service.DsTaskListService;
+import jakarta.websocket.*;
+import jakarta.websocket.server.PathParam;
+import jakarta.websocket.server.ServerEndpoint;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.Executors;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+
+@ServerEndpoint("/dp/sendOil/{userId}")
+@Component
+public class WebSocketEquServer implements ApplicationContextAware {
+    private final static Logger log = LoggerFactory.getLogger(WebSocketEquServer.class);
+    /**
+     * 鍦ㄧ嚎浜烘暟
+     */
+    private static int onlineCount = 0;
+    /**
+     * 鍦ㄧ嚎浜哄憳session
+     */
+    private static ConcurrentHashMap<String, WebSocketEquServer> webSocketMap = new ConcurrentHashMap<>();
+    /**
+     * 涓庢煇涓鎴风鐨勮繛鎺ヤ細璇濓紝闇�瑕侀�氳繃瀹冩潵缁欏鎴风鍙戦�佹暟鎹�
+     */
+    private Session session;
+    /**
+     * 鎺ユ敹userId
+     */
+    private String userId = "";
+
+    //瀹氭椂浠诲姟
+    private ScheduledExecutorService scheduler;
+    //娉婁綅ID
+    private Integer beId = 0;
+    private static final Object lock = new Object();
+
+    private static ApplicationContext context;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        context = applicationContext;
+    }
+
+    public static <T> T getBean(Class<T> beanClass) {
+        return context.getBean(beanClass);
+    }
+
+
+
+    /**
+     * 杩炴帴寤虹珛鎴愬姛璋冪敤鐨勬柟娉�
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("userId") String userId) {
+        this.session = session;
+        this.userId = userId;
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+            webSocketMap.put(userId, this);
+        } else {
+            webSocketMap.put(userId, this);
+        }
+        try {
+            sendMessage("杩炴帴鎴愬姛");
+        } catch (IOException e) {
+            log.error("鐢ㄦ埛:" + userId + ",缃戠粶寮傚父!");
+        }
+
+    }
+
+    /**
+     * 杩炴帴鍏抽棴璋冪敤鐨勬柟娉�
+     */
+    @OnClose
+    public void onClose() {
+        if (scheduler != null) {
+            scheduler.shutdown();
+        }
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+        }
+    }
+
+
+    /**
+     * 鏀跺埌瀹㈡埛绔秷鎭悗璋冪敤鐨勬柟娉�
+     *
+     * @param message 瀹㈡埛绔彂閫佽繃鏉ョ殑娑堟伅
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        JSONObject beObject = JSONObject.parseObject(message);
+        String type = beObject.getString("type");
+        try {
+            beId = Integer.parseInt(beObject.getString("beId"));
+            if (!type.isEmpty() && type.equals("startSupply") && beId != null && beId != 0) {
+                //鍒涘缓瀹氭椂浠诲姟
+                scheduler = Executors.newSingleThreadScheduledExecutor();
+                //姣�10绉掓墽琛屼竴娆�
+                scheduler.scheduleAtFixedRate(() -> {
+                            try {
+                                synchronized (lock) {
+                                    if (session != null && session.isOpen()) {
+                                        JSONObject jsonObject = new JSONObject();
+                                        jsonObject.put("type", "Supply");
+                                        EquipmentService equipmentService = getBean(EquipmentService.class);
+                                        LambdaQueryWrapper<DpEquipment> oilWrapper = new LambdaQueryWrapper<>();
+                                        oilWrapper.eq(DpEquipment::getBeId, beId)
+                                                .in(DpEquipment::getEquipmentTypeId, DataTypeEnum.LIJIUOIL.getCode(), DataTypeEnum.OIL.getCode(), DataTypeEnum.LIJIUJUN.getCode())
+                                                .orderByAsc(DpEquipment::getId);
+                                        List<DpEquipment> oilList = equipmentService.list(oilWrapper);
+                                        JSONArray oilArray = new JSONArray();
+                                        for (DpEquipment dpEquipment : oilList) {
+                                            ReceiveOilValue oilValue = (ReceiveOilValue) equDataList(dpEquipment.getId());
+                                            if (oilValue != null) {
+                                                oilValue.setId(dpEquipment.getId().longValue());
+                                            }
+                                            oilArray.add(oilValue);
+                                        }
+                                        jsonObject.put("oil", oilArray);
+
+                                        LambdaQueryWrapper<DpEquipment> waterWrapper = new LambdaQueryWrapper<>();
+                                        waterWrapper.eq(DpEquipment::getBeId, beId)
+                                                .eq(DpEquipment::getEquipmentTypeId, 2)
+                                                .orderByAsc(DpEquipment::getId);
+                                        List<DpEquipment> waterList = equipmentService.list(waterWrapper);
+                                        JSONArray waterArray = new JSONArray();
+                                        for (DpEquipment dpEquipment : waterList) {
+                                            ReceiveWaterValue waterValue = (ReceiveWaterValue) equDataList(dpEquipment.getId());
+                                            if (waterValue != null) {
+                                                waterValue.setId(dpEquipment.getId().longValue());
+                                            }
+                                            waterArray.add(waterValue);
+                                        }
+                                        jsonObject.put("water", waterArray);
+
+                                        LambdaQueryWrapper<DpEquipment> elecWrapper = new LambdaQueryWrapper<>();
+                                        elecWrapper.eq(DpEquipment::getBeId, beId)
+                                                .eq(DpEquipment::getEquipmentTypeId, 3)
+                                                .orderByAsc(DpEquipment::getId);
+                                        List<DpEquipment> elecList = equipmentService.list(elecWrapper);
+                                        JSONArray elecArray = new JSONArray();
+                                        for (DpEquipment dpEquipment : elecList) {
+                                            ReceiveElectricityValue electricityValue = (ReceiveElectricityValue) equDataList(dpEquipment.getId());
+                                            if (electricityValue != null) {
+                                                electricityValue.setId(dpEquipment.getId().longValue());
+                                            }
+                                            elecArray.add(electricityValue);
+                                        }
+                                        jsonObject.put("elec", elecArray);
+
+                                        DsTaskListService dsTaskListService = getBean(DsTaskListService.class);
+
+//                                        QueryWrapper<DsTaskList> queryWrapper = new QueryWrapper<>();
+//                                        queryWrapper.eq("BERTH_ID", beId).orderByDesc("PKID").last("LIMIT 1");
+
+//                                        String rfidNumStr = dsTaskList.getRfidNum();
+
+                                        QueryWrapper<DsTaskList> queryWrapperTask = new QueryWrapper<>();
+                                        queryWrapperTask.eq("TASK_ID",999).orderByDesc("CREATE_TIME").last("LIMIT 1");
+                                        DsTaskList dsTaskList = dsTaskListService.getOne(queryWrapperTask);
+
+                                        String rfidNumStr = dsTaskList.getTaskId()+dsTaskList.getShipNo();
+                                        //鏍规嵁浠诲姟鍒楄〃涓殑rfidNum鏌ヨRFID浠诲姟
+                                        List<DpRfidTask> rfidTaskList = GetRfidTaskList(rfidNumStr);
+                                        jsonObject.put("RFID_Task", rfidTaskList);
+
+                                        //RFID浠诲姟GoodsList涓幏鍙栫墿鍝佷俊鎭�
+//                                        if(rfidTaskList.size()>0){
+//                                            DpRfidTask dpRfidTask = rfidTaskList.get(0);
+//                                            JSONArray jsonArray = JSON.parseArray(dpRfidTask.getGoodsList().toString());
+//                                            JSONObject goods = jsonArray.getJSONObject(0);
+//                                            String rfidNum = goods.getString("rfid");
+//                                        }
+
+                                        //鏍规嵁浠诲姟鍒楄〃涓殑rfidNum鏌ヨRFID杞﹁締鏁版嵁
+                                        List<DpRfidVehicle> vehicleList = GetVehicleList(rfidNumStr);
+                                        jsonObject.put("RFID_Vehicle", vehicleList);
+
+                                        sendMessage(jsonObject.toString());
+
+                                    }
+                                }
+                            } catch (Exception e) {
+                                e.printStackTrace();
+                            }
+                        }, 0, 10, TimeUnit.SECONDS
+
+                );
+            } else if (type.equals("endSupply")) {
+                onClose();
+            } else {
+                sendMessage("浼犲弬澶辫触");
+            }
+
+        } catch (Exception e) {
+            log.error("蹇冭烦澶辫触锛屽鎴风宸叉柇绾�", e);
+        }
+    }
+
+    /**
+     * @param session
+     * @param error
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("鐢ㄦ埛閿欒:" + this.userId + ",鍘熷洜:" + error.getMessage());
+        error.printStackTrace();
+    }
+
+    /**
+     * 瀹炵幇鏈嶅姟鍣ㄤ富鍔ㄦ帹閫�
+     */
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+
+    /**
+     * 鍙戦�佽嚜瀹氫箟娑堟伅
+     */
+    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
+        log.info("鍙戦�佹秷鎭埌:" + userId + "锛屾姤鏂�:" + message);
+        if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
+            webSocketMap.get(userId).sendMessage(message);
+        } else {
+            log.error("鐢ㄦ埛" + userId + ",涓嶅湪绾匡紒");
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketEquServer.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketEquServer.onlineCount--;
+    }
+
+    /**
+     * 瀹炵幇鏈嶅姟鍣ㄤ富鍔ㄦ帹閫�
+     */
+    public static void sendAllMessage(String message) {
+        Iterator<String> key = webSocketMap.keys().asIterator();
+        while (key.hasNext()) {
+            String strList = (String) key.next();
+            try {
+                log.info(strList);
+                webSocketMap.get(strList).sendMessage(message);
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("鎺ㄩ�佸け璐�:", e);
+            }
+        }
+    }
+    //鏍规嵁FIELD_NAME鏌ヨ璁惧璇︽儏缁忕含搴︼紙RFID锛�
+    private DpEquipment GetEquipmentByFieldName(String fieldName){
+        EquipmentService equipmentService = getBean(EquipmentService.class);
+        QueryWrapper<DpEquipment> equipmentQueryWrapper = new QueryWrapper<>();
+        equipmentQueryWrapper.eq("FIELD_NAME", fieldName);
+        return equipmentService.getOne(equipmentQueryWrapper);
+    }
+    //鏍规嵁浠诲姟鍒楄〃涓殑rfidNum鏌ヨRFID杞﹁締鏁版嵁
+    private List<DpRfidVehicle> GetVehicleList(String rfidNumStr){
+        DpRfidVehicleService dpRfidVehicleService = getBean(DpRfidVehicleService.class);
+        List<DpRfidVehicle> rfidVehicleList = new ArrayList<>();
+
+            DpRfidVehicle rfidVehicle = dpRfidVehicleService.QueryVehicleByTask(rfidNumStr);
+            DpEquipment equipment = GetEquipmentByFieldName(rfidVehicle.getSn());
+
+            rfidVehicle.setEquId(equipment.getId());
+            rfidVehicle.setX(equipment.getX());
+            rfidVehicle.setY(equipment.getY());
+            rfidVehicle.setZ(equipment.getZ());
+            rfidVehicleList.add(rfidVehicle);
+            return rfidVehicleList;
+    }
+    //鏍规嵁浠诲姟鍒楄〃涓殑rfidNum鏌ヨRFID浠诲姟
+    private List<DpRfidTask> GetRfidTaskList(String rfidNumStr){
+        DpRfidTaskService dpRfidTaskService = getBean(DpRfidTaskService.class);
+        LambdaQueryWrapper<DpRfidTask> rfidTaskWrapper = new LambdaQueryWrapper<>();
+        List<DpRfidTask> rfidTaskList = new ArrayList<>();
+        rfidTaskWrapper.like(DpRfidTask::getWzData, rfidNumStr).orderByDesc(DpRfidTask::getPassTime).last("LIMIT 1");
+        rfidTaskList = dpRfidTaskService.list(rfidTaskWrapper);
+        return rfidTaskList;
+    }
+
+    private Object equDataList(Integer id) {
+        EquipmentService equipmentService = getBean(EquipmentService.class);
+        ReceiveOilValueService receiveOilValueService = getBean(ReceiveOilValueService.class);
+        ReceiveWaterValueService receiveWaterValueService = getBean(ReceiveWaterValueService.class);
+        ReceiveElectricityValueService receiveElectricityValueService = getBean(ReceiveElectricityValueService.class);
+        DpEquipment receiveInfo = equipmentService.getById(id);
+        if (receiveInfo == null) {
+            return new Object();
+        }
+        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquipmentTypeId()) ||
+                DataTypeEnum.LIJIUJUN.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+                or().eq(ReceiveOilValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .orderByDesc(ReceiveOilValue::getCreateTime).last("LIMIT 1");
+            }});
+        } else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquipmentTypeId()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquipmentTypeId())
+                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return receiveWaterValueService.getOne(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+                or().eq(ReceiveWaterValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .orderByDesc(ReceiveWaterValue::getCreateTime).last("LIMIT 1");
+            }});
+        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquipmentTypeId())) {
+            return receiveElectricityValueService.getOne(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+                or().eq(ReceiveElectricityValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+                        .orderByDesc(ReceiveElectricityValue::getCreateTime).last("LIMIT 1");
+            }});
+        }
+        return new Object();
+    }
+
+}
diff --git a/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties b/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties
new file mode 100644
index 0000000..37e7b58
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/META-INF/spring-devtools.properties
@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson2.*.jar
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml
new file mode 100644
index 0000000..dcfc53b
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/application-dev.yml
@@ -0,0 +1,63 @@
+# 鏁版嵁婧愰厤缃�
+spring:
+    datasource:
+        type: com.alibaba.druid.pool.DruidDataSource
+        driverClassName: dm.jdbc.driver.DmDriver
+        druid:
+            # 涓诲簱鏁版嵁婧�
+            master:
+                url: jdbc:dm://127.0.0.1:5236?schema=SYSDBA
+#                url: jdbc:dm://192.168.0.4:5236?schema=SYSDBA
+                username: SYSDBA
+                password: Sysdba2025!
+            # 浠庡簱鏁版嵁婧�
+            slave:
+                # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+                enabled: true
+                url: jdbc:dm://127.0.0.1:5236?schema=DATABASE
+#                url: jdbc:dm://192.168.0.4:5236?schema=DATABASE
+                username: SYSDBA
+                password: Sysdba2025!
+            # 鍒濆杩炴帴鏁�
+            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
+                    # 鎱QL璁板綍
+                    log-slow-sql: true
+                    slow-sql-millis: 1000
+                    merge-sql: true
+                wall:
+                    config:
+                        multi-statement-allow: true
diff --git a/ruoyi-admin/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml
new file mode 100644
index 0000000..947e055
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/application-prod.yml
@@ -0,0 +1,64 @@
+# 鏁版嵁婧愰厤缃�
+spring:
+    jackson:
+        date-format: yyyy-MM-dd HH:mm:ss
+        time-zone: GMT+8
+    datasource:
+        type: com.alibaba.druid.pool.DruidDataSource
+        driverClassName: dm.jdbc.driver.DmDriver
+        druid:
+            # 涓诲簱鏁版嵁婧�
+            master:
+                url: jdbc:dm://10.1.10.10:5236?schema=SYSDBA
+                username: SYSDBA
+                password: Sysdba2025!
+            # 浠庡簱鏁版嵁婧�
+            slave:
+                # 浠庢暟鎹簮寮�鍏�/榛樿鍏抽棴
+                enabled: true
+                url: jdbc:dm://10.1.10.10:5236?schema=DATABASE
+                username: SYSDBA
+                password: Sysdba2025!
+            # 鍒濆杩炴帴鏁�
+            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
+                    # 鎱QL璁板綍
+                    log-slow-sql: true
+                    slow-sql-millis: 1000
+                    merge-sql: true
+                wall:
+                    config:
+                        multi-statement-allow: true
diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml
new file mode 100644
index 0000000..d5aad73
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/application.yml
@@ -0,0 +1,147 @@
+# 椤圭洰鐩稿叧閰嶇疆
+ruoyi:
+  # 鍚嶇О
+  name: RuoYi
+  # 鐗堟湰
+  version: 3.8.9
+  # 鐗堟潈骞翠唤
+  copyrightYear: 2025
+  # 鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/uploadPath锛孡inux閰嶇疆 /home/ruoyi/uploadPath锛�
+  profile: /home/ruoyi/uploadPath
+  # json涓存椂鏂囦欢璺緞 绀轰緥锛� Windows閰嶇疆D:/ruoyi/json锛孡inux閰嶇疆 /home/ruoyi/json锛�
+  json: /home/ruoyi/json
+  # 鑾峰彇ip鍦板潃寮�鍏�
+  addressEnabled: false
+  # 楠岃瘉鐮佺被鍨� math 鏁板瓧璁$畻 char 瀛楃楠岃瘉
+  captchaType: math
+  bussRfidUrl: http://10.1.10.11:10800/open/goods/task
+
+knife4j:
+  # 寮�鍚寮洪厤缃�
+  enable: true
+  title: 绂忓窞
+  description: 鎺ュ彛鏂囨。
+  version: 1.0.0
+
+# 寮�鍙戠幆澧冮厤缃�
+server:
+  # 鏈嶅姟鍣ㄧ殑HTTP绔彛锛岄粯璁や负8080
+  port: 8095
+  servlet:
+    # 搴旂敤鐨勮闂矾寰�
+    context-path: /
+  tomcat:
+    # tomcat鐨刄RI缂栫爜
+    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:
+  jackson:
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  # 璧勬簮淇℃伅
+  messages:
+    # 鍥介檯鍖栬祫婧愭枃浠惰矾寰�
+    basename: i18n/messages
+  profiles:
+    active: dev
+  #    active: prod
+  # 鏂囦欢涓婁紶
+  servlet:
+    multipart:
+      # 鍗曚釜鏂囦欢澶у皬
+      max-file-size: 1024MB
+      # 璁剧疆鎬讳笂浼犵殑鏂囦欢澶у皬
+      max-request-size: 4096MB
+  # 鏈嶅姟妯″潡
+  devtools:
+    restart:
+      # 鐑儴缃插紑鍏�
+      enabled: true
+  data:
+    # redis 閰嶇疆
+    redis:
+      # 鍦板潃
+      host: 127.0.0.1
+      # 绔彛锛岄粯璁や负6379
+      port: 6369
+      # 鏁版嵁搴撶储寮�
+      database: 0
+      # 瀵嗙爜
+      password: rediS_5L#F4_Server
+      # 杩炴帴瓒呮椂鏃堕棿
+      timeout: 10s
+      lettuce:
+        pool:
+          # 杩炴帴姹犱腑鐨勬渶灏忕┖闂茶繛鎺�
+          min-idle: 0
+          # 杩炴帴姹犱腑鐨勬渶澶х┖闂茶繛鎺�
+          max-idle: 8
+          # 杩炴帴姹犵殑鏈�澶ф暟鎹簱杩炴帴鏁�
+          max-active: 8
+          # #杩炴帴姹犳渶澶ч樆濉炵瓑寰呮椂闂达紙浣跨敤璐熷�艰〃绀烘病鏈夐檺鍒讹級
+          max-wait: -1ms
+  mvc:
+    throw-exception-if-no-handler-found: false
+    static-path-pattern: "/**"
+  web:
+    resources:
+      add-mappings: true
+
+# token閰嶇疆
+token:
+  # 浠ょ墝鑷畾涔夋爣璇�
+  header: Authorization
+  # 浠ょ墝瀵嗛挜
+  secret: abcdefghijklmnopqrstuvwxyz
+  # 浠ょ墝鏈夋晥鏈燂紙榛樿30鍒嗛挓锛�
+  expireTime: 60
+
+mybatis-plus:
+  type-aliases-package: com.ruoyi.**.domain
+  mapper-locations: classpath*:mapper/**/*Mapper.xml
+  config-location: classpath:mybatis/mybatis-config.xml
+
+# PageHelper鍒嗛〉鎻掍欢
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# Springdoc閰嶇疆
+springdoc:
+  swagger-ui:
+    path: /swagger-ui.html  # Swagger UI 璁块棶璺緞
+  api-docs:
+    path: /v3/api-docs
+
+# 闃叉XSS鏀诲嚮
+xss:
+  # 杩囨护寮�鍏�
+  enabled: true
+  # 鎺掗櫎閾炬帴锛堝涓敤閫楀彿鍒嗛殧锛�
+  excludes: /system/notice
+  # 鍖归厤閾炬帴
+  urlPatterns: /system/*,/monitor/*,/tool/*
+
diff --git a/ruoyi-admin/src/main/resources/banner.txt b/ruoyi-admin/src/main/resources/banner.txt
new file mode 100644
index 0000000..caf7363
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/banner.txt
@@ -0,0 +1,11 @@
+Application Version: ${ruoyi.version}
+Spring Boot Version: ${spring-boot.version}
+                                   __                                 __
+                                  /\ \__                             /\ \__
+ _ __    __   _____     ___   _ __\ \ ,_\        ____  __  __    ____\ \ ,_\    __    ___ ___
+/\`'__\/'__`\/\ '__`\  / __`\/\`'__\ \ \/       /',__\/\ \/\ \  /',__\\ \ \/  /'__`\/' __` __`\
+\ \ \//\  __/\ \ \L\ \/\ \L\ \ \ \/ \ \ \_     /\__, `\ \ \_\ \/\__, `\\ \ \_/\  __//\ \/\ \/\ \
+ \ \_\\ \____\\ \ ,__/\ \____/\ \_\  \ \__\    \/\____/\/`____ \/\____/ \ \__\ \____\ \_\ \_\ \_\
+  \/_/ \/____/ \ \ \/  \/___/  \/_/   \/__/     \/___/  `/___/> \/___/   \/__/\/____/\/_/\/_/\/_/
+                \ \_\                                      /\___/
+                 \/_/                                      \/__/
diff --git a/ruoyi-admin/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties
new file mode 100644
index 0000000..93de005
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/i18n/messages.properties
@@ -0,0 +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}]
diff --git a/ruoyi-admin/src/main/resources/logback.xml b/ruoyi-admin/src/main/resources/logback.xml
new file mode 100644
index 0000000..a360583
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/logback.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 鏃ュ織瀛樻斁璺緞 -->
+	<property name="log.path" value="/home/ruoyi/logs" />
+    <!-- 鏃ュ織杈撳嚭鏍煎紡 -->
+	<property name="log.pattern" value="%d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - [%method,%line] - %msg%n" />
+
+	<!-- 鎺у埗鍙拌緭鍑� -->
+	<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+	</appender>
+	
+	<!-- 绯荤粺鏃ュ織杈撳嚭 -->
+	<appender name="file_info" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-info.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+		<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+			<fileNamePattern>${log.path}/sys-info.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+			<maxHistory>60</maxHistory>
+		</rollingPolicy>
+		<encoder>
+			<pattern>${log.pattern}</pattern>
+		</encoder>
+		<filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>INFO</level>
+            <!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+	</appender>
+	
+	<appender name="file_error" class="ch.qos.logback.core.rolling.RollingFileAppender">
+	    <file>${log.path}/sys-error.log</file>
+        <!-- 寰幆鏀跨瓥锛氬熀浜庢椂闂村垱寤烘棩蹇楁枃浠� -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鏃ュ織鏂囦欢鍚嶆牸寮� -->
+            <fileNamePattern>${log.path}/sys-error.%d{yyyy-MM-dd}.log</fileNamePattern>
+			<!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+			<maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 杩囨护鐨勭骇鍒� -->
+            <level>ERROR</level>
+			<!-- 鍖归厤鏃剁殑鎿嶄綔锛氭帴鏀讹紙璁板綍锛� -->
+            <onMatch>ACCEPT</onMatch>
+			<!-- 涓嶅尮閰嶆椂鐨勬搷浣滐細鎷掔粷锛堜笉璁板綍锛� -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+	
+	<!-- 鐢ㄦ埛璁块棶鏃ュ織杈撳嚭  -->
+    <appender name="sys-user" class="ch.qos.logback.core.rolling.RollingFileAppender">
+		<file>${log.path}/sys-user.log</file>
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 鎸夊ぉ鍥炴粴 daily -->
+            <fileNamePattern>${log.path}/sys-user.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 鏃ュ織鏈�澶х殑鍘嗗彶 60澶� -->
+            <maxHistory>60</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+	
+	<!-- 绯荤粺妯″潡鏃ュ織绾у埆鎺у埗  -->
+	<logger name="com.ruoyi" level="info" />
+	<!-- Spring鏃ュ織绾у埆鎺у埗  -->
+	<logger name="org.springframework" level="warn" />
+
+	<root level="info">
+		<appender-ref ref="console" />
+	</root>
+	
+	<!--绯荤粺鎿嶄綔鏃ュ織-->
+    <root level="info">
+        <appender-ref ref="file_info" />
+        <appender-ref ref="file_error" />
+    </root>
+	
+	<!--绯荤粺鐢ㄦ埛鎿嶄綔鏃ュ織-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+</configuration> 
\ No newline at end of file
diff --git a/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml b/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
new file mode 100644
index 0000000..ac47c03
--- /dev/null
+++ b/ruoyi-admin/src/main/resources/mybatis/mybatis-config.xml
@@ -0,0 +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>
diff --git a/ruoyi-admin/src/test/java/com/ruoyi/web/MybatisPlusGeneraotr.java b/ruoyi-admin/src/test/java/com/ruoyi/web/MybatisPlusGeneraotr.java
new file mode 100644
index 0000000..257aab2
--- /dev/null
+++ b/ruoyi-admin/src/test/java/com/ruoyi/web/MybatisPlusGeneraotr.java
@@ -0,0 +1,72 @@
+package com.ruoyi.web;
+
+import com.baomidou.mybatisplus.annotation.FieldFill;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.generator.FastAutoGenerator;
+import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
+import com.baomidou.mybatisplus.generator.engine.VelocityTemplateEngine;
+import com.baomidou.mybatisplus.generator.fill.Column;
+import org.junit.Test;
+
+/**
+ * @className: MybatisPlusGeneraotr
+ * @description: mybatis plus浠g爜鐢熸垚鍣�
+ **/
+public class MybatisPlusGeneraotr {
+
+    @Test
+   public void mybatisPlusGenerator() {
+                // 鏁版嵁婧愰厤缃�
+        FastAutoGenerator.create(
+                        "jdbc:dm://localhost:5236/DATABASE?rewriteBatchedStatements=true&zeroDateTimeBehavior=convertToNull&useUnicode=true&characterEncoding=utf-8",
+                        "SYSDBA",     // 杈炬ⅵ鏁版嵁搴撴ā寮忓悕
+                        "Sysdba2025!"        // 瀵嗙爜
+                )
+                // 鍏ㄥ眬閰嶇疆
+                .globalConfig(
+                        builder -> {
+                            builder
+                                    .author("sunjiawei")// 浣滆��
+                                    .outputDir(System.getProperty("user.dir") + "/src/test/java")// 鎸囧畾杈撳嚭鐩綍
+                                    .commentDate("yyyy-MM-dd")// 娉ㄩ噴鐨勬棩鏈�
+                                    // 淇敼Date绫诲瀷涓篖ocalDateTime
+                                    //.dateType(DateType.ONLY_DATE)
+                                    .enableSwagger()
+                                    .disableOpenDir();// 绂佹鎵撳紑杈撳嚭鐩綍锛岄粯璁わ細true
+                        }
+                )
+                // 鍖呴厤缃�
+                .packageConfig(
+                        builder -> {
+                            builder
+                                    .parent(this.getClass().getPackageName() + ".base") // 鐖跺寘鍚�
+                                    .entity("pojo.entity")  // 瀹炰綋绫诲寘鍚�
+                                    .other("utils"); // 鑷畾涔夋枃浠跺寘鍚�
+                        }
+                )
+                // 绛栫暐閰嶇疆
+                .strategyConfig(
+                        builder -> {
+                            builder
+                                    //todo 鍦ㄨ繖閲屾坊鍔犳暟鎹簱琛ㄥ悕 璁剧疆闇�瑕佺敓鎴愮殑琛ㄥ悕锛屽涓〃涔嬮棿鍙互鐢ㄩ�楀彿闅斿紑
+                                    .addInclude("HIK_EVENT")
+                                    .controllerBuilder().enableRestStyle()          // controller閰嶇疆绛栫暐
+                                    .serviceBuilder().formatServiceFileName("%sService")            // service閰嶇疆绛栫暐
+                                    .mapperBuilder().enableBaseColumnList().enableBaseResultMap().enableMapperAnnotation()// mapper閰嶇疆绛栫暐
+                                    .entityBuilder().enableLombok().enableRemoveIsPrefix().disableSerialVersionUID().enableTableFieldAnnotation() // 瀹炰綋閰嶇疆绛栫暐
+                                    .logicDeleteColumnName("is_deleted")// 閫昏緫鍒犻櫎瀛楁鍚�
+                                    .naming(NamingStrategy.underline_to_camel)// 鏁版嵁搴撹〃鏄犲皠鍒板疄浣撶殑鍛藉悕绛栫暐锛屼笅鍒掔嚎杞┘宄�
+                                    .columnNaming(NamingStrategy.underline_to_camel) // 鏁版嵁搴撹〃瀛楁鏄犲皠鐨勫懡鍚嶇瓥鐣ワ紝涓嬪垝绾胯浆椹煎嘲
+                                    .addTableFills(    // 娣诲姞琛ㄥ瓧娈靛~鍏咃紝"create_time"鑷姩濉厖涓烘彃鍏ユ椂闂达紝"update_time"鑷姩濉厖涓轰慨鏀规椂闂�
+                                            new Column("create_time", FieldFill.INSERT),
+                                            new Column("update_time", FieldFill.INSERT_UPDATE)
+                                    )
+                                    .idType(IdType.AUTO);
+                        }
+                )
+                // 妯℃澘閰嶇疆
+                .templateEngine(new VelocityTemplateEngine())    // 浣跨敤鐨勬槸榛樿鐨� Velocity 寮曟搸妯℃澘
+                // 鎵ц
+                .execute();
+    }
+}
diff --git a/ruoyi-buss/pom.xml b/ruoyi-buss/pom.xml
new file mode 100644
index 0000000..7ac5f2c
--- /dev/null
+++ b/ruoyi-buss/pom.xml
@@ -0,0 +1,61 @@
+<?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>
+
+  <artifactId>ruoyi-buss</artifactId>
+  <modelVersion>4.0.0</modelVersion>
+
+  <name>ruoyi-buss</name>
+
+  <description>
+    涓氬姟绯荤粺妯″潡
+  </description>
+
+
+
+  <dependencies>
+
+    <!-- 閫氱敤宸ュ叿-->
+<!--    <dependency>-->
+<!--      <groupId>com.ruoyi</groupId>-->
+<!--      <artifactId>ruoyi-common</artifactId>-->
+<!--    </dependency>-->
+
+      <dependency>
+          <groupId>com.ruoyi</groupId>
+          <artifactId>ruoyi-framework</artifactId>
+      </dependency>
+
+<!--    <dependency>-->
+<!--      <groupId>com.squareup.okhttp3</groupId>-->
+<!--      <artifactId>okhttp</artifactId>-->
+<!--      <version>4.10.0</version>-->
+<!--    </dependency>-->
+
+<!--      <dependency>-->
+<!--          <groupId>com.github.xiaoymin</groupId>-->
+<!--          <artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>-->
+<!--          <version>4.4.0</version>-->
+<!--      </dependency>-->
+
+      <!--        <dependency>-->
+      <!--            <groupId>org.springdoc</groupId>-->
+      <!--            <artifactId>springdoc-openapi-ui</artifactId>-->
+      <!--            <version>1.8.0</version> &lt;!&ndash; 璇蜂娇鐢ㄦ渶鏂扮増鏈� &ndash;&gt;-->
+      <!--        </dependency>-->
+
+<!--      <dependency>-->
+<!--          <groupId>org.springdoc</groupId>-->
+<!--          <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>-->
+<!--          <version>2.6.0</version>  &lt;!&ndash; 鐗堟湰鍙疯鏍规嵁浣犵殑Spring Boot鐗堟湰鍖归厤 &ndash;&gt;-->
+<!--      </dependency>-->
+
+  </dependencies>
+
+</project>
diff --git a/ruoyi-buss/ruoyi-buss.iml b/ruoyi-buss/ruoyi-buss.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-buss/ruoyi-buss.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/GeneticFleetAssignment.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/GeneticFleetAssignment.java
new file mode 100644
index 0000000..a192b3d
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/GeneticFleetAssignment.java
@@ -0,0 +1,151 @@
+package com.ruoyi.buss;
+
+import java.util.*;
+
+class Port {
+    String name;
+    int berths;
+    int supplyCapacity;
+    int x, y; // Coordinates for distance calculation
+
+    public Port(String name, int berths, int supplyCapacity, int x, int y) {
+        this.name = name;
+        this.berths = berths;
+        this.supplyCapacity = supplyCapacity;
+        this.x = x;
+        this.y = y;
+    }
+}
+
+class Ship {
+    String name;
+    int supplyNeed;
+    int x, y; // Current coordinates
+
+    public Ship(String name, int supplyNeed, int x, int y) {
+        this.name = name;
+        this.supplyNeed = supplyNeed;
+        this.x = x;
+        this.y = y;
+    }
+}
+
+class Assignment {
+    List<Integer> assignments; // Index of port for each ship
+    double fitness;
+
+    public Assignment(List<Integer> assignments) {
+        this.assignments = assignments;
+        this.fitness = 0.0;
+    }
+}
+
+public class GeneticFleetAssignment {
+
+    private static final int POPULATION_SIZE = 50;
+    private static final int GENERATIONS = 100;
+    private static final double MUTATION_RATE = 0.1;
+
+    public static double calculateDistance(Ship ship, Port port) {
+        return Math.sqrt(Math.pow(ship.x - port.x, 2) + Math.pow(ship.y - port.y, 2));
+    }
+
+    public static double evaluateFitness(Assignment assignment, List<Ship> ships, List<Port> ports) {
+        double totalDistance = 0.0;
+        int[] portBerths = new int[ports.size()];
+        int[] portSupply = new int[ports.size()];
+
+        for (int i = 0; i < assignment.assignments.size(); i++) {
+            int portIndex = assignment.assignments.get(i);
+            Ship ship = ships.get(i);
+            Port port = ports.get(portIndex);
+
+            totalDistance += calculateDistance(ship, port);
+            portBerths[portIndex]++;
+            portSupply[portIndex] += ship.supplyNeed;
+        }
+
+        for (int i = 0; i < ports.size(); i++) {
+            if (portBerths[i] > ports.get(i).berths || portSupply[i] > ports.get(i).supplyCapacity) {
+                return Double.MAX_VALUE; // Invalid assignment
+            }
+        }
+
+        return totalDistance;
+    }
+
+    public static Assignment crossover(Assignment parent1, Assignment parent2) {
+        Random rand = new Random();
+        int crossoverPoint = rand.nextInt(parent1.assignments.size());
+        List<Integer> childAssignments = new ArrayList<>(parent1.assignments.subList(0, crossoverPoint));
+        childAssignments.addAll(parent2.assignments.subList(crossoverPoint, parent2.assignments.size()));
+        return new Assignment(childAssignments);
+    }
+
+    public static void mutate(Assignment assignment, int numPorts) {
+        Random rand = new Random();
+        if (rand.nextDouble() < MUTATION_RATE) {
+            int index = rand.nextInt(assignment.assignments.size());
+            assignment.assignments.set(index, rand.nextInt(numPorts));
+        }
+    }
+
+    public static Assignment geneticAlgorithm(List<Ship> ships, List<Port> ports) {
+        Random rand = new Random();
+        List<Assignment> population = new ArrayList<>();
+
+        // Initialize population
+        for (int i = 0; i < POPULATION_SIZE; i++) {
+            List<Integer> assignments = new ArrayList<>();
+            for (int j = 0; j < ships.size(); j++) {
+                assignments.add(rand.nextInt(ports.size()));
+            }
+            population.add(new Assignment(assignments));
+        }
+
+        for (int generation = 0; generation < GENERATIONS; generation++) {
+            // Evaluate fitness
+            for (Assignment assignment : population) {
+                assignment.fitness = evaluateFitness(assignment, ships, ports);
+            }
+
+            // Sort by fitness
+            population.sort(Comparator.comparingDouble(a -> a.fitness));
+
+            // Selection and reproduction
+            List<Assignment> newPopulation = new ArrayList<>();
+            for (int i = 0; i < POPULATION_SIZE / 2; i++) {
+                Assignment parent1 = population.get(i);
+                Assignment parent2 = population.get(rand.nextInt(POPULATION_SIZE / 2));
+                Assignment child = crossover(parent1, parent2);
+                mutate(child, ports.size());
+                newPopulation.add(child);
+            }
+
+            population = newPopulation;
+        }
+
+        // Return the best solution
+        return population.get(0);
+    }
+
+    public static void main(String[] args) {
+        List<Port> ports = Arrays.asList(
+            new Port("Port A", 2, 100, 0, 0),
+            new Port("Port B", 1, 50, 5, 5),
+            new Port("Port C", 3, 150, 10, 10)
+        );
+
+        List<Ship> ships = Arrays.asList(
+            new Ship("Ship 1", 30, 0, 0),
+            new Ship("Ship 2", 70, 0, 0),
+            new Ship("Ship 3", 50, 9, 9)
+        );
+
+        Assignment bestAssignment = geneticAlgorithm(ships, ports);
+
+        for (int i = 0; i < ships.size(); i++) {
+            System.out.println("Ship " + ships.get(i).name + " assigned to port " + ports.get(bestAssignment.assignments.get(i)).name);
+        }
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/AssessUtil.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/AssessUtil.java
new file mode 100644
index 0000000..36ff34f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/AssessUtil.java
@@ -0,0 +1,251 @@
+package com.ruoyi.buss.common;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import javax.script.ScriptEngineFactory;
+import javax.tools.*;
+import java.lang.reflect.Method;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLClassLoader;
+import java.util.Arrays;
+import java.util.List;
+
+public class AssessUtil {
+
+    /**
+     * 鎵规鎬昏ˉ缁欐暟閲�  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForShipCount(int count){
+        if(count > 0 && count < 6){
+            return 0.2;
+        }
+        else if(count >= 6 && count < 12){
+            return 0.4;
+        }
+        else if(count >= 12 && count < 20){
+            return 0.6;
+        }
+        else if(count >= 20 && count < 30){
+            return 0.8;
+        }
+        else if(count >= 30){
+            return 1.0;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 鎵规鍗曡埌鎶樺彔琛ョ粰鏃堕棿  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForShipEmpty(int count){
+        if(count < 4){
+            return 1.0;
+        }
+        else if(count < 8 && count >= 4){
+            return 0.8;
+        }
+        else if(count >= 8 && count < 12){
+            return 0.6;
+        }
+        else if(count >= 12 && count < 18){
+            return 0.4;
+        }
+        else if(count >= 18 && count < 24){
+            return 0.2;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 鍚勬腐鍙g粨鏉熸渶澶ф椂闂村樊  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForHarborTimeDif(int count){
+        if(count < 4){
+            return 1.0;
+        }
+        else if(count >= 4 && count < 8){
+            return 0.8;
+        }
+        else if(count >= 8 && count < 12){
+            return 0.6;
+        }
+        else if(count >= 12 && count < 18){
+            return 0.4;
+        }
+        else if(count >= 18 && count < 24){
+            return 0.2;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 鍗曡埌骞冲潎鍋滈潬鏃堕棿  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForShipStopTime(int hour){
+        if(hour > 48){
+            return 0.4;
+        }
+        else if(hour > 36 && hour <= 48){
+            return 0.6;
+        }
+        else if(hour > 30 && hour <= 36){
+            return 0.7;
+        }
+        else if(hour > 24 && hour <= 30){
+            return 0.8;
+        }
+        else if(hour > 18 && hour <= 24){
+            return 1.0;
+        }
+        else if(hour > 12 && hour <= 18){
+            return 0.8;
+        }
+        else if(hour > 6 && hour <= 12){
+            return 0.7;
+        }
+        else if(hour <= 6){
+            return 0.6;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 琛ョ粰浣滀笟鏃堕棿鍧囧��  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForApplyTime(int hour){
+        if(hour > 36){
+            return 0.4;
+        }
+        else if(hour > 24 && hour <= 36){
+            return 0.6;
+        }
+        else if(hour > 20 && hour <= 24){
+            return 0.8;
+        }
+        else if(hour > 16 && hour <= 20){
+            return 1.0;
+        }
+        else if(hour > 12 && hour <= 16){
+            return 0.8;
+        }
+        else if(hour < 8){
+            return 0.6;
+        }
+        return 0.0;
+    }
+
+     /**
+     * 琛ョ粰闈炰綔涓氭椂闂村潎鍊�  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForNotApplyTime(int hour){
+        if(hour > 24){
+            return 0.0;
+        }
+        else if(hour > 16 && hour <= 24){
+            return 0.2;
+        }
+        else if(hour > 12 && hour <= 16){
+            return 0.4;
+        }
+        else if(hour > 8 && hour <= 12){
+            return 0.6;
+        }
+        else if(hour > 4 && hour <= 8){
+            return 0.8;
+        }
+        else if(hour <= 4){
+            return 1.0;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 娉婁綅鏃ュ潎鍛ㄨ浆鑹樻  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForBerthTime(double hour){
+        if (hour > 0) {
+            double result =  (double)hour / 3.0;
+            return result > 1.0 ? 1.0 : result;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 鍓嶆部鍗犲崐鏃堕暱鍧囧��  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForBerthHoldTime(double hour){
+        if (hour > 0) {
+            double result = (double) hour / 24.0;
+            return result > 1 ? 1.0 : result;
+        }
+        return 0.0;
+    }
+
+    /**
+     * 鍚勬硦浣嶇墿璧勮溅娆″潎鍊�  鏁堣兘璇勪及鏁板�艰绠�
+     */
+    public static double getPercentForCar(double count){
+        if (count > 0) {
+            double result = (double)count / 24.0;
+            return result > 1.0 ? 1.0 : result;
+        }
+        return 0.0;
+    }
+
+
+    private static Double getScore(Double list) {
+        try {
+            // 鍒涘缓Java缂栬瘧鍣�
+            JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
+            DiagnosticCollector<JavaFileObject> diagnostics = new DiagnosticCollector<>();
+            
+            // 鍒涘缓婧愪唬鐮�
+            String sourceCode = "public class DynamicScore {" +
+                "   public static double calculateScore(double value) {" +
+                "       return Math.round(value * 10 * 100) / 100.0;" +
+                "   }" +
+                "}";
+            
+            // 鍒涘缓鍐呭瓨涓殑Java婧愭枃浠�
+            JavaFileObject sourceFile = new SimpleJavaFileObject(
+                URI.create("string:///DynamicScore.java"),
+                JavaFileObject.Kind.SOURCE) {
+                @Override
+                public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+                    return sourceCode;
+                }
+            };
+            
+            // 缂栬瘧婧愪唬鐮�
+            StandardJavaFileManager fileManager = compiler.getStandardFileManager(diagnostics, null, null);
+            Iterable<? extends JavaFileObject> compilationUnits = Arrays.asList(sourceFile);
+            JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, diagnostics, null, null, compilationUnits);
+            boolean success = task.call();
+            
+            if (success) {
+                // 鍒涘缓鑷畾涔夌被鍔犺浇鍣�
+                ClassLoader classLoader = new URLClassLoader(new URL[0], AssessUtil.class.getClassLoader());
+                Class<?> dynamicClass = Class.forName("DynamicScore", true, classLoader);
+                
+                // 璋冪敤鏂规硶
+                Method method = dynamicClass.getMethod("calculateScore", double.class);
+                return (Double) method.invoke(null, list);
+            }
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("璁$畻鍒嗘暟澶辫触");
+        }
+        return 0.0;
+    }
+
+    public static void main(String[] args) {
+        System.out.println(getScore(32.1));
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/DateUtils.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/DateUtils.java
new file mode 100644
index 0000000..dc0aaf9
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/DateUtils.java
@@ -0,0 +1,115 @@
+package com.ruoyi.buss.common;
+
+import java.text.DecimalFormat;
+import java.time.*;
+import java.time.format.DateTimeFormatter;
+import java.util.Calendar;
+import java.util.Date;
+
+public class DateUtils {
+
+    public static Date setToNextDayZero(Date originalDate) {
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(originalDate);
+
+        // 澧炲姞涓�澶�
+        calendar.add(Calendar.DAY_OF_MONTH, 1);
+
+        // 璁剧疆涓洪浂鐐�
+        calendar.set(Calendar.HOUR_OF_DAY, 0);
+        calendar.set(Calendar.MINUTE, 0);
+        calendar.set(Calendar.SECOND, 0);
+        calendar.set(Calendar.MILLISECOND, 0);
+
+        return calendar.getTime();
+    }
+
+    /**
+     * 鑾峰彇涓や釜鏃ユ湡涔嬮棿鐨勫ぉ鏁板樊
+     * @param date1
+     * @param date2
+     * @return
+     */
+    public static long getSubtractOfTowDate(Date date1, Date date2) {
+        // 璁$畻姣宸�
+        long diffMillis = Math.abs(date2.getTime() - date1.getTime());
+        // 杞崲涓哄ぉ鏁板苟鍚戜笂鍙栨暣
+        double days = (double) diffMillis / (24 * 60 * 60 * 1000);
+        long roundedDays = (long) Math.ceil(days);
+        return roundedDays;
+    }
+
+    /**
+     * 鑾峰彇涓や釜鏃ユ湡涔嬮棿鐨勫皬鏃舵暟宸�
+     * @param date1
+     * @param date2
+     * @return
+     */
+    public static double getDisHourOfTowDate(Date date1, Date date2) {
+        // 灏咲ate杞崲涓篒nstant
+        Instant instant1 = date1.toInstant();
+        Instant instant2 = date2.toInstant();
+
+        // 璁$畻鎸佺画鏃堕棿
+        Duration duration = Duration.between(instant1, instant2);
+
+        // 鑾峰彇鎬荤鏁板苟杞崲涓哄皬鏃讹紙鍚戜笂鍙栨暣锛�
+        long totalSeconds = duration.getSeconds();
+        int hours = (int) Math.ceil((double) totalSeconds / 3600);
+        return hours;
+    }
+
+    /**
+     * 鏍规嵁寮�濮嬫椂闂磗tartTime锛岃幏鍙杊ours灏忔椂鍚庣殑鍏蜂綋鏃堕棿
+     * @param startDate
+     * @param hours
+     * @return
+     */
+    public static Date getDateAfterHours(Date startDate, int hours) {
+        // 鎶奃ate杞崲涓篖ocalDateTime
+        LocalDateTime localDateTime = startDate.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDateTime();
+
+        // 鍔犱笂鎸囧畾鐨勫皬鏃舵暟
+        LocalDateTime newDateTime = localDateTime.plusHours(hours);
+
+        // 鍐嶈浆鍥濪ate绫诲瀷
+        Instant instant = newDateTime.atZone(ZoneId.systemDefault()).toInstant();
+        return Date.from(instant);
+    }
+
+    /**
+     * 鍒ゆ柇涓や釜鏃堕棿鏄惁鍦ㄥ悓涓�澶╁唴
+     * @param date1
+     * @param date2
+     * @return
+     */
+    public static boolean isSameDay(Date date1, Date date2) {
+        // 杞崲涓篖ocalDate锛堝拷鐣ユ椂鍖猴紝浣跨敤绯荤粺榛樿鏃跺尯锛�
+        LocalDate localDate1 = date1.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDate();
+        LocalDate localDate2 = date2.toInstant()
+                .atZone(ZoneId.systemDefault())
+                .toLocalDate();
+        // 鍒ゆ柇鏄惁涓哄悓涓�澶�
+        return localDate1.isEqual(localDate2);
+    }
+
+    public static void main(String[] args) {
+        String date1 = "2025-05-21 21:10:00";
+        String date2 = "2025-05-22 23:20:00";
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        // 瑙f瀽瀛楃涓蹭负LocalDateTime
+        LocalDateTime localDateTime1 = LocalDateTime.parse(date1, formatter);
+        LocalDateTime localDateTime2 = LocalDateTime.parse(date2, formatter);
+        // 杞崲涓篋ate锛堥渶瑕佹寚瀹氭椂鍖猴紝杩欓噷浣跨敤绯荤粺榛樿鏃跺尯锛�
+        Instant instant1 = localDateTime1.atZone(ZoneId.systemDefault()).toInstant();
+        Instant instant2 = localDateTime2.atZone(ZoneId.systemDefault()).toInstant();
+        Date date11 = Date.from(instant1);
+        Date date22 = Date.from(instant2);
+        long result = getSubtractOfTowDate(date11, date22);
+        System.out.println(result);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/Normalization.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/Normalization.java
new file mode 100644
index 0000000..35d3fa3
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/Normalization.java
@@ -0,0 +1,49 @@
+package com.ruoyi.buss.common;
+
+import java.util.Arrays;
+
+/**
+ * 褰掍竴鍖栫畻娉曞伐鍏风被
+ *
+ * @author yl
+ * @date 2025-03-20
+ */
+
+public class Normalization {
+    // 鏈�灏� - 鏈�澶у綊涓�鍖�
+    public static double[] minMaxNormalization(double[] data) {
+        double min = Arrays.stream(data).min().getAsDouble();
+        double max = Arrays.stream(data).max().getAsDouble();
+        double[] normalized = new double[data.length];
+        for (int i = 0; i < data.length; i++) {
+            normalized[i] = (data[i] - min) / (max - min);
+        }
+        return normalized;
+    }
+
+    // Z - 鍒嗘暟褰掍竴鍖�
+    public static double[] zScoreNormalization(double[] data) {
+        double mean = Arrays.stream(data).average().getAsDouble();
+        double sumSquaredDiff = Arrays.stream(data).map(x -> Math.pow(x - mean, 2)).sum();
+        double stdDev = Math.sqrt(sumSquaredDiff / data.length);
+        double[] normalized = new double[data.length];
+        for (int i = 0; i < data.length; i++) {
+            normalized[i] = (data[i] - mean) / stdDev;
+        }
+        return normalized;
+    }
+
+    public static void main(String[] args) {
+        double[] data = {12, 4, 0.9, 0.3};
+
+        // 鏈�灏� - 鏈�澶у綊涓�鍖�
+        double[] minMaxNormalized = minMaxNormalization(data);
+        System.out.println("鏈�灏� - 鏈�澶у綊涓�鍖栫粨鏋�: " + Arrays.toString(minMaxNormalized));
+
+        System.out.println("鍔犳潈姹傚拰:" + Arrays.stream(minMaxNormalized).sum());
+        // Z - 鍒嗘暟褰掍竴鍖�
+        double[] zScoreNormalized = zScoreNormalization(data);
+        System.out.println("Z - 鍒嗘暟褰掍竴鍖栫粨鏋�: " + Arrays.toString(zScoreNormalized));
+        System.out.println("Z - 鍒嗘暟鍔犳潈姹傚拰:" +  Math.round(Arrays.stream(zScoreNormalized).sum()));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/NumberUtils.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/NumberUtils.java
new file mode 100644
index 0000000..82f7df3
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/NumberUtils.java
@@ -0,0 +1,29 @@
+package com.ruoyi.buss.common;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.util.Optional;
+
+public class NumberUtils {
+
+    /**
+     * 淇濈暀涓や綅灏忔暟锛堝洓鑸嶄簲鍏ワ級
+     * @param value 鍘熷鍊�
+     * @return 淇濈暀涓や綅灏忔暟鍚庣殑 double 鍊�
+     */
+    public static double roundToTwoDecimalPlaces(double value) {
+        if(value == 0.0){return 0.0;}
+        return BigDecimal.valueOf(value)
+                .setScale(2, RoundingMode.HALF_UP)
+                .doubleValue();
+    }
+
+    public static void main(String[] args) {
+        double num = 123.456789;
+        System.out.println(roundToTwoDecimalPlaces(num)); // 123.46
+    }
+
+    public static <T> T getOrDefault(T obj, T defaultValue) {
+        return Optional.ofNullable(obj).orElse(defaultValue);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/RfidUtil.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/RfidUtil.java
new file mode 100644
index 0000000..b4ddb10
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/RfidUtil.java
@@ -0,0 +1,149 @@
+package com.ruoyi.buss.common;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.buss.domain.vo.RfIdVo;
+
+import java.io.*;
+import java.net.ConnectException;
+import java.net.HttpURLConnection;
+import java.net.SocketTimeoutException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+
+public class RfidUtil {
+
+    public static void main(String[] args) {
+        String result = sendJsonPost("http://192.168.0.2:10800/open/goods/task","{\"id\":12,\"name\":\"浠诲姟鍚嶇О\", \"path\": \"璺緞淇℃伅\"}");
+        List<RfIdVo> list = new ArrayList<>();
+        list.add(new RfIdVo(1, "NAME1", "PATH1"));
+        list.add(new RfIdVo(2, "NAME2", "PATH2"));
+        list.add(new RfIdVo(3, "NAME3", "PATH3"));
+        list.add(new RfIdVo(4, "NAME4", "PATH4"));
+        list.add(new RfIdVo(5, "NAME5", "PATH5"));
+        list.add(new RfIdVo(6, "NAME6", "PATH6"));
+
+        System.out.println("姝e父" + result);
+    }
+
+    /**
+     * 寮傛鍙戦�佽姹�
+     * @param url
+     * @param list
+     */
+    public static void asyncSendJsonPost(String url, List<RfIdVo> list){
+        ExecutorService executor = Executors.newFixedThreadPool(50); // 鏍规嵁缃戠粶璋冩暣绾跨▼鏁�
+        List<Future<?>> futures = new ArrayList<>();
+
+        for (int i = 0, len = list.size(); i < len; i++) {
+            int finalI = i;
+            futures.add(executor.submit(() -> {
+                try {
+                    URL realUrl = new URL(url);
+                    HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
+                    conn.setRequestMethod("POST");
+                    conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
+                    conn.setRequestProperty("Accept", "*/*");
+                    conn.setConnectTimeout(3000); // 3绉掕秴鏃�
+                    conn.setDoOutput(true);
+                    conn.setDoInput(true);
+                    try(OutputStream os = conn.getOutputStream()){
+                        byte[] input = JSONObject.toJSONString(list.get(finalI)).getBytes("utf-8");
+                        os.write(input, 0, input.length);
+                    }
+                    conn.getResponseCode();
+                } catch (Exception ignored) {
+                    System.out.println("鍙戦�丷FID浠诲姟澶辫触锛岃閲嶈瘯銆�"+ JSONObject.toJSONString(list.get(finalI)));
+                }
+            }));
+        }
+        executor.shutdown();
+    }
+
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丳OST鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendJsonPost(String url, String jsonString) {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            URL realUrl = new URL(url);
+            HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
+
+            conn.setRequestMethod("POST");
+            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
+            conn.setRequestProperty("Accept", "*/*");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            try(OutputStream os = conn.getOutputStream()){
+                byte[] input = jsonString.getBytes("utf-8");
+                os.write(input, 0, input.length);
+            }
+
+            int responseCode = conn.getResponseCode();
+            if(responseCode == HttpURLConnection.HTTP_OK){
+                try(BufferedReader br = new BufferedReader(
+                        new InputStreamReader(conn.getInputStream(), "utf-8")
+                )){
+                    String responseLine;
+                    while ((responseLine = br.readLine()) != null){
+                        result.append(responseLine.trim());
+                    }
+                    System.out.println(result.toString());
+                }
+            }
+            conn.disconnect();
+            System.out.println("result=" + result);
+        }
+        catch (ConnectException e)
+        {
+            System.out.println("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + jsonString);
+            e.printStackTrace();
+        }
+        catch (SocketTimeoutException e)
+        {
+            System.out.println("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + jsonString);
+            e.printStackTrace();
+        }
+        catch (IOException e)
+        {
+            System.out.println("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + jsonString);
+            e.printStackTrace();
+        }
+        catch (Exception e)
+        {
+            System.out.println("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + jsonString);
+            e.printStackTrace();
+        }
+        finally
+        {
+            try
+            {
+                if (out != null)
+                {
+                    out.close();
+                }
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (IOException ex)
+            {
+                System.out.println("璋冪敤HttpUtils.sendPost ConnectException, url=" + url + ",param=" + jsonString);
+                ex.printStackTrace();
+            }
+        }
+        return result.toString();
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicBeanRegistrar.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicBeanRegistrar.java
new file mode 100644
index 0000000..43f8c78
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicBeanRegistrar.java
@@ -0,0 +1,20 @@
+package com.ruoyi.buss.common.dynamic;
+
+import org.springframework.beans.factory.support.DefaultListableBeanFactory;
+import org.springframework.context.ConfigurableApplicationContext;
+
+public class DynamicBeanRegistrar {
+    private final ConfigurableApplicationContext context;
+    private final DynamicCompiler compiler;
+
+    public DynamicBeanRegistrar(ConfigurableApplicationContext context) {
+        this.context = context;
+        this.compiler = new DynamicCompiler();
+    }
+
+    public void registerBean(String beanName, String className, String sourceCode) throws Exception {
+        DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) context.getBeanFactory();
+        Class<?> clazz = compiler.compile(className, sourceCode);
+        beanFactory.registerSingleton(beanName, clazz.getDeclaredConstructor().newInstance());
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicCompiler.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicCompiler.java
new file mode 100644
index 0000000..c0fa2dc
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/DynamicCompiler.java
@@ -0,0 +1,41 @@
+package com.ruoyi.buss.common.dynamic;
+
+import javax.tools.*;
+import java.net.URI;
+import java.util.List;
+
+public class DynamicCompiler {
+
+    private final JavaCompiler compiler;
+    private final StandardJavaFileManager stdFileManager;
+
+    public DynamicCompiler() {
+        this.compiler = ToolProvider.getSystemJavaCompiler();
+        this.stdFileManager = compiler.getStandardFileManager(null, null, null);
+    }
+
+    public Class<?> compile(String className, String sourceCode) throws Exception {
+        MemoryJavaFileManager fileManager = new MemoryJavaFileManager(stdFileManager);
+        JavaFileObject javaFile = new StringJavaFileObject(className, sourceCode);
+
+        List<String> options = List.of("--enable-preview", "--add-modules=jdk.compiler");
+        compiler.getTask(null, fileManager, null, options, null, List.of(javaFile)).call();
+
+        return fileManager.getClassLoader().loadClass(className);
+    }
+
+    private static class StringJavaFileObject extends SimpleJavaFileObject {
+        private final String code;
+
+        protected StringJavaFileObject(String name, String code) {
+            super(URI.create("string:///" + name.replace('.','/') + Kind.SOURCE.extension), Kind.SOURCE);
+            this.code = code;
+        }
+
+        @Override
+        public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+            return code;
+        }
+    }
+}
+
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/MemoryJavaFileManager.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/MemoryJavaFileManager.java
new file mode 100644
index 0000000..587b2fc
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/dynamic/MemoryJavaFileManager.java
@@ -0,0 +1,53 @@
+package com.ruoyi.buss.common.dynamic;
+
+import javax.tools.*;
+import java.util.*;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.URI;
+
+public class MemoryJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+    private final Map<String, byte[]> classBytes = new HashMap<>();
+    private final ClassLoader loader;
+
+    public MemoryJavaFileManager(JavaFileManager fileManager) {
+        super(fileManager);
+        this.loader = new ClassLoader() {
+            @Override
+            protected Class<?> findClass(String name) throws ClassNotFoundException {
+                byte[] buf = classBytes.get(name);
+                if (buf == null) throw new ClassNotFoundException(name);
+                return defineClass(name, buf, 0, buf.length);
+            }
+        };
+    }
+
+    @Override
+    public JavaFileObject getJavaFileForOutput(Location location, String className,
+                                               JavaFileObject.Kind kind, FileObject sibling) {
+        return new MemoryOutputJavaFileObject(className);
+    }
+
+    public ClassLoader getClassLoader() {
+        return loader;
+    }
+
+    class MemoryOutputJavaFileObject extends SimpleJavaFileObject {
+        private final String name;
+
+        MemoryOutputJavaFileObject(String name) {
+            super(URI.create("mem:///" + name.replace('.','/') + Kind.CLASS.extension), Kind.CLASS);
+            this.name = name;
+        }
+
+        @Override
+        public OutputStream openOutputStream() {
+            return new ByteArrayOutputStream() {
+                @Override
+                public void close() {
+                    classBytes.put(name, toByteArray());
+                }
+            };
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/ClassUriWrapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/ClassUriWrapper.java
new file mode 100644
index 0000000..aa64ed9
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/ClassUriWrapper.java
@@ -0,0 +1,25 @@
+package com.ruoyi.buss.common.liquor;
+
+import java.net.URI;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class ClassUriWrapper {
+    private final URI uri;
+
+    private final String className;
+
+    public ClassUriWrapper(String className, URI uri) {
+        this.className = className;
+        this.uri = uri;
+    }
+
+    public URI getUri() {
+        return uri;
+    }
+
+    public String getClassName() {
+        return className;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/CustomJavaFileObject.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/CustomJavaFileObject.java
new file mode 100644
index 0000000..3e8c303
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/CustomJavaFileObject.java
@@ -0,0 +1,84 @@
+package com.ruoyi.buss.common.liquor;
+
+
+import javax.lang.model.element.Modifier;
+import javax.lang.model.element.NestingKind;
+import javax.tools.JavaFileObject;
+import java.io.*;
+import java.net.URI;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class CustomJavaFileObject implements JavaFileObject {
+    private final String className;
+    private final URI uri;
+
+    public CustomJavaFileObject(String className, URI uri) {
+        this.uri = uri;
+        this.className = className;
+    }
+
+    public URI toUri() {
+        return uri;
+    }
+
+    public InputStream openInputStream() throws IOException {
+        return uri.toURL().openStream();
+    }
+
+    public OutputStream openOutputStream() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getName() {
+        return this.className;
+    }
+
+    public Reader openReader(boolean ignoreEncodingErrors) {
+        throw new UnsupportedOperationException();
+    }
+
+    public CharSequence getCharContent(boolean ignoreEncodingErrors) {
+        throw new UnsupportedOperationException();
+    }
+
+    public Writer openWriter() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+
+    public long getLastModified() {
+        return 0;
+    }
+
+    public boolean delete() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Kind getKind() {
+        return Kind.CLASS;
+    }
+
+    public boolean isNameCompatible(String simpleName, Kind kind) {
+        return Kind.CLASS.equals(getKind())
+                && this.className.endsWith(simpleName);
+    }
+
+    public NestingKind getNestingKind() {
+        throw new UnsupportedOperationException();
+    }
+
+    public Modifier getAccessLevel() {
+        throw new UnsupportedOperationException();
+    }
+
+    public String getClassName() {
+        return this.className;
+    }
+
+
+    public String toString() {
+        return this.getClass().getName() + "[" + this.toUri() + "]";
+    }
+}
+
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DemoApp.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DemoApp.java
new file mode 100644
index 0000000..42ce35f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DemoApp.java
@@ -0,0 +1,32 @@
+package com.ruoyi.buss.common.liquor;
+
+
+import com.ruoyi.framework.web.domain.server.Sys;
+
+import java.util.ArrayList;
+
+public class DemoApp {
+
+    public static void main(String[] args) throws Exception{
+        //鍙互澶嶇敤锛堜笉瑕侊紝涓嶆柇鐨勬柊寤猴級
+        String testParam = "hhhhh";
+        String className = "HelloWorld";
+        String classCode = "import java.util.List;\n\n"+
+                "public class HelloWorld { " +
+                "   public static String test99(List<String> code) { " +
+                "       return \"hhhhhh\";" +
+                "   } " +
+                "}";
+
+        Object obj = DynamicApp.exeJavaCode(classCode, className, "test99", new ArrayList<>());
+
+        System.out.println(obj.toString());
+//        //娣诲姞婧愮爜锛堝彲澶氫釜锛夊苟 鏋勫缓
+//        compiler.addSource(className, classCode).build();
+//
+//        Class<?> clazz = compiler.getClassLoader().loadClass(className);
+//        clazz.getMethod("test99", String.class).invoke(null, testParam);
+    }
+
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicApp.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicApp.java
new file mode 100644
index 0000000..ab0dac6
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicApp.java
@@ -0,0 +1,19 @@
+package com.ruoyi.buss.common.liquor;
+
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+import java.util.List;
+
+public class DynamicApp {
+
+    public static Object exeJavaCode(String classCode, String className, String method,  List<DsEffectAssessList> param) throws Exception{
+        //鍙互澶嶇敤锛堜笉瑕侊紝涓嶆柇鐨勬柊寤猴級
+        DynamicCompiler compiler = new DynamicCompiler();
+        String testParam = "hhhhh";
+        //娣诲姞婧愮爜锛堝彲澶氫釜锛夊苟 鏋勫缓
+        compiler.addSource(className, classCode).build();
+        Class<?> clazz = compiler.getClassLoader().loadClass(className);
+        Object object = clazz.getMethod(method, java.util.List.class).invoke(null, param);
+        return object;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicClassLoader.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicClassLoader.java
new file mode 100644
index 0000000..864d762
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicClassLoader.java
@@ -0,0 +1,70 @@
+package com.ruoyi.buss.common.liquor;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class DynamicClassLoader extends ClassLoader {
+    private final Map<String, MemoryByteCode> byteCodes = new HashMap<>();
+
+    public DynamicClassLoader(ClassLoader classLoader) {
+        super(classLoader != null ? classLoader : Thread.currentThread().getContextClassLoader());
+    }
+
+    protected void registerCompiledSource(MemoryByteCode byteCode) {
+        byteCodes.put(byteCode.getClassName(), byteCode);
+    }
+
+    protected Class<?> defineClass(MemoryByteCode byteCode) {
+        byteCode.defined = true;
+        byte[] bytes = byteCode.getByteCode();
+        return super.defineClass(byteCode.getClassName(), bytes, 0, bytes.length);
+    }
+
+    @Override
+    protected Class<?> findClass(String name) throws ClassNotFoundException {
+        MemoryByteCode byteCode = byteCodes.get(name);
+        if (byteCode == null || byteCode.defined) {
+            return super.findClass(name);
+        }
+
+        return defineClass(byteCode);
+    }
+
+    /**
+     * 棰勫鐞嗙被锛堝畬鎴愭壒閲忓畾涔夛級
+     */
+    protected void prepareClasses() {
+        for (MemoryByteCode byteCode : byteCodes.values()) {
+            if (byteCode.defined == false) {
+                defineClass(byteCode);
+            }
+        }
+    }
+
+    //================
+
+    /**
+     * 鑾峰彇绫诲悕闆嗗悎
+     */
+    public Collection<String> getClassNames() {
+        return byteCodes.keySet();
+    }
+
+    /**
+     * 鑾峰彇绫诲瓧鑺傜爜
+     */
+    public MemoryByteCode getClassBytes(String className) {
+        return byteCodes.get(className);
+    }
+
+    /**
+     * 鑾峰彇闆嗗悎澶у皬
+     */
+    public int size() {
+        return byteCodes.size();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompiler.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompiler.java
new file mode 100644
index 0000000..873b755
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompiler.java
@@ -0,0 +1,224 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.*;
+import java.io.File;
+import java.io.IOException;
+import java.util.*;
+import java.util.stream.Collectors;
+import java.util.stream.StreamSupport;
+
+/**
+ * 鍔ㄦ�佺紪璇戝櫒锛堢嚎绋嬩笉瀹夊叏锛�
+ *
+ * This code mainly from: Arthas project
+ * */
+public class DynamicCompiler {
+    private final JavaCompiler javaCompiler = ToolProvider.getSystemJavaCompiler();
+    private final StandardJavaFileManager standardFileManager;
+    private final List<String> options = new ArrayList<String>();
+    private final ClassLoader parentClassLoader;
+
+    private final Collection<JavaFileObject> compilationUnits = new ArrayList<JavaFileObject>();
+    private final List<Diagnostic<? extends JavaFileObject>> errors = new ArrayList<Diagnostic<? extends JavaFileObject>>();
+    private final List<Diagnostic<? extends JavaFileObject>> warnings = new ArrayList<Diagnostic<? extends JavaFileObject>>();
+
+    private DynamicClassLoader dynamicClassLoader;
+
+    public DynamicCompiler() {
+        this(null);
+    }
+
+    public DynamicCompiler(ClassLoader classLoader) {
+        if (classLoader == null) {
+            classLoader = Thread.currentThread().getContextClassLoader();
+        }
+
+        if (javaCompiler == null) {
+            throw new IllegalStateException(
+                    "Can not load JavaCompiler from javax.tools.ToolProvider#getSystemJavaCompiler(),"
+                            + " please confirm the application running in JDK not JRE.");
+        }
+        standardFileManager = javaCompiler.getStandardFileManager(null, null, null);
+
+        options.add("-Xlint:unchecked");
+        options.add("-g");
+        options.add("-XDuseUnsharedTable");//鍙伩鍏� SharedNameTable 鍐呭瓨澶ф定
+
+        parentClassLoader = classLoader;
+    }
+
+    /**
+     * 鑾峰彇绫诲姞杞藉櫒
+     */
+    public DynamicClassLoader getClassLoader() {
+        if (dynamicClassLoader == null) {
+            dynamicClassLoader = new DynamicClassLoader(parentClassLoader);
+        }
+
+        return dynamicClassLoader;
+    }
+
+    /**
+     * 鑾峰彇閫夐」
+     */
+    public List<String> getOptions() {
+        return options;
+    }
+
+    /**
+     * 鍒囨崲绫诲姞杞藉櫒
+     *
+     * @param dynamicClassLoader 鍔ㄦ�佺被鍔犺浇鍣�
+     */
+    public void setClassLoader(DynamicClassLoader dynamicClassLoader) {
+        this.dynamicClassLoader = dynamicClassLoader;
+    }
+
+    /**
+     * 鏂板缓绫诲姞杞藉櫒锛堟浛鎹㈡棫鐨勶級
+     */
+    public DynamicClassLoader newClassLoader() {
+        return new DynamicClassLoader(parentClassLoader);
+    }
+
+    /**
+     * 鑾峰彇浠g爜鏂囦欢绠$悊鍣�
+     *
+     * @since 1.3.9
+     */
+    public StandardJavaFileManager getStandardFileManager() {
+        return standardFileManager;
+    }
+
+    /**
+     * 娣诲姞绫昏矾寰�
+     *
+     * @param classPath 绫昏矾寰�
+     * @since 1.3.9
+     */
+    public DynamicCompiler addClassPath(File classPath) throws IOException {
+        Iterable<? extends File> locations = standardFileManager.getLocation(StandardLocation.CLASS_PATH);
+
+        List<File> classpaths = StreamSupport.stream(locations.spliterator(), false)
+                .collect(Collectors.toList());
+
+        classpaths.add(classPath);
+
+        standardFileManager.setLocation(StandardLocation.CLASS_PATH, classpaths);
+        return this;
+    }
+
+    /**
+     * 娣诲姞婧愮爜
+     *
+     * @param className 绫诲悕
+     * @param source    婧愮爜
+     */
+    public DynamicCompiler addSource(String className, String source) {
+        addSource(new StringSource(className, source));
+        return this;
+    }
+
+    /**
+     * 娣诲姞婧愮爜
+     *
+     * @param javaFileObject 鏂囦欢瀵硅薄
+     */
+    public DynamicCompiler addSource(JavaFileObject javaFileObject) {
+        compilationUnits.add(javaFileObject);
+        return this;
+    }
+
+    /**
+     * 閲嶇疆
+     */
+    public void reset() {
+        dynamicClassLoader = null;
+    }
+
+    /**
+     * 缂栬瘧
+     */
+    public void compile() {
+        errors.clear();
+        warnings.clear();
+
+        JavaFileManager fileManager = new DynamicJavaFileManager(standardFileManager, getClassLoader());
+
+        DiagnosticCollector<JavaFileObject> collector = new DiagnosticCollector<JavaFileObject>();
+        JavaCompiler.CompilationTask task = javaCompiler.getTask(null, fileManager, collector, options, null,
+                compilationUnits);
+
+        try {
+
+            if (!compilationUnits.isEmpty()) {
+                boolean result = task.call();
+
+                if (!result || collector.getDiagnostics().size() > 0) {
+
+                    for (Diagnostic<? extends JavaFileObject> diagnostic : collector.getDiagnostics()) {
+                        switch (diagnostic.getKind()) {
+                            case NOTE:
+                            case MANDATORY_WARNING:
+                            case WARNING:
+                                warnings.add(diagnostic);
+                                break;
+                            case OTHER:
+                            case ERROR:
+                            default:
+                                errors.add(diagnostic);
+                                break;
+                        }
+
+                    }
+
+                    if (!errors.isEmpty()) {
+                        throw new DynamicCompilerException("Compilation Error", errors);
+                    }
+                }
+            }
+        } catch (Throwable e) {
+            throw new DynamicCompilerException(e, errors);
+        } finally {
+            compilationUnits.clear();
+        }
+    }
+
+    /**
+     * 鏋勫缓
+     */
+    public void build() {
+        compile();
+        //棰勫鐞嗗姞杞界被锛堟垨锛岄娆¤皟鐢� loadClass 鏃跺姞杞斤級
+        getClassLoader().prepareClasses();
+    }
+
+    private List<String> diagnosticToString(List<Diagnostic<? extends JavaFileObject>> diagnostics) {
+
+        List<String> diagnosticMessages = new ArrayList<String>();
+
+        for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) {
+            diagnosticMessages.add(
+                    "line: " + diagnostic.getLineNumber() + ", message: " + diagnostic.getMessage(Locale.US));
+        }
+
+        return diagnosticMessages;
+
+    }
+
+    public List<Diagnostic<? extends JavaFileObject>> getOriginalErrors() {
+        return Collections.unmodifiableList(errors);
+    }
+
+    public List<Diagnostic<? extends JavaFileObject>> getOriginalWarnings() {
+        return Collections.unmodifiableList(warnings);
+    }
+
+    public List<String> getErrors() {
+        return diagnosticToString(errors);
+    }
+
+    public List<String> getWarnings() {
+        return diagnosticToString(warnings);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompilerException.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompilerException.java
new file mode 100644
index 0000000..9d0abca
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicCompilerException.java
@@ -0,0 +1,74 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.Diagnostic;
+import javax.tools.JavaFileObject;
+import java.util.*;
+
+/**
+ * This code mainly from: Arthas project
+ *
+ * @author noear
+ * @since 1.3.12
+ * */
+public class DynamicCompilerException extends RuntimeException {
+    private static final long serialVersionUID = 1L;
+    private List<Diagnostic<? extends JavaFileObject>> diagnostics;
+
+    public DynamicCompilerException(String message, List<Diagnostic<? extends JavaFileObject>> diagnostics) {
+        super(message);
+        this.diagnostics = diagnostics;
+    }
+
+    public DynamicCompilerException(Throwable cause, List<Diagnostic<? extends JavaFileObject>> diagnostics) {
+        super(cause);
+        this.diagnostics = diagnostics;
+    }
+
+    private String getErrors() {
+        StringBuilder buf = new StringBuilder();
+
+        if (diagnostics != null) {
+            for (Diagnostic<? extends JavaFileObject> diagnostic : diagnostics) {
+                String packagePath = getPackagePath(diagnostic);
+                String diagnosticString = diagnostic.toString();
+
+                if (packagePath == null) {
+                    buf.append(diagnosticString).append("\n");
+                } else {
+                    if (diagnosticString.startsWith(packagePath)) {
+                        buf.append(diagnosticString).append("\n");
+                    } else {
+                        buf.append(packagePath).append(diagnosticString).append("\n");
+                    }
+                }
+            }
+        }
+
+        if (buf.length() > 0) {
+            buf.setLength(buf.length() - 1);
+        }
+
+        return buf.toString();
+    }
+
+    private String getPackagePath(Diagnostic<? extends JavaFileObject> diagnostic) {
+        try {
+            String source = diagnostic.getSource().getCharContent(true).toString();
+            if (source.startsWith("package ")) {
+                int end = source.indexOf(";");
+                if (end > 0) {
+                    return "/" + source.substring("package ".length(), end).replace(".", "/");
+                }
+            }
+        } catch (Exception skip) {
+
+        }
+
+        return null;
+    }
+
+    @Override
+    public String getMessage() {
+        return super.getMessage() + ":\n\n" + getErrors();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicJavaFileManager.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicJavaFileManager.java
new file mode 100644
index 0000000..caaa967
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/DynamicJavaFileManager.java
@@ -0,0 +1,124 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.*;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class DynamicJavaFileManager extends ForwardingJavaFileManager<JavaFileManager> {
+    private static final String[] superLocationNames = { StandardLocation.PLATFORM_CLASS_PATH.name(),
+            /** JPMS StandardLocation.SYSTEM_MODULES **/
+            "SYSTEM_MODULES" };
+    private final PackageInternalsFinder finder;
+
+    private final DynamicClassLoader classLoader;
+    private final List<MemoryByteCode> byteCodes = new ArrayList<MemoryByteCode>();
+
+    public DynamicJavaFileManager(JavaFileManager fileManager, DynamicClassLoader classLoader) {
+        super(fileManager);
+        this.classLoader = classLoader;
+        this.finder = new PackageInternalsFinder(classLoader);
+    }
+
+    @Override
+    public JavaFileObject getJavaFileForOutput(Location location, String className,
+                                               JavaFileObject.Kind kind, FileObject sibling) throws IOException {
+
+        for (MemoryByteCode byteCode : byteCodes) {
+            if (byteCode.getClassName().equals(className)) {
+                return byteCode;
+            }
+        }
+
+        MemoryByteCode innerClass = new MemoryByteCode(className);
+        byteCodes.add(innerClass);
+        classLoader.registerCompiledSource(innerClass);
+        return innerClass;
+
+    }
+
+    @Override
+    public ClassLoader getClassLoader(Location location) {
+        return classLoader;
+    }
+
+    @Override
+    public String inferBinaryName(Location location, JavaFileObject file) {
+        if (file instanceof CustomJavaFileObject) {
+            return ((CustomJavaFileObject) file).getClassName();
+        } else {
+            /**
+             * if it's not CustomJavaFileObject, then it's coming from standard file manager
+             * - let it handle the file
+             */
+            return super.inferBinaryName(location, file);
+        }
+    }
+
+    @Override
+    public Iterable<JavaFileObject> list(Location location, String packageName, Set<JavaFileObject.Kind> kinds,
+                                         boolean recurse) throws IOException {
+        if (location instanceof StandardLocation) {
+            String locationName = ((StandardLocation) location).name();
+            for (String name : superLocationNames) {
+                if (name.equals(locationName)) {
+                    return super.list(location, packageName, kinds, recurse);
+                }
+            }
+        }
+
+        // merge JavaFileObjects from specified ClassLoader
+        if (location == StandardLocation.CLASS_PATH && kinds.contains(JavaFileObject.Kind.CLASS)) {
+            return new IterableJoin<JavaFileObject>(super.list(location, packageName, kinds, recurse),
+                    finder.find(packageName));
+        }
+
+        return super.list(location, packageName, kinds, recurse);
+    }
+
+    static class IterableJoin<T> implements Iterable<T> {
+        private final Iterable<T> first, next;
+
+        public IterableJoin(Iterable<T> first, Iterable<T> next) {
+            this.first = first;
+            this.next = next;
+        }
+
+        @Override
+        public Iterator<T> iterator() {
+            return new IteratorJoin<T>(first.iterator(), next.iterator());
+        }
+    }
+
+    static class IteratorJoin<T> implements Iterator<T> {
+        private final Iterator<T> first, next;
+
+        public IteratorJoin(Iterator<T> first, Iterator<T> next) {
+            this.first = first;
+            this.next = next;
+        }
+
+        @Override
+        public boolean hasNext() {
+            return first.hasNext() || next.hasNext();
+        }
+
+        @Override
+        public T next() {
+            if (first.hasNext()) {
+                return first.next();
+            }
+            return next.next();
+        }
+
+        @Override
+        public void remove() {
+            throw new UnsupportedOperationException("remove");
+        }
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/MemoryByteCode.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/MemoryByteCode.java
new file mode 100644
index 0000000..31b4247
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/MemoryByteCode.java
@@ -0,0 +1,55 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.SimpleJavaFileObject;
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStream;
+import java.net.URI;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class MemoryByteCode extends SimpleJavaFileObject {
+    private static final char PKG_SEPARATOR = '.';
+    private static final char DIR_SEPARATOR = '/';
+    private static final String CLASS_FILE_SUFFIX = ".class";
+
+    private ByteArrayOutputStream outputStream;
+    protected boolean defined;
+
+    public MemoryByteCode(String className) {
+        super(URI.create("byte:///" + className.replace(PKG_SEPARATOR, DIR_SEPARATOR)
+                + Kind.CLASS.extension), Kind.CLASS);
+    }
+
+    @Override
+    public OutputStream openOutputStream() {
+        if (outputStream == null) {
+            outputStream = new ByteArrayOutputStream();
+        }
+        return outputStream;
+    }
+
+    public byte[] getByteCode() {
+        return outputStream.toByteArray();
+    }
+
+    /**
+     * 绉婚櫎瀛楄妭鐮侊紙浠ュ噺灏戝唴瀛樺壇鏈級
+     */
+    protected void delByteCode() {
+        outputStream = null;
+    }
+
+    private String className;
+
+    public String getClassName() {
+        if (className == null) {
+            //缂撳瓨锛屽噺灏戣绠�
+            className = getName();
+            className = className.replace(DIR_SEPARATOR, PKG_SEPARATOR);
+            className = className.substring(1, className.indexOf(CLASS_FILE_SUFFIX));
+        }
+
+        return className;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/PackageInternalsFinder.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/PackageInternalsFinder.java
new file mode 100644
index 0000000..ae29a8f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/PackageInternalsFinder.java
@@ -0,0 +1,189 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.JavaFileObject;
+import java.io.File;
+import java.io.IOException;
+import java.net.JarURLConnection;
+import java.net.URI;
+import java.net.URL;
+import java.net.URLDecoder;
+import java.util.*;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.jar.JarEntry;
+import java.util.stream.Collectors;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class PackageInternalsFinder {
+    private final ClassLoader classLoader;
+    private static final String CLASS_FILE_EXTENSION = ".class";
+    private static final Map<String, JarFileIndex> INDEXS = new ConcurrentHashMap<>();
+
+    public PackageInternalsFinder(ClassLoader classLoader) {
+        this.classLoader = classLoader;
+    }
+
+    public List<JavaFileObject> find(String packageName) throws IOException {
+        String javaPackageName = packageName.replaceAll("\\.", "/");
+
+        List<JavaFileObject> result = new ArrayList<JavaFileObject>();
+
+        Enumeration<URL> urlEnumeration = classLoader.getResources(javaPackageName);
+        while (urlEnumeration.hasMoreElements()) { // one URL for each jar on the classpath that has the given package
+            URL packageFolderURL = urlEnumeration.nextElement();
+            result.addAll(listUnder(packageName, packageFolderURL));
+        }
+
+        return result;
+    }
+
+    private Collection<JavaFileObject> listUnder(String packageName, URL packageFolderURL) {
+        File directory = new File(decode(packageFolderURL.getFile()));
+        if (directory.isDirectory()) { // browse local .class files - useful for local execution
+            return processDir(packageName, directory);
+        } else { // browse a jar file
+            return processJar(packageName, packageFolderURL);
+        }
+    }
+
+    private List<JavaFileObject> processJar(String packageName, URL packageFolderURL) {
+        try {
+            String jarUri = packageFolderURL.toExternalForm().substring(0, packageFolderURL.toExternalForm().lastIndexOf("!/"));
+            JarFileIndex jarFileIndex = INDEXS.get(jarUri);
+            if (jarFileIndex == null) {
+                jarFileIndex = new JarFileIndex(jarUri, URI.create(jarUri + "!/"));
+                INDEXS.put(jarUri, jarFileIndex);
+            }
+            List<JavaFileObject> result = jarFileIndex.search(packageName);
+            if (result != null) {
+                return result;
+            }
+        } catch (Exception e) {
+            // ignore
+        }
+        // 淇濆簳
+        return fuse(packageFolderURL);
+    }
+
+    private List<JavaFileObject> fuse(URL packageFolderURL) {
+        List<JavaFileObject> result = new ArrayList<JavaFileObject>();
+        try {
+            String jarUri = packageFolderURL.toExternalForm().substring(0, packageFolderURL.toExternalForm().lastIndexOf("!/"));
+
+            JarURLConnection jarConn = (JarURLConnection) packageFolderURL.openConnection();
+            String rootEntryName = jarConn.getEntryName();
+
+            if (rootEntryName != null) {
+                //鍙兘涓� null锛堝唴閮ㄦ病鏈夌被鏂囦欢锛屽彧鏄紩鐢ㄥ叾瀹冨寘锛�
+                int rootEnd = rootEntryName.length() + 1;
+
+                Enumeration<JarEntry> entryEnum = jarConn.getJarFile().entries();
+                while (entryEnum.hasMoreElements()) {
+                    JarEntry jarEntry = entryEnum.nextElement();
+                    String name = jarEntry.getName();
+
+                    if (name.startsWith(rootEntryName) && name.indexOf('/', rootEnd) == -1 && name.endsWith(CLASS_FILE_EXTENSION)) {
+                        URI uri = URI.create(jarUri + "!/" + name);
+                        String binaryName = name.replaceAll("/", ".");
+                        binaryName = binaryName.replaceAll(CLASS_FILE_EXTENSION + "$", "");
+
+                        result.add(new CustomJavaFileObject(binaryName, uri));
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new RuntimeException("Wasn't able to open " + packageFolderURL + " as a jar file", e);
+        }
+
+        return result;
+    }
+
+    private List<JavaFileObject> processDir(String packageName, File directory) {
+        File[] files = directory.listFiles(item ->
+                item.isFile() && getKind(item.getName()) == JavaFileObject.Kind.CLASS);
+        if (files != null) {
+            return Arrays.stream(files).map(item -> {
+                String className = packageName + "." + item.getName()
+                        .replaceAll(CLASS_FILE_EXTENSION + "$", "");
+                return new CustomJavaFileObject(className, item.toURI());
+            }).collect(Collectors.toList());
+        }
+        return Collections.emptyList();
+    }
+
+    private String decode(String filePath) {
+        try {
+            return URLDecoder.decode(filePath, "utf-8");
+        } catch (Exception e) {
+            // ignore, return original string
+        }
+
+        return filePath;
+    }
+
+    public static JavaFileObject.Kind getKind(String name) {
+        if (name.endsWith(JavaFileObject.Kind.CLASS.extension))
+            return JavaFileObject.Kind.CLASS;
+        else if (name.endsWith(JavaFileObject.Kind.SOURCE.extension))
+            return JavaFileObject.Kind.SOURCE;
+        else if (name.endsWith(JavaFileObject.Kind.HTML.extension))
+            return JavaFileObject.Kind.HTML;
+        else
+            return JavaFileObject.Kind.OTHER;
+    }
+
+    public static class JarFileIndex {
+        private String jarUri;
+        private URI uri;
+
+        private Map<String, List<ClassUriWrapper>> packages = new HashMap<>();
+
+        public JarFileIndex(String jarUri, URI uri) throws IOException {
+            this.jarUri = jarUri;
+            this.uri = uri;
+            loadIndex();
+        }
+
+        private void loadIndex() throws IOException {
+            JarURLConnection jarConn = (JarURLConnection) uri.toURL().openConnection();
+            String rootEntryName = jarConn.getEntryName() == null ? "" : jarConn.getEntryName();
+            Enumeration<JarEntry> entryEnum = jarConn.getJarFile().entries();
+            while (entryEnum.hasMoreElements()) {
+                JarEntry jarEntry = entryEnum.nextElement();
+                String entryName = jarEntry.getName();
+                if (entryName.startsWith(rootEntryName) && entryName.endsWith(CLASS_FILE_EXTENSION)) {
+                    String className = entryName
+                            .substring(0, entryName.length() - CLASS_FILE_EXTENSION.length())
+                            .replace(rootEntryName, "")
+                            .replace("/", ".");
+                    if (className.startsWith(".")) className = className.substring(1);
+                    if (className.equals("package-info")
+                            || className.equals("module-info")
+                            || className.lastIndexOf(".") == -1) {
+                        continue;
+                    }
+                    String packageName = className.substring(0, className.lastIndexOf("."));
+                    List<ClassUriWrapper> classes = packages.get(packageName);
+                    if (classes == null) {
+                        classes = new ArrayList<>();
+                        packages.put(packageName, classes);
+                    }
+                    classes.add(new ClassUriWrapper(className, URI.create(jarUri + "!/" + entryName)));
+                }
+            }
+        }
+
+        public List<JavaFileObject> search(String packageName) {
+            if (this.packages.isEmpty()) {
+                return null;
+            }
+            if (this.packages.containsKey(packageName)) {
+                return packages.get(packageName).stream().map(item -> {
+                    return new CustomJavaFileObject(item.getClassName(), item.getUri());
+                }).collect(Collectors.toList());
+            }
+            return Collections.emptyList();
+        }
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/StringSource.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/StringSource.java
new file mode 100644
index 0000000..a35292f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/common/liquor/StringSource.java
@@ -0,0 +1,23 @@
+package com.ruoyi.buss.common.liquor;
+
+import javax.tools.SimpleJavaFileObject;
+import java.io.IOException;
+import java.net.URI;
+
+/**
+ * This code mainly from: Arthas project
+ * */
+public class StringSource extends SimpleJavaFileObject {
+    private final String contents;
+
+    public StringSource(String className, String contents) {
+        super(URI.create("string:///" + className.replace('.', '/') + Kind.SOURCE.extension), Kind.SOURCE);
+        this.contents = contents;
+    }
+
+    @Override
+    public CharSequence getCharContent(boolean ignoreEncodingErrors) throws IOException {
+        return contents;
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMAssessController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMAssessController.java
new file mode 100644
index 0000000..574d6d7
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMAssessController.java
@@ -0,0 +1,562 @@
+package com.ruoyi.buss.controller;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.buss.common.AssessUtil;
+import com.ruoyi.buss.common.NumberUtils;
+import com.ruoyi.buss.domain.*;
+import com.ruoyi.buss.domain.dto.TaskQueryParam;
+import com.ruoyi.buss.domain.vo.TaskAssess;
+import com.ruoyi.buss.domain.vo.TaskAssessHis;
+import com.ruoyi.buss.service.*;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.script.Invocable;
+import javax.script.ScriptEngine;
+import javax.script.ScriptEngineManager;
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@Tag(name = "鑳芥晥璇勪及鎺ュ彛")
+@RestController
+@RequestMapping("/buss/assess/ex")
+public class DMAssessController extends BaseController {
+
+    @Autowired
+    private IDmHarbor2Service iDmHarbor2Service;
+    @Autowired
+    private IDsTaskDetailService iDsTaskDetailService;
+    @Autowired
+    private IDsTaskList2Service iDsTaskList2Service;
+    @Autowired
+    private IDsEffectAssessService dsEffectAssessService;
+    @Autowired
+    private IDsEffectAssessListService dsEffectAssessListService;
+    @Autowired
+    private IDsEffectAssessHisService dsEffectAssessHisService;
+
+    private Double OIL_PLACE_PER = 0.3;
+    private Double MAT_PLACE_PER = 0.2;
+    private Double AMMO_PLACE_PER = 0.5;
+
+    @Operation(summary = "鑾峰彇鑳芥晥璇勪及鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public AjaxResult assessList() {
+        List<DsEffectAssess> list = dsEffectAssessService.selectDsEffectAssessList(new DsEffectAssess());
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇鑳芥晥璇勪及鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鏍规嵁浠诲姟ID鍜岄儴闂ㄧ紪鐮佽幏鍙栬瘎浼拌鎯�")
+    @GetMapping("/assess/{type}/{taskId}/{deptId}")
+    @ResponseBody
+    public AjaxResult getByTaskId(@Parameter(name = "type", required = true, description = "璇勪及绫诲瀷") @PathVariable("type") String type,
+                                  @Parameter(name = "taskId", required = true, description = "浠诲姟ID") @PathVariable("taskId") Long taskId,
+                                  @Parameter(name = "deptId", required = true, description = "閮ㄩ棬ID") @PathVariable("deptId") Long deptId) {
+        DsEffectAssess assess = new DsEffectAssess();
+        assess.setTaskId(taskId);
+        assess.setDeptId(deptId);
+        List<DsEffectAssess> assessList = dsEffectAssessService.selectDsEffectAssessList(assess);
+        if(null != assessList && assessList.size() > 0){
+            DsEffectAssess dsEffectAssess = assessList.get(0);
+            DsEffectAssessHis assessHis = new DsEffectAssessHis();
+            assessHis.setTaskId(taskId);
+            assessHis.setDeptId(deptId);
+            assessHis.setTYPE(type);
+            List<DsEffectAssessHis> hisList = dsEffectAssessHisService.selectDsEffectAssessHisList(assessHis);
+            TaskAssessHis taskAssess = new TaskAssessHis();
+            taskAssess.setList(hisList);
+            taskAssess.setAssess(dsEffectAssess);
+
+            return success(taskAssess);
+        }
+        else{
+            return calcDsEffectByTime(taskId, type);
+        }
+    }
+
+    @Operation(summary = "瀹炴椂-鏍规嵁浠诲姟ID鑾峰彇璇勪及璇︽儏")
+    @GetMapping("/assess/time/{type}/{taskid}")
+    @ResponseBody
+    public AjaxResult getTime(@Parameter(name = "type", required = true, description = "璇勪及绫诲瀷") @PathVariable("type") String type,
+                                  @Parameter(name = "taskid", required = true, description = "浠诲姟ID") @PathVariable("taskid") Long taskid) {
+        if(!type.equalsIgnoreCase("JD") && !type.equalsIgnoreCase("ZD")){
+           return error("鑾峰彇璇勪及绫诲瀷閿欒锛岃妫�鏌ュ弬鏁�");
+        }
+
+        return calcDsEffectByTime(taskid, type);
+    }
+
+    // 瀹炴椂璁$畻璇勪及鍊�
+    private AjaxResult calcDsEffectByTime(Long taskid, String type){
+
+        DsEffectAssessList assessList = new DsEffectAssessList();
+        assessList.setTYPE(type);
+        List<DsEffectAssessList> weightList = dsEffectAssessListService.selectDsEffectAssessListList(assessList);
+
+        List<DsTaskDetail> detailList = iDsTaskDetailService.selectDsTaskDetailByTaskId(taskid, null);
+        TaskQueryParam taskQueryParam = new TaskQueryParam();
+        if(null != taskid){taskQueryParam.setTaskId(taskid);}
+        List<DsTaskList2> taskList2List = iDsTaskList2Service.selectDsTaskListByParam(taskQueryParam);
+        List<DmHarbor2> harbor2List = iDmHarbor2Service.selectDmHarborList(new DmHarbor2());
+
+        List<DsEffectAssessList> dsEffectAssessLists = calcDsEffect(detailList, taskList2List, harbor2List);
+        // 鏇存柊鏉冮噸鎸囨爣鎴栬�呮槸鏁板��
+        dsEffectAssessLists = updateWeight(dsEffectAssessLists, weightList);
+
+        List<DsEffectAssessHis> hisList = covertToHis(dsEffectAssessLists, taskid);
+        dsEffectAssessHisService.updateEffectAssessHisList(hisList);
+
+        // 璁$畻鏈�缁堣瘎浼扮粨鏋�
+        double score = getScore(dsEffectAssessLists);
+        DsEffectAssess dsEffectAssess =  new DsEffectAssess(taskid, score);
+        dsEffectAssess.setCreateTime(new Date());
+        dsEffectAssess.setCreateBy(getUsername());
+        dsEffectAssess.setDeptId(getDeptId());
+        // 淇濆瓨璇勪及缁撴灉
+        dsEffectAssessService.updateOrInsertDsEffectAssess(dsEffectAssess);
+
+
+        TaskAssess assess = new TaskAssess();
+        assess.setList(dsEffectAssessLists);
+        assess.setAssess(dsEffectAssess);
+        if(null != dsEffectAssessLists){
+            return success(assess);
+        }
+
+        return error("鑾峰彇鑳芥晥璇勪及璇︽儏澶辫触锛岃閲嶈瘯");
+    }
+
+    // 鑾峰彇璇勪环璇︾粏鍊�
+    private List<DsEffectAssessList> calcDsEffect(List<DsTaskDetail> detailList, List<DsTaskList2> taskList2List, List<DmHarbor2> harbor2List){
+        List<DsEffectAssessList> result = new ArrayList<>();
+        if(null != detailList && detailList.size() >0){
+            int harborCount = 0;    // 娓彛鏁伴噺
+            int berthCount = 0;     // 娉婁綅鏁伴噺
+            int supplyTime = 0;     // 鍚勬腐鍙hˉ缁欎换鍔℃�绘椂闀�
+            int allocTime = 0;      // 鍚勬腐鍙e垎閰嶄换鍔℃�绘椂闀�
+            int supplyTimeDif = 0;  // 琛ョ粰鍜屼换鍔″垎閰嶆椂闀垮樊棰濇�诲拰
+            List<Integer> maxTimeDifList = new ArrayList<>();     // 涓ゆ腐鍙f渶澶ф椂闂村樊
+
+            int shipSupplyTime = 0; //鑸拌墖琛ョ粰鏃堕棿鎬诲拰
+            int shipAllocTime = 0;  // 鑸拌墖鍋滄硦鏃堕棿鎬诲拰
+
+            int allTime = 0;        // 浠诲姟鎬绘椂闀�
+            int workTime = 0;       // 绱琛ョ粰鏃堕棿鎬昏
+            int stopTime = 0;       // 绱鍋滈潬鏃堕棿
+            int oilTime = 0;        // 娌规枡琛ョ粰鎬绘椂闀�
+            int matTime = 0;        // 鐗╄祫琛ョ粰鎬绘椂闀�
+            int ammoTime = 0;       // 寮硅嵂琛ョ粰鎬绘椂闀�
+
+            double platMaxPer = 0.0;  // 鍦哄湴鍗犵敤鏈�澶у�兼�诲拰
+            int platHalfTime = 0;   // 娉婁綅鍗犵敤杩囧崐鏃堕棿
+            int posAreaNotSameCount = 0;
+            
+            Map<Long, List<DsTaskDetail>> groupedTaskList = detailList.stream()
+                    .collect(Collectors.groupingBy(DsTaskDetail::getHarborId));
+
+            Set<Long> harborIds = new HashSet<>();
+            Set<Long> berthIds = new HashSet<>();
+
+            AtomicReference<Double> carTotalCountRef = new AtomicReference<>(0.0); // 鍚勬硦浣嶇墿璧勮溅娆℃�诲��
+
+            for (Map.Entry<Long, List<DsTaskDetail>> entry : groupedTaskList.entrySet()) {
+
+                harborIds.add(entry.getKey());
+
+                Map<Long, List<DsTaskDetail>> groupedBerthTaskList = detailList.stream()
+                        .collect(Collectors.groupingBy(DsTaskDetail::getBerthId));
+
+                int maxHarborTime = 0;  // 娉婁綅鏈�澶ф椂闀�
+                int allocHarborTime = 0; //s
+                for (Map.Entry<Long, List<DsTaskDetail>> berthEntry : groupedBerthTaskList.entrySet()) {
+                    berthIds.add(berthEntry.getKey());
+
+                    int maxOilTime = berthEntry.getValue().stream()
+                            .mapToInt(DsTaskDetail::getOilTime)
+                            .max()
+                            .orElse(0);
+                    int maxMatTime = berthEntry.getValue().stream()
+                            .mapToInt(DsTaskDetail::getMatTime)
+                            .max()
+                            .orElse(0);
+                    int maxAmmoTime = berthEntry.getValue().stream()
+                            .mapToInt(DsTaskDetail::getAmmoTime)
+                            .max()
+                            .orElse(0);
+
+                    berthEntry.getValue().stream().forEach(item -> {
+                        int matTmpTime = item.getMatTime();
+                        int totalCount = 0;
+                        if(null != item.getFood()){
+                            totalCount += item.getFood();
+                        }
+                        if(null != item.getFoodW()){
+                            totalCount += item.getFoodW();
+                        }
+                        if(null != item.getFoodO()){
+                            totalCount += item.getFoodO();
+                        }
+
+                        if(matTmpTime <= 24) {
+                            int finalTotalCount = totalCount;
+                            carTotalCountRef.updateAndGet(v -> (v + finalTotalCount));
+                        }
+                        else{
+                            int finalTotalCount1 = totalCount;
+                            carTotalCountRef.updateAndGet(v -> (v +
+                                    NumberUtils.roundToTwoDecimalPlaces(finalTotalCount1 / matTmpTime * 24)));
+                        }
+                    });
+
+                    int maxTime = Math.max(Math.max(maxOilTime, maxMatTime), maxAmmoTime);
+                    oilTime += maxOilTime;
+                    matTime += maxMatTime;
+                    ammoTime += maxAmmoTime;
+                    if(maxTime > maxHarborTime){maxHarborTime = maxTime;}
+                    supplyTime += maxTime;
+                    allocHarborTime += maxTime;
+                    if(allTime < maxTime) {allTime = maxTime;}
+
+                    platMaxPer += getMaxPlat(berthEntry.getValue());
+                    platHalfTime += getPlatHalfTime(berthEntry.getValue());
+                }
+                allocTime += groupedBerthTaskList.size() * maxHarborTime;
+                supplyTimeDif += (allocTime - allocHarborTime);
+                maxTimeDifList.add(maxHarborTime);
+            }
+
+            for (DsTaskDetail detail : detailList) {
+                // 鍒嗛厤鏃堕棿
+                int maxTime = Math.max(Math.max(NumberUtils.getOrDefault(detail.getAmmoEtime(), 0) ,
+                        NumberUtils.getOrDefault(detail.getOilEtime(), 0)), NumberUtils.getOrDefault(detail.getMatEtime(), 0));
+                // 琛ョ粰鏃堕棿
+                int tApplyTime = 0;
+                // 琛ョ粰鏃堕棿
+                if(null != detail.getSupplySeq() && (detail.getSupplySeq().equals("2") || detail.getSupplySeq().equals("3"))) {
+                    // 濡傛灉涓哄厛娌瑰悗寮瑰垯涓や釜鏃堕棿鐩稿姞
+                    tApplyTime = (detail.getAmmoTime() == null ? 0 : detail.getAmmoTime())+ (null == detail.getOilTime() ? 0 : detail.getOilTime());
+                    if(tApplyTime < detail.getMatTime()){
+                        tApplyTime = detail.getMatTime();
+                    }
+                }
+                else{
+                    // 鍚屾椂琛ュ厖 閫夋嫨鏈�澶у��
+                    tApplyTime = Math.max(Math.max(Math.max(NumberUtils.getOrDefault(detail.getAmmoTime(), 0),
+                            NumberUtils.getOrDefault(detail.getMatTime(), 0)), NumberUtils.getOrDefault(detail.getOilTime(), 0)),
+                            NumberUtils.getOrDefault(detail.getWaterTime(), 0));
+                }
+                shipSupplyTime += tApplyTime;
+                shipAllocTime += maxTime;
+
+                if(!isShipPosAreaSame(taskList2List, detail.getTaskId(), detail.getShipNo(), harbor2List)){
+                    posAreaNotSameCount++;
+                }
+            }
+
+            workTime = oilTime + matTime;
+            harborCount = harborIds.size();
+            berthCount = berthIds.size();
+
+            int maxMinTimeDif = 0;
+            // 鍚勬腐鍙hˉ缁欎綔涓氭渶缁堢粨鏉熶袱涓ゆ椂闂村樊鐨勬渶澶у�糀3
+            if (!maxTimeDifList.isEmpty()) {
+                int maxTimeDif = maxTimeDifList.stream().mapToInt(Integer::intValue).max().orElse(0);
+                int minTimeDif = maxTimeDifList.stream().mapToInt(Integer::intValue).min().orElse(0);
+                maxMinTimeDif = maxTimeDif - minTimeDif;
+                // 杩欓噷鍙互鏍规嵁闇�瑕佷娇鐢� maxMinTimeDif 鍙橀噺
+            }
+
+            // 鏈壒娆¤埌鑹囨暟閲�
+            int shipCount = detailList.size();                                            // 鏈壒娆¤埞鏁伴噺
+            double days = NumberUtils.roundToTwoDecimalPlaces((double) allTime / 24);        // 鎬绘壒娆¤ˉ缁欏ぉ鏁�
+            double carTotalCount = carTotalCountRef.get();                                // 鍚勬硦浣嶇墿璧勮溅娆℃�诲��
+
+            // 琛ョ粰鏂规 -- 鎵规鎬昏ˉ缁欐暟閲�
+            double harborShipCountPercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForShipCount(shipCount));
+            // 琛ョ粰鏂规 -- 鎵规鍗曡埌鎶樺彔琛ョ粰鏃堕棿
+            double harborShipEmptyPercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForShipEmpty(supplyTimeDif/ shipCount));
+            // 琛ョ粰鏂规 -- 鍚勬腐鍙g粨鏉熸渶澶ф椂闂村樊
+            double harborEndTimeAvgPercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForHarborTimeDif(maxMinTimeDif));
+            // 琛ョ粰鏂规 -- 鏈�澶ф椂闂村樊鍗犳�绘椂闂存瘮
+            double harborMaxDifPercent = NumberUtils.roundToTwoDecimalPlaces( 1 - (double)maxMinTimeDif / allTime );
+            // 琛ョ粰鏂规 -- 鏈壒娆¤法鍖鸿皟搴﹁埌鑸规暟
+            double harborZoomDifPercent = NumberUtils.roundToTwoDecimalPlaces(1 - (double)posAreaNotSameCount / shipCount);
+            // 琛ョ粰鏂规  -- 鍚勬腐鍙g粨鏉熸椂闂村樊        0.4         寮�濮嬫椂闂�  缁撴潫鏃堕棿
+//            double harborAvgTimePercent = NumberUtils.roundToTwoDecimalPlaces(1-(double)(allocTime - supplyTime)/allocTime);
+//            // 琛ョ粰鏂规  -- 娓彛鏃堕棿宸崰姣斿潎鍊�                   姣忎釜娓彛 琛ョ粰鏃堕棿   寮�濮嬬粨鏉熸椂闂村樊
+//            double harborTimePercent = NumberUtils.roundToTwoDecimalPlaces(1- (double)supplyTime / allocTime);
+
+            // 鍙楄ˉ鑸拌埞 -- 鍗曡埌骞冲潎鍋滈潬鏃堕棿
+            double applyShipAvgStopTimePercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForShipStopTime(supplyTime / shipCount));
+            // 鍙楄ˉ鑸拌埞 -- 琛ョ粰浣滀笟鏃堕棿鍧囧��
+            double applyShipWorkTimePercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForApplyTime(supplyTime / shipCount));
+            // 鍙楄ˉ鑸拌埞 -- 琛ョ粰闈炰綔涓氭椂闂村潎鍊�
+            double applyShipWorkNoTimePercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForNotApplyTime(supplyTimeDif/ shipCount));
+            // 鍙楄ˉ鑸拌埞  -- 琛ョ粰浣滀笟鍋滄硦姣斾緥       0.2          鎵�鏈夎埞琛ョ粰鎬诲拰  鎵�鏈夎埞鍗犵敤鏃堕暱
+            double shipStopPercent = NumberUtils.roundToTwoDecimalPlaces((double)shipSupplyTime/shipAllocTime);
+            // 鍙楄ˉ鑸拌埞  -- 琛ョ粰鏃堕棿鎶樺彔姣斾緥                    鏈�澶у紑濮�-缁撴潫鏃堕棿  鎵�鏈夎埞琛ョ粰鏃堕棿鎬诲拰
+            double shipEmptyPercent = NumberUtils.roundToTwoDecimalPlaces(1 - (double)(shipSupplyTime/detailList.size()) / allTime);
+
+
+            // 琛ョ粰鍏靛姏  -- 姘翠繚鏃ヤ綔涓氭椂闂存瘮        0.2         榛樿鍊�  1 锛堜笉璁$畻锛�
+            double applyWaterPercent = 1;
+            // 琛ョ粰鍏靛姏  -- 娌逛繚鏃ヤ綔涓氭椂闂存瘮                    鍔犳补鎬绘椂闀�/娉婁綅鏁�/鍋滈潬鎬绘椂闀�
+            double applyOilPercent = NumberUtils.roundToTwoDecimalPlaces((double)oilTime / berthCount / allTime );
+            // 琛ョ粰鍏靛姏  -- 鐗╄祫鏃ヤ綔涓氭椂闂存瘮                    鍔犳补鎬绘椂闀�/娉婁綅鏁�/鍋滈潬鎬绘椂闀�
+            double applyMatPercent = NumberUtils.roundToTwoDecimalPlaces((double)matTime / allocTime);
+
+
+            // 琛ョ粰璁炬柦  --  娉婁綅鏃ュ潎鍛ㄨ浆鑹樻
+            double facBerthPercent = NumberUtils.roundToTwoDecimalPlaces(
+                    AssessUtil.getPercentForBerthTime( NumberUtils.roundToTwoDecimalPlaces(shipCount / days / berthCount )));
+            // 琛ョ粰璁炬柦  -- 鍓嶆部鍗犲湴鏈�澶у潎鍊�        0.2
+            double facPartPercent = NumberUtils.roundToTwoDecimalPlaces(platMaxPer / berthCount / 1.5);
+            if(facPartPercent > 1) facPartPercent = 1.0;
+            // 琛ョ粰璁炬柦  --  鍓嶆部鍗犲崐鏃堕暱鍧囧��
+            double facPartTimePercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForBerthHoldTime((double) platHalfTime / berthCount));
+            // 琛ョ粰璁炬柦  -- 鍔犳补璁炬柦鏃ュ潎浣跨敤鐜�
+            double facOilPercent = NumberUtils.roundToTwoDecimalPlaces((double)oilTime / berthCount / allTime );
+            // 琛ョ粰璁炬柦  -- 鍚勬硦浣嶇墿璧勮溅娆″潎鍊�
+            double facCarPercent = NumberUtils.roundToTwoDecimalPlaces(AssessUtil.getPercentForCar((double)carTotalCount / berthCount ));
+
+            result.add(new DsEffectAssessList("JD","A12", harborShipCountPercent, 0.1, 0.4));
+            result.add(new DsEffectAssessList("JD","A13", harborShipEmptyPercent, 0.2, 0.4));
+            result.add(new DsEffectAssessList("JD","A14", harborEndTimeAvgPercent, 0.2, 0.4));
+            result.add(new DsEffectAssessList("JD","A15", harborMaxDifPercent, 0.3, 0.4));
+            result.add(new DsEffectAssessList("JD","A16", harborZoomDifPercent, 0.2, 0.4));
+
+            result.add(new DsEffectAssessList("JD","A21", applyShipAvgStopTimePercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A22", applyShipWorkTimePercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A23", applyShipWorkNoTimePercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A24", shipStopPercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A25", shipEmptyPercent, 0.2, 0.2));
+
+            result.add(new DsEffectAssessList("JD","A31", applyWaterPercent, 0.3, 0.2));
+            result.add(new DsEffectAssessList("JD","A32", applyOilPercent, 0.4, 0.2));
+            result.add(new DsEffectAssessList("JD","A33", applyMatPercent, 0.3,0.2));
+
+            result.add(new DsEffectAssessList("JD","A41", facBerthPercent, 0.3, 0.2));
+            result.add(new DsEffectAssessList("JD","A42", facPartPercent, 0.1, 0.2));
+            result.add(new DsEffectAssessList("JD","A43", facPartTimePercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A44", facOilPercent, 0.2, 0.2));
+            result.add(new DsEffectAssessList("JD","A45", facCarPercent, 0.2, 0.2));
+        }
+
+        return result;
+    }
+
+    // 鑾峰彇娉婁綅鏈�澶у満鍦板崰鐢�
+    private Double getMaxPlat(List<DsTaskDetail> list){
+        double maxPlat = 0.0;
+        for (int i = 1; i <= 24; i++) {
+            int oilCount = 0;
+            int ammoCount = 0;
+            int matCount = 0;
+            for (DsTaskDetail task : list) {
+                if (task.getOilStime() != null && task.getOilStime() <= i && task.getOilEtime() >= i) {
+                    oilCount++;
+                } else if (task.getAmmoStime() != null && task.getAmmoStime() <= i && task.getAmmoEtime() >= i) {
+                    ammoCount++;
+                } else if (task.getMatStime() != null && task.getMatStime() <= i && task.getMatEtime() >= i) {
+                    matCount++;
+                }
+            }
+
+            Double totalSupply = NumberUtils.roundToTwoDecimalPlaces(oilCount * OIL_PLACE_PER + ammoCount * AMMO_PLACE_PER + matCount * MAT_PLACE_PER);
+            if(maxPlat < totalSupply){
+                maxPlat = totalSupply;
+            }
+        }
+        return maxPlat;
+    }
+
+    // 鑾峰彇娉婁綅鍗犵敤杩囧崐鐨勬椂闂�
+    private Integer getPlatHalfTime(List<DsTaskDetail> list){
+        Integer platTime = 0;
+        for (int i = 1; i <= 24; i++) {
+            int oilCount = 0;
+            int ammoCount = 0;
+            int matCount = 0;
+            for (DsTaskDetail task : list) {
+                if (task.getOilStime() != null && task.getOilStime() <= i && task.getOilEtime() >= i) {
+                    oilCount++;
+                } else if (task.getAmmoStime() != null && task.getAmmoStime() <= i && task.getAmmoEtime() >= i) {
+                    ammoCount++;
+                } else if (task.getMatStime() != null && task.getMatStime() <= i && task.getMatEtime() >= i) {
+                    matCount++;
+                }
+            }
+            Double totalSupply = NumberUtils.roundToTwoDecimalPlaces(oilCount * OIL_PLACE_PER + ammoCount * AMMO_PLACE_PER + matCount * MAT_PLACE_PER);
+            if(totalSupply >= 0.5){
+                platTime++;
+            }
+        }
+        return platTime;
+    }
+
+    // 璁$畻鏈�缁堝垎鏁�
+    private Double getScore(List<DsEffectAssessList> list){
+        Double score = 0.0;
+        if(null != list  && list.size() > 0){
+            Map<String, List<DsEffectAssessList>> groupedByCode = list.stream()
+                .collect(Collectors.groupingBy(item -> item.getCODE().substring(0, 2)));
+
+            for (Map.Entry<String, List<DsEffectAssessList>> berthEntry : groupedByCode.entrySet()) {
+                DsEffectAssessList effectAssess = berthEntry.getValue().get(0);
+                Double classifyWeight = null == effectAssess.getClassifyWeight()?0.0:effectAssess.getClassifyWeight();
+
+                Double totalValue = berthEntry.getValue().stream()
+                    .mapToDouble(item -> item.getVal() * item.getWEIGHT())
+                    .sum();
+                score += totalValue * classifyWeight;
+            }
+        }
+        return NumberUtils.roundToTwoDecimalPlaces(score * 10);
+    }
+
+    private Double getScore3(List<DsEffectAssessList> list){
+        
+        ScriptEngineManager manager = new ScriptEngineManager();
+        ScriptEngine engine = manager.getEngineByName("JavaScript");
+        
+        try {
+            // 鏋勫缓JavaScript鍑芥暟
+            String script = "function calculateScore(list) {" +
+                "   var score = 0;" +
+                "   if(list && list.length > 0) {" +
+                "       var groupedByCode = {};" +
+                "       for(var i = 0; i < list.length; i++) {" +
+                "           var code = list[i].CODE.substring(0,2);" +
+                "           if(!groupedByCode[code]) {" +
+                "               groupedByCode[code] = [];" +
+                "           }" +
+                "           groupedByCode[code].push(list[i]);" +
+                "       }" +
+                "       for(var code in groupedByCode) {" +
+                "           var items = groupedByCode[code];" +
+                "           var classifyWeight = items[0].classifyWeight || 0;" +
+                "           var totalValue = 0;" +
+                "           for(var j = 0; j < items.length; j++) {" +
+                "               totalValue += items[j].val * items[j].WEIGHT;" +
+                "           }" +
+                "           score += totalValue * classifyWeight;" +
+                "       }" +
+                "   }" +
+                "   return Math.round(score * 10 * 100) / 100;" +
+                "}";
+            
+            // 缂栬瘧骞舵墽琛岃剼鏈�
+            engine.eval(script);
+            
+            // 灏咼ava瀵硅薄杞崲涓篔SON
+            String jsonList = JSONObject.toJSONString(list);
+            
+            // 璋冪敤JavaScript鍑芥暟
+            Invocable invocable = (Invocable) engine;
+            Object result = invocable.invokeFunction("calculateScore", jsonList);
+            
+            return Double.parseDouble(result.toString());
+            
+        } catch (Exception e) {
+            e.printStackTrace();
+            System.out.println("璁$畻鍒嗘暟澶辫触");
+            return 0.0;
+        }
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岃埛鍙疯幏鍙栧搴旂殑浠诲姟
+     * @param list
+     * @param taskid
+     * @param shipNo
+     * @return
+     */
+    private boolean isShipPosAreaSame(List<DsTaskList2> list, Long taskid, String shipNo, List<DmHarbor2> harbor2List){
+        Optional<DsTaskList2> tmpTaskOptions = list.stream().filter(task -> task.getTaskId() == taskid && task.getShipNo().equals(shipNo)).findFirst();
+        if(!tmpTaskOptions.isEmpty()){
+            Optional<DmHarbor2> harbor2 = harbor2List.stream().filter(dmHarbor2 ->
+                    dmHarbor2.getDOCKNAME().equals(tmpTaskOptions.get().getPosArea()) && tmpTaskOptions.get().getHarborId() == dmHarbor2.getPKID()).findFirst();
+            if(!harbor2.isEmpty()){
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private DsEffectAssessHis covertToHis(DsEffectAssessList assessList, Long taskId){
+        DsEffectAssessHis his = null;
+        if(null != assessList){
+            his = new DsEffectAssessHis();
+            his.setClassifyIndex(assessList.getClassifyIndex());
+            his.setCODE(assessList.getCODE());
+            his.setClassifyWeight(assessList.getClassifyWeight());
+            his.setITEM(assessList.getITEM());
+            his.setDeptId(assessList.getDeptId());
+            his.setItemDetail(assessList.getItemDetail());
+            his.setNORMAL(assessList.getNORMAL());
+            his.setPLAN(assessList.getPLAN());
+            his.setTaskId(assessList.getAssessId());
+            his.setTYPE(assessList.getTYPE());
+            his.setWEIGHT(assessList.getWEIGHT());
+            his.setUNIT(assessList.getUNIT());
+            his.setCreateBy(assessList.getCreateBy());
+            his.setCreateTime(new Date());
+            his.setVal(assessList.getVal());
+            his.setTaskId(taskId);
+        }
+        return his;
+    }
+
+    private List<DsEffectAssessHis> covertToHis(List<DsEffectAssessList> assessLists, Long taskId){
+        List<DsEffectAssessHis> list = new ArrayList<>();
+        for(DsEffectAssessList tmp : assessLists){
+            list.add(this.covertToHis(tmp, taskId));
+        }
+        return list;
+    }
+
+    // 鏇存柊鏉冮噸鍊�
+    private List<DsEffectAssessList> updateWeight(List<DsEffectAssessList> list, List<DsEffectAssessList> weightList){
+        Long deptId = getDeptId();
+        List<DsEffectAssessList> result = new ArrayList<>();
+        if(null != list && list.size() > 0 && null != weightList && weightList.size() > 0) {
+            for(DsEffectAssessList item : list){
+                DsEffectAssessList tmpAssess = getWeightValFromList(weightList, item);
+                if(null != tmpAssess){
+                    item.setWEIGHT(tmpAssess.getWEIGHT());
+                    item.setClassifyWeight(tmpAssess.getClassifyWeight());
+                    item.setPLAN(tmpAssess.getPLAN());
+                    item.setITEM(tmpAssess.getITEM());
+                    item.setItemDetail(tmpAssess.getItemDetail());
+                    item.setUNIT(tmpAssess.getUNIT());
+                    item.setNORMAL(tmpAssess.getNORMAL());
+                    item.setClassifyIndex(tmpAssess.getClassifyIndex());
+                    item.setDeptId(deptId);
+                }
+                result.add(item);
+            }
+        }
+        return result;
+    }
+
+    // 鑾峰彇瀵瑰簲鐨勬潈閲嶅�艰
+    private DsEffectAssessList getWeightValFromList(List<DsEffectAssessList> list, DsEffectAssessList dsEffectAssessList){
+        for (DsEffectAssessList assessList : list ){
+            if(assessList.getTYPE().equals(dsEffectAssessList.getTYPE()) && assessList.getCODE().equals(dsEffectAssessList.getCODE())){
+                return assessList;
+            }
+        }
+        return null;
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskAQController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskAQController.java
new file mode 100644
index 0000000..f575db6
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskAQController.java
@@ -0,0 +1,285 @@
+package com.ruoyi.buss.controller;
+
+import com.ruoyi.buss.domain.DsTaskDetail;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.vo.*;
+import com.ruoyi.buss.service.IDsTaskDetailService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.text.DecimalFormat;
+import java.util.*;
+
+@Tag(name = "宀告儏浠诲姟鎺ュ彛")
+@RestController
+@RequestMapping("/buss/task/aq")
+public class DMTaskAQController extends BaseController {
+
+    private Double OIL_PLACE_PER = 0.3;
+    private Double MAT_PLACE_PER = 0.2;
+    private Double AMMO_PLACE_PER = 0.5;
+    private Double TOTAL_PLACE_PER = 1.5;
+    DecimalFormat decimalFormat = new DecimalFormat("#.##");
+
+    @Autowired
+    private IDsTaskDetailService dsTaskDetailService;
+
+    @Operation(summary = "鑾峰彇宀告儏褰撳墠浠诲姟鍒楄〃")
+    @GetMapping("/plan/list/statis")
+    @ResponseBody
+    public AjaxResult listPlan(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+
+        // 鐘舵�佷负2  骞朵笖
+        List<DsTaskDetail> detailList =  dsTaskDetailService.selectAQCurTaskDetailList(deptId);
+
+        if(null != detailList){
+            return success(covertToStatis(detailList));
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鑾峰彇宀告儏褰撳墠浠诲姟鍒楄〃TIME")
+    @GetMapping("/plan/list/statis/time")
+    @ResponseBody
+    public AjaxResult listPlanTime(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+
+        // 鐘舵�佷负2  骞朵笖
+        List<DsTaskDetail> detailList =  dsTaskDetailService.selectAQCurTaskDetailList(deptId);
+
+        if(null != detailList){
+            return success(covertToStatisTime(detailList));
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鎵�鏈変换鍔″垪琛�")
+    @GetMapping("/plan/list")
+    @ResponseBody
+    public AjaxResult list(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+
+        // 鐘舵�佷负2  骞朵笖
+        List<DsTaskDetail> detailList =  dsTaskDetailService.selectAQCurTaskDetailList(deptId);
+
+        if(null != detailList){
+            return success(detailList);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鎵�鏈変换鍔″垪琛═IME")
+    @GetMapping("/plan/list/time")
+    @ResponseBody
+    public AjaxResult listTime(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+
+        // 鐘舵�佷负2  骞朵笖
+        List<DsTaskDetail> detailList =  dsTaskDetailService.selectAQCurTaskDetailList(deptId);
+
+        List<DsTaskDetailVO> result = new ArrayList<>();
+        for(DsTaskDetail detail : detailList){
+            result.add(new DsTaskDetailVO(detail));
+        }
+
+        if(null != result){
+            return success(result);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鑾峰彇鍦哄湴缁熺")
+    @GetMapping("/place/list")
+    @ResponseBody
+    public AjaxResult getPlanList(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+        // 鐘舵�佷负2  骞朵笖
+        List<DsTaskDetail> detailList =  dsTaskDetailService.selectAQCurTaskDetailList(deptId);
+        if(null != detailList){
+            return success(covertToPlaceType(detailList));
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "淇敼鍦哄湴浣滀笟灏忕粍")
+    @PostMapping("/plan/edit/{id}")
+    @ResponseBody
+    public AjaxResult editPla(@Parameter(name = "id", required = true, description = "浠诲姟ID") @PathVariable("id") Long id,
+                              @Parameter(name = "workGrpId", required = true, description = "宸ヤ綔灏忕粍ID") Long workGrpId,
+                              @Parameter(name = "type", description = "宸ヤ綔灏忕粍绫诲瀷锛岄粯璁や负1姘寸數锛�2涓虹墿璧�") String type) {
+        DsTaskDetail detail = dsTaskDetailService.selectDsTaskDetailByPKID(id);
+        if(null != detail){
+            if(StringUtils.isNotBlank(type) && type.equals("2")){
+                detail.setWorkMatGrpId(workGrpId);
+            }
+            else{
+                detail.setWorkGrpId(workGrpId);
+            }
+            int flag = dsTaskDetailService.updateDsTaskDetail(detail);
+            if(flag == 1){
+                return success("鏇存柊浣滀笟灏忕粍鎴愬姛");
+            }
+            return error("鏇存柊浣滀笟灏忕粍澶辫触");
+        }
+        return error("鑾峰彇浠诲姟淇℃伅澶辫触锛岃妫�鏌ヤ换鍔D");
+    }
+
+    @Operation(summary = "淇敼璁″垝")
+    @PostMapping("/plan/update")
+    @ResponseBody
+    public AjaxResult editPlanDetail(@RequestBody DsTaskDetail detail) {
+        if(null != detail){
+            Long pkid = detail.getPKID();
+            if(null == pkid){
+                return error("瀵硅薄ID涓嶈兘涓虹┖");
+            }
+            DsTaskDetail newDetail = dsTaskDetailService.selectDsTaskDetailByPKID(pkid);
+            if(null == newDetail){
+                return error("鏈幏鍙栧埌瀵瑰簲鐨勮鍒掍俊鎭�");
+            }
+            if(null != detail.getMatStime())newDetail.setMatStime(detail.getMatStime());
+            if(null != detail.getMatEtime())newDetail.setMatEtime(detail.getMatEtime());
+            if(null != detail.getWaterStime())newDetail.setWaterStime(detail.getWaterStime());
+            if(null != detail.getWaterEtime())newDetail.setWaterEtime(detail.getWaterEtime());
+            if(null != detail.getOilStime())newDetail.setOilStime(detail.getOilStime());
+            if(null != detail.getOilEtime())newDetail.setOilEtime(detail.getOilEtime());
+            if(null != detail.getAmmoStime())newDetail.setAmmoStime(detail.getAmmoStime());
+            if(null != detail.getAmmoEtime())newDetail.setAmmoEtime(detail.getAmmoEtime());
+            if(null != detail.getWorkGrpId())newDetail.setWorkGrpId(detail.getWorkGrpId());
+            if(null != detail.getWorkMatGrpId())newDetail.setWorkMatGrpId(detail.getWorkMatGrpId());
+
+            int flag = dsTaskDetailService.updateDsTaskDetail(newDetail);
+            if(flag == 1){
+                return success("鏇存柊璁″垝浠诲姟鎴愬姛");
+            }
+            return error("鏇存柊璁″垝浠诲姟澶辫触");
+        }
+        return error("鑾峰彇浠诲姟淇℃伅澶辫触锛岃妫�鏌ヤ换鍔D");
+    }
+
+    private List<TaskPlace> covertToPlaceType(List<DsTaskDetail> list){
+        List<TaskPlace> taskPlaces = new ArrayList<>();
+
+        Map<Long, List<DsTaskDetail>> groupedByBerthId = new HashMap<>();
+        for (DsTaskDetail task : list) {
+            Long berthId = task.getBerthId();
+            if (!groupedByBerthId.containsKey(berthId)) {
+                groupedByBerthId.put(berthId, new ArrayList<>());
+            }
+            groupedByBerthId.get(berthId).add(task);
+        }
+
+        for (Map.Entry<Long, List<DsTaskDetail>> entry : groupedByBerthId.entrySet()) {
+            Long berthId = entry.getKey();
+            List<DsTaskDetail> tasks = entry.getValue();
+            String berthName = tasks.get(0).getBerthName();
+
+            TaskPlace waterSupply = new TaskPlace(berthId, berthName, "姘寸數琛ョ粰");
+            TaskPlace oilSupply = new TaskPlace(berthId, berthName, "娌规枡琛ョ粰");
+            TaskPlace ammoSupply = new TaskPlace(berthId, berthName, "寮硅嵂琛ョ粰");
+            TaskPlace materialSupply = new TaskPlace(berthId, berthName, "鐗╄祫琛ョ粰");
+            TaskPlace totalSupply = new TaskPlace(berthId, berthName, "鍚堣鍗犵敤");
+
+
+            // 鍒嗗埆璁$畻涓嶅悓绉嶇被鐨勫崰鐢ㄥ埌涓嶅悓鏃堕棿瀛楁锛屼緥濡倀1 浠h〃鏃堕棿1鐨勫崰鐢紝涓�鐩村埌t24 浠h〃绗�24灏忔椂鐨勫崰鐢ㄦ儏鍐碉紝
+            // waterSupply 浣跨敤 waterSTime 涓� waterETime 瀛楁锛� oilSupply浣跨敤 oilSTime 涓巓ilETime 瀛楁
+            // ammoSupply 浣跨敤 ammoSTime 涓� ammoETime 瀛楁锛� materialSupply 浣跨敤 matStime 涓� matETime 瀛楁
+            // 鍦ㄥ綋鍓峝staskdetail瀵硅薄涓紝渚嬪鏌ョ湅姘寸數琛ョ粰锛岄渶瑕佹煡鐪� waterStime 瀛楁浠h〃寮�濮嬫椂闂达紝watereTime浠h〃缁撴潫鏃堕棿
+            // totalSupply 瀛楁浠h〃鍚堣鍗犵敤 闇�瑕佹妸鍓嶉潰鍥涚绫诲瀷琛ョ粰鍚堝苟璧锋潵銆�
+            for (int i = 1; i <= 24; i++) {
+                String timeSlot = "t" + i;
+                int oilCount = 0;
+                int ammoCount = 0;
+                int matCount = 0;
+                for (DsTaskDetail task : tasks) {
+                    if (task.getOilStime() != null && task.getOilStime() <= i && task.getOilEtime() >= i) {
+                        oilCount++;
+                    } else if (task.getAmmoStime() != null && task.getAmmoStime() <= i && task.getAmmoEtime() >= i) {
+                        ammoCount++;
+                    } else if (task.getMatStime() != null && task.getMatStime() <= i && task.getMatEtime() >= i) {
+                        matCount++;
+                    }
+                }
+                waterSupply.setTimeSlot(timeSlot, 0.0);
+                oilSupply.setTimeSlot(timeSlot, Double.valueOf(decimalFormat.format(oilCount * OIL_PLACE_PER)));
+                ammoSupply.setTimeSlot(timeSlot, Double.valueOf(decimalFormat.format(ammoCount * AMMO_PLACE_PER)));
+                materialSupply.setTimeSlot(timeSlot, Double.valueOf(decimalFormat.format(matCount * MAT_PLACE_PER)));
+                totalSupply.setTimeSlot(timeSlot, Double.valueOf(decimalFormat.format(oilCount * OIL_PLACE_PER + ammoCount * AMMO_PLACE_PER + matCount * MAT_PLACE_PER)));
+            }
+            taskPlaces.add(waterSupply);
+            taskPlaces.add(oilSupply);
+            taskPlaces.add(ammoSupply);
+            taskPlaces.add(materialSupply);
+            taskPlaces.add(totalSupply);
+        }
+
+        return taskPlaces;
+    }
+
+    private List<TaskPlanStatis> covertToStatis(List<DsTaskDetail> list){
+        Map<Long, List<DsTaskDetail>> groupedByBerthId = new HashMap<>();
+        for (DsTaskDetail task : list) {
+            Long berthId = task.getBerthId();
+            if (!groupedByBerthId.containsKey(berthId)) {
+                groupedByBerthId.put(berthId, new ArrayList<>());
+            }
+            groupedByBerthId.get(berthId).add(task);
+        }
+
+        List<TaskPlanStatis> result = new ArrayList<>();
+        for (Map.Entry<Long, List<DsTaskDetail>> entry : groupedByBerthId.entrySet()) {
+            List<DsTaskDetail> tasks = entry.getValue();
+            TaskPlanStatis statis = new TaskPlanStatis();
+            statis.setBerthName(tasks.get(0).getBerthName());
+            statis.setHarborName(tasks.get(0).getHarborName());
+            statis.setBerthStrategy(tasks.get(0).getParkingType());
+            statis.setShipInfo(tasks);
+            result.add(statis);
+        }
+
+        return result;
+    }
+
+    private List<TaskPlanStatisTime> covertToStatisTime(List<DsTaskDetail> list){
+        Map<Long, List<DsTaskDetailVO>> groupedByBerthId = new HashMap<>();
+        for (DsTaskDetail task : list) {
+            Long berthId = task.getBerthId();
+            if (!groupedByBerthId.containsKey(berthId)) {
+                groupedByBerthId.put(berthId, new ArrayList<>());
+            }
+            DsTaskDetailVO taskDetailVO = new DsTaskDetailVO(task);
+            groupedByBerthId.get(berthId).add(taskDetailVO);
+        }
+
+        List<TaskPlanStatisTime> result = new ArrayList<>();
+        for (Map.Entry<Long, List<DsTaskDetailVO>> entry : groupedByBerthId.entrySet()) {
+            List<DsTaskDetailVO> tasks = entry.getValue();
+            TaskPlanStatisTime statis = new TaskPlanStatisTime();
+            statis.setBerthName(tasks.get(0).getBerthName());
+            statis.setHarborName(tasks.get(0).getHarborName());
+            statis.setBerthStrategy(tasks.get(0).getParkingType());
+            statis.setShipInfo(tasks);
+            result.add(statis);
+        }
+
+        return result;
+    }
+
+
+    public static void main(String[] args) {
+        double value = 1.23456789 * 2.34567890;
+        DecimalFormat df = new DecimalFormat("#.##"); // 璁剧疆鏍煎紡涓轰繚鐣�10浣嶅皬鏁�
+        String formattedValue = df.format(value);
+        System.out.println(value);
+        System.out.println(Double.valueOf(formattedValue));
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskController.java
new file mode 100644
index 0000000..e6ba455
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskController.java
@@ -0,0 +1,624 @@
+package com.ruoyi.buss.controller;
+
+import com.ruoyi.buss.common.DateUtils;
+import com.ruoyi.buss.domain.DmHarbor2;
+import com.ruoyi.buss.domain.DsTask;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.AllocationReqDTO;
+import com.ruoyi.buss.domain.dto.DsTaskQueryParam;
+import com.ruoyi.buss.domain.vo.TaskListStatis;
+import com.ruoyi.buss.service.IDmHarbor2Service;
+import com.ruoyi.buss.service.IDsTaskList2Service;
+import com.ruoyi.buss.service.IDsTaskService;
+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.ruoyi.common.utils.StringUtils;
+import com.ruoyi.framework.web.domain.server.Sys;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+@Tag(name = "鍩哄湴浠诲姟鎺ュ彛")
+@RestController
+@RequestMapping("/buss/task/ex")
+public class DMTaskController extends BaseController {
+
+    @Autowired
+    private IDsTaskService iDsTaskService;
+    @Autowired
+    private IDsTaskList2Service iDsTaskListService;
+    @Autowired
+    private IDmHarbor2Service iDmHarborService;
+
+    @Operation(summary = "鑾峰彇鎵�鏈変换鍔″垪琛�")
+    @PostMapping("/histask/list")
+    @ResponseBody
+    public AjaxResult getTaskList(@RequestBody DsTaskQueryParam param) {
+        if(null != param.getEtime()){
+            param.setEtime(DateUtils.setToNextDayZero(param.getEtime()));
+        }
+        List<DsTask> dsTaskList = iDsTaskService.selectDsTaskListByParam(param);
+        return success(dsTaskList);
+    }
+
+    @Operation(summary = "浠诲姟瀹屾垚鎺ュ彛_閫氳繃ID")
+    @PostMapping("/complete/{id}")
+    @ResponseBody
+    public AjaxResult complete(@Parameter(name = "id", required = true, description = "浠诲姟ID") @PathVariable("id") Long id) {
+        DsTaskList2 taskList2 = iDsTaskListService.selectDsTaskListByPkid(id);
+        if(null != taskList2){
+            taskList2.setStatus("10");
+            taskList2.setUpdateBy(getUsername());
+            int flag = iDsTaskListService.updateDsTaskList(taskList2);
+            if(flag == 1){
+                return success("浠诲姟瀹屾垚鎴愬姛");
+            }
+            return error("浠诲姟瀹屾垚澶辫触");
+        }
+        return error("鏈幏鍙栧埌浠诲姟");
+    }
+
+    @Operation(summary = "浠诲姟瀹屾垚鎺ュ彛_閫氳繃浠诲姟Id鍜岃埛鍙�")
+    @PostMapping("/complete/taskandship/{taskid}/{shipno}")
+    @ResponseBody
+    public AjaxResult completeWithShipAndTaskId(@Parameter(name = "taskid", required = true, description = "浠诲姟ID") @PathVariable("taskid") Long taskid,
+                                                @Parameter(name = "shipno", required = true, description = "鑸峰彿") @PathVariable("shipno") String shipno) {
+        DsTaskList2 queryParam = new DsTaskList2();
+        queryParam.setTaskId(taskid);
+        queryParam.setShipNo(shipno);
+        List<DsTaskList2> taskList2 = iDsTaskListService.selectDsTaskListList(queryParam);
+        if(null != taskList2 && taskList2.size() > 0){
+            DsTaskList2 tmpTask = taskList2.get(0);
+            tmpTask.setStatus("10");
+            tmpTask.setUpdateBy(getUsername());
+            int flag = iDsTaskListService.updateDsTaskList(tmpTask);
+            if(flag == 1){
+                return success("浠诲姟瀹屾垚鎴愬姛");
+            }
+            return error("浠诲姟瀹屾垚澶辫触");
+        }
+        return error("鏈幏鍙栧埌浠诲姟");
+    }
+
+    @Operation(summary = "浠诲姟鍒楄〃_榛樿鑾峰彇姝e湪鎵ц鐨勪换鍔�")
+    @PostMapping("/list")
+    @ResponseBody
+    public AjaxResult runningTask(@Parameter(name = "deptid", required = false, description = "閮ㄩ棬缂栫爜") @RequestParam(value = "deptid", required = false) Long deptid,
+                                  @Parameter(name = "status", description = "鐘舵�佺紪鐮�") @RequestParam(value = "status", required = false, defaultValue = "2") String status) {
+        if(StringUtils.isBlank(status)){status = "2";}
+        DsTaskList2 queryParam = new DsTaskList2();
+        queryParam.setStatus(status);
+        if(null != deptid){queryParam.setDeptId(deptid);}
+        List<DsTaskList2> taskList2 = iDsTaskListService.selectDsTaskListList(queryParam);
+        return success(taskList2);
+    }
+
+    @Operation(summary = "鍩哄湴浠诲姟涓嬪彂")
+    @Log(title = "鍩哄湴浠诲姟涓嬪彂", businessType = BusinessType.UPDATE)
+    @PostMapping("/apply/{taskid}")
+    @ResponseBody
+    public AjaxResult apply(@Parameter(name = "taskid", required = true, description = "浠诲姟ID") @PathVariable("taskid") Long taskid) {
+        DsTask dsTask = iDsTaskService.selectDsTaskByPKID(taskid);
+        dsTask.setStatus("1");
+        dsTask.setUpdateBy(getUsername());
+        int flag = iDsTaskService.updateDsTask(dsTask);
+        List<DsTaskList2> taskList2s = iDsTaskListService.selectDsTaskListByTaskId(taskid);
+        for(DsTaskList2 task : taskList2s){
+            task.setStatus("1");
+            iDsTaskListService.updateDsTaskList(task);
+        }
+        if(flag == 1){
+            return success(dsTask);
+        }
+        return error("涓嬪彂澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鏍规嵁浠诲姟ID鑾峰彇浠诲姟鍒楄〃")
+    @GetMapping("/taskId/{taskid}")
+    @ResponseBody
+    public AjaxResult getByTaskId(@Parameter(name = "taskid", required = true, description = "浠诲姟ID") @PathVariable("taskid") Long taskid) {
+        List<DsTaskList2> dsTaskList2s = iDsTaskListService.selectDsTaskListByTaskId(taskid);
+        return success(covertTaskToStatis(dsTaskList2s));
+    }
+
+    /**
+     * 鐮佸ご璋冨害鍒嗛厤鎺ュ彛
+     *
+     */
+    @Operation(summary = "鐮佸ご璋冨害鍒嗛厤")
+    @PostMapping("/allocation")
+    @ResponseBody
+    public AjaxResult allocation(@RequestBody AllocationReqDTO reqDTO) {
+        String shipnos = reqDTO.getShipnos();
+        String rule = reqDTO.getRule();
+        String harborIds = reqDTO.getHarborids();
+
+//        if(StringUtils.isBlank(shipnos)){
+//            return error("鑸峰彿涓嶈兘涓虹┖");
+//        }
+        String[] shipArr = shipnos.split(",");
+        List<DsTaskList2> taskLists = iDsTaskListService.selectCurrentDsTaskListWithShipNoV2(shipArr);
+        if(taskLists.size() == 0){
+            return error("鎵�閫夎埌鑹囦负绌猴紝璇烽噸鏂版鏌ュ弬鏁�");
+        }
+        
+        if (StringUtils.isBlank(harborIds)) {
+            return error("鐮佸ごID涓嶈兘涓虹┖");
+        }
+        String[] harborIdArr = harborIds.split(",");
+        List<Long> harborIdList = Arrays.stream(harborIdArr)
+                                        .map(Long::parseLong)
+                                        .collect(Collectors.toList());
+        List<DmHarbor2> harborList = iDmHarborService.selectDmHarborByPKIDs(harborIdList);
+
+        // 閲嶆柊缁勭粐鏁版嵁缁撴瀯锛岀劧鍚庡彂閫�
+        List<DsTaskList2> allocTaskList = allocationHarbor(taskLists, harborList, rule);
+        // 閲嶆柊璁惧畾瀵硅薄缁撴瀯锛屾寜鐓х爜澶村垎缁�
+        return success(covertTaskToStatis(allocTaskList));
+    }
+
+    /**
+     * 鏂板淇濆瓨浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "璋冮厤淇℃伅鏇存柊鎺ュ彛")
+    @PostMapping("/tasklist/add")
+    @ResponseBody
+    public AjaxResult addTaskListSave(@RequestBody List<DsTaskList2> taskList) {
+        // 缂哄皯鏁版嵁闈炵┖浠ュ強鍚堟硶鎬ф牎楠�
+
+        // 鍒犻櫎宸茬粡瀛樺湪鐨勮埞鑸版暟鎹�
+        List<DsTaskList2> dsTaskList2s = iDsTaskListService.selectCurrentDsTaskListV2();
+        // 澧炲姞涓�涓换鍔″苟淇濆瓨
+        DsTask dsTask = new DsTask();
+        String taskName = String.format("浠诲姟: %tF # %d", new Date(), System.currentTimeMillis());
+        dsTask.setNAME(taskName);
+        int addTag = iDsTaskService.insertDsTask(dsTask);
+
+
+        try{
+            if(addTag > 0){
+                // 浣跨敤Map浼樺寲鏌ユ壘鏁堢巼
+                Map<Long, DsTaskList2> existingTaskMap = dsTaskList2s.stream()
+                    .collect(Collectors.toMap(DsTaskList2::getPKID, Function.identity()));
+                
+                // 鎵归噺鏇存柊浠诲姟鍒楄〃
+                List<DsTaskList2> tasksToUpdate = taskList.stream()
+                    .filter(tmpTaskList -> existingTaskMap.containsKey(tmpTaskList.getPKID()))
+                    .map(tmpTaskList -> {
+                        DsTaskList2 existingTask = existingTaskMap.get(tmpTaskList.getPKID());
+                        existingTask.setTaskId(dsTask.getPKID());
+                        existingTask.setHarborName(tmpTaskList.getHarborName());
+                        existingTask.setHarborId(tmpTaskList.getHarborId());
+                        existingTask.setDeptId(tmpTaskList.getDeptId());
+                        existingTask.setDeptName(tmpTaskList.getDeptName());
+                        return existingTask;
+                    })
+                    .collect(Collectors.toList());
+                
+                // 鎵归噺鏇存柊鏁版嵁搴�
+                if (!tasksToUpdate.isEmpty()) {
+                    iDsTaskListService.batchUpdateDsTaskList(tasksToUpdate);
+                }
+                return success(dsTask);
+            }
+        }catch (Exception e){
+            iDsTaskService.deleteDsTaskByPKID(dsTask.getPKID());
+        }
+
+        return error("鍒涘缓浠诲姟澶辫触锛岃閲嶈瘯");
+    }
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     */
+    @Operation(summary = "NEW-鑾峰彇褰撴棩闇�瑕佸垎閰嶇殑鑸拌墖淇℃伅")
+    @PostMapping("/current/list")
+    @ResponseBody
+    public AjaxResult curListV2() {
+        List<DsTaskList2> list = iDsTaskListService.selectCurrentDsTaskListV2();
+        return success(list);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鑾峰彇褰撴棩闇�瑕佸垎閰嶇殑鑸拌墖淇℃伅V1")
+    @PostMapping("/current/list/v1")
+    @ResponseBody
+    public AjaxResult curListV1() {
+        List<DsTaskList2> list = iDsTaskListService.selectCurrentDsTaskList();
+        return success(list);
+    }
+
+
+    /**
+     * 瀵规硦浣嶆寜鐓ц鍒欒繘琛屽垎閰�
+     * @param list
+     * @param rule
+     * @return
+     */
+    private List<DsTaskList2> allocationHarbor(List<DsTaskList2> list, List<DmHarbor2> harborList, String rule){
+        List<DsTaskList2> dsTaskList2s = new ArrayList<>();
+        if(null != list && list.size() > 0){
+            switch (rule){
+                case "ZSBD":        // 鎴樻湳缂栭槦
+                    // 鍓嶆彁璇存槑锛氭补閲忛兘鏄寚oil_a 瀛楁锛�  鍓╀綑娌归噺鎸囨腐鍙f补瀛橀噺鍑忓幓宸茬粡鍒嗛厤鑸拌墖闇�瑕佺殑娌归渶姹傞噺锛屽彲鐢ㄦ硦浣嶄负 berth_no  娓彛椤哄簭鏄寚  宸插垎閰嶈埌鑹囨暟閲�/鍙敤娉婁綅 姝e簭鎺掑垪
+                    // 1 鍏堢瓫閫夊嚭鏈夋垬鏈紪闃熺殑鑸拌墖锛屾牴鎹垬鏈紪闃熻繘琛屽垎缁勶紝
+                    // 2 鍒嗗埆璁$畻姣忕粍鎬荤殑鍔犳补閲忥紝骞惰绠楄缁勭殑鏈�澶ф按娣憋紝
+                    // 3 濡傛灉璇ユ垬鏈紪闃熺殑浣嶇疆鍖哄煙瀛楁鍊间笉涓虹┖锛岄閫夋牴鎹腐鍙f按娣卞垽鏂鍖哄煙鏄惁婊¤冻锛屽鏋滄弧瓒冲啀鍒ゆ柇璇ュ尯鍩熸腐鍙e凡鏈夋补閲忔弧瓒抽渶姹傦紝濡傛灉閮芥弧瓒冲垯鍒嗛厤璇ユ腐鍙o紝
+                    // 4 濡傛灉鏈変竴涓潯浠朵笉婊¤冻鍒欒幏鍙栦笅涓�涓腐鍙h繘琛屽垽鏂紝濡傛灉鎵�鏈夋腐鍙i兘涓嶆弧瓒冲垯閫夋嫨绗竴涓腐鍙o紝骞跺湪remark 瀛楁澧炲姞鍒ゆ柇澶辫触鐨勫師鍥犮��
+                    // 5 濡傛灉浣嶇疆鍖哄煙瀛楁涓虹┖锛屽垯鏍规嵁娓彛椤哄簭渚濇閫夋嫨娓彛杩涜鍒ゆ柇锛屾瘡涓腐鍙e厛鏍规嵁娓彛姘存繁鍒ゆ柇璇ュ尯鍩熸槸鍚︽弧瓒筹紝濡傛灉婊¤冻鍐嶅垽鏂鍖哄煙娓彛宸叉湁娌归噺婊¤冻闇�姹傦紝濡傛灉閮芥弧瓒冲垯鍒嗛厤璇ユ腐鍙o紝
+                    // 6 濡傛灉鏈夋潯浠朵笉婊¤冻鍒欎緷娆¢�夋嫨涓嬩竴涓腐鍙h繘琛屽垽鏂洿鍒版腐鍙i亶鍘嗗畬锛屽鏋滆繕鏈壘鍒板垯鍒嗛厤绗竴涓腐鍙o紝骞跺湪remark 瀛楁澧炲姞鍒ゆ柇澶辫触鐨勫師鍥�
+                // 1-鍏堢瓫閫夊嚭鏈夋垬鏈紪闃熺殑鑸拌墖锛屾牴鎹垬鏈紪闃熻繘琛屽垎缁勶紝
+                Map<String, List<DsTaskList2>> tacticalGroupMap = list.stream()
+                        .collect(Collectors.groupingBy(task -> task.getGrpName() != null && !task.getGrpName().isEmpty() ? task.getGrpName() : UUID.randomUUID().toString()));
+                Map<Long, Double> allocatedOilMap = new HashMap<>();
+                // 1.1- 璁$畻璇ョ粍鎬荤殑oil_a閲忥紝鏍规嵁鎬籵il_a閲忛�夋嫨鍚堥�傜殑娓彛锛�
+                for (Map.Entry<String, List<DsTaskList2>> entry : tacticalGroupMap.entrySet()) {
+                    List<DsTaskList2> groupTasks = entry.getValue();
+                    double totalOilB = groupTasks.stream().mapToDouble(task -> {
+                        double oilA = 0.0;
+                        if (task.getOilB() != null) oilA += task.getOilB();
+                        return oilA;
+                    }).sum();
+                    double maxDepth = groupTasks.stream().mapToDouble(task -> task.getDraft() != null ? task.getDraft() : 0).max().orElse(0);
+
+                    DmHarbor2 selectedHarbor = null;
+                    List<DmHarbor2> suitableHarbors = harborList.stream()
+                            .filter(harbor -> (harbor.getOilB() != null && harbor.getOilB() >= totalOilB) && harbor.getDraft() >= maxDepth)
+                            .collect(Collectors.toList());
+
+                    if (!suitableHarbors.isEmpty()) {
+                        if (StringUtils.isNotBlank(groupTasks.get(0).getPosArea())) {
+                            selectedHarbor = suitableHarbors.stream()
+                                    .filter(harbor -> harbor.getHarborName() != null && harbor.getHarborName().equals(groupTasks.get(0).getPosArea()) && (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) < harbor.getBerthNo())
+                                    .findFirst()
+                                    .orElse(suitableHarbors.stream()
+                                            .filter(harbor -> (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) < harbor.getBerthNo())
+                                            .findFirst()
+                                            .orElse(suitableHarbors.get(0)));
+                        } else {
+                            selectedHarbor = suitableHarbors.stream()
+                                    .filter(harbor -> (harbor.getOilB() != null ? harbor.getOilB() : 0) - (harbor.getAllocatedOilA() != null ? harbor.getAllocatedOilA() : 0) >= totalOilB && (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) < harbor.getBerthNo())
+                                    .findFirst()
+                                    .orElse(suitableHarbors.stream()
+                                            .filter(harbor -> (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) < harbor.getBerthNo())
+                                            .findFirst()
+                                            .orElse(suitableHarbors.get(0)));
+                        }
+                    } else {
+                        selectedHarbor = harborList.stream()
+                                .filter(harbor -> (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) < harbor.getBerthNo())
+                                .min(Comparator.comparingDouble(harbor -> (double) (harbor.getBerthNo() - (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0)) / harbor.getBerthNo()))
+                                .orElse(harborList.get(0));
+                    }
+
+                    DmHarbor2 finalSelectedHarbor = selectedHarbor;
+                    groupTasks.forEach(task -> {
+                        if (finalSelectedHarbor != null) {
+                            task.setHarborId(finalSelectedHarbor.getPKID());
+                            task.setHarborName(finalSelectedHarbor.getHarborName());
+                            task.setDeptId(finalSelectedHarbor.getDeptId());
+                            task.setDeptName(finalSelectedHarbor.getDeptName());
+                            double allocatedOilA = finalSelectedHarbor.getAllocatedOilA() != null ? finalSelectedHarbor.getAllocatedOilA() : 0;
+                            finalSelectedHarbor.setAllocatedOilA(allocatedOilA + (task.getOilB() != null ? task.getOilB() : 0));
+                            int allocatedShipCount = finalSelectedHarbor.getAllocatedShipCount() != null ? finalSelectedHarbor.getAllocatedShipCount() : 0;
+                            finalSelectedHarbor.setAllocatedShipCount(allocatedShipCount + 1);
+                            dsTaskList2s.add(task);
+                        }
+
+                        // 閲嶆柊璁$畻绌虹疆姣�
+                        harborList.forEach(harbor -> {
+                            int currentAllocatedShipCount = harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0;
+                            double vacancyRatio = (double) (harbor.getBerthNo() - currentAllocatedShipCount) / harbor.getBerthNo();
+                            // 鍙互鍦ㄦ澶勪娇鐢╲acancyRatio杩涜杩涗竴姝ョ殑閫昏緫澶勭悊
+                        });
+                    });
+                }
+                break;
+                case "JTXH":        // 鑸拌墖鍨嬪彿
+                    // 1- 鍏堟牴鎹埌鑹囧瀷鍙疯繘琛屽垎缁勶紝鏍规嵁鍒嗙粍淇℃伅锛屽鏋滃悓涓�缁勭殑浼樺厛鍒嗛厤鍚屼竴涓爜澶达紝
+                    // 1.1- 璁$畻姣忎竴缁勭殑鎬诲姞娌归噺锛屾牴鎹姞娌归噺閫夋嫨鍚堥�傜殑娓彛锛�
+                    // 1.2- 濡傛灉澶氫釜娓彛鍔犳补閲忛兘鍙互婊¤冻鍒欐寜鐓т綅缃尯鍩熼�夋嫨娓彛锛�
+                    // 1.3- 濡傛灉鏃犱綅缃尯鍩燂紝鍒欓�夋嫨绗竴涓腐鍙c��
+                // 1- 鍏堟牴鎹埌鑹囧瀷鍙疯繘琛屽垎缁�
+                Map<String, List<DsTaskList2>> shipTypeGroupMap = list.stream()
+                        .collect(Collectors.groupingBy(DsTaskList2::getShipType));
+
+                for (Map.Entry<String, List<DsTaskList2>> entry : shipTypeGroupMap.entrySet()) {
+                    List<DsTaskList2> groupTasks = entry.getValue();
+                    double totalOilB = groupTasks.stream().mapToDouble(task -> {
+                        double oilB = 0.0;
+                        if (task.getOilB() != null) oilB += task.getOilB();
+                        return oilB;
+                    }).sum();
+                    double maxDepth = groupTasks.stream().mapToDouble(task -> task.getDraft() != null ? task.getDraft() : 0).max().orElse(0);
+
+                    DmHarbor2 selectedHarbor = null;
+                    boolean harborFound = false;
+
+                    // 3- 濡傛灉鍒嗙粍鐨勪綅缃尯鍩熷瓧娈靛�间笉涓虹┖
+                    if (groupTasks != null && !groupTasks.isEmpty() && groupTasks.get(0).getPosArea() != null && !groupTasks.get(0).getPosArea().isEmpty()) {
+                        for (DmHarbor2 harbor : harborList) {
+                            if (harbor != null && harbor.getDraft() >= maxDepth && 
+                                (harbor.getOilB() != null && harbor.getAllocatedOilA() != null && 
+                                 (harbor.getOilB() - harbor.getAllocatedOilA() >= totalOilB)) && 
+                                harbor.getHarborName() != null && 
+                                harbor.getHarborName().equals(groupTasks.get(0).getPosArea())) {
+                                selectedHarbor = harbor;
+                                harborFound = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    // 5- 濡傛灉浣嶇疆鍖哄煙瀛楁涓虹┖
+                    if (!harborFound) {
+                        for (DmHarbor2 harbor : harborList.stream().sorted(Comparator.comparingDouble(h -> {
+                            int allocatedShipCount = h.getAllocatedShipCount() != null ? h.getAllocatedShipCount() : 0;
+                            return (double) allocatedShipCount / (h.getBerthNo() != null ? h.getBerthNo() : 1);
+                        })).collect(Collectors.toList())) {
+                            double allocatedOilA = harbor.getAllocatedOilA() != null ? harbor.getAllocatedOilA() : 0;
+                            if (harbor.getDraft() >= maxDepth && 
+                                (harbor.getOilB() != null && (harbor.getOilB() - allocatedOilA >= totalOilB))) {
+                                selectedHarbor = harbor;
+                                harborFound = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    // 4- 濡傛灉鎵�鏈夋腐鍙i兘涓嶆弧瓒冲垯閫夋嫨绗竴涓腐鍙o紝骞跺湪remark 瀛楁澧炲姞鍒ゆ柇澶辫触鐨勫師鍥�
+                    if (!harborFound && !harborList.isEmpty()) {
+                        selectedHarbor = harborList.get(0);
+                        groupTasks.forEach(task -> task.setRemark("鎵�鏈夋腐鍙e潎涓嶆弧瓒虫潯浠�"));
+                    }
+
+                    DmHarbor2 finalSelectedHarbor = selectedHarbor;
+                    groupTasks.forEach(task -> {
+                        if (finalSelectedHarbor != null) {
+                            task.setHarborId(finalSelectedHarbor.getPKID());
+                            task.setHarborName(finalSelectedHarbor.getHarborName());
+                            finalSelectedHarbor.setAllocatedOilA((finalSelectedHarbor.getAllocatedOilA() != null ? finalSelectedHarbor.getAllocatedOilA() : 0) + (task.getOilB() != null ? task.getOilB() : 0));
+                            finalSelectedHarbor.setAllocatedShipCount((finalSelectedHarbor.getAllocatedShipCount() != null ? finalSelectedHarbor.getAllocatedShipCount() : 0) + 1);
+                            dsTaskList2s.add(task);
+                        } else {
+                            task.setRemark("鏈壘鍒板悎閫傜殑娓彛");
+                        }
+                    });
+                }
+                break;
+                case "BJZD":        // 琛ョ粰閲嶇偣
+                for (DsTaskList2 task : list) {
+                    Double taskDraft = task.getDraft() != null ? task.getDraft() : 0.0;
+                    boolean ammoSupplyNeeded = (task.getAmmoD() != null && task.getAmmoD() > 0) ||
+                                               (task.getAmmoO() != null && task.getAmmoO() > 0) ||
+                                               (task.getAmmoP() != null && task.getAmmoP() > 0) ||
+                                               (task.getAmmoS() != null && task.getAmmoS() > 0);
+                    //harborList.stream().mapToDouble(h -> h.getDraft() != null ? h.getDraft() : 0.0).min().orElse(0.0);
+                    DmHarbor2 selectedHarbor = null;
+                    boolean harborFound = false;
+                    if (ammoSupplyNeeded) {
+                        boolean canDockAtQingyuOrJiaotou = harborList.stream()
+                                .anyMatch(harbor -> (harbor.getHarborName().equals("闈掑笨") || harbor.getHarborName().equals("绀佸ご")) &&
+                                                     harbor.getDraft() >= taskDraft);
+
+                        if (canDockAtQingyuOrJiaotou) {
+                            for (DmHarbor2 harbor : harborList) {
+                                if ((harbor.getHarborName().equals("闈掑笨") || harbor.getHarborName().equals("绀佸ご")) &&
+                                    harbor.getDraft() >= taskDraft &&
+                                    (harbor.getOilB() - (harbor.getAllocatedOilA() != null ? harbor.getAllocatedOilA() : 0) >= task.getOilB()) &&
+                                    (harbor.getAllocatedShipCount() != null ? harbor.getAllocatedShipCount() : 0) / (harbor.getBerthNo() != null ? harbor.getBerthNo() : 1) < 1) {
+                                    selectedHarbor = harbor;
+                                    harborFound = true;
+                                    break;
+                                }
+                            }
+                        } else {
+                            for (DmHarbor2 harbor : harborList) {
+                                if (harbor.getDraft() >= taskDraft) {
+                                    selectedHarbor = harbor;
+                                    harborFound = true;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    
+                    if (!harborFound) {
+                        for (DmHarbor2 harbor : harborList) {
+                            if (harbor.getDraft() >= taskDraft) {
+                                selectedHarbor = harbor;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (selectedHarbor != null) {
+                        task.setHarborId(selectedHarbor.getPKID());
+                        task.setHarborName(selectedHarbor.getHarborName());
+                        selectedHarbor.setAllocatedOilA((selectedHarbor.getAllocatedOilA() != null ? selectedHarbor.getAllocatedOilA() : 0) + (task.getOilB() != null ? task.getOilB() : 0));
+                        selectedHarbor.setAllocatedShipCount((selectedHarbor.getAllocatedShipCount() != null ? selectedHarbor.getAllocatedShipCount() : 0) + 1);
+                        dsTaskList2s.add(task);
+                    } else {
+                        task.setRemark("鏈壘鍒板悎閫傜殑娓彛");
+                    }
+                }
+                break;
+                case "WZQJ":        // 浣嶇疆鍖洪棿
+                // 1- 鍏堟寜鐓у寘鍚綅缃尯闂寸殑杩涜鍒嗙粍
+                // 2- 鍓╀綑鐨勬寜鐓ф硦浣嶆暟閲忓崰姣旇繘琛屽垎閰嶏紝
+                // 3- 濡傛灉鍗犳瘮绫讳技鍒欐寜鐓ч『搴忚繘琛屽尯鍒嗐��
+                // 1- 鍏堟寜鐓ф槸鍚﹀寘鍚綅缃尯闂磋繘琛屽尯鍒�
+                // 1- 鍏堟寜鐓т綅缃尯闂磋繘琛屽垎缁�
+                Map<String, List<DsTaskList2>> posAreaGroupMap = list.stream()
+                        .collect(Collectors.groupingBy(task -> {
+                            String posArea = task.getPosArea();
+                            return (posArea != null && !posArea.isEmpty()) ? posArea : UUID.randomUUID().toString();
+                        }));
+
+                // 2- 鍒嗗埆璁$畻姣忕粍鎬荤殑鍔犳补閲忥紝浠ュ強鏈�澶ф按娣憋紝
+                for (Map.Entry<String, List<DsTaskList2>> entry : posAreaGroupMap.entrySet()) {
+                    List<DsTaskList2> groupTasks = entry.getValue();
+                    double totalOilB = groupTasks.stream().mapToDouble(task -> {
+                        Double oilB = task.getOilB();
+                        return (oilB != null) ? oilB : 0.0;
+                    }).sum();
+                    double maxDepth = groupTasks.stream().mapToDouble(task -> {
+                        Double draft = task.getDraft();
+                        return (draft != null) ? draft : 0.0;
+                    }).max().orElse(0.0);
+
+                    DmHarbor2 selectedHarbor = null;
+                    boolean harborFound = false;
+
+                    // 3- 鍏堥亶鍘嗕綅缃尯闂翠笉涓虹┖鐨勭粍
+                    if (groupTasks.get(0).getPosArea() != null && !groupTasks.get(0).getPosArea().isEmpty()) {
+                        for (DmHarbor2 harbor : harborList) {
+                            Double harborDraft = harbor.getDraft() != null ? harbor.getDraft() : 0.0;
+                            Double harborOilB = harbor.getOilB() != null ? harbor.getOilB() : 0.0;
+                            Double allocatedOilA = harbor.getAllocatedOilA() != null ? harbor.getAllocatedOilA() : 0.0;
+
+                            if (harborDraft >= maxDepth && (harborOilB - allocatedOilA >= totalOilB)) {
+                                selectedHarbor = harbor;
+                                harborFound = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    // 5- 鍐嶉亶鍘嗕綅缃尯闂翠负绌虹殑缁�
+                    if (!harborFound) {
+                        for (DmHarbor2 harbor : harborList.stream()
+                                .sorted(Comparator.comparingDouble(h -> {
+                                    int allocatedShipCount = h.getAllocatedShipCount() != null ? h.getAllocatedShipCount() : 0;
+                                    long berthNo = h.getBerthNo() != null ? h.getBerthNo() : 1;
+                                    return (double) allocatedShipCount / berthNo;
+                                }))
+                                .collect(Collectors.toList())) {
+                            Double harborDraft = harbor.getDraft() != null ? harbor.getDraft() : 0.0;
+                            Double harborOilB = harbor.getOilB() != null ? harbor.getOilB() : 0.0;
+                            Double allocatedOilA = harbor.getAllocatedOilA() != null ? harbor.getAllocatedOilA() : 0.0;
+
+                            if (harborDraft >= maxDepth && (harborOilB - allocatedOilA >= totalOilB)) {
+                                selectedHarbor = harbor;
+                                harborFound = true;
+                                break;
+                            }
+                        }
+                    }
+
+                    if (!harborFound) {
+                        selectedHarbor = harborList.stream()
+                                .min(Comparator.comparingDouble(h -> {
+                                    int allocatedShipCount = h.getAllocatedShipCount() != null ? h.getAllocatedShipCount() : 0;
+                                    long berthNo = h.getBerthNo() != null ? h.getBerthNo() : 1;
+                                    return (double) allocatedShipCount / berthNo;
+                                }))
+                                .orElse(harborList.get(0));
+                    }
+
+                    DmHarbor2 finalSelectedHarbor = selectedHarbor;
+                    groupTasks.forEach(task -> {
+                        task.setHarborId(finalSelectedHarbor.getPKID());
+                        task.setHarborName(finalSelectedHarbor.getHarborName());
+                        task.setDeptId(finalSelectedHarbor.getDeptId());
+                        task.setDeptName(finalSelectedHarbor.getDeptName());
+                        double allocatedOilA = finalSelectedHarbor.getAllocatedOilA() != null ? finalSelectedHarbor.getAllocatedOilA() : 0.0;
+                        finalSelectedHarbor.setAllocatedOilA(allocatedOilA + (task.getOilB() != null ? task.getOilB() : 0.0));
+                        int allocatedShipCount = finalSelectedHarbor.getAllocatedShipCount() != null ? finalSelectedHarbor.getAllocatedShipCount() : 0;
+                        finalSelectedHarbor.setAllocatedShipCount(allocatedShipCount + 1);
+                        dsTaskList2s.add(task);
+                    });
+                }
+                break;
+                default:
+                    if(null != harborList && harborList.size() > 0){
+                        int harborLen1 = harborList.size();
+                        int shipCount1 = list.size();
+                        int harborWithShipCount1 =  (int)Math.ceil((double) shipCount1 / harborLen1);
+                        for(int i=0; i <shipCount1; i++){
+                            DsTaskList2 task = list.get(i);
+                            int harborTag = (int) Math.ceil((double)(i+1) / harborWithShipCount1) - 1;
+                            DmHarbor2 dmHarbor2 = harborList.get(harborTag);
+                            task.setHarborId(dmHarbor2.getPKID());
+                            task.setHarborName(dmHarbor2.getHarborName());
+                            dsTaskList2s.add(task);
+                        }
+                    }
+            }
+        }
+        return dsTaskList2s;
+    }
+    
+    /**
+     * 鎶婄粨鏋滃垪琛ㄩ噸鏂拌浆鎹负缁熻鏍煎紡
+     * @param allocTaskList
+     * @return
+     */
+    private List<TaskListStatis> covertTaskToStatis(List<DsTaskList2> allocTaskList){
+        List<TaskListStatis> taskListStatis = new ArrayList<>();
+        Map<Long, List<DsTaskList2>> tmpTaskMap = new HashMap<>();
+        allocTaskList.stream().forEach(item -> {
+            Long harborId = item.getHarborId();
+            List<DsTaskList2> itemTaskLists = new ArrayList<>();
+            if(tmpTaskMap.containsKey(harborId)){
+                itemTaskLists = tmpTaskMap.get(harborId);
+            }
+            itemTaskLists.add(item);
+            tmpTaskMap.put(harborId, itemTaskLists);
+        });
+
+        tmpTaskMap.forEach((harborId, tasks) -> {
+            TaskListStatis statis = new TaskListStatis();
+            DmHarbor2 harbor = iDmHarborService.selectDmHarborByPKID(harborId);
+            statis.setHarbor(harbor);
+            statis.setTasks(tasks);
+
+            // 缁熻tasks鏁板�煎瓧娈电殑鍊�
+            DsTaskList2 taskStatis = new DsTaskList2();
+            tasks.forEach(task -> {
+                taskStatis.setOilB((taskStatis.getOilB() == null ? 0 : taskStatis.getOilB()) + (task.getOilB() == null ? 0 : task.getOilB()));
+                taskStatis.setOilG((taskStatis.getOilG() == null ? 0 : taskStatis.getOilG()) + (task.getOilG() == null ? 0 : task.getOilG()));
+                taskStatis.setOilA((taskStatis.getOilA() == null ? 0 : taskStatis.getOilA()) + (task.getOilA() == null ? 0 : task.getOilA()));
+                taskStatis.setAmmoD((taskStatis.getAmmoD() == null ? 0 : taskStatis.getAmmoD()) + (task.getAmmoD() == null ? 0 : task.getAmmoD()));
+                taskStatis.setAmmoP((taskStatis.getAmmoP() == null ? 0 : taskStatis.getAmmoP()) + (task.getAmmoP() == null ? 0 : task.getAmmoP()));
+                taskStatis.setAmmoS((taskStatis.getAmmoS() == null ? 0 : taskStatis.getAmmoS()) + (task.getAmmoS() == null ? 0 : task.getAmmoS()));
+                taskStatis.setAmmoO((taskStatis.getAmmoO() == null ? 0 : taskStatis.getAmmoO()) + (task.getAmmoO() == null ? 0 : task.getAmmoO()));
+                taskStatis.setWATER((taskStatis.getWATER() == null ? 0 : taskStatis.getWATER()) + (task.getWATER() == null ? 0 : task.getWATER()));
+                taskStatis.setWaterP((taskStatis.getWaterP() == null ? 0 : taskStatis.getWaterP()) + (task.getWaterP() == null ? 0 : task.getWaterP()));
+                taskStatis.setFOOD((taskStatis.getFOOD() == null ? 0 : taskStatis.getFOOD()) + (task.getFOOD() == null ? 0 : task.getFOOD()));
+                taskStatis.setFoodW((taskStatis.getFoodW() == null ? 0 : taskStatis.getFoodW()) + (task.getFoodW() == null ? 0 : task.getFoodW()));
+                taskStatis.setFoodO((taskStatis.getFoodO() == null ? 0 : taskStatis.getFoodO()) + (task.getFoodO() == null ? 0 : task.getFoodO()));
+            });
+
+            statis.setStatis(taskStatis);
+            taskListStatis.add(statis);
+        });
+
+        return  taskListStatis;
+    }
+
+    /**
+     * 鏍规嵁瀵硅薄ID鑾峰彇瀵瑰簲瀵硅薄
+     * @param list
+     * @param id
+     * @return
+     */
+    private DsTaskList2 getDsTaskListById(List<DsTaskList2> list, Long id){
+        for(DsTaskList2 task : list){
+            if(task.getPKID() == id){
+                return task;
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskTimeController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskTimeController.java
new file mode 100644
index 0000000..7ad302d
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DMTaskTimeController.java
@@ -0,0 +1,560 @@
+package com.ruoyi.buss.controller;
+
+
+import com.ruoyi.buss.common.DateUtils;
+import com.ruoyi.buss.common.RfidUtil;
+import com.ruoyi.buss.domain.*;
+import com.ruoyi.buss.domain.dto.AllocBerthReqDTO;
+import com.ruoyi.buss.domain.dto.AllocBerthTimeReqDTO;
+import com.ruoyi.buss.domain.dto.DsTaskQueryParam;
+import com.ruoyi.buss.domain.dto.TaskQueryParam;
+import com.ruoyi.buss.domain.vo.RfIdVo;
+import com.ruoyi.buss.service.*;
+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.ruoyi.common.utils.StringUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.*;
+import java.util.concurrent.atomic.AtomicReference;
+import java.util.stream.Collectors;
+
+@Tag(name = "鏀槦浠诲姟鎺ュ彛")
+@RestController
+@RequestMapping("/buss/tasklist/ex")
+public class DMTaskTimeController  extends BaseController {
+
+    @Autowired
+    private IDsTaskService iDsTaskService;
+    @Autowired
+    private IDsTaskList2Service iDsTaskListService;
+    @Autowired
+    private IDmBerth2Service dmBerthService;
+    @Autowired
+    private IDmHarbor2Service dmHarborService;
+    @Autowired
+    private IDmDdConfigService iDmDdConfigService;
+    @Autowired
+    private IDsTaskDetailService iDsTaskDetailService;
+
+    @Value("${ruoyi.buss.rfid.url:http://192.168.0.2:10800/open/goods/task}")
+    private String rfidUrl;
+
+    private static String WATER_FLAG = "water";
+    private static String MATER_FLAG = "mater";
+    private static String OIL_FLAG = "oil";
+    private static String AMMO_FLAG = "ammo";
+    private static String AMMO_O_FLAG = "ammo_o";
+
+
+    @Operation(summary = "鑾峰彇鏈敮闃熸墍鏈変换鍔″垪琛�")
+    @PostMapping("/histask/list")
+    @ResponseBody
+    public AjaxResult getTaskList(@RequestBody DsTaskQueryParam param) {
+        if(null != param.getEtime()){
+            param.setEtime(DateUtils.setToNextDayZero(param.getEtime()));
+        }
+        List<DsTask> dsTaskList = iDsTaskService.selectDsTaskListByParam(param);
+        return success(dsTaskList);
+    }
+
+    @Operation(summary = "鏀槦浠诲姟涓嬪彂")
+    @Log(title = "鏀槦浠诲姟涓嬪彂", businessType = BusinessType.UPDATE)
+    @PostMapping("/apply/{taskid}/{deptid}")
+    @ResponseBody
+    public AjaxResult apply(@Parameter(name = "taskid", required = true, description = "浠诲姟缂栧彿") @PathVariable("taskid") Long taskid,
+                            @Parameter(name = "deptid", required = true, description = "閮ㄩ棬ID") @PathVariable("deptid") Long deptid,
+                            @Parameter(name = "ids", required = false, description = "浠诲姟Ids") @RequestParam(value = "ids", required = false) String ids) {
+        TaskQueryParam queryParam = new TaskQueryParam();
+        if(null != taskid){
+            queryParam.setTaskId(taskid);
+        }
+        queryParam.setDeptId(deptid);
+        queryParam.setStatus("1");
+
+        if(StringUtils.isNotBlank(ids)){
+            List<Long> idList = Arrays.stream(ids.split(","))
+                    .map(Long::valueOf)
+                    .collect(Collectors.toList());
+            if(null != idList && idList.size() > 0){
+                queryParam.setIds(idList);
+            }
+        }
+
+        List<DsTaskList2> dsTaskList = iDsTaskListService.selectDsTaskListByParam(queryParam);
+        if(null == dsTaskList || dsTaskList.size() == 0){
+            return error("鏈幏鍙栧埌瀵瑰簲鐨勪换鍔�");
+        }
+
+
+        // 鑾峰彇鎵�鏈夌殑娉婁綅淇℃伅
+        List<DmBerth2> berth2List = dmBerthService.selectDmBerthList(new DmBerth2());
+
+        Map<Long, DmBerth2> berth2Map = berth2List.stream().collect(Collectors.toMap(DmBerth2::getPKID, berth -> berth));
+
+
+        List<DsTaskList2> taskToUpdate = dsTaskList.stream().map(tmp -> {
+            tmp.setStatus("2");
+            DmBerth2 berth2 = berth2Map.get(tmp.getPKID());
+            if(null != berth2){
+                tmp.setPath(berth2.getPath());
+            }
+            return tmp;
+        }).collect(Collectors.toList());
+
+        if(!taskToUpdate.isEmpty()){
+            iDsTaskListService.batchUpdateDsTaskList(taskToUpdate);
+        }
+
+        List<RfIdVo> rfIdVoList = new ArrayList<>();
+        //rfIdVoList.add(new RfIdVo(Integer.valueOf(task.getShipNo()), task.getShipNo()+"鑸拌墖琛ョ粰浠诲姟", task.getPath()));
+
+        // 鎺ㄩ�佹暟鎹埌 RFID
+//        try{
+//            RfidUtil.asyncSendJsonPost(rfidUrl, rfIdVoList);
+//        }catch (Exception e){e.printStackTrace();}
+
+        // 鏇存柊Detail  璺緞瑙勫垝
+        this.updateDetailPath(taskid, deptid, berth2List);
+
+        DsTaskList2 tmpTaskList = new DsTaskList2();
+        tmpTaskList.setStatus("1");
+        tmpTaskList.setTaskId(taskid);
+        List<DsTaskList2> taskList2List = iDsTaskListService.selectDsTaskListList(tmpTaskList);
+
+        if(null != taskList2List && taskList2List.size() > 0){
+            DsTask dsTask = iDsTaskService.selectDsTaskByPKID(taskid);
+            dsTask.setStatus("2");
+            iDsTaskService.updateDsTask(dsTask);
+            return success("涓嬪彂鎴愬姛");
+        }
+
+
+        return error("涓嬪彂澶辫触锛岃閲嶈瘯");
+    }
+
+
+    @Operation(summary = "鏀槦浠诲姟涓嬪彂")
+    @Log(title = "鏀槦浠诲姟涓嬪彂", businessType = BusinessType.UPDATE)
+    @PostMapping("/apply/{deptid}")
+    @ResponseBody
+    public AjaxResult applyV2(@Parameter(name = "taskid", required = true, description = "浠诲姟缂栧彿") @RequestParam("taskid") Long taskid,
+                            @Parameter(name = "deptid", required = true, description = "閮ㄩ棬ID") @PathVariable("deptid") Long deptid,
+                            @Parameter(name = "ids", required = true, description = "浠诲姟Ids") @RequestParam("ids") String ids) {
+        TaskQueryParam queryParam = new TaskQueryParam();
+        if(null != taskid){
+            queryParam.setTaskId(taskid);
+        }
+        queryParam.setDeptId(deptid);
+        queryParam.setStatus("1");
+
+        if(StringUtils.isNotBlank(ids)){
+            List<Long> idList = Arrays.stream(ids.split(","))
+                    .map(Long::valueOf)
+                    .collect(Collectors.toList());
+            if(null != idList && idList.size() > 0){
+                queryParam.setIds(idList);
+            }
+        }
+
+        List<DsTaskList2> dsTaskList = iDsTaskListService.selectDsTaskListByParam(queryParam);
+
+        if(null == dsTaskList || dsTaskList.size() == 0){
+            return error("鏈幏鍙栧埌瀵瑰簲鐨勪换鍔�");
+        }
+
+        int flag = 1;
+        for (DsTaskList2 task : dsTaskList) {
+            task.setStatus("2");
+            int updateResult = iDsTaskListService.updateDsTaskList(task);
+            if (updateResult != 1) {
+                flag = 0;
+                break;
+            }
+        }
+        DsTaskList2 tmpTaskList = new DsTaskList2();
+        tmpTaskList.setStatus("1");
+        tmpTaskList.setTaskId(taskid);
+        List<DsTaskList2> taskList2List = iDsTaskListService.selectDsTaskListList(tmpTaskList);
+        if(null != taskList2List && taskList2List.size() == 0){
+            DsTask dsTask = iDsTaskService.selectDsTaskByPKID(taskid);
+            dsTask.setStatus("2");
+            iDsTaskService.updateDsTask(dsTask);
+        }
+
+        if(flag == 1){
+            return success("涓嬪彂鎴愬姛");
+        }
+        return error("涓嬪彂澶辫触锛岃閲嶈瘯");
+    }
+
+
+    @Operation(summary = "鑾峰彇鏈�鏂颁笅鍙戠殑浠诲姟鍒楄〃")
+    @GetMapping("/task")
+    @ResponseBody
+    public AjaxResult getByTaskId(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+        // 鑾峰彇鏀槦姝e湪杩涜鐨勪换鍔�
+//        DsTask taskEntity = new DsTask();
+//        taskEntity.setStatus("1");          // 1 鐘舵�佷负  鏀槦   2 鐘舵�佷负 瀹屾垚鐘舵�併��
+//        List<DsTask> tasks = iDsTaskService.selectDsTaskList(taskEntity);
+//        if(null != tasks && tasks.size() > 0){
+//            DsTask curTask = tasks.get(0);
+            DsTaskList2 taskListEntity = new DsTaskList2();
+//            taskListEntity.setTaskId(curTask.getPKID());
+            taskListEntity.setDeptId(deptId);
+            taskListEntity.setStatus("1");
+            List<DsTaskList2> dsTaskList2s = iDsTaskListService.selectDsTaskListList(taskListEntity);
+            return success(dsTaskList2s);
+//        }
+//        return success();
+    }
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ娉婁綅淇℃伅鍒楄〃")
+    @GetMapping("/berth/list")
+    @ResponseBody
+    public AjaxResult dmBerthList(@Parameter(name = "deptId", description = "閮ㄩ棬缂栫爜") Long deptId) {
+        if(null == deptId)deptId = getDeptId();
+        if(null == deptId){
+            return error("鑾峰彇褰撳墠鐢ㄦ埛淇℃伅澶辫触锛岃閲嶆柊鐧诲綍鍚庡皾璇曘��");
+        }
+        DmHarbor2 harbor = new DmHarbor2();
+        harbor.setDeptId(deptId);
+        List<DmHarbor2> harborList = dmHarborService.selectDmHarborList(harbor);
+        List<Long> tmpHarborIds = new ArrayList<>();
+        harborList.stream().forEach(item -> {
+            tmpHarborIds.add(item.getPKID());
+        });
+        List<DmBerth2> list = dmBerthService.selectDmBerthByHarborIdsAndStatus(tmpHarborIds);
+
+        list = list.stream()
+                .filter(task -> task.getDEPTH() != null)
+                .sorted(Comparator.comparing(DmBerth2::getHarborId).thenComparing(DmBerth2::getOrderNum))
+                .collect(Collectors.toList());
+
+        return success(list);
+    }
+
+    @Operation(summary = "鏌ヨ鐮佸ご淇℃伅璇︽儏")
+    @GetMapping("/harbor/id/{harborid}")
+    @ResponseBody
+    public AjaxResult dmBerthById(@Parameter(name = "harborid", description = "鐮佸ご缂栫爜") @PathVariable("harborid") Long harborid) {
+        return success(dmHarborService.selectDmHarborByPKID(harborid));
+    }
+
+    /**
+     * 鐮佸ご璋冨害鍒嗛厤鎺ュ彛
+     *
+     */
+    @Operation(summary = "鐮佸ご璋冨害鍒嗛厤")
+    @PostMapping("/allocation")
+    @ResponseBody
+    public AjaxResult allocation(@RequestBody AllocBerthReqDTO reqDTO) {
+        Long deptId = getDeptId();
+        if(null != reqDTO.getDeptId()){
+            deptId =reqDTO.getDeptId();
+        }
+
+        if(null == reqDTO.getTaskId()){
+            return error("浠诲姟缂栫爜涓嶈兘涓虹┖");
+        }
+
+        if(StringUtils.isBlank(reqDTO.getBerthids())){
+            return error("娉婁綅缂栧彿涓嶈兘涓虹┖");
+        }
+        DsTaskList2 dsTaskList2Entity = new DsTaskList2();
+        dsTaskList2Entity.setTaskId(reqDTO.getTaskId());
+        dsTaskList2Entity.setDeptId(deptId);
+        List<DsTaskList2> taskLists = iDsTaskListService.selectDsTaskListList(dsTaskList2Entity);
+        if(taskLists.size() == 0){
+            return error("鎵�閫夎埌鑹囦负绌猴紝璇烽噸鏂版鏌ュ弬鏁�");
+        }
+
+        return success(allocationBerth(taskLists, reqDTO.getRule(), reqDTO.getBerthids()));
+    }
+
+    /**
+     * 鏂板淇濆瓨浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "娉婁綅璋冮厤淇℃伅鏇存柊鎺ュ彛")
+    @Log(title = "娉婁綅璋冮厤淇℃伅鏇存柊鎺ュ彛", businessType = BusinessType.UPDATE)
+    @PostMapping("/tasklist/update")
+    @ResponseBody
+    public AjaxResult addTaskListSave(@RequestBody List<DsTaskList2> taskList) {
+        // 缂哄皯鏁版嵁闈炵┖浠ュ強鍚堟硶鎬ф牎楠�
+
+        List<Long> pkidList = taskList.stream()
+                                      .map(DsTaskList2::getPKID)
+                                      .collect(Collectors.toList());
+
+        List<DsTaskList2> existingTaskLists = iDsTaskListService.selectDsTaskListByPkids(pkidList);
+
+        for (DsTaskList2 existingTask : existingTaskLists) {
+            for (DsTaskList2 newTask : taskList) {
+                if (existingTask.getPKID().equals(newTask.getPKID())) {
+                    existingTask.setBerthId(newTask.getBerthId());
+                    existingTask.setBerthName(newTask.getBerthName());
+                    existingTask.setUpdateBy(getUsername());
+                    iDsTaskListService.updateDsTaskList(existingTask);
+                }
+            }
+        }
+        return success("鏇存柊鎴愬姛");
+    }
+
+    /**
+     * 鐮佸ご璋冨害鍒嗛厤鎺ュ彛
+     *
+     */
+    @Operation(summary = "娉婁綅琛ョ粰璁″垝鍒嗛厤")
+    @PostMapping("/berth/alloc")
+    @ResponseBody
+    public AjaxResult berthAllocation(@RequestBody AllocBerthTimeReqDTO reqDTO) {
+        //鑾峰彇褰撳墠鐢ㄦ埛閮ㄩ棬缂栧彿
+        Long deptId = getDeptId();
+        if(null != reqDTO.getDeptId()){
+            deptId = reqDTO.getDeptId();
+        }
+        if(null == reqDTO.getTaskId()){
+            return error("浠诲姟缂栧彿涓嶈兘涓虹┖");
+        }
+
+        DsTaskList2 dsTaskList2Entity = new DsTaskList2();
+        dsTaskList2Entity.setTaskId(reqDTO.getTaskId());
+        dsTaskList2Entity.setDeptId(deptId);
+        List<DsTaskList2> taskLists = iDsTaskListService.selectDsTaskListList(dsTaskList2Entity);
+        if(taskLists.size() == 0){
+            return error("褰撳墠鏃犱换鍔★紝璇烽噸鏂版鏌ュ弬鏁�");
+        }
+        // 閲嶆柊缁勭粐鏁版嵁缁撴瀯锛岀劧鍚庡彂閫�
+        return success(allocationBerthTime(taskLists, reqDTO.getRule()));
+    }
+
+
+    /**
+     * 鑸拌墖鍒嗙粍
+     * @param list
+     * @param rule
+     * @param berthids
+     * @return
+     */
+    private List<DsTaskList2> allocationBerth(List<DsTaskList2> list, String rule, String berthids){
+        List<DsTaskList2> resultTask =  new ArrayList<>();
+        String[] berthArr = berthids.split(",");
+
+        if(null != list && list.size() > 0){
+            switch (rule){
+                case "JTXH":        //鎸夎埌鑹囧瀷鍙�
+                case "DYYX":        //鎸夊脊鑽紭鍏�
+                case "YXSX":        //鎸変紭鍏堥『搴�
+                case "RGFZ":        //鎸変汉宸ュ垎缁�
+                default:
+                    if(null != berthArr && berthArr.length > 0){
+
+                        Map<Long, List<DmBerth2>> harborBerthMap = new HashMap<>();
+
+                        List<Long> berthIdList = Arrays.stream(berthArr)
+                                                    .map(Long::valueOf)
+                                                    .collect(Collectors.toList());
+                        List<DmBerth2> berthList = dmBerthService.selectDmBerthByHarborIds(berthIdList);
+
+                        for (DmBerth2 dmBerth2 : berthList) {
+                            if (dmBerth2 != null) {
+                                harborBerthMap.computeIfAbsent(dmBerth2.getHarborId(), k -> new ArrayList<>()).add(dmBerth2);
+                            }
+                        }
+
+                        for (DsTaskList2 task : list) {
+                            Long harborId = task.getHarborId();
+                            List<DmBerth2> availableBerths = harborBerthMap.get(harborId);
+                            if (availableBerths != null && !availableBerths.isEmpty()) {
+                                DmBerth2 assignedBerth = availableBerths.remove(0);
+                                task.setBerthId(assignedBerth.getPKID());
+                                task.setBerthName(assignedBerth.getNAME());
+                                resultTask.add(task);
+                            } else {
+                                // 濡傛灉娌℃湁鍙敤鐨勬硦浣嶅垯缁х画鎸夌収鍘熸潵鐨勯�昏緫閲嶅鍒嗛厤
+                                for (Map.Entry<Long, List<DmBerth2>> entry : harborBerthMap.entrySet()) {
+                                    if (!entry.getValue().isEmpty()) {
+                                        DmBerth2 assignedBerth = entry.getValue().remove(0);
+                                        task.setBerthId(assignedBerth.getPKID());
+                                        task.setBerthName(assignedBerth.getNAME());
+                                        resultTask.add(task);
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                    }
+            }
+        }
+        return resultTask;
+    }
+
+    /**
+     * 鑸拌墖鏃堕棿鍒嗛厤
+     * @param list
+     * @param rule
+     * @return
+     */
+    private List<DsTaskDetail> allocationBerthTime(List<DsTaskList2> list, String rule){
+        List<DsTaskDetail> result = new ArrayList<>();
+
+        // 鑾峰彇鏃堕棿璁$畻閰嶇疆淇℃伅
+        List<DmDdConfig> configList = iDmDdConfigService.selectDmDdConfigList(new DmDdConfig());
+
+        // 閬嶅巻鎵�鏈夐渶瑕佽绠楃殑鑸逛俊鎭�
+        for (DsTaskList2 task : list) {
+            Long berthId = task.getBerthId();
+            List<DsTaskDetail> taskDetails = new ArrayList<>();
+
+            // 鑾峰彇褰撳墠娉婁綅鐨勬墍鏈夎埞鍙�
+            List<DsTaskList2> berthTasks = list.stream()
+                    .filter(t -> t.getBerthId().equals(berthId))
+                    .sorted(Comparator.comparing(DsTaskList2::getLEVEL))
+                    .collect(Collectors.toList());
+
+            // 閬嶅巻娉婁綅鐨勬墍鏈夎埞鍙紝璁$畻姣忚墭鑸圭殑宸ヤ綔鏃堕棿
+            for (DsTaskList2 berthTask : berthTasks) {
+                DsTaskDetail taskDetail = new DsTaskDetail();
+                taskDetail.setTaskId(berthTask.getTaskId());
+                taskDetail.setBerthId(berthTask.getBerthId());
+                taskDetail.setShipNo(berthTask.getShipNo());
+                taskDetail.setBerthName(berthTask.getBerthName());
+                taskDetail.setHarborId(berthTask.getHarborId());
+                taskDetail.setHarborName(berthTask.getHarborName());
+                taskDetail.setParkingType(berthTask.getParkingType());
+                taskDetail.setShipType(berthTask.getShipType());
+
+                // 鏍规嵁configList璁$畻姣忎竴涓被鍨嬬墿璧勫伐浣滈渶瑕佺殑鏃堕棿
+                double totalOil = 0.0;
+                double totalWater = 0.0;
+                double totalMater = 0.0;
+                double totalAmmo = 0.0;
+
+                // 娌�
+                if (berthTask.getOilA() != null && berthTask.getOilA() > 0) {
+                    totalOil += berthTask.getOilA();
+                }
+                if (berthTask.getOilB() != null && berthTask.getOilB() > 0) {
+                    totalOil += berthTask.getOilB();
+                }
+                if (berthTask.getOilG() != null && berthTask.getOilG() > 0) {
+                    totalOil += berthTask.getOilG();
+                }
+                // 姘�
+                if (berthTask.getWATER() != null && berthTask.getWATER() > 0) {
+                    totalWater += berthTask.getWATER();
+                }
+                if (berthTask.getWaterP() != null && berthTask.getWaterP() > 0) {
+                    totalWater += berthTask.getWaterP();
+                }
+                // 鐗╄祫
+                if (berthTask.getFOOD() != null && berthTask.getFOOD() > 0) {
+                    totalMater += berthTask.getFOOD();
+                }
+                if (berthTask.getFoodO() != null && berthTask.getFoodO() > 0) {
+                    totalMater += berthTask.getFoodO();
+                }
+                if (berthTask.getFoodW() != null && berthTask.getFoodW() > 0) {
+                    totalMater += berthTask.getFoodW();
+                }
+
+                // 鐐脊
+                if (berthTask.getAmmoD() != null && berthTask.getAmmoD() > 0) {
+                    totalAmmo += berthTask.getAmmoD();
+                }
+                if (berthTask.getAmmoP() != null && berthTask.getAmmoP() > 0) {
+                    totalAmmo += berthTask.getAmmoP();
+                }
+                if (berthTask.getAmmoS() != null && berthTask.getAmmoS() > 0) {
+                    totalAmmo += berthTask.getAmmoS();
+                }
+
+//                taskDetail.setWaterTime(getTimeByType(configList, totalWater, WATER_FLAG));
+//                taskDetail.setOilTime(getTimeByType(configList, totalOil, OIL_FLAG));
+//                taskDetail.setMatTime(getTimeByType(configList, totalMater, MATER_FLAG));
+                // 寮硅嵂鏃堕棿闇�瑕佹牴鎹脊鑽绫昏繘琛屽垎鍒绠�
+                Double totalAmmoTime = getTimeByType(configList, null == berthTask.getAmmoO() ? 0.0 : (double)(berthTask.getAmmoO()), AMMO_O_FLAG);
+                totalAmmoTime += getTimeByType(configList, totalAmmo, AMMO_FLAG);
+
+//                taskDetail.setAmmoTime(totalAmmoTime);
+
+                double totalTime = 0.0;
+                if ("TS".equals(rule)) {
+                    totalTime = Math.max(taskDetail.getWaterTime(), Math.max(taskDetail.getOilTime(), Math.max(taskDetail.getMatTime(), taskDetail.getAmmoTime())));
+                } else if ("XYHD".equals(rule)) {
+                    totalTime = Math.max(taskDetail.getWaterTime(), Math.max(taskDetail.getMatTime(), taskDetail.getAmmoTime())) + taskDetail.getOilTime();
+                }
+//                taskDetail.setTotalTime(totalTime);
+
+                // 灏嗚绠楃粨鏋滄坊鍔犲埌缁撴灉鍒楄〃涓�
+                taskDetails.add(taskDetail);
+            }
+
+            // 灏嗗綋鍓嶆硦浣嶇殑鎵�鏈夎埞鍙殑璁$畻缁撴灉娣诲姞鍒版渶缁堢粨鏋滀腑
+            result.addAll(taskDetails);
+        }
+        return result;
+    }
+
+    /**
+     * 鏍规嵁绫诲瀷鑾峰彇娑堣�楁椂闂�
+     * @param list
+     * @param val
+     * @param type
+     * @return
+     */
+    private Double getTimeByType(List<DmDdConfig> list, Double val, String type){
+        AtomicReference<Double> totalTime = new AtomicReference<>(0.0);
+        // 鍙傛暟涓虹┖ 鍒欒繑鍥�0
+        if(null != val && StringUtils.isNotBlank(type)){
+            list.stream().forEach(item -> {
+                if(item.getTYPE().equals(type) && null != item.getTIME()){
+                    totalTime.set(item.getTIME() * val);
+                }
+            });
+        }
+        return totalTime.get();
+    }
+
+    // 鏍规嵁ID鑾峰彇娉婁綅璺緞淇℃伅璇︽儏
+    private String getBerthPathById(List<DmBerth2> list, Long id){
+        for(DmBerth2 berth2 : list){
+            if(berth2.getPKID() == id){
+                return berth2.getPath();
+            }
+        }
+        return "";
+    }
+
+    private void updateDetailPath(Long taskId, Long deptId, List<DmBerth2> berth2List){
+        // 鑾峰彇浠诲姟璇︽儏鍒楄〃
+        List<DsTaskDetail> taskDetails = iDsTaskDetailService.selectDsTaskDetailByTaskId(taskId, null);
+        
+        // 鍒涘缓娉婁綅ID鍒拌矾寰勭殑鏄犲皠
+        Map<Long, DmBerth2> berth2Map = berth2List.stream().collect(Collectors.toMap(DmBerth2::getPKID, berth -> berth));
+
+
+        // 鎵归噺鏇存柊浠诲姟璇︽儏
+        List<DsTaskDetail> updatedDetails = taskDetails.stream()
+            .filter(detail -> detail.getBerthId() != null)
+            .peek(detail -> detail.setPath(berth2Map.get(detail.getBerthId()).getPath()))
+            .collect(Collectors.toList());
+            
+        // 鎵归噺淇濆瓨鏇存柊
+        if (!updatedDetails.isEmpty()) {
+            iDsTaskDetailService.batchUpdateDsTaskDetail(updatedDetails);
+        }
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DemoController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DemoController.java
new file mode 100644
index 0000000..333017c
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DemoController.java
@@ -0,0 +1,44 @@
+package com.ruoyi.buss.controller;
+
+import com.ruoyi.buss.common.dynamic.DynamicBeanRegistrar;
+import eu.bitwalker.useragentutils.Application;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ConfigurableApplicationContext;
+import org.springframework.web.bind.annotation.*;
+
+import java.lang.reflect.Method;
+
+@Tag(name = "浠g爜鍔犺浇娴嬭瘯")
+@RestController
+@RequestMapping("/dynamic")
+public class DemoController {
+    private final DynamicBeanRegistrar registrar;
+
+    public DemoController(ApplicationContext context) {
+        this.registrar = new DynamicBeanRegistrar((ConfigurableApplicationContext) context);
+    }
+
+
+    @Autowired
+    private ApplicationContext applicationContext;
+
+    @Operation(summary = "鍔ㄦ�佷唬鐮佸姞杞芥祴璇�")
+    @GetMapping("/compile")
+    @ResponseBody
+    public String compile(@RequestParam("code") String code) throws Exception {
+        String sourceCode = "public class Demo { public String test(String code) { return \"Hello\" + code; } }";
+        String className = "DynamicService_" + System.currentTimeMillis();
+        registrar.registerBean(className.toLowerCase(), "Demo", sourceCode);
+        System.out.println("Compiled:" + className);
+        Object bean = applicationContext.getBean(className);
+        Method method = bean.getClass().getMethod("test");
+        Object object = method.invoke(code);
+
+        System.out.println(object.toString());
+
+        return "Compiled: " + className;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmBerth2Controller.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmBerth2Controller.java
new file mode 100644
index 0000000..4e6ad48
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmBerth2Controller.java
@@ -0,0 +1,113 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DmBerth2;
+import com.ruoyi.buss.service.IDmBerth2Service;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 娉婁綅淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+//@Tag(name = "娉婁綅淇℃伅")
+//@Controller
+//@RequestMapping("/buss/berth")
+public class DmBerth2Controller extends BaseController
+{
+    private String prefix = "buss/berth";
+
+    @Autowired
+    private IDmBerth2Service dmBerthService;
+
+    @GetMapping()
+    public String berth()
+    {
+        return prefix + "/berth";
+    }
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     */
+    @Operation(description = "鏌ヨ娉婁綅淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DmBerth2 dmBerth2)
+    {
+        startPage();
+        List<DmBerth2> list = dmBerthService.selectDmBerthList(dmBerth2);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板娉婁綅淇℃伅
+     */
+    @Operation(summary="鏂板娉婁綅淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨娉婁綅淇℃伅
+     */
+    @Operation(summary="鏂板淇濆瓨娉婁綅淇℃伅")
+    @Log(title = "娉婁綅淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DmBerth2 dmBerth2)
+    {
+        return toAjax(dmBerthService.insertDmBerth(dmBerth2));
+    }
+
+    /**
+     * 淇敼娉婁綅淇℃伅
+     */
+    @Operation(summary="淇敼娉婁綅淇℃伅")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") Long PKID, ModelMap mmap)
+    {
+        DmBerth2 dmBerth2 = dmBerthService.selectDmBerthByPKID(PKID);
+        mmap.put("dmBerth", dmBerth2);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨娉婁綅淇℃伅
+     */
+    @Operation(summary="淇敼淇濆瓨娉婁綅淇℃伅")
+    @Log(title = "娉婁綅淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DmBerth2 dmBerth2)
+    {
+        return toAjax(dmBerthService.updateDmBerth(dmBerth2));
+    }
+
+    /**
+     * 鍒犻櫎娉婁綅淇℃伅
+     */
+    @Operation(summary="鍒犻櫎娉婁綅淇℃伅")
+    @Log(title = "娉婁綅淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dmBerthService.deleteDmBerthByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmDdConfigController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmDdConfigController.java
new file mode 100644
index 0000000..7448ab2
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmDdConfigController.java
@@ -0,0 +1,117 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DmDdConfig;
+import com.ruoyi.buss.service.IDmDdConfigService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 璋冮厤閰嶇疆淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "璋冮厤閰嶇疆淇℃伅")
+@Controller
+@RequestMapping("/buss/config")
+public class DmDdConfigController extends BaseController
+{
+    private String prefix = "buss/config";
+
+    @Autowired
+    private IDmDdConfigService dmDdConfigService;
+
+    @GetMapping()
+    public String config()
+    {
+        return prefix + "/config";
+    }
+
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ璋冮厤閰嶇疆淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DmDdConfig dmDdConfig)
+    {
+        startPage();
+        List<DmDdConfig> list = dmDdConfigService.selectDmDdConfigList(dmDdConfig);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板璋冮厤閰嶇疆淇℃伅
+     */
+    @Operation(summary = "鏂板璋冮厤閰嶇疆淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨璋冮厤閰嶇疆淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨璋冮厤閰嶇疆淇℃伅")
+    @Log(title = "璋冮厤閰嶇疆淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DmDdConfig dmDdConfig)
+    {
+        return toAjax(dmDdConfigService.insertDmDdConfig(dmDdConfig));
+    }
+
+    /**
+     * 淇敼璋冮厤閰嶇疆淇℃伅
+     */
+    @Operation(summary = "淇敼璋冮厤閰嶇疆淇℃伅")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") Long PKID, ModelMap mmap)
+    {
+        DmDdConfig dmDdConfig = dmDdConfigService.selectDmDdConfigByPKID(PKID);
+        mmap.put("dmDdConfig", dmDdConfig);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨璋冮厤閰嶇疆淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨璋冮厤閰嶇疆淇℃伅")
+    @Log(title = "璋冮厤閰嶇疆淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DmDdConfig dmDdConfig)
+    {
+        return toAjax(dmDdConfigService.updateDmDdConfig(dmDdConfig));
+    }
+
+    /**
+     * 鍒犻櫎璋冮厤閰嶇疆淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎璋冮厤閰嶇疆淇℃伅")
+    @Log(title = "璋冮厤閰嶇疆淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dmDdConfigService.deleteDmDdConfigByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmHarbor2Controller.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmHarbor2Controller.java
new file mode 100644
index 0000000..0ff49fe
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmHarbor2Controller.java
@@ -0,0 +1,112 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import com.ruoyi.buss.domain.DmHarbor2;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+import org.springframework.web.bind.annotation.*;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.service.IDmHarbor2Service;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 娓彛淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "娓彛淇℃伅")
+@Controller
+@RequestMapping("/buss/harbor")
+public class DmHarbor2Controller extends BaseController
+{
+    private String prefix = "buss/harbor";
+
+    @Autowired
+    private IDmHarbor2Service dmHarborService;
+
+    @GetMapping()
+    public String harbor()
+    {
+        return prefix + "/harbor";
+    }
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ娓彛淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DmHarbor2 dmHarbor2)
+    {
+        startPage();
+        List<DmHarbor2> list = dmHarborService.selectDmHarborList(dmHarbor2);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板娓彛淇℃伅
+     */
+    @Operation(summary = "鏂板娓彛淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨娓彛淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨娓彛淇℃伅")
+    @Log(title = "娓彛淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DmHarbor2 dmHarbor2)
+    {
+        return toAjax(dmHarborService.insertDmHarbor(dmHarbor2));
+    }
+
+    /**
+     * 淇敼娓彛淇℃伅
+     */
+    @Operation(summary = "淇敼娓彛淇℃伅")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") Long PKID, ModelMap mmap)
+    {
+        DmHarbor2 dmHarbor2 = dmHarborService.selectDmHarborByPKID(PKID);
+        mmap.put("dmHarbor", dmHarbor2);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨娓彛淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨娓彛淇℃伅")
+    @Log(title = "娓彛淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DmHarbor2 dmHarbor2)
+    {
+        return toAjax(dmHarborService.updateDmHarbor(dmHarbor2));
+    }
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎娓彛淇℃伅")
+    @Log(title = "娓彛淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dmHarborService.deleteDmHarborByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmWarshipController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmWarshipController.java
new file mode 100644
index 0000000..3e12f80
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DmWarshipController.java
@@ -0,0 +1,117 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DmWarship;
+import com.ruoyi.buss.service.IDmWarshipService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 鑸拌墖淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "鑸拌墖淇℃伅")
+@Controller
+@RequestMapping("/buss/warship")
+public class DmWarshipController extends BaseController
+{
+    private String prefix = "buss/warship";
+
+    @Autowired
+    private IDmWarshipService dmWarshipService;
+
+    @GetMapping()
+    public String warship()
+    {
+        return prefix + "/warship";
+    }
+
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ鑸拌墖淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DmWarship dmWarship)
+    {
+        startPage();
+        List<DmWarship> list = dmWarshipService.selectDmWarshipList(dmWarship);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板鑸拌墖淇℃伅
+     */
+    @Operation(summary = "鏂板鑸拌墖淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨鑸拌墖淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨鑸拌墖淇℃伅")
+    @Log(title = "鑸拌墖淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DmWarship dmWarship)
+    {
+        return toAjax(dmWarshipService.insertDmWarship(dmWarship));
+    }
+
+    /**
+     * 淇敼鑸拌墖淇℃伅
+     */
+    @Operation(summary = "淇敼鑸拌墖淇℃伅")
+    @GetMapping("/edit/{shipNo}")
+    public String edit(@PathVariable("shipNo") String shipNo, ModelMap mmap)
+    {
+        DmWarship dmWarship = dmWarshipService.selectDmWarshipByShipNo(shipNo);
+        mmap.put("dmWarship", dmWarship);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨鑸拌墖淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨鑸拌墖淇℃伅")
+    @Log(title = "鑸拌墖淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DmWarship dmWarship)
+    {
+        return toAjax(dmWarshipService.updateDmWarship(dmWarship));
+    }
+
+    /**
+     * 鍒犻櫎鑸拌墖淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎鑸拌墖淇℃伅")
+    @Log(title = "鑸拌墖淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dmWarshipService.deleteDmWarshipByShipNos(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessController.java
new file mode 100644
index 0000000..6618bc8
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessController.java
@@ -0,0 +1,116 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DsEffectAssess;
+import com.ruoyi.buss.service.IDsEffectAssessService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 鑳芥晥璇勪及Controller
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+@Tag(name = "鑳芥晥璇勪及")
+@Controller
+@RequestMapping("/buss/assess")
+public class DsEffectAssessController extends BaseController
+{
+    private String prefix = "buss/assess";
+
+    @Autowired
+    private IDsEffectAssessService dsEffectAssessService;
+
+    @GetMapping()
+    public String assess()
+    {
+        return prefix + "/assess";
+    }
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ鑳芥晥璇勪及鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DsEffectAssess dsEffectAssess)
+    {
+        startPage();
+        List<DsEffectAssess> list = dsEffectAssessService.selectDsEffectAssessList(dsEffectAssess);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板鑳芥晥璇勪及
+     */
+    @Operation(summary = "鏂板鑳芥晥璇勪及")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨鑳芥晥璇勪及
+     */
+    @Operation(summary = "鏂板淇濆瓨鑳芥晥璇勪及")
+    @Log(title = "鑳芥晥璇勪及", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DsEffectAssess dsEffectAssess)
+    {
+        return toAjax(dsEffectAssessService.insertDsEffectAssess(dsEffectAssess));
+    }
+
+    /**
+     * 淇敼鑳芥晥璇勪及
+     */
+    @Operation(summary = "淇敼鑳芥晥璇勪及")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") String PKID, ModelMap mmap)
+    {
+        DsEffectAssess dsEffectAssess = dsEffectAssessService.selectDsEffectAssessByPKID(PKID);
+        mmap.put("dsEffectAssess", dsEffectAssess);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨鑳芥晥璇勪及
+     */
+    @Operation(summary = "淇敼淇濆瓨鑳芥晥璇勪及")
+    @Log(title = "鑳芥晥璇勪及", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsEffectAssess dsEffectAssess)
+    {
+        return toAjax(dsEffectAssessService.updateDsEffectAssess(dsEffectAssess));
+    }
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及
+     */
+    @Operation(summary = "鍒犻櫎鑳芥晥璇勪及")
+    @Log(title = "鑳芥晥璇勪及", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dsEffectAssessService.deleteDsEffectAssessByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessListController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessListController.java
new file mode 100644
index 0000000..deb228e
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsEffectAssessListController.java
@@ -0,0 +1,116 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+import com.ruoyi.buss.service.IDsEffectAssessListService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匔ontroller
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+@Tag(name = "鑳芥晥璇勪及椤硅鎯�")
+@Controller
+@RequestMapping("/buss/assesslist")
+public class DsEffectAssessListController extends BaseController
+{
+    private String prefix = "buss/assesslist";
+
+    @Autowired
+    private IDsEffectAssessListService dsEffectAssessListService;
+
+    @GetMapping()
+    public String list()
+    {
+        return prefix + "/list";
+    }
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     */
+    @Operation(summary = "鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DsEffectAssessList dsEffectAssessList)
+    {
+        startPage();
+        List<DsEffectAssessList> list = dsEffectAssessListService.selectDsEffectAssessListList(dsEffectAssessList);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     */
+    @Operation(summary = "鏂板鑳芥晥璇勪及椤硅鎯�")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨鑳芥晥璇勪及椤硅鎯�
+     */
+    @Operation(summary = "鏂板淇濆瓨鑳芥晥璇勪及椤硅鎯�")
+    @Log(title = "鑳芥晥璇勪及椤硅鎯�", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DsEffectAssessList dsEffectAssessList)
+    {
+        return toAjax(dsEffectAssessListService.insertDsEffectAssessList(dsEffectAssessList));
+    }
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     */
+    @Operation(summary = "淇敼鑳芥晥璇勪及椤硅鎯�")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") String PKID, ModelMap mmap)
+    {
+        DsEffectAssessList dsEffectAssessList = dsEffectAssessListService.selectDsEffectAssessListByPKID(PKID);
+        mmap.put("dsEffectAssessList", dsEffectAssessList);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨鑳芥晥璇勪及椤硅鎯�
+     */
+    @Operation(summary = "淇敼淇濆瓨鑳芥晥璇勪及椤硅鎯�")
+    @Log(title = "鑳芥晥璇勪及椤硅鎯�", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsEffectAssessList dsEffectAssessList)
+    {
+        return toAjax(dsEffectAssessListService.updateDsEffectAssessList(dsEffectAssessList));
+    }
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     */
+    @Operation(summary = "鍒犻櫎鑳芥晥璇勪及椤硅鎯�")
+    @Log(title = "鑳芥晥璇勪及椤硅鎯�", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dsEffectAssessListService.deleteDsEffectAssessListByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsMatDispatch2Controller.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsMatDispatch2Controller.java
new file mode 100644
index 0000000..2f0be81
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsMatDispatch2Controller.java
@@ -0,0 +1,228 @@
+package com.ruoyi.buss.controller;
+
+import com.ruoyi.buss.domain.DmHarbor2;
+import com.ruoyi.buss.domain.DsMatDispatch2;
+import com.ruoyi.buss.service.IDmHarbor2Service;
+import com.ruoyi.buss.service.IDsMatDispatch2Service;
+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.model.LoginUser;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.StringUtils;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.Date;
+import java.util.List;
+
+@Tag(name = "璺ㄦ腐鍖鸿皟搴︽帴鍙�")
+@RestController
+@RequestMapping("/buss/matdispatch")
+public class DsMatDispatch2Controller extends BaseController {
+
+    private static String STATUS_1 = "1";   // 鏈彁浜�
+    private static String STATUS_2 = "2";   // 瀹℃壒涓�
+    private static String STATUS_3 = "3";   // 瀹℃壒閫氳繃
+    private static String STATUS_4 = "4";   // 椹冲洖
+
+
+    @Autowired
+    private IDmHarbor2Service iDmHarbor2Service;
+
+    @Autowired
+    private IDsMatDispatch2Service iDsMatDispatch2Service;
+
+    @Operation(summary = "鑾峰彇浠诲姟鍒楄〃")
+    @PostMapping("/list/all")
+    @ResponseBody
+    public AjaxResult list() {
+        List<DsMatDispatch2> list = iDsMatDispatch2Service.selectDsMatDispatchForApply();
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鏍规嵁鏉′欢鑾峰彇浠诲姟鍒楄〃")
+    @PostMapping("/list/param")
+    @ResponseBody
+    public AjaxResult list(DsMatDispatch2 dsMatDispatch2) {
+        List<DsMatDispatch2> list = iDsMatDispatch2Service.selectDsMatDispatchList(dsMatDispatch2);
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鑾峰彇鑷繁鏉冮檺鍐呯殑浠诲姟鍒楄〃")
+    @PostMapping("/list/self")
+    @ResponseBody
+    public AjaxResult list3(@RequestParam(value = "status", required = false) String status) {
+        List<DsMatDispatch2> list = iDsMatDispatch2Service.selectDsMatDispatchByDeptId(getDeptId(), status);
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鑾峰彇浠诲姟鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public AjaxResult list2(@RequestParam(value = "status", required = false) String status) {
+        LoginUser loginUser = getLoginUser();
+        DsMatDispatch2 dsMatDispatch2 = new DsMatDispatch2();
+        dsMatDispatch2.setResHarborId(loginUser.getDeptId().toString());
+        if(StringUtils.isNotBlank(status)){
+            dsMatDispatch2.setStatus(status);
+        }
+        List<DsMatDispatch2> list = iDsMatDispatch2Service.selectDsMatDispatchList(dsMatDispatch2);
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "鑾峰彇鑷繁鏂板缓鐨勪换鍔″垪琛�")
+    @PostMapping("/list2")
+    @ResponseBody
+    public AjaxResult list2() {
+        LoginUser loginUser = getLoginUser();
+        DsMatDispatch2 dsMatDispatch2 = new DsMatDispatch2();
+        dsMatDispatch2.setResHarborId(loginUser.getDeptId().toString());
+        dsMatDispatch2.setResHarborName(loginUser.getUsername());
+        List<DsMatDispatch2> list = iDsMatDispatch2Service.selectDsMatDispatchList(new DsMatDispatch2());
+        if(null != list){
+            return success(list);
+        }
+        return error("鑾峰彇浠诲姟鍒楄〃澶辫触锛岃閲嶈瘯");
+    }
+
+    @Operation(summary = "浠诲姟鎻愪氦瀹℃壒")
+    @PostMapping("/apply/{id}")
+    @ResponseBody
+    public AjaxResult toApply(@PathVariable("id") Long id) {
+        DsMatDispatch2 matDispatch2 = iDsMatDispatch2Service.selectDsMatDispatchById(id);
+        if(null != matDispatch2){
+            if(matDispatch2.getStatus().equals(STATUS_1)){
+                matDispatch2.setStatus(STATUS_2);
+                matDispatch2.setUpdateBy(getUsername());
+                matDispatch2.setUpdateTime(new Date());
+                int rst = iDsMatDispatch2Service.updateDsMatDispatch(matDispatch2);
+                if(rst > 0){
+                    return success("鎻愪氦瀹℃壒鎴愬姛");
+                }
+                else {
+                    return error("鎻愪氦瀹℃壒澶辫触");
+                }
+            }
+            else {
+                return error("褰撳墠浠诲姟涓嶅彲鎻愪氦瀹℃壒");
+            }
+        }
+        else{
+            return error("鑾峰彇浠诲姟澶辫触锛岃閲嶈瘯");
+        }
+    }
+
+    @Operation(summary = "浠诲姟瀹℃壒")
+    @PostMapping("/prove")
+    @ResponseBody
+    public AjaxResult prove(@RequestBody DsMatDispatch2 dsMatDispatch2) {
+        if(null != dsMatDispatch2 && null != dsMatDispatch2.getId()){
+            DsMatDispatch2 matDispatch2 = iDsMatDispatch2Service.selectDsMatDispatchById(dsMatDispatch2.getId());
+            DmHarbor2 harborRes = null;
+            List<DmHarbor2> harbor2List = iDmHarbor2Service.selectDmHarborList(new DmHarbor2());
+            for(DmHarbor2 harbor2 : harbor2List){
+                if(StringUtils.isNotBlank(dsMatDispatch2.getDesHarborId()) && harbor2.getPKID().toString().equals(dsMatDispatch2.getDesHarborId())){
+                    harborRes = harbor2;
+                }
+            }
+            if(null != matDispatch2){
+                if(matDispatch2.getStatus().equals(STATUS_2)){
+                    if(dsMatDispatch2.getApplyResult().equals("1")){
+                        matDispatch2.setStatus(STATUS_3);
+                    }
+                    else{
+                        matDispatch2.setStatus(STATUS_4);
+                    }
+
+                    matDispatch2.setApplyResult(dsMatDispatch2.getApplyResult());
+                    matDispatch2.setApplyTime(new Date());
+                    matDispatch2.setApplyContent(dsMatDispatch2.getApplyContent());
+                    matDispatch2.setApplyBy(getUsername());
+                    matDispatch2.setUpdateBy(getUsername());
+                    matDispatch2.setUpdateTime(new Date());
+                    if(null != harborRes){
+                        matDispatch2.setResHarborId(harborRes.getDeptId().toString());
+                        matDispatch2.setResHarborName(harborRes.getDeptName());
+                    }
+                    int rst = iDsMatDispatch2Service.updateDsMatDispatch(matDispatch2);
+                    if(rst > 0){
+                        return success("瀹℃壒鎴愬姛");
+                    }
+                    else {
+                        return error("瀹℃壒澶辫触");
+                    }
+                }
+                else {
+                    return error("褰撳墠浠诲姟涓嶅彲瀹℃壒");
+                }
+            }
+            else{
+                return error("鑾峰彇浠诲姟澶辫触锛岃閲嶈瘯");
+            }
+        }
+        return error("鍙傛暟澶辫触锛岄渶瑕�");
+    }
+
+    /**
+     * 鏂板淇濆瓨娉婁綅淇℃伅
+     */
+    @Operation(summary="鏂板璺ㄦ腐鍖鸿皟搴︿俊鎭�")
+    @Log(title = "璺ㄦ腐鍖鸿皟搴︿俊鎭�", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(@RequestBody DsMatDispatch2 dsMatDispatch2) {
+        if(null == dsMatDispatch2){
+            return error("鍙傛暟涓嶈兘涓虹┖");
+        }
+        if(StringUtils.isBlank(dsMatDispatch2.getContent())){
+            return error("璋冨害鍐呭涓嶈兘涓虹┖");
+        }
+        LoginUser loginUser = getLoginUser();
+        dsMatDispatch2.setResHarborId(loginUser.getDeptId().toString());
+        dsMatDispatch2.setResHarborName(loginUser.getUsername());
+        dsMatDispatch2.setCreateTime(new Date());
+        dsMatDispatch2.setCreateBy(getUsername());
+        dsMatDispatch2.setStatus(STATUS_1);
+        return toAjax(iDsMatDispatch2Service.insertDsMatDispatch(dsMatDispatch2));
+    }
+
+    /**
+     * 淇敼淇濆瓨娉婁綅淇℃伅
+     */
+    @Operation(summary="淇敼淇濆瓨璺ㄦ腐鍖鸿皟搴︿俊鎭�")
+    @Log(title = "璺ㄦ腐鍖鸿皟搴︿俊鎭�", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsMatDispatch2 dsMatDispatch2)
+    {
+        return toAjax(iDsMatDispatch2Service.updateDsMatDispatch(dsMatDispatch2));
+    }
+
+    /**
+     * 鍒犻櫎娉婁綅淇℃伅
+     */
+    @Operation(summary="鍒犻櫎璺ㄦ腐鍖鸿皟搴︿俊鎭�")
+    @Log(title = "娉婁綅淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove/{id}")
+    @ResponseBody
+    public AjaxResult remove(@PathVariable("id") Long id)
+    {
+        return toAjax(iDsMatDispatch2Service.deleteDsMatDispatchById(id));
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskController.java
new file mode 100644
index 0000000..1200dd8
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskController.java
@@ -0,0 +1,130 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DsTask;
+import com.ruoyi.buss.service.IDsTaskService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 浠诲姟淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "浠诲姟淇℃伅")
+@Controller
+@RequestMapping("/buss/task")
+public class DsTaskController extends BaseController
+{
+    private String prefix = "buss/task";
+
+    @Autowired
+    private IDsTaskService dsTaskService;
+
+    @GetMapping()
+    public String task()
+    {
+        return prefix + "/task";
+    }
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ浠诲姟淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DsTask dsTask)
+    {
+        startPage();
+        List<DsTask> list = dsTaskService.selectDsTaskList(dsTask);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板浠诲姟淇℃伅
+     */
+    @Operation(summary = "鏂板浠诲姟淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨浠诲姟淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨浠诲姟淇℃伅")
+    @Log(title = "浠诲姟淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DsTask dsTask)
+    {
+        return toAjax(dsTaskService.insertDsTask(dsTask));
+    }
+
+//    /**
+//     * 淇敼浠诲姟淇℃伅
+//     */
+//    @Operation("浠诲姟涓嬪彂")
+//    @GetMapping("/task/apply/{PKID}")
+//    public String apply(@PathVariable("PKID") Long PKID)
+//    {
+//        DsTask dsTask = dsTaskService.selectDsTaskByPKID(PKID);
+//        dsTask.setSTATUS("1");
+//        dsTask.setUpdateTime(new Date());
+//        dsTask.setUpdateBy(getLoginName());
+//        return prefix + "/edit";
+//    }
+
+    /**
+     * 淇敼浠诲姟淇℃伅
+     */
+    @Operation(summary = "淇敼浠诲姟淇℃伅")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") Long PKID, ModelMap mmap)
+    {
+        DsTask dsTask = dsTaskService.selectDsTaskByPKID(PKID);
+        mmap.put("dsTask", dsTask);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨浠诲姟淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨浠诲姟淇℃伅")
+    @Log(title = "浠诲姟淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsTask dsTask)
+    {
+        return toAjax(dsTaskService.updateDsTask(dsTask));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎浠诲姟淇℃伅")
+    @Log(title = "浠诲姟淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dsTaskService.deleteDsTaskByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskDetailController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskDetailController.java
new file mode 100644
index 0000000..5e7fff6
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskDetailController.java
@@ -0,0 +1,117 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.domain.DsTaskDetail;
+import com.ruoyi.buss.service.IDsTaskDetailService;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 浠诲姟璋冮厤璇︽儏淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "浠诲姟璋冮厤璇︽儏淇℃伅")
+@Controller
+@RequestMapping("/buss/detail")
+public class DsTaskDetailController extends BaseController
+{
+    private String prefix = "buss/detail";
+
+    @Autowired
+    private IDsTaskDetailService dsTaskDetailService;
+
+    @GetMapping()
+    public String detail()
+    {
+        return prefix + "/detail";
+    }
+
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DsTaskDetail dsTaskDetail)
+    {
+        startPage();
+        List<DsTaskDetail> list = dsTaskDetailService.selectDsTaskDetailList(dsTaskDetail);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Operation(summary = "鏂板浠诲姟璋冮厤璇︽儏淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨浠诲姟璋冮厤璇︽儏淇℃伅")
+    @Log(title = "浠诲姟璋冮厤璇︽儏淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DsTaskDetail dsTaskDetail)
+    {
+        return toAjax(dsTaskDetailService.insertDsTaskDetail(dsTaskDetail));
+    }
+
+    /**
+     * 淇敼浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Operation(summary = "淇敼浠诲姟璋冮厤璇︽儏淇℃伅")
+    @GetMapping("/edit/{PKID}")
+    public String edit(@PathVariable("PKID") Long PKID, ModelMap mmap)
+    {
+        DsTaskDetail dsTaskDetail = dsTaskDetailService.selectDsTaskDetailByPKID(PKID);
+        mmap.put("dsTaskDetail", dsTaskDetail);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨浠诲姟璋冮厤璇︽儏淇℃伅")
+    @Log(title = "浠诲姟璋冮厤璇︽儏淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsTaskDetail dsTaskDetail)
+    {
+        return toAjax(dsTaskDetailService.updateDsTaskDetail(dsTaskDetail));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅")
+    @Log(title = "浠诲姟璋冮厤璇︽儏淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dsTaskDetailService.deleteDsTaskDetailByPKIDs(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskList2Controller.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskList2Controller.java
new file mode 100644
index 0000000..c7eec5a
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/DsTaskList2Controller.java
@@ -0,0 +1,141 @@
+package com.ruoyi.buss.controller;
+
+import java.util.List;
+
+import com.ruoyi.buss.domain.DsTaskList2;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.ui.ModelMap;
+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.ResponseBody;
+import com.ruoyi.common.annotation.Log;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.buss.service.IDsTaskList2Service;
+import com.ruoyi.common.core.controller.BaseController;
+import com.ruoyi.common.core.domain.AjaxResult;
+import com.ruoyi.common.core.page.TableDataInfo;
+
+/**
+ * 浠诲姟鍒楄〃淇℃伅Controller
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Tag(name = "浠诲姟鍒楄〃淇℃伅")
+@Controller("TaskListController")
+@RequestMapping("/buss/list")
+public class DsTaskList2Controller extends BaseController
+{
+    private String prefix = "buss/list";
+
+    @Autowired
+    private IDsTaskList2Service dsTaskListService;
+
+    @GetMapping()
+    public String list()
+    {
+        return prefix + "/list";
+    }
+
+    /**
+     * 鐮佸ご璋冨害鍒嗛厤鎺ュ彛
+     */
+    @Operation(summary = "鐮佸ご璋冨害鍒嗛厤")
+    @PostMapping("/allocation")
+    @ResponseBody
+    public TableDataInfo allocation(String ship, String rule)
+    {
+        List<DsTaskList2> list = dsTaskListService.selectDsTaskListByTaskId(100l);
+        return getDataTable(list);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鑾峰彇褰撴棩闇�瑕佸垎閰嶇殑鑸拌墖淇℃伅")
+    @PostMapping("/current/list")
+    @ResponseBody
+    public TableDataInfo curList()
+    {
+        List<DsTaskList2> list = dsTaskListService.selectCurrentDsTaskList();
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     */
+    @Operation(summary = "鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃")
+    @PostMapping("/list")
+    @ResponseBody
+    public TableDataInfo list(DsTaskList2 dsTaskList2)
+    {
+        startPage();
+        List<DsTaskList2> list = dsTaskListService.selectDsTaskListList(dsTaskList2);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 鏂板浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "鏂板浠诲姟鍒楄〃淇℃伅")
+    @GetMapping("/add")
+    public String add()
+    {
+        return prefix + "/add";
+    }
+
+    /**
+     * 鏂板淇濆瓨浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "鏂板淇濆瓨浠诲姟鍒楄〃淇℃伅")
+    @Log(title = "浠诲姟鍒楄〃淇℃伅", businessType = BusinessType.INSERT)
+    @PostMapping("/add")
+    @ResponseBody
+    public AjaxResult addSave(DsTaskList2 dsTaskList2)
+    {
+        return toAjax(dsTaskListService.insertDsTaskList(dsTaskList2));
+    }
+
+    /**
+     * 淇敼浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "淇敼浠诲姟鍒楄〃淇℃伅")
+    @GetMapping("/edit/{taskId}")
+    public String edit(@PathVariable("taskId") Long taskId, ModelMap mmap)
+    {
+        List<DsTaskList2> dsTaskList2 = dsTaskListService.selectDsTaskListByTaskId(taskId);
+        mmap.put("dsTaskList", dsTaskList2);
+        return prefix + "/edit";
+    }
+
+    /**
+     * 淇敼淇濆瓨浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "淇敼淇濆瓨浠诲姟鍒楄〃淇℃伅")
+    @Log(title = "浠诲姟鍒楄〃淇℃伅", businessType = BusinessType.UPDATE)
+    @PostMapping("/edit")
+    @ResponseBody
+    public AjaxResult editSave(DsTaskList2 dsTaskList2)
+    {
+        return toAjax(dsTaskListService.updateDsTaskList(dsTaskList2));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟鍒楄〃淇℃伅
+     */
+    @Operation(summary = "鍒犻櫎浠诲姟鍒楄〃淇℃伅")
+    @Log(title = "浠诲姟鍒楄〃淇℃伅", businessType = BusinessType.DELETE)
+    @PostMapping( "/remove")
+    @ResponseBody
+    public AjaxResult remove(String ids)
+    {
+        return toAjax(dsTaskListService.deleteDsTaskListByTaskIds(ids));
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdBerthGroupController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdBerthGroupController.java
new file mode 100644
index 0000000..410467a
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdBerthGroupController.java
@@ -0,0 +1,802 @@
+package com.ruoyi.buss.controller;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.buss.domain.DmBerth2;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.ShipGroupDTO;
+import com.ruoyi.buss.domain.dto.Subdata;
+import com.ruoyi.buss.domain.dto.TaskRecordList;
+import com.ruoyi.buss.domain.dto.ZdGroupDTO;
+import com.ruoyi.buss.service.IDmBerth2Service;
+import com.ruoyi.buss.service.IDsTaskList2Service;
+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.model.LoginUser;
+import com.ruoyi.common.enums.BusinessType;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+/**
+ * 鏀槦绾ц埌鑸规硦浣嶅垎缁勯�昏緫Controller
+ *
+ * @author yl
+ * @date 2025-03-20
+ */
+
+@Tag(name = "鏀槦鑸拌埞娉婁綅鍒嗙粍")
+@Controller
+@RequestMapping("/buss/zd")
+public class ZdBerthGroupController extends BaseController {
+    private static final Logger log = LoggerFactory.getLogger(ZdBerthGroupController.class);
+
+    private final static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    @Autowired
+    private IDmBerth2Service dmBerthService;
+
+    @Autowired
+    private IDsTaskList2Service dsTaskListService;
+
+    /**
+     * 鑾峰彇鏀槦鐮佸ご娉婁綅鍒嗙粍鏁版嵁缁撴灉銆�
+     *
+     * @return
+     */
+    @Operation(description = "鑾峰彇鏀槦娉婁綅鍒嗙粍缁撴灉")
+    @Log(title = "鏀槦娉婁綅鍒嗙粍", businessType = BusinessType.INSERT)
+    @PostMapping("/berthgroup")
+    @ResponseBody
+    public AjaxResult getZdBerthGroup(@RequestBody ZdGroupDTO zdGroupDTO) throws IOException {
+        String berthIds = zdGroupDTO.getBerthIds();
+        String berthRuleStr = zdGroupDTO.getBerthGroupRule();
+        String taskIdStr = zdGroupDTO.getTaskId();
+        List<DmBerth2> dmBerthList = dmBerthService.getDmBerthListByIds(berthIds);
+        log.debug("dmBerthList = " + dmBerthList);
+        Integer berthRule = Integer.parseInt(berthRuleStr);
+
+        // 鏍规嵁鐢ㄦ埛鎵�灞為儴闂↖D锛屾煡璇㈢杈栫爜澶村垎閰嶇殑鑸拌墖淇℃伅
+        LoginUser sysUser = getLoginUser();
+        Long deptId = sysUser.getDeptId();
+        log.debug("deptId = : " + deptId);
+        List<DsTaskList2> dsTaskListList = dsTaskListService.getDsTaskListByTaskIdAndDeptId(Long.parseLong(taskIdStr), deptId);
+        log.debug("鏍规嵁浠诲姟銆侀儴鍒咺D鑾峰彇鐮佸ごJT淇℃伅DsTaskList = " + dsTaskListList);
+        JSONArray jsonArray = null;
+        switch (berthRule) {
+            case 1:
+                // 鎸塉T鍨嬪彿鍒嗙粍
+                jsonArray = calcZdBerthGroupByJTModel(berthRuleStr, deptId, dmBerthList, dsTaskListList);
+                break;
+            case 2:
+                // 鎸塂Y浼樺厛鍒嗙粍
+                jsonArray = calcZdBerthGroupByBullet(berthRuleStr, deptId, dmBerthList, dsTaskListList);
+                break;
+            case 3:
+                // 鎸変紭鍏堥『搴忓垎缁�
+                jsonArray = calcZdBerthGroupByOrder(berthRuleStr, deptId, dmBerthList, dsTaskListList);
+                break;
+            case 4:
+                // 鎸変汉宸ュ垎缁�
+                break;
+            default:
+                // 榛樿鎸塉T鍨嬪彿鍒嗙粍
+        }
+        return AjaxResult.success(jsonArray);
+    }
+
+    /**
+     * 鎸塉T鍨嬪彿鍒嗙粍绠楁硶銆�
+     * @param berthList
+     * @param dsTaskLists
+     * @return
+     */
+    private JSONArray calcZdBerthGroupByJTModel(String parkingType, Long deptId, List<DmBerth2> berthList, List<DsTaskList2> dsTaskLists) {
+        // 瀹氫箟姣忎釜娉婁綅鐨勬渶澶ч暱搴�
+        Long[] berthLengths = new Long[berthList.size()];
+        for(int i = 0; i < berthList.size(); i++){
+            berthLengths[i] = berthList.get(i).getBerthLen();
+        }
+
+        // 鎸夊瀷鍙峰垎缁勫苟涓や袱閰嶅
+        Map<String, List<DsTaskList2>> typeShipMap = new HashMap<>();
+        for (DsTaskList2 ship : dsTaskLists) {
+            typeShipMap.computeIfAbsent(ship.getShipType(), k -> new ArrayList<>()).add(ship);
+        }
+        log.debug("typeShipMap =====: " + typeShipMap);
+
+        List<List<DsTaskList2>> shipPairs = new ArrayList<>();
+        for (List<DsTaskList2> shipsOfType : typeShipMap.values()) {
+            for (int i = 0; i < shipsOfType.size(); i += 2) {
+                shipPairs.add(shipsOfType.subList(i, i + 2));
+            }
+        }
+        log.debug("shipPairs =====: " + shipPairs);
+
+        // 鎸夋瘡缁勪腑涓よ墭鑸瑰仠闈犳椂闂存�诲拰浠庡皬鍒板ぇ鎺掑簭
+        shipPairs.sort(Comparator.comparingDouble(pair -> (pair.get(0).getDockTime() == null ? 0:pair.get(0).getDockTime()) + (pair.get(1).getDockTime()==null ? 0:pair.get(1).getDockTime())));
+
+        // 璁板綍姣忎釜娉婁綅鐨勫綋鍓嶆�诲仠闈犳椂闂�
+        int[] berthTotalTimes = new int[berthLengths.length];
+        // 璁板綍姣忕粍鑸瑰垎閰嶅埌鐨勬硦浣�
+        int[] pairAssignments = new int[shipPairs.size()];
+
+        // 鍒嗛厤鑸瑰彧鍒版硦浣�
+        for (int i = 0; i < shipPairs.size(); i++) {
+            List<DsTaskList2> pair = shipPairs.get(i);
+            Double totalLength = pair.get(0).getShipLen(); // 鍙岃埞骞堕潬锛屽彇涓�鑹樿埞闀垮害鍒ゆ柇鏄惁鑳藉仠闈�
+            int minTime = Integer.MAX_VALUE;
+            int bestBerth = -1;
+            for (int j = 0; j < berthLengths.length; j++) {
+                if (totalLength <= berthLengths[j]) {
+                    Double dockTimeMax = Math.max(pair.get(0).getDockTime() == null ? 0 : pair.get(0).getDockTime(), pair.get(1).getDockTime() == null ? 0 : pair.get(1).getDockTime());
+                    int newTime = berthTotalTimes[j] + dockTimeMax.intValue();
+                    if (newTime < minTime) {
+                        minTime = newTime;
+                        bestBerth = j;
+                    }
+                }
+            }
+            pairAssignments[i] = bestBerth;
+            berthTotalTimes[bestBerth] = minTime;
+        }
+
+        // 杈撳嚭缁撴灉
+        for (int i = 0; i < shipPairs.size(); i++) {
+            List<DsTaskList2> pair = shipPairs.get(i);
+            log.debug("鑸拌埞 " + pair.get(0).getShipNo() + " 鍜� " + pair.get(1).getShipNo() + "锛堝瀷鍙� " + pair.get(0).getShipType() + "锛夊仠闈犲湪娉婁綅 " + (pairAssignments[i] + 1));
+        }
+        int totalTime = Arrays.stream(berthTotalTimes).max().getAsInt();
+        log.debug("鎵�鏈夎埞鍋滈潬鍒扮寮�娉婁綅鐨勬�绘椂闂存渶鐭负: " + totalTime + " 灏忔椂");
+
+        log.debug("******** 鎸夋硦浣嶅彿瑙f瀽渚濇鎺掑垪鐨凞sTaskList瀵硅薄 ********");
+        // 鎸夋硦浣嶅彿瑙f瀽渚濇鎺掑垪鐨凞sTaskList瀵硅薄
+        // 鎸夌収娉婁綅鍙烽『搴忥紝璁$畻姣忎釜娉婁綅涓婂仠闈犺埌鑸圭殑瀵硅薄DsTaskList
+        HashMap<String, List<DsTaskList2>> resultList = new HashMap<>();
+        for (int i = 0; i < pairAssignments.length; i++) {
+            int berthNumber = pairAssignments[i];
+            String berthKey = "" + (berthNumber + 1);
+            List<DsTaskList2> shipsOnBerth = resultList.computeIfAbsent(berthKey, k -> new ArrayList<>());
+            List<DsTaskList2> pair = shipPairs.get(i);
+            shipsOnBerth.addAll(pair);
+        }
+
+        // 杈撳嚭缁撴灉
+        JSONArray rootJSONArray = new JSONArray();
+        if (resultList != null) {
+            Date firstStartDate = new Date(System.currentTimeMillis());
+            Date lastEndDate = new Date(System.currentTimeMillis());
+            Long totalAmmoD = 0L;//鎬诲寮规暟
+            Long totalAmmoP = 0L;//鎬荤偖寮规暟
+            Long totalAmmoS = 0L;//鎬婚奔姘撮浄鏁�
+            Long totalAmmoO = 0L;//鎬诲叾浠栧脊鑽暟
+            Double totalWater = 0.0;//鎬绘贰姘存暟
+            Double totalWaterP = 0.0;//鎬荤函姘存暟
+            Long totalFood = 0L;//鎬讳富鍓鏁�
+            Long totalFoodW = 0L;//鎬绘《瑁呮按鏁�
+            Long totalFoodO = 0L;//鎬诲叾浠栫墿璧勬暟
+
+            for (Map.Entry<String, List<DsTaskList2>> entry : resultList.entrySet()) {
+                JSONObject rootJSONObj = new JSONObject();
+                JSONObject sub1JsonObj = new JSONObject();
+                JSONArray jsonArray = new JSONArray();
+                log.debug("JT鍨嬪彿鍒嗙粍娉婁綅 " + entry.getKey() + " 涓婂仠闈犵殑鑸拌埞锛�");
+                sub1JsonObj.put("berthName", entry.getKey());
+
+                JSONArray subJSONArray = new JSONArray();
+                for (int i = 0; i < dsTaskLists.size(); i++) {
+                    DsTaskList2 ship = dsTaskLists.get(i);
+                    // 鏇存柊DsTaskList鏁版嵁涓殑娉婁綅缂栧彿銆佹硦浣嶅悕绉般�佸苟闈犵瓥鐣ュ拰琛ョ粰椤哄簭瀛楁
+                    DsTaskList2 updateDsTaskList = new DsTaskList2();
+                    updateDsTaskList.setPKID(ship.getPKID());
+                    DmBerth2 berthValue = dmBerthService.selectDmBerthByPKID(Long.parseLong(entry.getKey()));
+                    updateDsTaskList.setBerthId(berthValue.getPKID());
+                    updateDsTaskList.setBerthName(berthValue.getNAME());
+                    updateDsTaskList.setParkingType(parkingType);
+                    updateDsTaskList.setSupplySeq(String.valueOf(i+1));
+                    updateDsTaskList.setDeptId(deptId);
+                    log.debug("Update DsTaskList2 PKID =====: " + ship.getPKID());
+                    log.debug("Update DsTaskList2 BerthId =====: " + berthValue.getPKID());
+                    log.debug("Update DsTaskList2 BerthName =====: " + berthValue.getNAME());
+                    log.debug("Update DsTaskList2 ParkingType =====: " + parkingType);
+                    log.debug("Update DsTaskList2 SupplySeq =====: " + (i+1));
+                    int result = dsTaskListService.updateDsTaskList(updateDsTaskList);
+                    log.debug("==================================: " + result);
+
+                    totalAmmoD += ship.getAmmoD() == null ? 0 : ship.getAmmoD();
+                    totalAmmoP += ship.getAmmoP() == null ? 0 : ship.getAmmoP();
+                    totalAmmoS += ship.getAmmoS() == null ? 0 : ship.getAmmoS();
+                    totalAmmoO += ship.getAmmoO() == null ? 0 : ship.getAmmoO();
+
+                    totalWater += ship.getWATER() == null ? 0 : ship.getWATER();
+                    totalWaterP += ship.getWaterP() == null ? 0 : ship.getWaterP();
+                    totalFood += ship.getFOOD() == null ? 0 : ship.getFOOD();
+                    totalFoodW += ship.getFoodW() == null ? 0 : ship.getFoodW();
+                    totalFoodO += ship.getFoodO() == null ? 0 : ship.getFoodO();
+
+                    Date startDate = ship.getpSTime(); //璁″垝鎶垫腐鏃堕棿
+                    Date endDate = ship.getpETime(); //璁″垝绂绘腐鏃堕棿
+                    if (firstStartDate.after(startDate)) {
+                        firstStartDate = startDate;
+                    }
+                    if (lastEndDate.before(endDate)) {
+                        lastEndDate = endDate;
+                    }
+                    log.debug("  - 鑸瑰悕锛�" + ship.getShipNo() + "锛屽瀷鍙凤細" + ship.getShipType() + "锛屽仠闈犳椂闂达細" + (ship.getDockTime() == null ? 0 : ship.getDockTime()) + " 鍒嗛挓");
+
+                    // 鏋勫缓JSON瀵硅薄
+                    JSONObject tmpJsonObject = new JSONObject();
+                    tmpJsonObject.put("pkId", ship.getPKID());
+                    tmpJsonObject.put("taskId", ship.getTaskId());
+                    tmpJsonObject.put("shipNo", ship.getShipNo());
+                    tmpJsonObject.put("shipType", ship.getShipType());
+                    tmpJsonObject.put("tonnage", ship.getTONNAGE());
+                    Long level = ship.getLEVEL() == null ? 1L : ship.getLEVEL();
+                    if(level == 2L){//鍏堟补鍚庡脊
+                        tmpJsonObject.put("supplySeq", "鍏堟补鍚庡脊");
+                    }else if(level == 3L){//鍏堝脊鍚庢补
+                        tmpJsonObject.put("supplySeq", "鍏堝脊鍚庢补");
+                    }else{
+                        tmpJsonObject.put("supplySeq", "鍚屾椂浣滀笟");
+                    }
+                    tmpJsonObject.put("level", ship.getLEVEL());
+                    tmpJsonObject.put("oilB", ship.getOilB() == null ? 0 : ship.getOilB());
+                    tmpJsonObject.put("oilG", ship.getOilG() == null ? 0 : ship.getOilG());
+                    tmpJsonObject.put("oilA", ship.getOilA() == null ? 0 : ship.getOilA());
+                    tmpJsonObject.put("ammoD", ship.getAmmoD() == null ? 0 : ship.getAmmoD());
+                    tmpJsonObject.put("ammoP", ship.getAmmoP() == null ? 0 : ship.getAmmoP());
+                    tmpJsonObject.put("ammoS", ship.getAmmoS() == null ? 0 : ship.getAmmoS());
+                    tmpJsonObject.put("ammoO", ship.getAmmoO() == null ? 0 : ship.getAmmoO());
+                    tmpJsonObject.put("water", ship.getWATER() == null ? 0 : ship.getWATER());
+                    tmpJsonObject.put("waterP", ship.getWaterP() == null ? 0 : ship.getWaterP());
+                    tmpJsonObject.put("food", ship.getFOOD() == null ? 0 : ship.getFOOD());
+                    tmpJsonObject.put("foodW", ship.getFoodW() == null ? 0 : ship.getFoodW());
+                    tmpJsonObject.put("foodO", ship.getFoodO() == null ? 0 : ship.getFoodO());
+                    tmpJsonObject.put("pSTime", ship.getpSTime() == null ? 0 : ship.getpSTime());
+                    tmpJsonObject.put("pETime", ship.getpETime() == null ? 0 : ship.getpETime());
+                    subJSONArray.add(tmpJsonObject);
+                    sub1JsonObj.put("subData", subJSONArray);
+                }
+                jsonArray.add(sub1JsonObj);
+                rootJSONObj.put("parkingType", parkingType);
+                rootJSONObj.put("dsTaskList", jsonArray);
+                rootJSONObj.put("totalAmmoD", totalAmmoD);
+                rootJSONObj.put("totalAmmoP", totalAmmoP);
+                rootJSONObj.put("totalAmmoS", totalAmmoS);
+                rootJSONObj.put("totalAmmoO", totalAmmoO);
+                rootJSONObj.put("totalWater", totalWater);
+                rootJSONObj.put("totalWaterP", totalWaterP);
+                rootJSONObj.put("totalFood", totalFood);
+                rootJSONObj.put("totalFoodW", totalFoodW);
+                rootJSONObj.put("totalFoodO", totalFoodO);
+                rootJSONObj.put("firstStartDate", format.format(firstStartDate));
+                rootJSONObj.put("lastEndDate", format.format(lastEndDate));
+                rootJSONArray.add(rootJSONObj);
+            }
+        }
+        log.debug("************************************************");
+        return rootJSONArray;
+    }
+
+    /**
+     * 鎸塂Y浼樺厛鍒嗙粍绠楁硶銆�
+     */
+    private JSONArray calcZdBerthGroupByBullet(String parkingType, Long deptId, List<DmBerth2> berthList, List<DsTaskList2> dsTaskLists) {
+        // 鎸夊姞娌归渶姹傘�佽埞绫诲瀷鍜屾姷娓椂闂存帓搴�
+        dsTaskLists.sort(Comparator.comparing(DsTaskList2::needRefueling).reversed()
+                .thenComparing(DsTaskList2::getShipType)
+                .thenComparing(DsTaskList2::getpSTime));
+
+        // 鎸夊悓鍨嬪彿 2 鑹樹竴缁勫垎缁�
+        List<List<DsTaskList2>> shipGroups = new ArrayList<>();
+        Map<String, List<DsTaskList2>> typeMap = new HashMap<>();
+        for (DsTaskList2 ship : dsTaskLists) {
+            String shipType = ship.getShipType();
+            typeMap.computeIfAbsent(shipType, k -> new ArrayList<>()).add(ship);
+        }
+        for (List<DsTaskList2> shipsOfType : typeMap.values()) {
+            for (int i = 0; i < shipsOfType.size(); i += 2) {
+                if (i + 1 < shipsOfType.size()) {
+                    // 纭繚涓�缁勪腑闇�瑕佸姞娌圭殑鑸规帓鍦ㄥ墠闈�
+                    if (!shipsOfType.get(i).needRefueling() && shipsOfType.get(i + 1).needRefueling()) {
+                        Collections.swap(shipsOfType, i, i + 1);
+                    }
+                    shipGroups.add(Arrays.asList(shipsOfType.get(i), shipsOfType.get(i + 1)));
+                } else {
+                    // 澶勭悊鍗曡墭鍓╀綑鐨勬儏鍐�
+                    shipGroups.add(Collections.singletonList(shipsOfType.get(i)));
+                }
+            }
+        }
+        log.debug("鎸夊脊鑽紭鍏堝垎缁剆hipGroups =====: " + shipGroups);
+
+        Date currentTime = null;
+        try {
+            currentTime = format.parse("2025-03-01 00:00:00");
+        }catch (Exception ex) {
+            ex.printStackTrace();
+        }
+
+        // 瀵硅埌鑸圭粍鎸夊仠闈犵粨鏉熸椂闂存帓搴�
+        shipGroups.sort(Comparator.comparing(group -> {
+            long maxEndTime = 0;
+            for (DsTaskList2 ship : group) {
+                maxEndTime = Math.max(maxEndTime, ship.getpETime().getTime());
+            }
+            return maxEndTime;
+        }));
+
+        // 妯℃嫙鍋滈潬杩囩▼
+        Map<DsTaskList2, DmBerth2> dockingMap = new HashMap<>();
+        Map<DmBerth2, Date> berthAvailableTime = new HashMap<>();
+        for (DmBerth2 berth : berthList) {
+            berthAvailableTime.put(berth, currentTime);
+        }
+
+        for (List<DsTaskList2> group : shipGroups) {
+            DmBerth2 bestBerth = null;
+            Date earliestAvailableTime = null;
+            for (DmBerth2 berth : berthList) {
+                if (canDock(group, berth)) {
+                    Date availableTime = berthAvailableTime.get(berth);
+                    if (earliestAvailableTime == null || availableTime.before(earliestAvailableTime)) {
+                        earliestAvailableTime = availableTime;
+                        bestBerth = berth;
+                    }
+                }
+            }
+            if (bestBerth != null) {
+                for (DsTaskList2 ship : group) {
+                    dockingMap.put(ship, bestBerth);
+                }
+                long startTime = Math.max(group.get(0).getpSTime().getTime(), earliestAvailableTime.getTime());
+                long endTime = 0;
+                for (DsTaskList2 ship : group) {
+                    endTime = Math.max(endTime, ship.getpETime().getTime());
+                }
+                berthAvailableTime.put(bestBerth, new Date(endTime));
+            }
+        }
+
+        // 鏁寸悊杈撳嚭缁撴灉
+        Map<DmBerth2, List<DsTaskList2>> berthShipMap = new LinkedHashMap<>();
+        for (Map.Entry<DsTaskList2, DmBerth2> entry : dockingMap.entrySet()) {
+            DmBerth2 berth = entry.getValue();
+            DsTaskList2 ship = entry.getKey();
+            berthShipMap.computeIfAbsent(berth, k -> new ArrayList<>()).add(ship);
+        }
+        log.debug("berthShipMap ========: " + berthShipMap);
+
+        //****** add BerthShipMap handle ********//
+        // 灏� LinkedHashMap 鐨勯敭鍊煎杞Щ鍒� List 涓�
+        List<Map.Entry<DmBerth2, List<DsTaskList2>>> list = new ArrayList<>(berthShipMap.entrySet());
+
+        // 瀵� List 杩涜鎺掑簭
+        Collections.sort(list, new Comparator<Map.Entry<DmBerth2, List<DsTaskList2>>>() {
+            @Override
+            public int compare(Map.Entry<DmBerth2, List<DsTaskList2>> o1, Map.Entry<DmBerth2, List<DsTaskList2>> o2) {
+                return (int) (((o1.getKey().getHarborId() * 100) + o1.getKey().getOrderNum()) - ((o2.getKey().getHarborId() * 100) + o2.getKey().getOrderNum()));
+            }
+        });
+
+        // 灏嗘帓搴忓悗鐨勯敭鍊煎瀛樹簬鏂扮殑 LinkedHashMap 涓�
+        LinkedHashMap<DmBerth2, List<DsTaskList2>> sortedMap = new LinkedHashMap<>();
+        for (Map.Entry<DmBerth2, List<DsTaskList2>> entry : list) {
+            sortedMap.put(entry.getKey(), entry.getValue());
+        }
+        //***************************************//
+
+
+        // 鎸夊垎缁勮緭鍑虹粨鏋�
+        /**
+         for (Map.Entry<DmBerth, List<DsTaskList>> entry : berthShipMap.entrySet()) {
+         DmBerth berth = entry.getKey();
+         List<DsTaskList> shipsInBerth = entry.getValue();
+         StringBuilder shipNos = new StringBuilder();
+         String shipType = shipsInBerth.get(0).getShipType();
+         for (int i = 0; i < shipsInBerth.size(); i++) {
+         if (i > 0) {
+         shipNos.append(" 鍜� ");
+         }
+         shipNos.append(shipsInBerth.get(i).getShipNo());
+         }
+         System.out.println("鑸� " + shipNos + "锛堝瀷鍙� " + shipType + "锛夊仠闈犲湪娉婁綅 " + berth.getNAME());
+         }
+         */
+
+        JSONArray jsonObj = getJSONObject(parkingType, deptId, sortedMap);
+        return jsonObj;
+    }
+
+    private static boolean canDock(List<DsTaskList2> group, DmBerth2 berth) {
+        for (DsTaskList2 ship : group) {
+            if (ship.getShipLen() > berth.getBerthLen()) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    /**
+     * 鎸変紭鍏堥『搴忓垎缁勭畻娉曘��
+     */
+    private JSONArray calcZdBerthGroupByOrder(String parkingType, Long deptId, List<DmBerth2> berthList, List<DsTaskList2> dsTaskLists) {
+        // 鎸変紭鍏堢骇銆佽埞绫诲瀷鍜屾姷娓椂闂存帓搴�
+        dsTaskLists.sort(Comparator.comparing(DsTaskList2::getLEVEL).reversed()
+                .thenComparing(DsTaskList2::getShipType)
+                .thenComparing(DsTaskList2::getpSTime));
+        JSONArray jsonObj = null;
+        try {
+            jsonObj = handleJtGroup(parkingType, deptId, berthList, dsTaskLists);
+        }catch (Exception e) {
+            e.printStackTrace();
+        }
+        return jsonObj;
+    }
+
+    /**
+     * 鏍规嵁娉婁綅涓婅埌鑸瑰苟鎺掑仠闈犳暟閲忥紝瀵规帓搴忓悗鐨勮埌鑸硅繘琛屽垎缁勬搷浣滐紝杩斿洖鍚勬硦浣嶇殑鑸拌埞鍋滈潬缁撴灉銆�
+     *
+     * @return
+     */
+    private JSONArray handleJtGroup(String parkingType, Long deptId, List<DmBerth2> berthList, List<DsTaskList2> dsTaskLists) throws ParseException {
+        // 榛樿鎸夊悓鍨嬪彿 2 鑹樹竴缁勫垎缁�
+        List<List<DsTaskList2>> shipGroups = new ArrayList<>();
+        Map<String, List<DsTaskList2>> typeMap = new HashMap<>();
+        for (DsTaskList2 ship : dsTaskLists) {
+            String shipType = ship.getShipType();
+            typeMap.computeIfAbsent(shipType, k -> new ArrayList<>()).add(ship);
+        }
+        for (List<DsTaskList2> shipsOfType : typeMap.values()) {
+            for (int i = 0; i < shipsOfType.size(); i += 2) {
+                if (i + 1 < shipsOfType.size()) {
+                    // 纭繚涓�缁勪腑闇�瑕佸姞娌圭殑鑸规帓鍦ㄥ墠闈�
+                    if (!shipsOfType.get(i).needRefueling() && shipsOfType.get(i + 1).needRefueling()) {
+                        Collections.swap(shipsOfType, i, i + 1);
+                    }
+                    shipGroups.add(Arrays.asList(shipsOfType.get(i), shipsOfType.get(i + 1)));
+                } else {
+                    // 澶勭悊鍗曡墭鍓╀綑鐨勬儏鍐�
+                    shipGroups.add(Collections.singletonList(shipsOfType.get(i)));
+                }
+            }
+        }
+        System.out.println("shipGroups =====: " + shipGroups);
+
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        Date currentTime = sdf.parse("2025-03-23 00:00:00");
+
+        // 瀵硅埌鑸圭粍鎸夊仠闈犵粨鏉熸椂闂存帓搴�
+        shipGroups.sort(Comparator.comparing(group -> {
+            long maxEndTime = 0;
+            for (DsTaskList2 ship : group) {
+                maxEndTime = Math.max(maxEndTime, ship.getpETime().getTime());
+            }
+            return maxEndTime;
+        }));
+
+        // 妯℃嫙鍋滈潬杩囩▼
+        Map<DsTaskList2, DmBerth2> dockingMap = new HashMap<>();
+        Map<DmBerth2, Date> berthAvailableTime = new HashMap<>();
+        for (DmBerth2 berth : berthList) {
+            berthAvailableTime.put(berth, currentTime);
+        }
+
+        for (List<DsTaskList2> group : shipGroups) {
+            DmBerth2 bestBerth = null;
+            Date earliestAvailableTime = null;
+            for (DmBerth2 berth : berthList) {
+                if (canDock(group, berth)) {
+                    Date availableTime = berthAvailableTime.get(berth);
+                    if (earliestAvailableTime == null || availableTime.before(earliestAvailableTime)) {
+                        earliestAvailableTime = availableTime;
+                        bestBerth = berth;
+                    }
+                }
+            }
+            if (bestBerth != null) {
+                for (DsTaskList2 ship : group) {
+                    dockingMap.put(ship, bestBerth);
+                }
+                long startTime = Math.max(group.get(0).getpSTime().getTime(), earliestAvailableTime.getTime());
+                long endTime = 0;
+                for (DsTaskList2 ship : group) {
+                    endTime = Math.max(endTime, ship.getpETime().getTime());
+                }
+                berthAvailableTime.put(bestBerth, new Date(endTime));
+            }
+        }
+
+        // 鏁寸悊杈撳嚭缁撴灉
+        Map<DmBerth2, List<DsTaskList2>> berthShipMap = new HashMap<>();
+        for (Map.Entry<DsTaskList2, DmBerth2> entry : dockingMap.entrySet()) {
+            DmBerth2 berth = entry.getValue();
+            DsTaskList2 ship = entry.getKey();
+            berthShipMap.computeIfAbsent(berth, k -> new ArrayList<>()).add(ship);
+        }
+
+        // 鎸夊垎缁勮緭鍑虹粨鏋�
+//        for (Map.Entry<DmBerth2, List<DsTaskList2>> entry : berthShipMap.entrySet()) {
+//            DmBerth2 berth = entry.getKey();
+//            List<DsTaskList2> shipsInBerth = entry.getValue();
+//            StringBuilder shipNos = new StringBuilder();
+//            String shipType = shipsInBerth.get(0).getShipType();
+//            for (int i = 0; i < shipsInBerth.size(); i++) {
+//                if (i > 0) {
+//                    shipNos.append(" 鍜� ");
+//                }
+//                shipNos.append(shipsInBerth.get(i).getShipNo());
+//            }
+//            System.out.println("鑸� " + shipNos + "锛堝瀷鍙� " + shipType + "锛夊仠闈犲湪娉婁綅 " + berth.getNAME());
+//        }
+
+        //****** add BerthShipMap handle ********//
+        // 灏� LinkedHashMap 鐨勯敭鍊煎杞Щ鍒� List 涓�
+        List<Map.Entry<DmBerth2, List<DsTaskList2>>> list = new ArrayList<>(berthShipMap.entrySet());
+
+        // 瀵� List 杩涜鎺掑簭
+        Collections.sort(list, new Comparator<Map.Entry<DmBerth2, List<DsTaskList2>>>() {
+            @Override
+            public int compare(Map.Entry<DmBerth2, List<DsTaskList2>> o1, Map.Entry<DmBerth2, List<DsTaskList2>> o2) {
+                return o1.getKey().getPKID().compareTo(o2.getKey().getPKID());
+            }
+        });
+
+        // 灏嗘帓搴忓悗鐨勯敭鍊煎瀛樹簬鏂扮殑 LinkedHashMap 涓�
+        LinkedHashMap<DmBerth2, List<DsTaskList2>> sortedMap = new LinkedHashMap<>();
+        for (Map.Entry<DmBerth2, List<DsTaskList2>> entry : list) {
+            sortedMap.put(entry.getKey(), entry.getValue());
+        }
+        //***************************************//
+        JSONArray jsonObj = getJSONObject(parkingType, deptId, sortedMap);
+        return null;
+    }
+
+    /**
+     * 鏋勫缓鑸拌埞鍒嗙粍鐨凧SON瀵硅薄銆�
+     * @param berthShipMap
+     * @return
+     */
+    private JSONArray getJSONObject(String parkingType, Long deptId, LinkedHashMap<DmBerth2, List<DsTaskList2>> berthShipMap) {
+        JSONArray rootJSONArray = new JSONArray();
+        if(berthShipMap != null) {
+            Long totalAmmoD = 0L;//鎬诲寮规暟
+            Long totalAmmoP = 0L;//鎬荤偖寮规暟
+            Long totalAmmoS = 0L;//鎬婚奔姘撮浄鏁�
+            Long totalAmmoO = 0L;//鎬诲叾浠栧脊鑽暟
+            Double totalWater = 0.0;//鎬绘贰姘存暟
+            Double totalWaterP = 0.0;//鎬荤函姘存暟
+            Long totalFood = 0L;//鎬讳富鍓鏁�
+            Long totalFoodW = 0L;//鎬绘《瑁呮按鏁�
+            Long totalFoodO = 0L;//鎬诲叾浠栫墿璧勬暟
+            Date firstStartDate = new Date(System.currentTimeMillis());
+            Date lastEndDate = new Date(System.currentTimeMillis());
+
+            for (Map.Entry<DmBerth2, List<DsTaskList2>> entry : berthShipMap.entrySet()) {
+                JSONObject rootJSONObj = new JSONObject();
+                JSONArray jsonArray = new JSONArray();
+                JSONObject sub1JsonObj = new JSONObject();
+                List<DsTaskList2> dsTaskLists = entry.getValue();
+                DmBerth2 berthValue = entry.getKey();
+                String berthName = berthValue.getNAME();
+                Long berthId = berthValue.getPKID();
+                Long harborId = berthValue.getHarborId();
+                String harborName = berthValue.getHarborName();
+                sub1JsonObj.put("harborId", harborId);
+                sub1JsonObj.put("harborName", harborName);
+                sub1JsonObj.put("berthId", berthId);
+                sub1JsonObj.put("berthName", berthName);
+
+                // 杈撳嚭缁撴灉
+                if (dsTaskLists != null) {
+                    JSONArray subJSONArray = new JSONArray();
+                    for (int i = 0; i < dsTaskLists.size(); i++) {
+                        DsTaskList2 ship = dsTaskLists.get(i);
+                        // 鏇存柊DsTaskList鏁版嵁涓殑娉婁綅缂栧彿銆佹硦浣嶅悕绉般�佸苟闈犵瓥鐣ュ拰琛ョ粰椤哄簭瀛楁
+                        DsTaskList2 updateDsTaskList = new DsTaskList2();
+                        updateDsTaskList.setPKID(ship.getPKID());
+                        updateDsTaskList.setBerthId(berthValue.getPKID());
+                        updateDsTaskList.setBerthName(berthValue.getNAME());
+                        updateDsTaskList.setParkingType(parkingType);
+                        updateDsTaskList.setSupplySeq(String.valueOf(i+1));
+                        updateDsTaskList.setDeptId(deptId);
+                        log.debug("Update DsTaskList2 PKID =====: " + ship.getPKID());
+                        log.debug("Update DsTaskList2 BerthId =====: " + berthValue.getPKID());
+                        log.debug("Update DsTaskList2 BerthName =====: " + berthValue.getNAME());
+                        log.debug("Update DsTaskList2 ParkingType =====: " + parkingType);
+                        log.debug("Update DsTaskList2 SupplySeq =====: " + (i+1));
+                        int result = dsTaskListService.updateDsTaskList(updateDsTaskList);
+                        log.debug("==================================: " + result);
+
+                        totalAmmoD += ship.getAmmoD() == null ? 0 : ship.getAmmoO();
+                        totalAmmoP += ship.getAmmoP() == null ? 0 : ship.getAmmoP();
+                        totalAmmoS += ship.getAmmoS() == null ? 0 : ship.getAmmoS();
+                        totalAmmoO += ship.getAmmoO() == null ? 0 : ship.getAmmoO();
+
+                        totalWater += ship.getWATER() == null ? 0 : ship.getWATER();
+                        totalWaterP += ship.getWaterP() == null ? 0 : ship.getWaterP();
+                        totalFood += ship.getFOOD() == null ? 0 : ship.getFOOD();
+                        totalFoodW += ship.getFoodW() == null ? 0 : ship.getFoodW();
+                        totalFoodO += ship.getFoodO() == null ? 0 : ship.getFoodW();
+
+                        Date startDate = ship.getpSTime(); //璁″垝鎶垫腐鏃堕棿
+                        Date endDate = ship.getpETime(); //璁″垝绂绘腐鏃堕棿
+                        if (firstStartDate.after(startDate)) {
+                            firstStartDate = startDate;
+                        }
+                        if (lastEndDate.before(endDate)) {
+                            lastEndDate = endDate;
+                        }
+
+                        // 鏋勫缓JSON瀵硅薄
+                        JSONObject tmpJsonObject = new JSONObject();
+                        tmpJsonObject.put("pkId", ship.getPKID());
+                        tmpJsonObject.put("taskId", ship.getTaskId());
+                        tmpJsonObject.put("shipNo", ship.getShipNo());
+                        tmpJsonObject.put("shipType", ship.getShipType());
+                        tmpJsonObject.put("tonnage", ship.getTONNAGE() == null ? 0 : ship.getTONNAGE());
+                        Long level = ship.getLEVEL() == null ? 1L : ship.getLEVEL();
+                        if(level == 2L){//鍏堟补鍚庡脊
+                            tmpJsonObject.put("supplySeq", "鍏堟补鍚庡脊");
+                        }else if(level == 3L){//鍏堝脊鍚庢补
+                            tmpJsonObject.put("supplySeq", "鍏堝脊鍚庢补");
+                        }else{
+                            tmpJsonObject.put("supplySeq", "鍚屾椂浣滀笟");
+                        }
+                        tmpJsonObject.put("level", ship.getLEVEL());
+                        tmpJsonObject.put("oilB", ship.getOilB() == null ? 0 : ship.getOilB());
+                        tmpJsonObject.put("oilG", ship.getOilG() == null ? 0 : ship.getOilG());
+                        tmpJsonObject.put("oilA", ship.getOilA() == null ? 0 : ship.getOilA());
+                        tmpJsonObject.put("ammoD", ship.getAmmoD() == null ? 0 : ship.getAmmoD());
+                        tmpJsonObject.put("ammoP", ship.getAmmoP() == null ? 0 : ship.getAmmoP());
+                        tmpJsonObject.put("ammoS", ship.getAmmoS() == null ? 0 : ship.getAmmoS());
+                        tmpJsonObject.put("ammoO", ship.getAmmoO() == null ? 0 : ship.getAmmoO());
+                        tmpJsonObject.put("water", ship.getWATER() == null ? 0 : ship.getWATER());
+                        tmpJsonObject.put("waterP", ship.getWaterP() == null ? 0 : ship.getWaterP());
+                        tmpJsonObject.put("food", ship.getFOOD() == null ? 0 : ship.getFOOD());
+                        tmpJsonObject.put("foodW", ship.getFoodW() == null ? 0 : ship.getFoodW());
+                        tmpJsonObject.put("foodO", ship.getFoodO() == null ? 0 : ship.getFoodO());
+                        tmpJsonObject.put("pSTime", ship.getpSTime());
+                        tmpJsonObject.put("pETime", ship.getpETime());
+                        subJSONArray.add(tmpJsonObject);
+                        sub1JsonObj.put("subData", subJSONArray);
+                    }
+                }
+                jsonArray.add(sub1JsonObj);
+                rootJSONObj.put("parkingType", parkingType);
+                rootJSONObj.put("dsTaskList", jsonArray);
+                rootJSONObj.put("totalAmmoD", totalAmmoD);
+                rootJSONObj.put("totalAmmoP", totalAmmoP);
+                rootJSONObj.put("totalAmmoS", totalAmmoS);
+                rootJSONObj.put("totalAmmoO", totalAmmoO);
+                rootJSONObj.put("totalWater", totalWater);
+                rootJSONObj.put("totalWaterP", totalWaterP);
+                rootJSONObj.put("totalFood", totalFood);
+                rootJSONObj.put("totalFoodW", totalFoodW);
+                rootJSONObj.put("totalFoodO", totalFoodO);
+                rootJSONObj.put("firstStartDate", format.format(firstStartDate));
+                rootJSONObj.put("lastEndDate", format.format(lastEndDate));
+                rootJSONArray.add(rootJSONObj);
+            }
+        }
+        log.debug("XXXXXX =====锛� " + rootJSONArray);
+        return rootJSONArray;
+    }
+
+    /**
+     * 鎸変汉宸ュ垎缁勭畻娉曘��
+     */
+    private void calcZdBerthGroupByHandMove(List<DmBerth2> berthList, List<DsTaskList2> dsTaskLists) {
+
+    }
+
+    /**
+     * 鑾峰彇鏀槦鐮佸ご娉婁綅鍒嗙粍鏁版嵁缁撴灉銆�
+     *
+     * @return
+     */
+    @Operation(description = "淇敼鑸拌埞琛ョ粰椤哄簭")
+    @Log(title = "淇敼鑸拌埞琛ョ粰椤哄簭", businessType = BusinessType.INSERT)
+    @PostMapping("/updatelevel")
+    @ResponseBody
+    public AjaxResult updateSupplyLevelBy(Long pkId, Long supplyLevel) {
+        DsTaskList2 dsTaskList2 = new DsTaskList2();
+        dsTaskList2.setPKID(pkId);
+        dsTaskList2.setLEVEL(supplyLevel);
+        try {
+            int result = dsTaskListService.updateDsTaskList(dsTaskList2);
+            if (result > 0) {
+                return AjaxResult.success("PKID = [" + String.valueOf(pkId) + "]璁板綍琛ョ粰椤哄簭鏇存柊鎴愬姛");
+            } else {
+                return AjaxResult.success("鏈壘鍒扮鍚堟潯浠剁殑璁板綍杩涜鏇存柊");
+            }
+        } catch (Exception ex) {
+            return AjaxResult.error("PKID = [" + String.valueOf(pkId) + "]璁板綍琛ョ粰椤哄簭鏇存柊澶辫触");
+        }
+    }
+
+    @Operation(description = "鏇存柊鏀槦鍒嗙粍椤哄簭")
+    @Log(title = "鏇存柊鏀槦鍒嗙粍椤哄簭", businessType = BusinessType.INSERT)
+    @PostMapping("/updategroupseq")
+    @ResponseBody
+    public AjaxResult updateShipGroupSeq(@RequestBody List<ShipGroupDTO> shipGroupDTOList){
+        int flag = 0;
+        if(shipGroupDTOList != null && shipGroupDTOList.size() > 0){
+            // 鑾峰彇鎵�鏈夌殑娉婁綅淇℃伅
+            List<DmBerth2> berth2List = dmBerthService.selectDmBerthList(new DmBerth2());
+
+            for(ShipGroupDTO shipGroupDTO : shipGroupDTOList){
+                // String parkingType = shipGroupDTO.getParkingType();
+                List<TaskRecordList> taskRecordList = shipGroupDTO.getDsTaskList();
+                Long berthId = taskRecordList.get(0).getBerthId();
+                Long harborId = taskRecordList.get(0).getHarborId();
+                List<Subdata> subDataList = taskRecordList.get(0).getSubData();
+                if(subDataList!= null && subDataList.size() > 0){
+                    for(int i = 0; i < subDataList.size(); i++){
+                        Subdata subdata = subDataList.get(i);
+                        Long pkId = subdata.getPkId();
+                        String supplySeq = subdata.getSupplySeq();
+                        if(supplySeq.equals("鍚屾椂浣滀笟")){
+                            supplySeq = "1";
+                        }
+                        else if(supplySeq.equals("鍏堟补鍚庡脊")){
+                            supplySeq = "2";
+                        }if(supplySeq.equals("鍏堝脊鍚庢补")){
+                            supplySeq = "3";
+                        }
+
+//                        DsTaskList2 dsTaskList = new DsTaskList2();
+//                        dsTaskList.setPKID(pkId);
+                        DsTaskList2 existDsTaskList = dsTaskListService.selectDsTaskListByPkid(pkId);
+                        if(existDsTaskList != null){
+//                            Long tempBerthId = existDsTaskList.getBerthId();
+//                            Long tempHarborId = existDsTaskList.getHarborId();
+//                            String tempSupplySeq = existDsTaskList.getSupplySeq();
+                           // if(berthId != tempBerthId || harborId != tempHarborId){
+                                DsTaskList2 newDsTaskList = new DsTaskList2();
+                                newDsTaskList.setPKID(pkId);
+                                newDsTaskList.setHarborId(harborId);
+                                newDsTaskList.setBerthId(berthId);
+                                newDsTaskList.setSupplySeq(supplySeq);
+                                newDsTaskList.setPath(getBerthPathById(berth2List, berthId));
+                                int result = dsTaskListService.updateDsTaskList(newDsTaskList);
+                                if(result > 0 || result == 0){
+                                    flag += 1;
+                                }
+                           // }
+                        }
+                    }
+                }
+            }
+            if(flag > 0){
+                return AjaxResult.success("鏀槦鍒嗙粍椤哄簭鏇存柊鎴愬姛锛�");
+            }else{
+                return AjaxResult.success("鍒嗙粍椤哄簭鏃犺皟鏁达紒");
+            }
+        }
+        return AjaxResult.success("鏀槦鍒嗙粍椤哄簭娌℃湁鍙樺寲锛屾湭鏇存柊锛�");
+    }
+
+    // 鏍规嵁ID鑾峰彇娉婁綅璺緞淇℃伅璇︽儏
+    private String getBerthPathById(List<DmBerth2> list, Long id){
+        for(DmBerth2 berth2 : list){
+            if(berth2.getPKID() == id){
+                return berth2.getPath();
+            }
+        }
+        return "";
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdEffectEstimateController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdEffectEstimateController.java
new file mode 100644
index 0000000..9a19b4a
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdEffectEstimateController.java
@@ -0,0 +1,893 @@
+package com.ruoyi.buss.controller;
+
+
+import com.ruoyi.buss.common.DateUtils;
+import com.ruoyi.buss.common.NumberUtils;
+import com.ruoyi.buss.domain.*;
+import com.ruoyi.buss.domain.vo.TaskAssess;
+import com.ruoyi.buss.service.*;
+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.model.LoginUser;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.system.service.ISysDictDataService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.text.DecimalFormat;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 鏀槦鏁堣兘璇勪及閫昏緫Controller
+ *
+ * @author yl
+ * @date 2025-03-20
+ */
+
+@Tag(name = "鏀槦鏁堣兘璇勪及")
+@Controller
+@RequestMapping("/buss/zd/effect")
+public class ZdEffectEstimateController extends BaseController {
+    private static final Logger log = LoggerFactory.getLogger(ZdEffectEstimateController.class);
+
+
+    private static DecimalFormat df = new DecimalFormat("#.00");
+    private static DecimalFormat df2 = new DecimalFormat("#.0");
+
+    @Autowired
+    private IDsTaskList2Service dsTaskList2Service;
+    @Autowired
+    private IDmBerth2Service dmBerth2Service;
+    @Autowired
+    private ISysDictDataService sysDictDataService;
+    @Autowired
+    private IDsTaskDetailService iDsTaskDetailService;
+    @Autowired
+    private IDsEffectAssessService dsEffectAssessService;
+    @Autowired
+    private IDsEffectAssessListService dsEffectAssessListService;
+    @Autowired
+    private IDmHarbor2Service dmHarbor2Service;
+
+    private final static double B11_VALUE = 24; // 鑸拌埞骞冲潎浠诲姟鏃堕棿
+
+    private final static int X_TOLERANCE_VALUE = 0; // 鑸硅埗鏁伴噺
+
+    private final static Double OIL_PLACE_PER = 0.3;
+    private final static Double MAT_PLACE_PER = 0.2;
+    private final static Double AMMO_PLACE_PER = 0.5;
+
+    private final static int SUPPLY_X_TIME = 2;
+
+    /**
+     * 璁$畻鏀槦鏁堣兘璇勪及
+     * @return
+     */
+    @Operation(description = "鏀槦鏁堣兘璇勪及璁$畻")
+    @Log(title = "鏀槦鏁堣兘璇勪及璁$畻", businessType = BusinessType.INSERT)
+    @PostMapping("/estimate")
+    @ResponseBody
+    public AjaxResult estimate(@Parameter(name = "type", required = true, description = "璇勪及绫诲瀷") String type,
+                               @Parameter(name = "taskId", required = true, description = "浠诲姟ID") Long taskId,
+                               @Parameter(name = "deptId", required = true, description = "閮ㄩ棬ID") Long deptId) {
+        DmHarbor2 dmHarbor2 = new DmHarbor2();
+        dmHarbor2.setDeptId(deptId);
+        List<DmHarbor2> dmHarbor2List = dmHarbor2Service.selectDmHarborList(dmHarbor2);
+        String dmHarborPkIds = "";
+        if (dmHarbor2List != null || dmHarbor2List.size() > 0) {
+            for (DmHarbor2 dmHarbor : dmHarbor2List){
+                dmHarbor.getPKID();
+                dmHarborPkIds += dmHarbor.getPKID() + ",";
+            }
+            dmHarborPkIds = dmHarborPkIds.substring(0, dmHarborPkIds.length() - 1);
+            dmHarborPkIds = "(" + dmHarborPkIds + ")";
+        }
+
+        DsEffectAssessList assess = new DsEffectAssessList();
+        assess.setTYPE(type);
+        List<DsEffectAssessList> dsEffectAssessLists = dsEffectAssessListService.selectDsEffectAssessListList(assess);
+        List<DsTaskDetail> dsTaskDetailList = iDsTaskDetailService.selectDsTaskDetailByTaskIdAndHarborIds(taskId, dmHarborPkIds);
+        if (dsEffectAssessLists != null && dsEffectAssessLists.size() > 0) {
+            for(int i = 0; i < dsEffectAssessLists.size(); i++){
+                DsEffectAssessList dsEffectAssessList = dsEffectAssessLists.get(i);
+                log.debug("銆�" + dsEffectAssessList.getCODE() + "銆� DsEffectAssessList Obj =====: " + dsEffectAssessList);
+                String code = dsEffectAssessList.getCODE();
+                double weights = dsEffectAssessList.getWEIGHT();
+                double classifyWeight = dsEffectAssessList.getClassifyWeight();
+
+                double itemResult = calcNormItemResult(code, weights, dsTaskDetailList);
+                DsEffectAssessList asscessList = new DsEffectAssessList();
+                asscessList.setPKID(dsEffectAssessList.getPKID());
+                asscessList.setVal(itemResult);
+                dsEffectAssessListService.updateDsEffectAssessList(asscessList);
+            }
+        }
+
+        // 璁$畻鏈�缁堣瘎浼扮粨鏋�
+        List<DsEffectAssessList> dsEffectAssessLists2 = dsEffectAssessListService.selectDsEffectAssessListList(assess);
+        double score = getScore(dsEffectAssessLists2);
+        log.debug("Score =====锛� " + score);
+        DsEffectAssess dsEffectAssess =  new DsEffectAssess(taskId, score);
+        dsEffectAssess.setCreateTime(new Date());
+        dsEffectAssess.setCreateBy(getUsername());
+        dsEffectAssess.setDeptId(getDeptId());
+        // 淇濆瓨璇勪及缁撴灉
+        dsEffectAssessService.updateOrInsertDsEffectAssess(dsEffectAssess);
+        log.debug("瀹屾垚鏇存柊/鏂板Access璁板綍銆�");
+
+        TaskAssess taskAssess = new TaskAssess();
+        taskAssess.setList(dsEffectAssessLists);
+        taskAssess.setAssess(dsEffectAssess);
+        if(null != dsEffectAssessLists){
+            return success(taskAssess);
+        }
+        return error("鑾峰彇鑳芥晥璇勪及璇︽儏澶辫触锛岃閲嶈瘯");
+    }
+
+    private double calcNormItemResult(String code, double weights, List<DsTaskDetail> dsTaskDetailList) {
+        int result = 0;
+        if ("B11".equals(code)) {
+            // 鐙珛鍙傝�冩寚鏍囦笉鍙備笌鍔犳潈璁$畻
+        } else if ("B12".equals(code)) {
+            result = calcB12(dsTaskDetailList);
+        } else if ("B13".equals(code)) {
+            result = calcB13(dsTaskDetailList);
+        } else if ("B14".equals(code)) {
+            result = calcB14(dsTaskDetailList);
+        } else if ("B15".equals(code)) {
+            result = calcB15(dsTaskDetailList);
+        } else if ("B16".equals(code)) {
+            result = calcB16(dsTaskDetailList);
+        } else if ("B17".equals(code)) {
+            result = calcB17(dsTaskDetailList);
+        } else if ("B21".equals(code)) {
+            result = calcB21(dsTaskDetailList);
+        } else if ("B22".equals(code)) {
+            result = calcB22(dsTaskDetailList);
+        } else if ("B23".equals(code)) {
+            result = calcB23(dsTaskDetailList);
+        } else if ("B24".equals(code)) {
+            result = calcB24(dsTaskDetailList);
+        } else if ("B25".equals(code)) {
+            result = calcB25(dsTaskDetailList);
+        } else if ("B31".equals(code)) {
+            // 鐙珛鍙傝�冩寚鏍囦笉鍙備笌鍔犳潈璁$畻
+        } else if ("B32".equals(code)) {
+            result = calcB32(dsTaskDetailList);
+        } else if ("B33".equals(code)) {
+            // 鐙珛鍙傝�冩寚鏍囦笉鍙備笌鍔犳潈璁$畻
+        } else if ("B34".equals(code)) {
+            result = calcB34(dsTaskDetailList);
+        } else if ("B35".equals(code)) {
+            // 鐙珛鍙傝�冩寚鏍囦笉鍙備笌鍔犳潈璁$畻
+        } else if ("B36".equals(code)) {
+            result = calcB36(dsTaskDetailList);
+        } else if ("B41".equals(code)) {
+            result = calcB41(dsTaskDetailList);
+        } else if ("B42".equals(code)) {
+            result = calcB42(dsTaskDetailList);
+        } else if ("B43".equals(code)) {
+            result = calcB43(dsTaskDetailList);
+        } else if ("B44".equals(code)) {
+            result = calcB44(dsTaskDetailList);
+        } else if ("B45".equals(code)) {
+            result = calcB45(dsTaskDetailList);
+        }
+        log.debug("銆�" + code + "銆戞潈閲嶅�� ===锛�" + weights);
+        log.debug("銆�" + code + "銆戣绠楃粨鏋� ===锛�" + result);
+        log.debug("銆�" + code + "銆戝姞鏉冨�� ===锛�" + result * weights);
+        return result * weights;
+    }
+
+    // 璁$畻鏈�缁堝垎鏁�
+    private Double getScore(List<DsEffectAssessList> list){
+        Double score = 0.0;
+        if(null != list  && list.size() > 0){
+            Map<String, List<DsEffectAssessList>> groupedByCode = list.stream()
+                    .collect(Collectors.groupingBy(item -> item.getCODE().substring(0, 2)));
+
+            for (Map.Entry<String, List<DsEffectAssessList>> berthEntry : groupedByCode.entrySet()) {
+                DsEffectAssessList effectAssess = berthEntry.getValue().get(0);
+                Double classifyWeight = null == effectAssess.getClassifyWeight()?0.0:effectAssess.getClassifyWeight();
+
+                Double totalValue = berthEntry.getValue().stream()
+                        .mapToDouble(item -> item.getVal() * item.getWEIGHT())
+                        .sum();
+                score += totalValue * classifyWeight;
+            }
+        }
+        return NumberUtils.roundToTwoDecimalPlaces(score);
+    }
+
+    /**
+     * B12锛氳埌鑸瑰钩鍧囦换鍔℃椂闂达細鏈腐浠嶵鏃跺埢璧风畻锛屾墍鏈夎埌鑸逛粠绛夊緟鍒板畬鎴愯ˉ缁欑殑骞冲潎鏃堕棿銆�
+     * 鍏紡锛�10*(璇ュ師濮嬫寚鏍�/B11)銆傛敞锛氳绠楃殑鏄埌鑸瑰钩鍧囪ˉ缁欐椂闂翠笌骞冲潎浠诲姟鏃堕棿鐨勬瘮渚嬶紝璇ュ�艰秺澶ц秺濂�
+     * @return
+     */
+    private int calcB12(List<DsTaskDetail> dsTaskDetails) {
+        double result = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                int oilTime = dsTaskDetail1.getOilTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                // result += DateUtils.getDisHourOfTowDate(tTime,eTime1);
+                result += oilTime + matTime +  ammoTime + waterTime;
+            }
+        }
+        double temp = (result / dsTaskDetails.size() / B11_VALUE) > 1 ? 1 : (result / dsTaskDetails.size() / B11_VALUE);
+        log.debug("B12 Value =====锛�" + (10 * Double.parseDouble(df2.format(temp))));
+        return (int) (10 * Double.parseDouble(df2.format(temp)));
+    }
+
+    /**
+     * B13锛氳埌鑸瑰钩鍧囩瓑寰呮椂闂达細鏈腐浠嶵鏃跺埢璧风畻锛屽悗缁墍鏈夎埌鑸圭瓑寰呮椂闂村潎鍊笺��
+     * 鍏紡锛�10*(1-璇ュ師濮嬫寚鏍�/B11)銆傛敞锛氳绠楃殑鏄埌鑸瑰钩鍧囩瓑寰呮椂闂翠笌骞冲潎浠诲姟鏃堕棿鐨勬瘮渚嬶紝绛夊緟鏃堕棿瓒婂皬瓒婂ソ锛屾墍浠ユ姌绠楁寚鏍囩敤1鍑忓幓璇ュ��
+     * @return
+     */
+    private int calcB13(List<DsTaskDetail> dsTaskDetails){
+        // 鎸夊姞娌归渶姹傘�佽埞绫诲瀷鍜屾姷娓椂闂存帓搴�
+        dsTaskDetails.sort(Comparator.comparing(DsTaskDetail::getBerthId).thenComparing(DsTaskDetail::getSupplySeq));
+
+        // 鎸夋硦浣嶅彿杩涜鍒嗙粍
+        Map<Long, List<DsTaskDetail>> detailMap = new HashMap<>();
+        for (DsTaskDetail detail : dsTaskDetails) {
+            Long berthId = detail.getBerthId();
+            detailMap.computeIfAbsent(berthId, k -> new ArrayList<>()).add(detail);
+        }
+        double waitTime = 0.0;
+        for (List<DsTaskDetail> groupDsTaskDetails : detailMap.values()) {
+            Date startTDate = null;
+            for (int i = 0; i < groupDsTaskDetails.size(); i++) {
+                DsTaskDetail detail = groupDsTaskDetails.get(i);
+                if (i == 0) {
+                    startTDate = detail.getT1();
+                }
+                Date sTime = detail.getSTIME();
+                waitTime += DateUtils.getDisHourOfTowDate(startTDate, sTime);
+            }
+        }
+        double temp = (waitTime / B11_VALUE) > 1 ? 1 : (waitTime / B11_VALUE);
+        log.debug("B13 Value =====锛�" + (10 * (1 - Double.parseDouble(df2.format(temp)))));
+        return (int) (10 * (1 - Double.parseDouble(df2.format(temp))));
+    }
+
+    /**
+     * B14锛氬崟鑸版姌鍙犺ˉ缁欐椂闂达細鏈腐琛ョ粰璧锋鏃堕棿宸�/鑸拌墖鏁伴噺銆�
+     * 24灏忔椂浠ヤ笂0鍒嗭紝18-24灏忔椂2鍒嗭紝12-18灏忔椂4鍒嗭紝8-12灏忔椂6鍒嗭紝4-8灏忔椂8鍒嗭紝4灏忔椂浠ヤ笅10鍒�
+     * @return
+     */
+    private int calcB14(List<DsTaskDetail> dsTaskDetails){
+        double result = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail = dsTaskDetails.get(i);
+                // Date sTime1 = dsTaskDetail.getSTIME();
+                int oilTime = dsTaskDetail.getOilTime();
+                int matTime = dsTaskDetail.getMatTime();
+                int ammoTime = dsTaskDetail.getAmmoTime();
+                int waterTime = dsTaskDetail.getWaterTime();
+                result += oilTime + matTime +  ammoTime + waterTime;
+                // result += DateUtils.getDisHourOfTowDate(sTime1, eTime1);
+            }
+            double point = result / (dsTaskDetails.size());
+            log.debug("B14 Value =====锛�" + point);
+            if(point >= 24){
+                return 0;
+            }else if(point > 18 && point <= 24){
+                return 2;
+            }else if(point > 12 && point <= 18){
+                return 4;
+            }else if(point > 8 && point <= 12){
+                return 6;
+            }else if(point > 4 && point <= 8){
+                return 8;
+            }else if(point <= 4){
+                return 10;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B15锛氳埌鑸瑰悓鏃惰ˉ缁欐暟閲忥細鏈腐鏍规嵁娉婁綅鏁板拰骞堕潬绛栫暐锛岃绠楀彲鍚屾椂琛ョ粰鐨勮埌鑸规暟銆�
+     * 10*鍘熷鎸囨爣/锛�2*鎬绘硦浣嶆暟锛夛紝娉細鎸夋湰娓墍鏈夋硦浣嶅彲鐢ㄤ笖鍙岃埌骞堕潬涓哄弬鑰冩暟锛屽ぇ浜�10鏃跺彇10
+     * @return
+     */
+    private int calcB15(List<DsTaskDetail> dsTaskDetails){
+        int berthCount = getBerthCountOfHarbor();
+
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            String parkingType = dsTaskDetails.get(0).getParkingType();
+            if ("1".equals(parkingType)) {
+                if (dsTaskDetails.size() >= berthCount) {
+                    return berthCount;
+                } else if (dsTaskDetails.size() < berthCount) {
+                    return dsTaskDetails.size();
+                }
+            } else if ("2".equals(parkingType)) {
+                if (dsTaskDetails.size() / 2 >= berthCount) {
+                    return berthCount * 2;
+                } else if (dsTaskDetails.size() / 2 < berthCount) {
+                    if (dsTaskDetails.size() % 2 == 0) {
+                        return dsTaskDetails.size() / 2;
+                    } else {
+                        return (dsTaskDetails.size() / 2) + 1;
+                    }
+                }
+            } else if ("3".equals(parkingType)) {
+                if (dsTaskDetails.size() / 3 >= berthCount) {
+                    return berthCount * 3;
+                } else if (dsTaskDetails.size() / 3 < berthCount) {
+                    if (dsTaskDetails.size() % 3 == 0) {
+                        return dsTaskDetails.size() / 3;
+                    } else {
+                        return (dsTaskDetails.size() / 3) + 1;
+                    }
+                }
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B16锛氬悇娉婁綅缁撴潫鏃堕棿鏈�澶у樊锛氭湰娓悇娉婁綅琛ョ粰浣滀笟鏈�缁堢粨鏉熸椂闂存渶澶у樊鍊笺��
+     * 24灏忔椂浠ヤ笂0鍒嗭紝16-24灏忔椂2鍒嗭紝12-16灏忔椂4鍒嗭紝8-12灏忔椂6鍒嗭紝4-8灏忔椂8鍒嗭紝4灏忔椂浠ュ唴10鍒�
+     * @return
+     */
+    private int calcB16(List<DsTaskDetail> dsTaskDetails){
+        List<Date> eTimeList = new ArrayList<>();
+        if(dsTaskDetails != null && dsTaskDetails.size() > 0){
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                Date sTime = dsTaskDetail1.getSTIME();
+                int oilTime = dsTaskDetail1.getOilTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int result = oilTime + matTime +  ammoTime + waterTime;
+                Date eTime = DateUtils.getDateAfterHours(sTime, result);
+                eTimeList.add(eTime);
+            }
+            // 鑾峰彇鏈�灏忔椂闂�
+            Date minDate = Collections.min(eTimeList);
+            // 鑾峰彇鏈�澶ф椂闂�
+            Date maxDate = Collections.max(eTimeList);
+            // 璁$畻鏃堕棿宸�
+            double dateInterval = DateUtils.getDisHourOfTowDate(minDate, maxDate);
+            log.debug("B16 Value =====锛�" + dateInterval);
+            if(dateInterval >= 24){
+                return 0;
+            }else if(dateInterval >= 16 && dateInterval < 24){
+                return 2;
+            }else if(dateInterval >= 12 && dateInterval < 16){
+                return 4;
+            }else if (dateInterval >= 8 && dateInterval < 12){
+                return 6;
+            }else if (dateInterval >= 4 && dateInterval < 8){
+                return 8;
+            }else if (dateInterval < 4){
+                return 10;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B17锛氳ˉ缁欏宸崰姣斿潎鍊硷細鏈腐鍚勮埌瀹瑰樊X鐩稿浜庤ˉ缁欐椂闂碅2鎵�鍗犳瘮渚嬬殑骞冲潎鍊笺��
+     * 10*(1-璇ュ師濮嬫寚鏍囧��)
+     * @return
+     */
+    private int calcB17(List<DsTaskDetail> dsTaskDetails) {
+        double allValue = 0.0;
+        for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+            DsTaskDetail detail = dsTaskDetails.get(i);
+            int oilTime = detail.getOilTime();
+            int ammoTime = detail.getAmmoTime();
+            int matTime = detail.getMatTime();
+            int waterTime = detail.getWaterTime();
+            int totalTime = oilTime + ammoTime + matTime + waterTime;
+            allValue += (double) totalTime / SUPPLY_X_TIME;
+        }
+        double avg = allValue / dsTaskDetails.size() > 1 ? 1 : allValue / dsTaskDetails.size();
+        log.debug("B17 Value =====锛�" + (10 * (1 - Double.parseDouble(df2.format(avg)))));
+        return (int) (10 * (1 - Double.parseDouble(df2.format(avg))));
+    }
+
+    /**
+     * B21锛氬崟鑸板钩鍧囧仠闈犳椂闂达細鏈腐鍚勮埌鑹囦粠T鏃跺埢鍒癟+X琛ョ粰缁撴潫鐨勫钩鍧囧�笺��
+     * 48灏忔椂浠ヤ笂4鍒嗭紝36-48灏忔椂6鍒嗭紝24-30灏忔椂8鍒嗭紝18-24灏忔椂10鍒嗭紝12-18灏忔椂8鍒嗭紝12灏忔椂浠ヤ笅6鍒嗭紝浠�24灏忔椂涓轰腑蹇冪殑姝f�佸垎甯冦��
+     * @return
+     */
+    private int calcB21(List<DsTaskDetail> dsTaskDetails) {
+        double dateInterval = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                Date tTime = dsTaskDetail1.getT1();
+                int oilTime = dsTaskDetail1.getOilTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int totalTime = oilTime + ammoTime + matTime + waterTime;
+                dateInterval += totalTime + 1;
+            }
+            double avg = dateInterval / dsTaskDetails.size();
+            log.debug("B21 Value =====锛�" + avg);
+            if (avg >= 48) {
+                return 4;
+            } else if (avg >= 36 && avg < 48) {
+                return 6;
+            } else if (avg >= 24 && avg < 30) {
+                return 8;
+            } else if (avg >= 18 && avg < 24) {
+                return 10;
+            } else if (avg >= 12 && avg < 18) {
+                return 8;
+            } else if (avg < 12) {
+                return 6;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B22锛氳ˉ缁欎綔涓氭椂闂村潎鍊硷細鍚勮埌鑹囦富绾胯ˉ缁欎綔涓氭椂闂寸殑骞冲潎鍊笺��
+     * 36灏忔椂浠ヤ笂4鍒嗭紝24-36灏忔椂6鍒嗭紝20-24灏忔椂8鍒嗭紝16-20灏忔椂10鍒嗭紝12-16灏忔椂8鍒嗭紝8灏忔椂浠ヤ笅6鍒嗭紝浠�18灏忔椂涓轰腑蹇冪殑姝f�佸垎甯冦��
+     * @return
+     */
+    private int calcB22(List<DsTaskDetail> dsTaskDetails){
+        double dateInterval = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                Date sTime = dsTaskDetail1.getSTIME();
+                int oilTime = dsTaskDetail1.getOilTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int result = oilTime + matTime +  ammoTime + waterTime;
+                dateInterval += result - X_TOLERANCE_VALUE;
+            }
+            double avg = dateInterval / dsTaskDetails.size();
+            log.debug("B22 Value =====锛�" + avg);
+            if(avg >= 36){
+                return 4;
+            }else if(avg >= 24 && avg < 36){
+                return 6;
+            }else if(avg >= 20 && avg < 24){
+                return 8;
+            }else if (avg >= 16 && avg < 20){
+                return 10;
+            }else if (avg >= 12 && avg < 16){
+                return 8;
+            }else if (avg < 8){
+                return 6;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B23锛氳ˉ缁欓潪浣滀笟鏃堕棿鍧囧�硷細锛堝悇鑸拌墖鍋滄硦鏃堕棿-浣滀笟鏃堕棿锛夌殑骞冲潎鍊笺��
+     * 24灏忔椂浠ヤ笂0鍒嗭紝16-24灏忔椂2鍒嗭紝12-16灏忔椂4鍒嗭紝8-12灏忔椂6鍒嗭紝4-8灏忔椂8鍒嗭紝4灏忔椂浠ュ唴10鍒嗐�傝鍊艰秺灏忚秺濂斤紝浣嗕篃涓嶅彲鑳戒负0锛屾墍浠�4灏忔椂浠ヤ笅鍧囦负鏈�濂姐��
+     * @return
+     */
+    private int calcB23(List<DsTaskDetail> dsTaskDetails){
+        double allTime = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                int oilTime = dsTaskDetail1.getOilTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int totalTime = oilTime + ammoTime + matTime + waterTime;
+
+                //int elecSTime = dsTaskDetail1.getElecStime();
+                //int elecETime = dsTaskDetail1.getElecEtime();
+
+                int waterSTime = dsTaskDetail1.getWaterStime();
+                int waterETime = dsTaskDetail1.getWaterEtime();
+
+                int oilSTime = dsTaskDetail1.getOilStime();
+                int oilETime = dsTaskDetail1.getOilEtime();
+
+                int ammoSTime = dsTaskDetail1.getAmmoStime();
+                int ammoETime = dsTaskDetail1.getAmmoEtime();
+
+                int matSTime = dsTaskDetail1.getMatStime();
+                int matETime = dsTaskDetail1.getMatEtime();
+
+                int workTime = (waterETime - waterSTime) + (oilETime - oilSTime) + (ammoETime - ammoSTime) + (matETime - matSTime);
+
+                allTime += Math.abs(totalTime + 1 - workTime);
+            }
+            double avg = allTime / dsTaskDetails.size();
+            log.debug("B23 Value =====锛�" + avg);
+            if(avg >= 24){
+                return 0;
+            }else if(avg >= 16 && avg < 24){
+                return 2;
+            }else if(avg >= 12 && avg < 16){
+                return 4;
+            }else if (avg >= 8 && avg < 12){
+                return 6;
+            }else if (avg >= 4 && avg < 8){
+                return 8;
+            }else if (avg < 4){
+                return 10;
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * B24锛氳ˉ缁欎綔涓氬仠娉婃瘮渚嬶細鍚勮埌绱琛ョ粰鏃堕棿鎬诲拰/绱闈犳硦鏃堕棿鎬诲拰
+     * 10*璇ュ師濮嬫寚鏍囧�笺��
+     * @return
+     */
+    private int calcB24(List<DsTaskDetail> dsTaskDetails) {
+        double allBerthTime = 0;
+        double allWorkTime = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                int oilTime = dsTaskDetail1.getOilTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int totalTime = oilTime + ammoTime + matTime + waterTime;
+
+                int waterSTime = dsTaskDetail1.getWaterStime();
+                int waterETime = dsTaskDetail1.getWaterEtime();
+
+                int oilSTime = dsTaskDetail1.getOilStime();
+                int oilETime = dsTaskDetail1.getOilEtime();
+
+                int ammoSTime = dsTaskDetail1.getAmmoStime();
+                int ammoETime = dsTaskDetail1.getAmmoEtime();
+
+                int matSTime = dsTaskDetail1.getMatStime();
+                int matETime = dsTaskDetail1.getMatEtime();
+
+                allWorkTime += (waterETime - waterSTime) + (oilETime - oilSTime) + (ammoETime - ammoSTime) + (matETime - matSTime);
+                allBerthTime += Math.abs(totalTime);
+            }
+            double temp = allWorkTime / allBerthTime > 1 ? 1 : allWorkTime / allBerthTime;
+            log.debug("B24 Value =====锛�" + (10 * (Double.parseDouble(df2.format(temp)))));
+            return (int) (10 * (Double.parseDouble(df2.format(temp))));
+        }
+        return 0;
+    }
+
+    /**
+     * B25锛氳ˉ缁欐椂闂存姌鍙犳瘮渚嬶細鏈壒琛ョ粰璧锋鏃堕棿宸�/鍚勮埌琛ョ粰鏃堕棿鎬诲拰
+     * 10*(1-璇ュ師濮嬫寚鏍囧��)
+     * @return
+     */
+    private int calcB25(List<DsTaskDetail> dsTaskDetails){
+        List<Date> eTimeList = new ArrayList<>();
+        double allWorkTime = 0;
+        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+            for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+                DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+                eTimeList.add(dsTaskDetail1.getSTIME());
+                int oilTime = dsTaskDetail1.getOilTime();
+                int ammoTime = dsTaskDetail1.getAmmoTime();
+                int matTime = dsTaskDetail1.getMatTime();
+                int waterTime = dsTaskDetail1.getWaterTime();
+                int totalTime = oilTime + ammoTime + matTime + waterTime + X_TOLERANCE_VALUE;
+                Date eTime = DateUtils.getDateAfterHours(dsTaskDetail1.getSTIME(), totalTime);
+                eTimeList.add(eTime);
+
+                int waterSTime = dsTaskDetail1.getWaterStime();
+                int waterETime = dsTaskDetail1.getWaterEtime();
+
+                int oilSTime = dsTaskDetail1.getOilStime();
+                int oilETime = dsTaskDetail1.getOilEtime();
+
+                int ammoSTime = dsTaskDetail1.getAmmoStime();
+                int ammoETime = dsTaskDetail1.getAmmoEtime();
+
+                int matSTime = dsTaskDetail1.getMatStime();
+                int matETime = dsTaskDetail1.getMatEtime();
+
+                allWorkTime += (waterETime - waterSTime) + (oilETime - oilSTime) + (ammoETime - ammoSTime) + (matETime - matSTime);
+            }
+            // 鑾峰彇鏈�灏忔椂闂�
+            Date minDate = Collections.min(eTimeList);
+            // 鑾峰彇鏈�澶ф椂闂�
+            Date maxDate = Collections.max(eTimeList);
+            // 璁$畻鏃堕棿宸�
+            double dateInterval = DateUtils.getDisHourOfTowDate(maxDate, minDate);
+            double temp = (dateInterval / allWorkTime) > 1 ? 1 : (dateInterval / allWorkTime);
+            log.debug("B25 Value =====锛�" + (10 * (1 - Double.parseDouble(df2.format(temp)))));
+            return (int) (10 * (1 - Double.parseDouble(df2.format(temp))));
+        }
+        return 0;
+    }
+
+    /**
+     * B32锛氭按鐢典繚闅滄棩浣滀笟寮哄害锛氬悇姘寸數灏忕粍24灏忔椂鍐呭钩鍧囦綔涓氭椂闂�/24灏忔椂锛屽钩鍧囧��
+     * 10 * 璇ュ師濮嬫寚鏍囧��
+     * @return
+     */
+    private int calcB32(List<DsTaskDetail> dsTaskDetails){
+        double allTime = 0;
+        for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+            DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+            // int elecSTime = dsTaskDetail1.getElecStime();
+            // int elecETime = dsTaskDetail1.getElecEtime();
+            // int eleTime = elecETime - elecSTime;
+            int waterTime = dsTaskDetail1.getWaterTime();
+            allTime += waterTime;
+        }
+        double avgValue = (allTime / (dsTaskDetails.size() * 24)) > 1 ? 1 : (allTime / (dsTaskDetails.size() * 24));
+        log.debug("B32 Value =====锛�" + (10 * Double.parseDouble(df2.format(avgValue))));
+        return (int) (10 * Double.parseDouble(df2.format(avgValue)));
+    }
+
+    /**
+     * B34锛氭补鏂欒ˉ缁欐棩浣滀笟寮哄害锛氬悇鍔犳补灏忕粍24灏忔椂鍐呭钩鍧囦綔涓氭椂闂�/24灏忔椂锛屽钩鍧囧��
+     * 10 * 璇ュ師濮嬫寚鏍囧��
+     * @return
+     */
+    private int calcB34(List<DsTaskDetail> dsTaskDetails){
+        double days = 0;
+        double allTime = 0;
+        for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+            DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+            Date sTime= dsTaskDetail1.getSTIME();
+            int oilTime = dsTaskDetail1.getOilTime();
+            Date oilEndTime = DateUtils.getDateAfterHours(sTime, oilTime);
+
+            double hourDistance = DateUtils.getDisHourOfTowDate(sTime, oilEndTime);
+            if(hourDistance < 24){
+                days += 1;
+            }else {
+                days += (int) Math.ceil(hourDistance / 24);
+            }
+            allTime += oilTime;
+        }
+        double avgValue = (allTime / (days * 24)) > 1 ? 1 : (allTime / (days * 24));
+        log.debug("B34 Value =====锛�" + (10 * Double.parseDouble(df2.format(avgValue))));
+        return (int) (10 * Double.parseDouble(df2.format(avgValue)));
+    }
+
+    /**
+     * B36锛氱墿璧勮ˉ缁欐棩浣滀笟寮哄害锛氬悇鐗╄祫杞﹁締24灏忔椂鍐呬綔涓氭椂闂�/24灏忔椂锛屽钩鍧囧��
+     * 10 * 璇ュ師濮嬫寚鏍囧��
+     * @return
+     */
+    private int calcB36(List<DsTaskDetail> dsTaskDetails) {
+        double days = 0;
+        double allTime = 0;
+        for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+            DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+            Date sTime= dsTaskDetail1.getSTIME();
+            int matTime = dsTaskDetail1.getMatTime();
+            Date matEndTime = DateUtils.getDateAfterHours(sTime, matTime);
+
+            double hourDistance = DateUtils.getDisHourOfTowDate(sTime, matEndTime);
+            if(hourDistance < 24){
+                days += 1;
+            }else {
+                days += (int) Math.ceil(hourDistance / 24);
+            }
+            allTime += matTime;
+        }
+        double avgValue = (allTime / (days * 24)) > 1 ? 1 : (allTime / (days * 24));
+        log.debug("B36 Value =====锛�" + (10 * Double.parseDouble(df2.format(avgValue))));
+        return (int) (10 * Double.parseDouble(df2.format(avgValue)));
+    }
+
+    /**
+     * B41锛氭硦浣嶆棩鍧囧懆杞墭娆★細鏈腐琛ョ粰鑸拌埞鎬绘暟閲�/澶╂暟/娉婁綅鏁�
+     * 10 * 璇ュ師濮嬫寚鏍囧��/3锛屾敞锛�3涓哄弬鑰冨�硷紝閫氬父鏈�澶у懆杞噺涓嶅ぇ浜�3锛堝氨鏄笁鑹樺苟闈�1澶╃殑鎯呭喌锛夛紝濡傛灉澶т簬10鍒欏彇鍊间负10
+     * @return
+     */
+    private int calcB41(List<DsTaskDetail> dsTaskDetails) {
+        List<Date> timeList = new ArrayList<>();
+        for (int i = 0; i < dsTaskDetails.size() - 1; i++) {
+            DsTaskDetail dsTaskDetail1 = dsTaskDetails.get(i);
+            timeList.add(dsTaskDetail1.getSTIME());
+            int oilTime = dsTaskDetail1.getOilTime();
+            int ammoTime = dsTaskDetail1.getAmmoTime();
+            int matTime = dsTaskDetail1.getMatTime();
+            int waterTime = dsTaskDetail1.getWaterTime();
+            int totalTime = oilTime + ammoTime + matTime + waterTime;
+            Date eTime = DateUtils.getDateAfterHours(dsTaskDetail1.getSTIME(), totalTime + X_TOLERANCE_VALUE);
+            timeList.add(eTime);
+        }
+        // 鑾峰彇鏈�灏忔椂闂�
+        Date minDate = Collections.min(timeList);
+        // 鑾峰彇鏈�澶ф椂闂�
+        Date maxDate = Collections.max(timeList);
+        // 璁$畻鏃堕棿宸�
+        double days = DateUtils.getSubtractOfTowDate(maxDate, minDate);
+        int berthCount = getBerthCountOfHarbor();
+        double originalValue = (dsTaskDetails.size() / days / berthCount / 3) > 1 ? 1 : (dsTaskDetails.size() / days / berthCount / 3);
+        log.debug("B41 Value =====锛�" + (10 * Double.parseDouble(df2.format(originalValue))));
+        return (int) (10 * Double.parseDouble(df2.format(originalValue)));
+    }
+
+    /**
+     * B42锛氬墠娌垮崰鍦版渶澶у潎鍊硷細鏈腐琛ョ粰鍚勬腐鍚勭爜澶村悇娉婁綅鏈�澶у崰鍦板潎鍊�
+     * 妫�绱㈠悇鍓嶆部鍦哄湴鍗犵敤鐜囷紝鍙栨渶澶у�煎潎鍊�
+     * @return
+     */
+    private int calcB42(List<DsTaskDetail> dsTaskDetails) {
+        double allValue = 0.0;
+        for (int i = 1; i <= 24; i++) {
+            String timeSlot = "t" + i;
+            int oilCount = 0;
+            int ammoCount = 0;
+            int matCount = 0;
+            for (DsTaskDetail task : dsTaskDetails) {
+                if (task.getOilStime() != null && task.getOilStime() <= i && task.getOilEtime() >= i) {
+                    oilCount++;
+                } else if (task.getAmmoStime() != null && task.getAmmoStime() <= i && task.getAmmoEtime() >= i) {
+                    ammoCount++;
+                } else if (task.getMatStime() != null && task.getMatStime() <= i && task.getMatEtime() >= i) {
+                    matCount++;
+                }
+            }
+
+            Double totalSupply = NumberUtils.roundToTwoDecimalPlaces(oilCount * OIL_PLACE_PER + ammoCount * AMMO_PLACE_PER + matCount * MAT_PLACE_PER);
+            double maxPlat = 0.0;
+            if(maxPlat < totalSupply){
+                maxPlat = totalSupply;
+            }
+            allValue += maxPlat;
+        }
+        double temp = (allValue / dsTaskDetails.size()) > 1 ? 1 : (allValue / dsTaskDetails.size());
+        log.debug("B42 Value =====锛�" + (10 * Double.parseDouble(df2.format(temp))));
+        return (int) (10 * Double.parseDouble(df2.format(temp)));
+    }
+
+    /**
+     * B43锛氬墠娌垮崰鍗婃椂闀垮潎鍊硷細鏈腐琛ョ粰鍚勬硦浣嶉涓�24灏忔椂鍐呭崰鍦�0.5浠ヤ笂鐨勬椂闂村潎鍊�
+     * 10*璇ュ師濮嬫寚鏍囧��/24锛屾敞锛氬熀鍑嗗�煎彇24灏忔椂
+     * @return
+     */
+    private int calcB43(List<DsTaskDetail> dsTaskDetails) {
+        Integer platTime = 0;
+        for (int i = 1; i <= 24; i++) {
+            int oilCount = 0;
+            int ammoCount = 0;
+            int matCount = 0;
+            for (DsTaskDetail task : dsTaskDetails) {
+                if (task.getOilStime() != null && task.getOilStime() <= i && task.getOilEtime() >= i) {
+                    oilCount++;
+                } else if (task.getAmmoStime() != null && task.getAmmoStime() <= i && task.getAmmoEtime() >= i) {
+                    ammoCount++;
+                } else if (task.getMatStime() != null && task.getMatStime() <= i && task.getMatEtime() >= i) {
+                    matCount++;
+                }
+            }
+            Double totalSupply = NumberUtils.roundToTwoDecimalPlaces(oilCount * OIL_PLACE_PER + ammoCount * AMMO_PLACE_PER + matCount * MAT_PLACE_PER);
+            if(totalSupply >= 0.5){
+                platTime++;
+            }
+        }
+        double temp = (platTime / 24) > 1 ? 1 : (platTime / 24);
+        log.debug("B43 Value =====锛�" + (10 * Double.parseDouble(df2.format(temp))));
+        return (int) (10 * Double.parseDouble(df2.format(temp)));
+    }
+
+    /**
+     * B44锛氬姞娌硅鏂芥棩鍧囦娇鐢ㄧ巼锛氭湰娓寜娉婁綅缁熻璁炬柦棣栦釜24灏忔椂鍐呭姞娌逛綔涓氭椂闂�/24灏忔椂锛屾眰鍧囧��
+     * 妫�绱㈠悇娉婁綅棣栦釜24灏忔椂鍐呭姞娌逛綔涓氭椂闂�/24
+     * @return
+     */
+    private int calcB44(List<DsTaskDetail> dsTaskDetails) {
+        // 鎸夊姞娌归渶姹傘�佽埞绫诲瀷鍜屾姷娓椂闂存帓搴�
+        dsTaskDetails.sort(Comparator.comparing(DsTaskDetail::getBerthId).thenComparing(DsTaskDetail::getSupplySeq));
+
+        // 鎸夋硦浣嶅彿杩涜鍒嗙粍
+        Map<Long, List<DsTaskDetail>> detailMap = new HashMap<>();
+        for (DsTaskDetail detail : dsTaskDetails) {
+            Long berthId = detail.getBerthId();
+            detailMap.computeIfAbsent(berthId, k -> new ArrayList<>()).add(detail);
+        }
+        Date after24Hour = null; // 棣栦釜24灏忔椂鎴鏃堕棿
+        double allTime = 0.0;
+        for (List<DsTaskDetail> groupDsTaskDetails : detailMap.values()) {
+            for (int i = 0; i < groupDsTaskDetails.size(); i++) {
+                DsTaskDetail detail1 = groupDsTaskDetails.get(i);
+                int oilStartTime = detail1.getOilStime();
+                int oilEndTime = detail1.getOilEtime();
+                int oilTime = detail1.getOilTime();
+                Date t1Date = detail1.getT1();
+                Date oilStartDate = DateUtils.getDateAfterHours(t1Date, oilStartTime);
+                Date oilEndDate = DateUtils.getDateAfterHours(t1Date, oilTime);
+
+                if (i == 0) {
+                    after24Hour = DateUtils.getDateAfterHours(t1Date, 24);
+                }
+
+                if (oilStartDate.before(after24Hour) && oilEndDate.before(after24Hour)) {
+                    allTime += oilTime;
+                } else if (oilStartDate.before(after24Hour) && oilEndDate.after(after24Hour)) {
+                    allTime += DateUtils.getDisHourOfTowDate(oilStartDate, after24Hour);
+                } else {
+                    allTime += 0;
+                }
+            }
+        }
+        double temp = (allTime / 24) > 1 ? 1 : (allTime / 24);
+        log.debug("B44 Value =====锛�" + (10 * Double.parseDouble(df2.format(temp))));
+        return (int) (10 * Double.parseDouble(df2.format(temp)));
+    }
+
+    /**
+     * B45锛氬悇娉婁綅鐗╄祫杞︽鍧囧�硷細鏈腐琛ョ粰鍚勬硦浣嶉涓�24灏忔椂鍐呯墿璧勮溅杈嗘潵寰�娆℃暟鐨勫潎鍊�
+     * 10 * 璇ュ師濮嬫寚鏍囧��/24锛屾敞锛氬熀鍑嗗�煎彇24锛屽嵆骞冲潎姣忓皬鏃�1杞︽琛ョ粰銆�
+     * @return
+     */
+    private static final int VECHILE_COUNT = 10; // 杞﹁締鏁伴噺
+    private int calcB45(List<DsTaskDetail> dsTaskDetails) {
+        // 鎸夋硦浣嶃�佽ˉ缁欓『搴忔帓搴�
+        dsTaskDetails.sort(Comparator.comparing(DsTaskDetail::getBerthId).thenComparing(DsTaskDetail::getSupplySeq));
+
+        // 鎸夋硦浣嶅彿杩涜鍒嗙粍
+        Map<Long, List<DsTaskDetail>> detailMap = new HashMap<>();
+        for (DsTaskDetail detail : dsTaskDetails) {
+            Long berthId = detail.getBerthId();
+            detailMap.computeIfAbsent(berthId, k -> new ArrayList<>()).add(detail);
+        }
+        Date after24Hour = null; // 棣栦釜24灏忔椂鎴鏃堕棿
+        double allCount = 0.0;
+        for (List<DsTaskDetail> groupDsTaskDetails : detailMap.values()) {
+            for (int i = 0; i < groupDsTaskDetails.size(); i++) {
+                DsTaskDetail detail1 = groupDsTaskDetails.get(i);
+                int matStartTime = detail1.getMatStime();
+                int matEndTime = detail1.getMatEtime();
+                int matTime = detail1.getMatTime();
+                Date t1Date = detail1.getT1();
+                Date matStartDate = DateUtils.getDateAfterHours(t1Date, matStartTime);
+                Date matEndDate = DateUtils.getDateAfterHours(t1Date, matEndTime);
+
+                if (i == 0) {
+                    after24Hour = DateUtils.getDateAfterHours(t1Date, 24);
+                }
+
+                if (matStartDate.before(after24Hour) && matEndDate.before(after24Hour)) {
+                    allCount += detail1.getFood() + detail1.getFoodO() + detail1.getFoodW();
+                } else {
+                    allCount += 0;
+                }
+            }
+        }
+        double temp = (allCount / VECHILE_COUNT / 24) > 1? 1 : (allCount / VECHILE_COUNT / 24);
+        log.debug("B45 Value =====锛�" + (10 * Double.parseDouble(df2.format(temp))));
+        return  (int) (10 * Double.parseDouble(df2.format(temp)));
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛褰撳墠鎵�鍦ㄩ儴闂紝鑾峰彇鐢ㄦ埛绠¤緰涓嬬殑娓彛娉婁綅鏁伴噺銆�
+     * @return
+     */
+    private int getBerthCountOfHarbor(){
+        LoginUser sysUser = getLoginUser();
+        Long deptId = sysUser.getDeptId();
+        DmBerth2 dmBerth2 = new DmBerth2();
+        dmBerth2.setDeptId(deptId);
+        List<DmBerth2> dmBerth2List = dmBerth2Service.selectDmBerthList(dmBerth2);
+        return dmBerth2List.size();
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdSupplyPlanController.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdSupplyPlanController.java
new file mode 100644
index 0000000..13b6cdc
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/controller/ZdSupplyPlanController.java
@@ -0,0 +1,621 @@
+package com.ruoyi.buss.controller;
+
+/**
+ * 鏀槦鑸拌埞琛ョ粰璁″垝閫昏緫Controller
+ *
+ * @author yl
+ * @date 2025-03-20
+ */
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.buss.domain.DsTaskDetail;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.ZdSupplyPlanDTO;
+import com.ruoyi.buss.service.IDsTaskDetailService;
+import com.ruoyi.buss.service.IDsTaskList2Service;
+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.model.LoginUser;
+import com.ruoyi.common.enums.BusinessType;
+import com.ruoyi.common.utils.DateUtils;
+import com.ruoyi.system.service.ISysDictDataService;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import java.io.IOException;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+@Tag(name = "鏀槦鑸拌埞琛ョ粰璁″垝")
+@Controller
+@RequestMapping("/buss/zd/supplyplan")
+public class ZdSupplyPlanController extends BaseController {
+    private static final Logger log = LoggerFactory.getLogger(ZdSupplyPlanController.class);
+
+    private static SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+
+    private static String OIL_SUPPLY_TYPE = "1";
+    private static String MISSILE_SUPPLY_TYPE = "2";
+    private static String GOODS_SUPPLY_TYPE = "3";
+    private static String WATER_SUPPLY_TYPE = "4";
+
+    private static int OIL_UNIT_NUM = 100;  // 鍗曚綅锛�100鍚�
+    private static int WATER_UNIT_NUM = 10;  // 鍗曚綅锛�10鍚�
+    private static int GOODS_UNIT_NUM = 1;  // 鍗曚綅锛�1杞�
+    private static int MISSILE_UNIT_NUM = 4; //鍗曚綅锛�4鏋�
+
+    // 濡備笅瀹氫箟054銆�056銆�073鑸板瀷涓嶅悓琛ョ粰绫诲瀷鍗曚綅鏁伴噺鎵�闇�鏃堕棿
+    private static int[] OIL_USE_TIME = new int[]{3, 3, 3, 3, 3}; // 100鍚ㄦ补鏂欐墍闇�鏃堕棿
+    private static int[] WATER_USE_TIME = new int[]{1, 1, 1, 1, 1};  // 10鍚ㄦ贰姘存墍闇�鏃堕棿
+    private static int[] GOODS_USE_TIME = new int[]{2, 2, 2, 2, 2};  // 1杞︾墿璧勬惉杩愪笂鑸�2灏忔椂
+    private static int[] MISSILE_USE_TIME = new int[]{4, 4, 4, 4, 4};  // 10鍚ㄧ墿璧勬墍闇�鏃堕棿
+
+    // 瀹氫箟鑸板瀷
+    private static String[] SHIP_TYPE = new String[]{"052D", "054A", "056A", "071", "072"};
+
+    @Autowired
+    private IDsTaskList2Service dsTaskListService;
+    @Autowired
+    private IDsTaskDetailService dsTaskDetailService;
+    @Autowired
+    private ISysDictDataService sysDictDataService;
+
+    @Operation(description = "鑾峰彇鏀槦鑸拌埞琛ョ粰璁″垝")
+    @Log(title = "鏀槦琛ョ粰璁″垝", businessType = BusinessType.INSERT)
+    @PostMapping("/get")
+    @ResponseBody
+    public AjaxResult getZdSupplyPlan(@RequestBody ZdSupplyPlanDTO zdSupplyPlanDTO) throws IOException, ParseException {
+        Long taskId = zdSupplyPlanDTO.getTaskId();
+        String t1Time = zdSupplyPlanDTO.getT1Time();
+        String usedBerthIds = zdSupplyPlanDTO.getUsedBerthIds();
+
+        LoginUser sysUser = getLoginUser();
+        Long deptId = sysUser.getDeptId();
+
+        JSONArray rootJSONArray = new JSONArray();
+        if (usedBerthIds != null && usedBerthIds.length() > 0) {
+            String[] berthIdArray = usedBerthIds.split(","); // usedBerthIds涓哄涓硦浣岻D锛屼互閫楀彿鍒嗛殧
+            for (int i = 0; i < berthIdArray.length; i++) {
+                JSONObject rootJSONObj = new JSONObject();
+                JSONArray jsonArray = new JSONArray();
+                JSONObject sub1JsonObj = new JSONObject();
+                List<DsTaskList2> dsTaskLists = dsTaskListService.getDsTaskListForSupplyPlan(deptId, taskId, Long.parseLong(berthIdArray[i]));
+
+                // 閬嶅巻鍚勬硦浣嶇殑鍚勮埌鑸癸紝璁$畻姣忚墭鑸拌埞鎵�闇�琛ョ粰鏃堕棿锛岀敓鎴愬悇鑸拌埞鐨勮ˉ缁欒鍒掓暟鎹�
+                if (dsTaskLists.size() > 0) {
+                    sub1JsonObj.put("harborName", dsTaskLists.get(0).getHarborName());
+                    sub1JsonObj.put("berthName", dsTaskLists.get(0).getBerthName());
+                    sub1JsonObj.put("berthId", dsTaskLists.get(0).getBerthId());
+                    sub1JsonObj.put("parkingType", dsTaskLists.get(0).getParkingType());
+                    // 宀哥數鑺傜偣鎬绘椂闀�
+                    int andianTotalTime = 0;
+                    // 娣℃按琛ョ粰鎬绘椂闀�
+                    int waterTotalTime = 0;
+                    // 鐕冩枡琛ョ粰鎬绘椂闀�
+                    int oilTotalTime = 0;
+                    // 寮硅嵂琛ョ粰鎬绘椂闀�
+                    int missileTotalTime = 0;
+                    // 鐗╄祫琛ョ粰鎬绘椂闀�
+                    int goodsTotalTime = 0;
+
+                    JSONArray subJSONArray = new JSONArray();
+                    for (int j = 0; j < dsTaskLists.size(); j++) {
+                        DsTaskDetail dsTaskDetail = new DsTaskDetail();
+                        JSONObject jsonObj =  new JSONObject();
+                        DsTaskList2 tempDsTaskList = dsTaskLists.get(j);
+                        String shipType = tempDsTaskList.getShipType(); // 鑸板瀷
+                        String shipNo = tempDsTaskList.getShipNo(); // 鑸峰彿
+                        String supplySeq = tempDsTaskList.getSupplySeq(); // 琛ョ粰搴忓垪
+
+                        String supplySeqLabel = sysDictDataService.selectDictLabel("dd_rule_supply", supplySeq); // 琛ョ粰搴忓垪鏍囩
+                        // 绗竴缂嗙怀
+                        String firstCabelLabel = "T" + (j + 1);
+                        // 宀哥數鎺ョ數璧峰鏃堕棿Label
+                        String andianStartTimeLabel = firstCabelLabel + "+1";
+
+                        // 娣℃按琛ョ粰璧峰鏃堕棿Label
+                        String waterStartTimeLabel = firstCabelLabel + "+1";
+                        // 娣℃按琛ョ粰缁撴潫鏃堕棿Label
+                        int addWaterTimeNum = calcSupplyTimeBySupplyType(WATER_SUPPLY_TYPE, shipType, tempDsTaskList.getWATER());
+                        String waterEndTimeLabel = firstCabelLabel + "+" +(addWaterTimeNum + 1);
+                        waterTotalTime += addWaterTimeNum;
+
+                        // 鐕冩补琛ョ粰鏃堕棿Label
+                        String oilStartTimeLabel = "";
+                        String oilEndTimeLabel = "";
+                        // 寮硅嵂琛ョ粰鏃堕棿Label
+                        String missileStartTimeLabel = "";
+                        String missileEndTimeLabel = "";
+
+                        // 琛ョ粰缁撴潫娴嬬畻鏃堕棿
+                        String supplyEndTimeLabel = "";
+                        Double oilA = tempDsTaskList.getOilA() == null ? 0 : tempDsTaskList.getOilA();
+                        Double oilB = tempDsTaskList.getOilB() == null ? 0 : tempDsTaskList.getOilB();
+                        Double oilG = tempDsTaskList.getOilG() == null ? 0 : tempDsTaskList.getOilG();
+                        double totalOilNum = oilA + oilB + oilG; // 鎬诲姞娌归噺
+                        int addOilTimeNum = calcSupplyTimeBySupplyType(OIL_SUPPLY_TYPE, shipType, totalOilNum);
+                        Long ammoD = tempDsTaskList.getAmmoD() == null ? 0 : tempDsTaskList.getAmmoD();
+                        int addMissileTimeNum = calcSupplyTimeBySupplyType(MISSILE_SUPPLY_TYPE, shipType, (double) ammoD);
+                        if("1".equals(tempDsTaskList.getSupplySeq())){//鍚屾椂杩涜
+                            oilStartTimeLabel = firstCabelLabel + "+" + "2";
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            missileStartTimeLabel = firstCabelLabel + "+" + "2";;
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            if(addOilTimeNum > addMissileTimeNum){
+                                supplyEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + 1);
+                                dsTaskDetail.setETIME(DateUtils.addDays(format.parse(t1Time), addOilTimeNum + 2 + 1));
+                            }else{
+                                supplyEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + 1);
+                                dsTaskDetail.setETIME(DateUtils.addDays(format.parse(t1Time), addMissileTimeNum + 2 + 1));
+                            }
+
+                            dsTaskDetail.setOilStime(2);
+                            dsTaskDetail.setOilEtime(2 + addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(2);
+                            dsTaskDetail.setAmmoEtime(2 + addMissileTimeNum);
+                        }else if("2".equals(tempDsTaskList.getSupplySeq())){//鍏堟补鍚庡脊
+                            oilStartTimeLabel = firstCabelLabel + "+" + "2";
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            missileStartTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + addMissileTimeNum);
+                            supplyEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + addMissileTimeNum + 1);
+
+                            dsTaskDetail.setOilStime(2);
+                            dsTaskDetail.setOilEtime(2+ addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(addOilTimeNum + 2 + 1);
+                            dsTaskDetail.setAmmoEtime(addOilTimeNum + 2 + 1 + addMissileTimeNum);
+                            dsTaskDetail.setETIME(DateUtils.addDays(format.parse(t1Time), addOilTimeNum + 2 + addMissileTimeNum + 1));
+                        }else if("3".equals(tempDsTaskList.getSupplySeq())){//鍏堝脊鍚庢补
+                            missileStartTimeLabel = firstCabelLabel + "+2";
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            oilStartTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + addOilTimeNum);
+                            supplyEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + addOilTimeNum + 1);
+
+                            dsTaskDetail.setOilStime(addMissileTimeNum + 2 + 1);
+                            dsTaskDetail.setOilEtime(addMissileTimeNum + 2 + 1 + addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(2);
+                            dsTaskDetail.setAmmoEtime(addMissileTimeNum + 2);
+                            dsTaskDetail.setETIME(DateUtils.addDays(format.parse(t1Time), addMissileTimeNum + 2 + addOilTimeNum + 1));
+                        }
+                        oilTotalTime += addOilTimeNum;
+                        missileTotalTime += addMissileTimeNum;
+
+                        if(addOilTimeNum >= addMissileTimeNum){
+                            andianTotalTime += addOilTimeNum;
+                        } else {
+                            andianTotalTime += addMissileTimeNum;
+                        }
+
+                        // 鐗╄祫琛ョ粰鏃堕棿Label
+                        String goodsStartTimeLabel = "";
+                        String goodsEndTimeLabel = "";
+                        Long food = tempDsTaskList.getFOOD() == null? 0 : tempDsTaskList.getFOOD();
+                        Long foodW = tempDsTaskList.getFoodW() == null? 0 : tempDsTaskList.getFoodW();
+                        Long foodO = tempDsTaskList.getFoodO() == null? 0 : tempDsTaskList.getFoodO();
+                        double totalGoodsNum = food + foodW + foodO; // 鎬诲姞鐗╄祫閲�
+                        int addGoodTimeNum = calcSupplyTimeBySupplyType(GOODS_SUPPLY_TYPE, shipType, totalGoodsNum);
+                        goodsStartTimeLabel = firstCabelLabel + "+2";
+                        goodsEndTimeLabel = firstCabelLabel + "+" + (addGoodTimeNum + 2);
+                        goodsTotalTime += addGoodTimeNum;
+
+                        // 鏋勫缓姣忚墭鑸拌埞鏋勫缓JSON瀵硅薄
+                        jsonObj.put("id", String.valueOf(j+1));
+                        jsonObj.put("shipType", shipType);
+                        jsonObj.put("shipNo", shipNo);
+                        jsonObj.put("supplySeq", supplySeqLabel);
+                        jsonObj.put("sTime", firstCabelLabel);
+                        jsonObj.put("electSTime", andianStartTimeLabel);
+                        jsonObj.put("waterSTime", waterStartTimeLabel);
+                        jsonObj.put("waterETime", waterEndTimeLabel);
+                        jsonObj.put("oilSTime", oilStartTimeLabel);
+                        jsonObj.put("oilETime", oilEndTimeLabel);
+                        jsonObj.put("ammoSTime", missileStartTimeLabel);
+                        jsonObj.put("ammoETime", missileEndTimeLabel);
+                        jsonObj.put("matSTime", goodsStartTimeLabel);
+                        jsonObj.put("matETime", goodsEndTimeLabel);
+                        jsonObj.put("supplyETime", supplyEndTimeLabel);
+                        jsonObj.put("path", tempDsTaskList.getPath());
+                        subJSONArray.add(jsonObj);
+                        sub1JsonObj.put("subData", subJSONArray);
+
+                        // 鏇存柊鑸硅埗琛ョ粰璁″垝鏁版嵁
+                        dsTaskDetail.setTaskId(taskId);
+                        dsTaskDetail.setHarborId(tempDsTaskList.getHarborId());
+                        dsTaskDetail.setHarborName(tempDsTaskList.getHarborName());
+                        dsTaskDetail.setBerthId(Long.parseLong(berthIdArray[i]));
+                        dsTaskDetail.setBerthName(tempDsTaskList.getBerthName());
+                        dsTaskDetail.setParkingType(tempDsTaskList.getParkingType());
+                        dsTaskDetail.setShipNo(tempDsTaskList.getShipNo());
+                        dsTaskDetail.setShipType(tempDsTaskList.getShipType());
+                        dsTaskDetail.setSTIME(format.parse(t1Time));
+                        dsTaskDetail.setElecStime(1);
+                        dsTaskDetail.setWaterStime(1);
+                        dsTaskDetail.setWaterEtime(addWaterTimeNum);
+                        dsTaskDetail.setMatStime(2);
+                        dsTaskDetail.setMatEtime(addGoodTimeNum + 2);
+                        dsTaskDetail.setOilTime(addOilTimeNum);
+                        dsTaskDetail.setAmmoTime(addMissileTimeNum);
+                        dsTaskDetail.setMatTime(addGoodTimeNum);
+                        dsTaskDetail.setWaterTime(addWaterTimeNum);
+                        dsTaskDetail.setT1(format.parse(t1Time));
+                        dsTaskDetail.setSupplySeq(tempDsTaskList.getSupplySeq());
+                        dsTaskDetail.setCarCount((int) totalGoodsNum);
+                        dsTaskDetail.setFood((double) food);
+                        dsTaskDetail.setFoodW((double) foodW);
+                        dsTaskDetail.setFoodO((double) foodO);
+
+                        // 鏍规嵁taskId鍜宻hipNo鍜宻hipType鍒ゆ柇鏄惁瀛樺湪鑸硅埗琛ョ粰璁″垝鏁版嵁
+                        DsTaskDetail tempDsTaskDetail = new DsTaskDetail();
+                        tempDsTaskDetail.setTaskId(taskId);
+                        tempDsTaskDetail.setShipNo(shipNo);
+                        tempDsTaskDetail.setShipType(shipType);
+                        List<DsTaskDetail> dsTaskDetails = dsTaskDetailService.selectDsTaskDetailList(tempDsTaskDetail);
+                        if (dsTaskDetails != null && dsTaskDetails.size() > 0) {
+                            dsTaskDetail.setPKID(dsTaskDetails.get(0).getPKID());
+                            dsTaskDetailService.updateDsTaskDetail(dsTaskDetail);
+                        } else {
+                            dsTaskDetailService.insertDsTaskDetail(dsTaskDetail);
+                        }
+                    }
+                    jsonArray.add(sub1JsonObj);
+                    rootJSONObj.put("berthDatas", jsonArray);
+                    rootJSONObj.put("totalJiedianTime", andianTotalTime);
+                    rootJSONObj.put("totalWaterTime", waterTotalTime);
+                    rootJSONObj.put("totalOilTime", oilTotalTime);
+                    rootJSONObj.put("totalAmmoTime", missileTotalTime);
+                    rootJSONObj.put("totalMatTime", goodsTotalTime);
+                    rootJSONArray.add(rootJSONObj);
+                }
+            }
+        }
+        return AjaxResult.success(rootJSONArray);
+    }
+
+    @Operation(description = "鑾峰彇鏀槦鏃堕棿琛ョ粰璁″垝")
+    @Log(title = "鏀槦鏀槦鏃堕棿琛ョ粰璁″垝", businessType = BusinessType.INSERT)
+    @PostMapping("/getdate")
+    @ResponseBody
+    // 涓嶆樉绀篢锛屾樉绀簓yyy-MM-dd HH:mm:ss
+    public AjaxResult getZdSupplyPlanDate(@RequestBody ZdSupplyPlanDTO zdSupplyPlanDTO) throws IOException, ParseException {
+        Long taskId = zdSupplyPlanDTO.getTaskId();
+        String t1Time = zdSupplyPlanDTO.getT1Time();
+        String usedBerthIds = zdSupplyPlanDTO.getUsedBerthIds();
+
+        LoginUser sysUser = getLoginUser();
+        Long deptId = sysUser.getDeptId();
+
+        JSONArray rootJSONArray = new JSONArray();
+        if (usedBerthIds != null && usedBerthIds.length() > 0) {
+            String[] berthIdArray = usedBerthIds.split(","); // usedBerthIds涓哄涓硦浣岻D锛屼互閫楀彿鍒嗛殧
+            for (int i = 0; i < berthIdArray.length; i++) {
+                JSONObject rootJSONObj = new JSONObject();
+                JSONArray jsonArray = new JSONArray();
+                JSONObject sub1JsonObj = new JSONObject();
+                List<DsTaskList2> dsTaskLists = dsTaskListService.getDsTaskListForSupplyPlan(deptId, taskId, Long.parseLong(berthIdArray[i]));
+
+                // 閬嶅巻鍚勬硦浣嶇殑鍚勮埌鑸癸紝璁$畻姣忚墭鑸拌埞鎵�闇�琛ョ粰鏃堕棿锛岀敓鎴愬悇鑸拌埞鐨勮ˉ缁欒鍒掓暟鎹�
+                if (dsTaskLists.size() > 0) {
+                    sub1JsonObj.put("harborName", dsTaskLists.get(0).getHarborName());
+                    sub1JsonObj.put("berthName", dsTaskLists.get(0).getBerthName());
+                    sub1JsonObj.put("berthId", dsTaskLists.get(0).getBerthId());
+                    sub1JsonObj.put("parkingType", dsTaskLists.get(0).getParkingType());
+                    // 宀哥數鑺傜偣鎬绘椂闀�
+                    int andianTotalTime = 0;
+                    // 娣℃按琛ョ粰鎬绘椂闀�
+                    int waterTotalTime = 0;
+                    // 鐕冩枡琛ョ粰鎬绘椂闀�
+                    int oilTotalTime = 0;
+                    // 寮硅嵂琛ョ粰鎬绘椂闀�
+                    int missileTotalTime = 0;
+                    // 鐗╄祫琛ョ粰鎬绘椂闀�
+                    int goodsTotalTime = 0;
+
+                    JSONArray subJSONArray = new JSONArray();
+                    for (int j = 0; j < dsTaskLists.size(); j++) {
+                        DsTaskDetail dsTaskDetail = new DsTaskDetail();
+                        JSONObject jsonObj =  new JSONObject();
+                        DsTaskList2 tempDsTaskList = dsTaskLists.get(j);
+                        String shipType = tempDsTaskList.getShipType(); // 鑸板瀷
+                        String shipNo = tempDsTaskList.getShipNo(); // 鑸峰彿
+                        String supplySeq = tempDsTaskList.getSupplySeq(); // 琛ョ粰搴忓垪
+
+                        String supplySeqLabel = sysDictDataService.selectDictLabel("dd_rule_supply", supplySeq); // 琛ョ粰搴忓垪鏍囩
+                        // 绗竴缂嗙怀
+                        String firstCabelLabel = "T" + (j + 1);
+                        String firstCabelLabelDate = format.format(addHoursToDate(t1Time, (j+1)));
+
+                        // 宀哥數鎺ョ數璧峰鏃堕棿Label
+                        String andianStartTimeLabel = firstCabelLabel + "+1";
+                        String andianStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 1));
+
+                        // 娣℃按琛ョ粰璧峰鏃堕棿Label
+                        String waterStartTimeLabel = firstCabelLabel + "+1";
+                        String waterStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 1));
+
+                        // 娣℃按琛ョ粰缁撴潫鏃堕棿Label
+                        int addWaterTimeNum = calcSupplyTimeBySupplyType(WATER_SUPPLY_TYPE, shipType, tempDsTaskList.getWATER());
+                        String waterEndTimeLabel = firstCabelLabel + "+" +(addWaterTimeNum + 1);
+                        String waterEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addWaterTimeNum + 1)));
+                        waterTotalTime += addWaterTimeNum;
+
+                        // 鐕冩补琛ョ粰鏃堕棿Label
+                        String oilStartTimeLabel = "";
+                        String oilStartTimeLabelDate = "";
+                        String oilEndTimeLabel = "";
+                        String oilEndTimeLabelDate = "";
+                        // 寮硅嵂琛ョ粰鏃堕棿Label
+                        String missileStartTimeLabel = "";
+                        String missileStartTimeLabelDate = "";
+                        String missileEndTimeLabel = "";
+                        String missileEndTimeLabelDate = "";
+
+                        // 琛ョ粰缁撴潫娴嬬畻鏃堕棿
+                        String supplyEndTimeLabel = "";
+                        String supplyEndTimeLabelDate = "";
+                        Double oilA = tempDsTaskList.getOilA() == null ? 0 : tempDsTaskList.getOilA();
+                        Double oilB = tempDsTaskList.getOilB() == null ? 0 : tempDsTaskList.getOilB();
+                        Double oilG = tempDsTaskList.getOilG() == null ? 0 : tempDsTaskList.getOilG();
+                        double totalOilNum = oilA + oilB + oilG; // 鎬诲姞娌归噺
+                        int addOilTimeNum = calcSupplyTimeBySupplyType(OIL_SUPPLY_TYPE, shipType, totalOilNum);
+                        Long ammoD = tempDsTaskList.getAmmoD() == null ? 0 : tempDsTaskList.getAmmoD();
+                        int addMissileTimeNum = calcSupplyTimeBySupplyType(MISSILE_SUPPLY_TYPE, shipType, (double) ammoD);
+                        if("1".equals(tempDsTaskList.getSupplySeq())){//鍚屾椂杩涜
+                            oilStartTimeLabel = firstCabelLabel + "+" + "2";
+                            oilStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 2));
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            oilEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2)));
+                            missileStartTimeLabel = firstCabelLabel + "+" + "2";;
+                            missileStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 2));
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            missileEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2)));
+                            if(addOilTimeNum > addMissileTimeNum){
+                                supplyEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + 1);
+                                supplyEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2 + 1)));
+                                dsTaskDetail.setETIME(DateUtils.addHours(format.parse(t1Time), addOilTimeNum + 2 + 1));
+                            }else{
+                                supplyEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + 1);
+                                supplyEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2 + 1)));
+                                dsTaskDetail.setETIME(DateUtils.addHours(format.parse(t1Time), addMissileTimeNum + 2 + 1));
+                            }
+
+                            dsTaskDetail.setOilStime(2);
+                            dsTaskDetail.setOilEtime(2 + addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(2);
+                            dsTaskDetail.setAmmoEtime(2 + addMissileTimeNum);
+                        }else if("2".equals(tempDsTaskList.getSupplySeq())){//鍏堟补鍚庡脊
+                            oilStartTimeLabel = firstCabelLabel + "+" + "2";
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            missileStartTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2);
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + addMissileTimeNum);
+                            supplyEndTimeLabel = firstCabelLabel + "+" + (addOilTimeNum + 2 + addMissileTimeNum + 1);
+                            oilStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 2));
+                            oilEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2)));
+                            missileStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2)));
+                            missileEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2 + addMissileTimeNum)));
+                            supplyEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addOilTimeNum + 2 + addMissileTimeNum + 1)));
+
+                            dsTaskDetail.setOilStime(2);
+                            dsTaskDetail.setOilEtime(2+ addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(addOilTimeNum + 2 + 1);
+                            dsTaskDetail.setAmmoEtime(addOilTimeNum + 2 + 1 + addMissileTimeNum);
+                            dsTaskDetail.setETIME(DateUtils.addHours(format.parse(t1Time), addOilTimeNum + 2 + addMissileTimeNum + 1));
+                        }else if("3".equals(tempDsTaskList.getSupplySeq())){//鍏堝脊鍚庢补
+                            missileStartTimeLabel = firstCabelLabel + "+2";
+                            missileEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            oilStartTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2);
+                            oilEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + addOilTimeNum);
+                            supplyEndTimeLabel = firstCabelLabel + "+" + (addMissileTimeNum + 2 + addOilTimeNum + 1);
+                            oilStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2)));
+                            oilEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2 + addOilTimeNum)));
+                            missileStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 2));
+                            missileEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2)));
+                            supplyEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addMissileTimeNum + 2 + addOilTimeNum + 1)));
+
+                            dsTaskDetail.setOilStime(addMissileTimeNum + 2 + 1);
+                            dsTaskDetail.setOilEtime(addMissileTimeNum + 2 + 1 + addOilTimeNum);
+                            dsTaskDetail.setAmmoStime(2);
+                            dsTaskDetail.setAmmoEtime(addMissileTimeNum + 2);
+                            dsTaskDetail.setETIME(DateUtils.addHours(format.parse(t1Time), addMissileTimeNum + 2 + addOilTimeNum + 1));
+                        }
+                        oilTotalTime += addOilTimeNum;
+                        missileTotalTime += addMissileTimeNum;
+
+                        if(addOilTimeNum >= addMissileTimeNum){
+                            andianTotalTime += addOilTimeNum;
+                        } else {
+                            andianTotalTime += addMissileTimeNum;
+                        }
+
+                        // 鐗╄祫琛ョ粰鏃堕棿Label
+                        String goodsStartTimeLabel = "";
+                        String goodsStartTimeLabelDate = "";
+                        String goodsEndTimeLabel = "";
+                        String goodsEndTimeLabelDate = "";
+                        Long food = tempDsTaskList.getFOOD() == null? 0 : tempDsTaskList.getFOOD();
+                        Long foodW = tempDsTaskList.getFoodW() == null? 0 : tempDsTaskList.getFoodW();
+                        Long foodO = tempDsTaskList.getFoodO() == null? 0 : tempDsTaskList.getFoodO();
+                        double totalGoodsNum = food + foodW + foodO; // 鎬诲姞鐗╄祫閲�
+                        int addGoodTimeNum = calcSupplyTimeBySupplyType(GOODS_SUPPLY_TYPE, shipType, totalGoodsNum);
+                        goodsStartTimeLabel = firstCabelLabel + "+2";
+                        goodsStartTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, 2));
+                        goodsEndTimeLabel = firstCabelLabel + "+" + (addGoodTimeNum + 2);
+                        goodsEndTimeLabelDate = format.format(addHoursToDate(firstCabelLabelDate, (addGoodTimeNum + 2)));
+                        goodsTotalTime += addGoodTimeNum;
+
+                        // 鏋勫缓姣忚墭鑸拌埞鏋勫缓JSON瀵硅薄
+                        jsonObj.put("id", String.valueOf(j+1));
+                        jsonObj.put("shipType", shipType);
+                        jsonObj.put("shipNo", shipNo);
+                        jsonObj.put("supplySeq", supplySeqLabel);
+                        jsonObj.put("sTime", firstCabelLabelDate);
+                        jsonObj.put("electSTime", andianStartTimeLabelDate);
+                        jsonObj.put("waterSTime", waterStartTimeLabelDate);
+                        jsonObj.put("waterETime", waterEndTimeLabelDate);
+                        jsonObj.put("oilSTime", oilStartTimeLabelDate);
+                        jsonObj.put("oilETime", oilEndTimeLabelDate);
+                        jsonObj.put("ammoSTime", missileStartTimeLabelDate);
+                        jsonObj.put("ammoETime", missileEndTimeLabelDate);
+                        jsonObj.put("matSTime", goodsStartTimeLabelDate);
+                        jsonObj.put("matETime", goodsEndTimeLabelDate);
+                        jsonObj.put("supplyETime", supplyEndTimeLabelDate);
+                        subJSONArray.add(jsonObj);
+                        sub1JsonObj.put("subData", subJSONArray);
+
+                        // 鏇存柊鑸硅埗琛ョ粰璁″垝鏁版嵁
+                        dsTaskDetail.setTaskId(taskId);
+                        dsTaskDetail.setHarborId(tempDsTaskList.getHarborId());
+                        dsTaskDetail.setHarborName(tempDsTaskList.getHarborName());
+                        dsTaskDetail.setBerthId(Long.parseLong(berthIdArray[i]));
+                        dsTaskDetail.setBerthName(tempDsTaskList.getBerthName());
+                        dsTaskDetail.setParkingType(tempDsTaskList.getParkingType());
+                        dsTaskDetail.setShipNo(tempDsTaskList.getShipNo());
+                        dsTaskDetail.setShipType(tempDsTaskList.getShipType());
+                        dsTaskDetail.setSTIME(format.parse(t1Time));
+                        dsTaskDetail.setElecStime(1);
+                        dsTaskDetail.setWaterStime(1);
+                        dsTaskDetail.setWaterEtime(addWaterTimeNum);
+                        dsTaskDetail.setMatStime(2);
+                        dsTaskDetail.setMatEtime(addGoodTimeNum + 2);
+                        dsTaskDetail.setOilTime(addOilTimeNum);
+                        dsTaskDetail.setAmmoTime(addMissileTimeNum);
+                        dsTaskDetail.setMatTime(addGoodTimeNum);
+                        dsTaskDetail.setWaterTime(addWaterTimeNum);
+                        dsTaskDetail.setT1(format.parse(t1Time));
+                        dsTaskDetail.setSupplySeq(tempDsTaskList.getSupplySeq());
+                        dsTaskDetail.setCarCount((int) totalGoodsNum);
+                        dsTaskDetail.setFood((double) food);
+                        dsTaskDetail.setFoodW((double) foodW);
+                        dsTaskDetail.setFoodO((double) foodO);
+
+                        // 鏍规嵁taskId鍜宻hipNo鍜宻hipType鍒ゆ柇鏄惁瀛樺湪鑸硅埗琛ョ粰璁″垝鏁版嵁
+                        DsTaskDetail tempDsTaskDetail = new DsTaskDetail();
+                        tempDsTaskDetail.setTaskId(taskId);
+                        tempDsTaskDetail.setShipNo(shipNo);
+                        tempDsTaskDetail.setShipType(shipType);
+                        List<DsTaskDetail> dsTaskDetails = dsTaskDetailService.selectDsTaskDetailList(tempDsTaskDetail);
+                        if (dsTaskDetails == null && dsTaskDetails.size() > 0) {
+                            dsTaskDetail.setPKID(dsTaskDetails.get(0).getPKID());
+                            dsTaskDetailService.updateDsTaskDetail(dsTaskDetail);
+                        } else {
+                            dsTaskDetailService.insertDsTaskDetail(dsTaskDetail);
+                        }
+                    }
+                    jsonArray.add(sub1JsonObj);
+                    rootJSONObj.put("berthDatas", jsonArray);
+                    rootJSONObj.put("totalJiedianTime", andianTotalTime);
+                    rootJSONObj.put("totalWaterTime", waterTotalTime);
+                    rootJSONObj.put("totalOilTime", oilTotalTime);
+                    rootJSONObj.put("totalAmmoTime", missileTotalTime);
+                    rootJSONObj.put("totalMatTime", goodsTotalTime);
+                    rootJSONArray.add(rootJSONObj);
+                }
+            }
+        }
+        return AjaxResult.success(rootJSONArray);
+    }
+
+    /**
+     * 鏍规嵁琛ョ粰闇�姹傞噺锛岃绠楀悇绉嶈ˉ鍓傛墍闇�鏃堕棿銆�
+     * @param supplyType
+     * @param shipType
+     * @param supplyTotalNum
+     * @return 鏁村皬鏃�
+     */
+    private int calcSupplyTimeBySupplyType(String supplyType, String shipType, double supplyTotalNum) {
+        if (OIL_SUPPLY_TYPE.equals(supplyType)) {//琛ョ粰娌规枡
+            for (int i = 0; i < SHIP_TYPE.length; i++) {
+                if (shipType.equals(SHIP_TYPE[i])) {
+                    return (int) Math.ceil(supplyTotalNum / OIL_UNIT_NUM * OIL_USE_TIME[i]);
+                }
+            }
+        } else if (MISSILE_SUPPLY_TYPE.equals(supplyType)) {//琛ョ粰DY
+            for (int i = 0; i < SHIP_TYPE.length; i++) {
+                if (shipType.equals(SHIP_TYPE[i])) {
+                    return (int) Math.ceil(supplyTotalNum / MISSILE_UNIT_NUM * MISSILE_USE_TIME[i]);
+                }
+            }
+        } else if (GOODS_SUPPLY_TYPE.equals(supplyType)) {//琛ョ粰鐗╄祫
+            for (int i = 0; i < SHIP_TYPE.length; i++) {
+                if (shipType.equals(SHIP_TYPE[i])) {
+                    return (int) Math.ceil(supplyTotalNum / GOODS_UNIT_NUM * GOODS_USE_TIME[i]);
+                }
+            }
+        } else if (WATER_SUPPLY_TYPE.equals(supplyType)) {//琛ョ粰娣℃按
+            for (int i = 0; i < SHIP_TYPE.length; i++) {
+                if (shipType.equals(SHIP_TYPE[i])) {
+                    return (int) Math.ceil(supplyTotalNum / WATER_UNIT_NUM * WATER_USE_TIME[i]);
+                }
+            }
+        }
+        return 0;
+    }
+
+    @Operation(description = "淇敼鑸拌埞琛ョ粰椤哄簭")
+    @Log(title = "淇敼鑸拌埞琛ョ粰椤哄簭", businessType = BusinessType.INSERT)
+    @PostMapping("/changeSupplySeq")
+    @ResponseBody
+    public AjaxResult changeSupplySeqById(Long taskId, String shipNo, String supplySeq) throws IOException, ParseException {
+        // 鏇存柊DsTaskList2涓殑SupplySeq鍊�
+        DsTaskList2 dsTaskList2 = new DsTaskList2();
+        dsTaskList2.setTaskId(taskId);
+        dsTaskList2.setShipNo(shipNo);
+        List<DsTaskList2> dsTaskLists = dsTaskListService.selectDsTaskListList(dsTaskList2);
+        int result1 = -1;
+        if(dsTaskLists != null && dsTaskLists.size() >0){
+            dsTaskList2.setPKID(dsTaskLists.get(0).getPKID());
+            dsTaskList2.setSupplySeq(supplySeq);
+            result1 = dsTaskListService.updateDsTaskList(dsTaskList2);
+            log.debug("鏇存柊DsTaskList琛ㄤ腑鐨凷upplySeq瀛楁缁撴灉 =====锛� " + result1);
+        }
+        // 鏇存柊DsTaskDetail涓殑SupplySeq鍊�
+        DsTaskDetail dsTaskDetail = new DsTaskDetail();
+        dsTaskDetail.setTaskId(taskId);
+        dsTaskDetail.setShipNo(shipNo);
+        List<DsTaskDetail> dsTaskDetails = dsTaskDetailService.selectDsTaskDetailList(dsTaskDetail);
+        int result2 = -1;
+        if(dsTaskDetails != null && dsTaskDetails.size() >0){
+            dsTaskDetail.setPKID(dsTaskDetails.get(0).getPKID());
+            dsTaskDetail.setSupplySeq(supplySeq);
+            result2 = dsTaskDetailService.updateDsTaskDetail(dsTaskDetail);
+            log.debug("鏇存柊DsTaskDetail琛ㄤ腑鐨凷upplySeq瀛楁缁撴灉 =====锛� " + result2);
+        }
+        if (result2 >= 0 && result2 >= 0) {
+            return AjaxResult.success("琛ョ粰椤哄簭淇敼鎴愬姛");
+        } else {
+            return AjaxResult.error(-1, "琛ョ粰椤哄簭淇敼澶辫触");
+        }
+    }
+
+    /**
+     * 鍦ㄦ寚瀹氱殑鏃ユ湡锛堝瓧绗︿覆锛変笂澧炲姞鎸囧畾鐨勫皬鏃舵暟銆�
+     * @param dateStr
+     * @param hours
+     * @return
+     * @throws ParseException
+     */
+    private Date addHoursToDate(String dateStr, int hours) throws ParseException {
+        // 灏嗚緭鍏ョ殑鏃ユ湡瀛楃涓茶В鏋愪负 Date 瀵硅薄
+        Date date = format.parse(dateStr);
+        // 鍒涘缓 Calendar 瀹炰緥骞惰缃棩鏈�
+        Calendar calendar = Calendar.getInstance();
+        calendar.setTime(date);
+        // 澧炲姞鎸囧畾鐨勫皬鏃舵暟
+        calendar.add(Calendar.HOUR_OF_DAY, hours);
+        // 鑾峰彇澧炲姞灏忔椂鏁板悗鐨� Date 瀵硅薄
+        return calendar.getTime();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmBerth2.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmBerth2.java
new file mode 100644
index 0000000..d86e5dd
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmBerth2.java
@@ -0,0 +1,179 @@
+package com.ruoyi.buss.domain;
+
+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;
+
+/**
+ * 娉婁綅淇℃伅瀵硅薄 dm_berth
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DmBerth2 extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private String NAME;
+
+    /**  */
+    @Excel(name = "")
+    private Long harborId;
+
+    /**  */
+    @Excel(name = "")
+    private String harborName;
+
+    /**  */
+    @Excel(name = "")
+    private Long berthLen;
+
+    /**  */
+    @Excel(name = "")
+    private Long DEPTH;
+
+    /**  */
+    @Excel(name = "")
+    private String STATUS;
+
+    /**  */
+    @Excel(name = "")
+    private Long orderNum;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    private Long deptId;
+
+    private String path;
+
+    public void setPKID(Long PKID) 
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public void setNAME(String NAME) 
+    {
+        this.NAME = NAME;
+    }
+
+    public String getNAME() 
+    {
+        return NAME;
+    }
+
+    public void setHarborId(Long harborId) 
+    {
+        this.harborId = harborId;
+    }
+
+    public Long getHarborId() 
+    {
+        return harborId;
+    }
+
+    public void setHarborName(String harborName) 
+    {
+        this.harborName = harborName;
+    }
+
+    public String getHarborName() 
+    {
+        return harborName;
+    }
+
+    public void setBerthLen(Long berthLen) 
+    {
+        this.berthLen = berthLen;
+    }
+
+    public Long getBerthLen() 
+    {
+        return berthLen;
+    }
+
+    public void setDEPTH(Long DEPTH) 
+    {
+        this.DEPTH = DEPTH;
+    }
+
+    public Long getDEPTH() 
+    {
+        return DEPTH;
+    }
+
+    public void setSTATUS(String STATUS) 
+    {
+        this.STATUS = STATUS;
+    }
+
+    public String getSTATUS() 
+    {
+        return STATUS;
+    }
+
+    public void setOrderNum(Long orderNum) 
+    {
+        this.orderNum = orderNum;
+    }
+
+    public Long getOrderNum() 
+    {
+        return orderNum;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    @Override
+    public String toString() {
+        return "DmBerth2 =: {" +
+                "PKID=" + PKID +
+                ", NAME='" + NAME + '\'' +
+                ", harborId=" + harborId +
+                ", harborName='" + harborName + '\'' +
+                ", berthLen=" + berthLen +
+                ", DEPTH=" + DEPTH +
+                ", STATUS='" + STATUS + '\'' +
+                ", orderNum=" + orderNum +
+                ", delFlag='" + delFlag + '\'' +
+                ", deptId=" + deptId +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmDdConfig.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmDdConfig.java
new file mode 100644
index 0000000..f0c01eb
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmDdConfig.java
@@ -0,0 +1,99 @@
+package com.ruoyi.buss.domain;
+
+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;
+
+/**
+ * 璋冮厤閰嶇疆淇℃伅瀵硅薄 dm_dd_config
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DmDdConfig extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private String TYPE;
+
+    /**  */
+    @Excel(name = "")
+    private String UNIT;
+
+    /**  */
+    @Excel(name = "")
+    private String shipType;
+
+    /**  */
+    @Excel(name = "")
+    private Double TIME;
+
+    public void setPKID(Long PKID) 
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public void setTYPE(String TYPE) 
+    {
+        this.TYPE = TYPE;
+    }
+
+    public String getTYPE() 
+    {
+        return TYPE;
+    }
+
+    public void setUNIT(String UNIT) 
+    {
+        this.UNIT = UNIT;
+    }
+
+    public String getUNIT() 
+    {
+        return UNIT;
+    }
+
+    public void setShipType(String shipType) 
+    {
+        this.shipType = shipType;
+    }
+
+    public String getShipType() 
+    {
+        return shipType;
+    }
+
+    public void setTIME(Double TIME) 
+    {
+        this.TIME = TIME;
+    }
+
+    public Double getTIME() 
+    {
+        return TIME;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("PKID", getPKID())
+            .append("TYPE", getTYPE())
+            .append("UNIT", getUNIT())
+            .append("shipType", getShipType())
+            .append("TIME", getTIME())
+            .append("REMARK", getRemark())
+            .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmHarbor2.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmHarbor2.java
new file mode 100644
index 0000000..15624b8
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmHarbor2.java
@@ -0,0 +1,321 @@
+package com.ruoyi.buss.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+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;
+
+/**
+ * 娓彛淇℃伅瀵硅薄 dm_harbor
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DmHarbor2 extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private String harborName;
+
+    /**  */
+    @Excel(name = "")
+    private Long deptId;
+
+    /**  */
+    @Excel(name = "")
+    private String deptName;
+
+    /**  */
+    @Excel(name = "")
+    private Long berthNo;
+
+    /**  */
+    @Excel(name = "")
+    private Float oilB;
+
+    /**  */
+    @Excel(name = "")
+    private Float oilG;
+
+    /**  */
+    @Excel(name = "")
+    private Float oilA;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoD;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoP;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoS;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    /**  */
+    @Excel(name = "")
+    private String DOCKNAME;
+
+    /**  */
+    @Excel(name = "")
+    private Float WATER;
+
+    /**  */
+    @Excel(name = "")
+    private Float MATERIAL;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoO;
+
+    private Integer vehicleCount;   // VEHICLE_COUNT
+
+    private String roadConditions;
+
+    /**  */
+    @Excel(name = "")
+    private Double draft;
+
+    @JsonIgnore
+    private Double allocatedOilA;
+
+    @JsonIgnore
+    private Integer allocatedShipCount;
+
+    public void setPKID(Long PKID) 
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getDeptId() 
+    {
+        return deptId;
+    }
+
+    public void setDeptName(String deptName) 
+    {
+        this.deptName = deptName;
+    }
+
+    public String getDeptName() 
+    {
+        return deptName;
+    }
+
+    public void setBerthNo(Long berthNo) 
+    {
+        this.berthNo = berthNo;
+    }
+
+    public Long getBerthNo() 
+    {
+        return berthNo;
+    }
+
+    public void setOilB(Float oilB) 
+    {
+        this.oilB = oilB;
+    }
+
+    public Float getOilB() 
+    {
+        return oilB;
+    }
+
+    public void setOilG(Float oilG) 
+    {
+        this.oilG = oilG;
+    }
+
+    public Float getOilG() 
+    {
+        return oilG;
+    }
+
+    public void setOilA(Float oilA) 
+    {
+        this.oilA = oilA;
+    }
+
+    public Float getOilA() 
+    {
+        return oilA;
+    }
+
+    public void setAmmoD(Long ammoD) 
+    {
+        this.ammoD = ammoD;
+    }
+
+    public Long getAmmoD() 
+    {
+        return ammoD;
+    }
+
+    public void setAmmoP(Long ammoP) 
+    {
+        this.ammoP = ammoP;
+    }
+
+    public Long getAmmoP() 
+    {
+        return ammoP;
+    }
+
+    public void setAmmoS(Long ammoS) 
+    {
+        this.ammoS = ammoS;
+    }
+
+    public Long getAmmoS() 
+    {
+        return ammoS;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    public void setDOCKNAME(String DOCKNAME) 
+    {
+        this.DOCKNAME = DOCKNAME;
+    }
+
+    public String getDOCKNAME() 
+    {
+        return DOCKNAME;
+    }
+
+    public void setWATER(Float WATER) 
+    {
+        this.WATER = WATER;
+    }
+
+    public Float getWATER() 
+    {
+        return WATER;
+    }
+
+    public void setMATERIAL(Float MATERIAL) 
+    {
+        this.MATERIAL = MATERIAL;
+    }
+
+    public Float getMATERIAL() 
+    {
+        return MATERIAL;
+    }
+
+    public void setAmmoO(Long ammoO) 
+    {
+        this.ammoO = ammoO;
+    }
+
+    public Long getAmmoO() 
+    {
+        return ammoO;
+    }
+
+    public Double getAllocatedOilA() {
+        return allocatedOilA;
+    }
+
+    public void setAllocatedOilA(Double allocatedOilA) {
+        this.allocatedOilA = allocatedOilA;
+    }
+
+    public Integer getAllocatedShipCount() {
+        return allocatedShipCount;
+    }
+
+    public void setAllocatedShipCount(Integer allocatedShipCount) {
+        this.allocatedShipCount = allocatedShipCount;
+    }
+
+    public Integer getVehicleCount() {
+        return vehicleCount;
+    }
+
+    public void setVehicleCount(Integer vehicleCount) {
+        this.vehicleCount = vehicleCount;
+    }
+
+    public String getRoadConditions() {
+        return roadConditions;
+    }
+
+    public void setRoadConditions(String roadConditions) {
+        this.roadConditions = roadConditions;
+    }
+
+    public Double getDraft() {
+        return draft;
+    }
+
+    public void setDraft(Double draft) {
+        this.draft = draft;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("PKID", getPKID())
+            .append("harborName", getHarborName())
+            .append("deptId", getDeptId())
+            .append("deptName", getDeptName())
+            .append("berthNo", getBerthNo())
+            .append("oilB", getOilB())
+            .append("oilG", getOilG())
+            .append("oilA", getOilA())
+            .append("ammoD", getAmmoD())
+            .append("ammoP", getAmmoP())
+            .append("ammoS", getAmmoS())
+            .append("REMARK", getRemark())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("DOCKNAME", getDOCKNAME())
+            .append("WATER", getWATER())
+            .append("MATERIAL", getMATERIAL())
+            .append("ammoO", getAmmoO())
+            .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmWarship.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmWarship.java
new file mode 100644
index 0000000..a072bf7
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DmWarship.java
@@ -0,0 +1,193 @@
+package com.ruoyi.buss.domain;
+
+import java.math.BigDecimal;
+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;
+
+/**
+ * 鑸拌墖淇℃伅瀵硅薄 dm_warship
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DmWarship extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private String shipNo;
+
+    /**  */
+    @Excel(name = "")
+    private String shipType;
+
+    /**  */
+    @Excel(name = "")
+    private BigDecimal TONNAGE;
+
+    /**  */
+    @Excel(name = "")
+    private BigDecimal DRAFT;
+
+    /**  */
+    @Excel(name = "")
+    private String LEADER;
+
+    /**  */
+    @Excel(name = "")
+    private Long STAFF;
+
+    /**  */
+    @Excel(name = "")
+    private String grpName;
+
+    /**  */
+    @Excel(name = "")
+    private Long LEVEL;
+
+    /**  */
+    @Excel(name = "")
+    private BigDecimal LAT;
+
+    /**  */
+    @Excel(name = "")
+    private BigDecimal LON;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    public void setShipNo(String shipNo) 
+    {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipNo() 
+    {
+        return shipNo;
+    }
+
+    public void setShipType(String shipType) 
+    {
+        this.shipType = shipType;
+    }
+
+    public String getShipType() 
+    {
+        return shipType;
+    }
+
+    public void setTONNAGE(BigDecimal TONNAGE) 
+    {
+        this.TONNAGE = TONNAGE;
+    }
+
+    public BigDecimal getTONNAGE() 
+    {
+        return TONNAGE;
+    }
+
+    public void setDRAFT(BigDecimal DRAFT) 
+    {
+        this.DRAFT = DRAFT;
+    }
+
+    public BigDecimal getDraft() 
+    {
+        return DRAFT;
+    }
+
+    public void setLEADER(String LEADER) 
+    {
+        this.LEADER = LEADER;
+    }
+
+    public String getLEADER() 
+    {
+        return LEADER;
+    }
+
+    public void setSTAFF(Long STAFF) 
+    {
+        this.STAFF = STAFF;
+    }
+
+    public Long getSTAFF() 
+    {
+        return STAFF;
+    }
+
+    public void setGrpName(String grpName) 
+    {
+        this.grpName = grpName;
+    }
+
+    public String getGrpName() 
+    {
+        return grpName;
+    }
+
+    public void setLEVEL(Long LEVEL) 
+    {
+        this.LEVEL = LEVEL;
+    }
+
+    public Long getLEVEL() 
+    {
+        return LEVEL;
+    }
+
+    public void setLAT(BigDecimal LAT) 
+    {
+        this.LAT = LAT;
+    }
+
+    public BigDecimal getLAT() 
+    {
+        return LAT;
+    }
+
+    public void setLON(BigDecimal LON) 
+    {
+        this.LON = LON;
+    }
+
+    public BigDecimal getLON() 
+    {
+        return LON;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("shipNo", getShipNo())
+            .append("shipType", getShipType())
+            .append("TONNAGE", getTONNAGE())
+            .append("DRAFT", getDraft())
+            .append("LEADER", getLEADER())
+            .append("STAFF", getSTAFF())
+            .append("grpName", getGrpName())
+            .append("LEVEL", getLEVEL())
+            .append("LAT", getLAT())
+            .append("LON", getLON())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssess.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssess.java
new file mode 100644
index 0000000..157ff47
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssess.java
@@ -0,0 +1,118 @@
+package com.ruoyi.buss.domain;
+
+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;
+
+/**
+ * 鑳芥晥璇勪及瀵硅薄 ds_effect_assess
+ *
+ * @author lx
+ * @date 2025-03-24
+ */
+public class DsEffectAssess extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private Long taskId;
+
+    /**  */
+    @Excel(name = "")
+    private Double SCORE;
+
+    private Long deptId;
+//
+//    private String type;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    private String type;
+
+    public void setPKID(Long PKID)
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID()
+    {
+        return PKID;
+    }
+
+    public void setTaskId(Long taskId)
+    {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId()
+    {
+        return taskId;
+    }
+
+    public void setSCORE(Double SCORE)
+    {
+        this.SCORE = SCORE;
+    }
+
+    public Double getSCORE()
+    {
+        return SCORE;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public DsEffectAssess(Long taskId, Double SCORE) {
+        this.taskId = taskId;
+        this.SCORE = SCORE;
+    }
+
+    public DsEffectAssess() {
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    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("PKID", getPKID())
+                .append("taskId", getTaskId())
+                .append("SCORE", getSCORE())
+                .append("delFlag", getDelFlag())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("REMARK", getRemark())
+                .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessHis.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessHis.java
new file mode 100644
index 0000000..36efc5b
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessHis.java
@@ -0,0 +1,258 @@
+package com.ruoyi.buss.domain;
+
+import com.ruoyi.common.annotation.Excel;
+import com.ruoyi.common.core.domain.BaseEntity;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯呭璞� ds_effect_assess_list
+ *
+ * @author lx
+ * @date 2025-03-24
+ */
+public class DsEffectAssessHis extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private Long taskId;
+
+    /**  */
+    @Excel(name = "")
+    private String TYPE;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    /**  */
+    @Excel(name = "")
+    private String PLAN;
+
+    /**  */
+    @Excel(name = "")
+    private String ITEM;
+
+    /**  */
+    @Excel(name = "")
+    private String itemDetail;
+
+    /**  */
+    @Excel(name = "")
+    private String UNIT;
+
+    /**  */
+    @Excel(name = "")
+    private String CODE;
+
+    /**  */
+    @Excel(name = "")
+    private String NORMAL;
+
+    /**  */
+    @Excel(name = "")
+    private Double WEIGHT;
+
+    /**  */
+    @Excel(name = "")
+    private String classifyIndex;
+
+    /**  */
+    @Excel(name = "")
+    private Double classifyWeight;
+
+    private Double val;
+
+    private Long deptId;
+
+    public void setPKID(Long PKID)
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID()
+    {
+        return PKID;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public void setTYPE(String TYPE)
+    {
+        this.TYPE = TYPE;
+    }
+
+    public String getTYPE()
+    {
+        return TYPE;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setPLAN(String PLAN)
+    {
+        this.PLAN = PLAN;
+    }
+
+    public String getPLAN()
+    {
+        return PLAN;
+    }
+
+    public void setITEM(String ITEM)
+    {
+        this.ITEM = ITEM;
+    }
+
+    public String getITEM()
+    {
+        return ITEM;
+    }
+
+    public void setItemDetail(String itemDetail)
+    {
+        this.itemDetail = itemDetail;
+    }
+
+    public String getItemDetail()
+    {
+        return itemDetail;
+    }
+
+    public void setUNIT(String UNIT)
+    {
+        this.UNIT = UNIT;
+    }
+
+    public String getUNIT()
+    {
+        return UNIT;
+    }
+
+    public void setCODE(String CODE)
+    {
+        this.CODE = CODE;
+    }
+
+    public String getCODE()
+    {
+        return CODE;
+    }
+
+    public void setNORMAL(String NORMAL)
+    {
+        this.NORMAL = NORMAL;
+    }
+
+    public String getNORMAL()
+    {
+        return NORMAL;
+    }
+
+    public void setWEIGHT(Double WEIGHT)
+    {
+        this.WEIGHT = WEIGHT;
+    }
+
+    public Double getWEIGHT()
+    {
+        return WEIGHT;
+    }
+
+    public void setClassifyIndex(String classifyIndex)
+    {
+        this.classifyIndex = classifyIndex;
+    }
+
+    public String getClassifyIndex()
+    {
+        return classifyIndex;
+    }
+
+    public void setClassifyWeight(Double classifyWeight)
+    {
+        this.classifyWeight = classifyWeight;
+    }
+
+    public Double getClassifyWeight()
+    {
+        return classifyWeight;
+    }
+
+    public DsEffectAssessHis() {
+    }
+
+    public Double getVal() {
+        return val;
+    }
+
+    public void setVal(Double val) {
+        this.val = val;
+    }
+
+    public DsEffectAssessHis(String TYPE, String CODE, Double val, Double WEIGHT, Double classifyWeight) {
+        this.TYPE = TYPE;
+        this.CODE = CODE;
+        this.val = val;
+        this.WEIGHT = WEIGHT;
+        this.classifyWeight = classifyWeight;
+    }
+
+    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("PKID", getPKID())
+                .append("taskId", getTaskId())
+                .append("TYPE", getTYPE())
+                .append("delFlag", getDelFlag())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("REMARK", getRemark())
+                .append("PLAN", getPLAN())
+                .append("ITEM", getITEM())
+                .append("itemDetail", getItemDetail())
+                .append("UNIT", getUNIT())
+                .append("CODE", getCODE())
+                .append("NORMAL", getNORMAL())
+                .append("WEIGHT", getWEIGHT())
+                .append("classifyIndex", getClassifyIndex())
+                .append("classifyWeight", getClassifyWeight())
+                .toString();
+    }
+
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessList.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessList.java
new file mode 100644
index 0000000..db9f112
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsEffectAssessList.java
@@ -0,0 +1,254 @@
+package com.ruoyi.buss.domain;
+
+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;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯呭璞� ds_effect_assess_list
+ *
+ * @author lx
+ * @date 2025-03-24
+ */
+public class DsEffectAssessList extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private Long assessId;
+
+    /**  */
+    @Excel(name = "")
+    private String TYPE;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    /**  */
+    @Excel(name = "")
+    private String PLAN;
+
+    /**  */
+    @Excel(name = "")
+    private String ITEM;
+
+    /**  */
+    @Excel(name = "")
+    private String itemDetail;
+
+    /**  */
+    @Excel(name = "")
+    private String UNIT;
+
+    /**  */
+    @Excel(name = "")
+    private String CODE;
+
+    /**  */
+    @Excel(name = "")
+    private String NORMAL;
+
+    /**  */
+    @Excel(name = "")
+    private Double WEIGHT;
+
+    /**  */
+    @Excel(name = "")
+    private String classifyIndex;
+
+    /**  */
+    @Excel(name = "")
+    private Double classifyWeight;
+
+    private Double val;
+
+    private Long deptId;
+
+    public void setPKID(Long PKID)
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID()
+    {
+        return PKID;
+    }
+
+    public void setAssessId(Long assessId)
+    {
+        this.assessId = assessId;
+    }
+
+    public Long getAssessId()
+    {
+        return assessId;
+    }
+
+    public void setTYPE(String TYPE)
+    {
+        this.TYPE = TYPE;
+    }
+
+    public String getTYPE()
+    {
+        return TYPE;
+    }
+
+    public void setDelFlag(String delFlag)
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag()
+    {
+        return delFlag;
+    }
+
+    public void setPLAN(String PLAN)
+    {
+        this.PLAN = PLAN;
+    }
+
+    public String getPLAN()
+    {
+        return PLAN;
+    }
+
+    public void setITEM(String ITEM)
+    {
+        this.ITEM = ITEM;
+    }
+
+    public String getITEM()
+    {
+        return ITEM;
+    }
+
+    public void setItemDetail(String itemDetail)
+    {
+        this.itemDetail = itemDetail;
+    }
+
+    public String getItemDetail()
+    {
+        return itemDetail;
+    }
+
+    public void setUNIT(String UNIT)
+    {
+        this.UNIT = UNIT;
+    }
+
+    public String getUNIT()
+    {
+        return UNIT;
+    }
+
+    public void setCODE(String CODE)
+    {
+        this.CODE = CODE;
+    }
+
+    public String getCODE()
+    {
+        return CODE;
+    }
+
+    public void setNORMAL(String NORMAL)
+    {
+        this.NORMAL = NORMAL;
+    }
+
+    public String getNORMAL()
+    {
+        return NORMAL;
+    }
+
+    public void setWEIGHT(Double WEIGHT)
+    {
+        this.WEIGHT = WEIGHT;
+    }
+
+    public Double getWEIGHT()
+    {
+        return WEIGHT;
+    }
+
+    public void setClassifyIndex(String classifyIndex)
+    {
+        this.classifyIndex = classifyIndex;
+    }
+
+    public String getClassifyIndex()
+    {
+        return classifyIndex;
+    }
+
+    public void setClassifyWeight(Double classifyWeight)
+    {
+        this.classifyWeight = classifyWeight;
+    }
+
+    public Double getClassifyWeight()
+    {
+        return classifyWeight;
+    }
+
+    public DsEffectAssessList() {
+    }
+
+    public Double getVal() {
+        return val;
+    }
+
+    public void setVal(Double val) {
+        this.val = val;
+    }
+
+    public DsEffectAssessList(String TYPE, String CODE, Double val,  Double WEIGHT, Double classifyWeight) {
+        this.TYPE = TYPE;
+        this.CODE = CODE;
+        this.val = val;
+        this.WEIGHT = WEIGHT;
+        this.classifyWeight = classifyWeight;
+    }
+
+    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("PKID", getPKID())
+                .append("assessId", getAssessId())
+                .append("TYPE", getTYPE())
+                .append("delFlag", getDelFlag())
+                .append("createBy", getCreateBy())
+                .append("createTime", getCreateTime())
+                .append("updateBy", getUpdateBy())
+                .append("updateTime", getUpdateTime())
+                .append("REMARK", getRemark())
+                .append("PLAN", getPLAN())
+                .append("ITEM", getITEM())
+                .append("itemDetail", getItemDetail())
+                .append("UNIT", getUNIT())
+                .append("CODE", getCODE())
+                .append("NORMAL", getNORMAL())
+                .append("WEIGHT", getWEIGHT())
+                .append("classifyIndex", getClassifyIndex())
+                .append("classifyWeight", getClassifyWeight())
+                .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsMatDispatch2.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsMatDispatch2.java
new file mode 100644
index 0000000..beba3e5
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsMatDispatch2.java
@@ -0,0 +1,120 @@
+package com.ruoyi.buss.domain;
+
+import com.ruoyi.common.core.domain.BaseEntity;
+
+import java.util.Date;
+
+public class DsMatDispatch2 extends BaseEntity {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long id;
+
+    private String  resHarborId;
+
+    private String resHarborName;
+
+    private String desHarborId;
+
+    private String desHarborName;
+
+    private String content;
+
+    private String status;
+
+    private String applyBy;
+
+    private Date applyTime;
+
+    private String applyResult;
+
+    private String applyContent;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getResHarborId() {
+        return resHarborId;
+    }
+
+    public void setResHarborId(String resHarborId) {
+        this.resHarborId = resHarborId;
+    }
+
+    public String getResHarborName() {
+        return resHarborName;
+    }
+
+    public void setResHarborName(String resHarborName) {
+        this.resHarborName = resHarborName;
+    }
+
+    public String getDesHarborId() {
+        return desHarborId;
+    }
+
+    public void setDesHarborId(String desHarborId) {
+        this.desHarborId = desHarborId;
+    }
+
+    public String getDesHarborName() {
+        return desHarborName;
+    }
+
+    public void setDesHarborName(String desHarborName) {
+        this.desHarborName = desHarborName;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getApplyBy() {
+        return applyBy;
+    }
+
+    public void setApplyBy(String applyBy) {
+        this.applyBy = applyBy;
+    }
+
+    public Date getApplyTime() {
+        return applyTime;
+    }
+
+    public void setApplyTime(Date applyTime) {
+        this.applyTime = applyTime;
+    }
+
+    public String getApplyResult() {
+        return applyResult;
+    }
+
+    public void setApplyResult(String applyResult) {
+        this.applyResult = applyResult;
+    }
+
+    public String getApplyContent() {
+        return applyContent;
+    }
+
+    public void setApplyContent(String applyContent) {
+        this.applyContent = applyContent;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTask.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTask.java
new file mode 100644
index 0000000..143320e
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTask.java
@@ -0,0 +1,114 @@
+package com.ruoyi.buss.domain;
+
+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;
+
+/**
+ * 浠诲姟淇℃伅瀵硅薄 ds_task
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DsTask extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private String NAME;
+
+    /**  */
+    @Excel(name = "")
+    private String TYPE;
+
+    /**  */
+    @Excel(name = "")
+    private String status;
+
+    /**  */
+    @Excel(name = "")
+    private String NOTES;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    public void setPKID(Long PKID) 
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public void setNAME(String NAME) 
+    {
+        this.NAME = NAME;
+    }
+
+    public String getNAME() 
+    {
+        return NAME;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public void setTYPE(String TYPE)
+    {
+        this.TYPE = TYPE;
+    }
+
+    public String getTYPE() 
+    {
+        return TYPE;
+    }
+
+    public void setNOTES(String NOTES) 
+    {
+        this.NOTES = NOTES;
+    }
+
+    public String getNOTES() 
+    {
+        return NOTES;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("PKID", getPKID())
+            .append("NAME", getNAME())
+            .append("TYPE", getTYPE())
+            .append("NOTES", getNOTES())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskDetail.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskDetail.java
new file mode 100644
index 0000000..b2bc716
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskDetail.java
@@ -0,0 +1,553 @@
+package com.ruoyi.buss.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+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;
+
+/**
+ * 浠诲姟璋冮厤璇︽儏淇℃伅瀵硅薄 ds_task_detail
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DsTaskDetail extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private Long taskId;
+
+    /**  */
+    @Excel(name = "")
+    private Long harborId;
+
+    /**  */
+    @Excel(name = "")
+    private String harborName;
+
+    /**  */
+    @Excel(name = "")
+    private Long berthId;
+
+    /**  */
+    @Excel(name = "")
+    private String berthName;
+
+    /**  */
+    @Excel(name = "")
+    private String parkingType;
+
+    /**  */
+    @Excel(name = "")
+    private String shipNo;
+
+    /**  */
+    @Excel(name = "")
+    private String shipType;
+
+    /**  */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @Excel(name = "", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date STIME;
+
+    /**  */
+    private Integer elecStime;
+
+    /**  */
+    private Integer elecEtime;
+
+    /**  */
+    private Integer waterStime;
+
+    /**  */
+    private Integer waterEtime;
+
+    /**  */
+    private Integer oilStime;
+
+    /**  */
+    private Integer oilEtime;
+
+    /**  */
+    private Integer ammoStime;
+
+    /**  */
+    private Integer ammoEtime;
+
+    /**  */
+    private Integer matStime;
+
+    /**  */
+    private Integer matEtime;
+
+    /**  */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @Excel(name = "", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date ETIME;
+
+    /**  */
+    @Excel(name = "")
+    private Integer oilTime;
+
+    /**  */
+    @Excel(name = "")
+    private Integer ammoTime;
+
+    /**  */
+    @Excel(name = "")
+    private Integer matTime;
+
+    /**  */
+    @Excel(name = "")
+    private Integer waterTime;
+
+    private Integer totalTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    @Excel(name = "", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss")
+    private Date t1;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    private String supplySeq;
+
+    private Integer carCount;
+
+    private Integer oilApply;
+
+    private Integer oilReady;
+
+    private Integer ammoTest;
+
+    private Integer ammoStart;
+
+    private Double food;
+
+    private Double foodW;
+
+    private Double foodO;
+
+    private Long workGrpId;
+
+    private String workGrpName;
+
+    private Long deptId;
+
+    private Long workMatGrpId;
+
+    private String workMatGrpName;
+
+    private String path;
+
+    public void setPKID(Long PKID)
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public void setTaskId(Long taskId) 
+    {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() 
+    {
+        return taskId;
+    }
+
+    public void setHarborId(Long harborId) 
+    {
+        this.harborId = harborId;
+    }
+
+    public Long getHarborId() 
+    {
+        return harborId;
+    }
+
+    public void setHarborName(String harborName) 
+    {
+        this.harborName = harborName;
+    }
+
+    public String getHarborName() 
+    {
+        return harborName;
+    }
+
+    public void setBerthId(Long berthId) 
+    {
+        this.berthId = berthId;
+    }
+
+    public Long getBerthId() 
+    {
+        return berthId;
+    }
+
+    public void setBerthName(String berthName) 
+    {
+        this.berthName = berthName;
+    }
+
+    public String getBerthName() 
+    {
+        return berthName;
+    }
+
+    public void setParkingType(String parkingType) 
+    {
+        this.parkingType = parkingType;
+    }
+
+    public String getParkingType() 
+    {
+        return parkingType;
+    }
+
+    public void setShipNo(String shipNo) 
+    {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipNo() 
+    {
+        return shipNo;
+    }
+
+    public void setShipType(String shipType) 
+    {
+        this.shipType = shipType;
+    }
+
+    public String getShipType() 
+    {
+        return shipType;
+    }
+
+    public void setSTIME(Date STIME) 
+    {
+        this.STIME = STIME;
+    }
+
+    public Date getSTIME() 
+    {
+        return STIME;
+    }
+
+    public Integer getElecStime() {
+        return elecStime;
+    }
+
+    public void setElecStime(Integer elecStime) {
+        this.elecStime = elecStime;
+    }
+
+    public Integer getElecEtime() {
+        return elecEtime;
+    }
+
+    public void setElecEtime(Integer elecEtime) {
+        this.elecEtime = elecEtime;
+    }
+
+    public Integer getWaterStime() {
+        return waterStime;
+    }
+
+    public void setWaterStime(Integer waterStime) {
+        this.waterStime = waterStime;
+    }
+
+    public Integer getWaterEtime() {
+        return waterEtime;
+    }
+
+    public void setWaterEtime(Integer waterEtime) {
+        this.waterEtime = waterEtime;
+    }
+
+    public Integer getOilStime() {
+        return oilStime;
+    }
+
+    public void setOilStime(Integer oilStime) {
+        this.oilStime = oilStime;
+    }
+
+    public Integer getOilEtime() {
+        return oilEtime;
+    }
+
+    public void setOilEtime(Integer oilEtime) {
+        this.oilEtime = oilEtime;
+    }
+
+    public Integer getAmmoStime() {
+        return ammoStime;
+    }
+
+    public void setAmmoStime(Integer ammoStime) {
+        this.ammoStime = ammoStime;
+    }
+
+    public Integer getAmmoEtime() {
+        return ammoEtime;
+    }
+
+    public void setAmmoEtime(Integer ammoEtime) {
+        this.ammoEtime = ammoEtime;
+    }
+
+    public Integer getMatStime() {
+        return matStime;
+    }
+
+    public void setMatStime(Integer matStime) {
+        this.matStime = matStime;
+    }
+
+    public Integer getMatEtime() {
+        return matEtime;
+    }
+
+    public void setMatEtime(Integer matEtime) {
+        this.matEtime = matEtime;
+    }
+
+    public void setETIME(Date ETIME)
+    {
+        this.ETIME = ETIME;
+    }
+
+    public Date getETIME() 
+    {
+        return ETIME;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    public Date getT1() {
+        return t1;
+    }
+
+    public void setT1(Date t1) {
+        this.t1 = t1;
+    }
+
+    public String getSupplySeq() {
+        return supplySeq;
+    }
+
+    public void setSupplySeq(String supplySeq) {
+        this.supplySeq = supplySeq;
+    }
+
+    public Integer getCarCount() {
+        return carCount;
+    }
+
+    public void setCarCount(Integer carCount) {
+        this.carCount = carCount;
+    }
+
+    public Double getFood() {
+        return food;
+    }
+
+    public Integer getOilTime() {
+        return oilTime;
+    }
+
+    public void setOilTime(Integer oilTime) {
+        this.oilTime = oilTime;
+    }
+
+    public Integer getAmmoTime() {
+        return ammoTime;
+    }
+
+    public void setAmmoTime(Integer ammoTime) {
+        this.ammoTime = ammoTime;
+    }
+
+    public Integer getMatTime() {
+        return matTime;
+    }
+
+    public void setMatTime(Integer matTime) {
+        this.matTime = matTime;
+    }
+
+    public Integer getWaterTime() {
+        return waterTime;
+    }
+
+    public void setWaterTime(Integer waterTime) {
+        this.waterTime = waterTime;
+    }
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+    public Integer getOilApply() {
+        return oilApply;
+    }
+
+    public void setOilApply(Integer oilApply) {
+        this.oilApply = oilApply;
+    }
+
+    public Integer getOilReady() {
+        return oilReady;
+    }
+
+    public void setOilReady(Integer oilReady) {
+        this.oilReady = oilReady;
+    }
+
+    public Integer getAmmoTest() {
+        return ammoTest;
+    }
+
+    public void setAmmoTest(Integer ammoTest) {
+        this.ammoTest = ammoTest;
+    }
+
+    public Integer getAmmoStart() {
+        return ammoStart;
+    }
+
+    public void setAmmoStart(Integer ammoStart) {
+        this.ammoStart = ammoStart;
+    }
+
+    public void setFood(Double food) {
+        this.food = food;
+    }
+
+    public Double getFoodW() {
+        return foodW;
+    }
+
+    public void setFoodW(Double foodW) {
+        this.foodW = foodW;
+    }
+
+    public Double getFoodO() {
+        return foodO;
+    }
+
+    public void setFoodO(Double foodO) {
+        this.foodO = foodO;
+    }
+
+    public Long getWorkGrpId() {
+        return workGrpId;
+    }
+
+    public void setWorkGrpId(Long workGrpId) {
+        this.workGrpId = workGrpId;
+    }
+
+    public String getWorkGrpName() {
+        return workGrpName;
+    }
+
+    public void setWorkGrpName(String workGrpName) {
+        this.workGrpName = workGrpName;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getWorkMatGrpId() {
+        return workMatGrpId;
+    }
+
+    public void setWorkMatGrpId(Long workMatGrpId) {
+        this.workMatGrpId = workMatGrpId;
+    }
+
+    public String getWorkMatGrpName() {
+        return workMatGrpName;
+    }
+
+    public void setWorkMatGrpName(String workMatGrpName) {
+        this.workMatGrpName = workMatGrpName;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this,ToStringStyle.MULTI_LINE_STYLE)
+            .append("PKID", getPKID())
+            .append("taskId", getTaskId())
+            .append("harborId", getHarborId())
+            .append("harborName", getHarborName())
+            .append("berthId", getBerthId())
+            .append("berthName", getBerthName())
+            .append("parkingType", getParkingType())
+            .append("shipNo", getShipNo())
+            .append("shipType", getShipType())
+            .append("STIME", getSTIME())
+            .append("elecStime", getElecStime())
+            .append("elecEtime", getElecEtime())
+            .append("waterStime", getWaterStime())
+            .append("waterEtime", getWaterEtime())
+            .append("oilStime", getOilStime())
+            .append("oilEtime", getOilEtime())
+            .append("ammoStime", getAmmoStime())
+            .append("ammoEtime", getAmmoEtime())
+            .append("matStime", getMatStime())
+            .append("matEtime", getMatEtime())
+            .append("ETIME", getETIME())
+            .append("delFlag", getDelFlag())
+            .append("createBy", getCreateBy())
+            .append("createTime", getCreateTime())
+            .append("updateBy", getUpdateBy())
+            .append("updateTime", getUpdateTime())
+            .append("deptId", getDeptId())
+            .toString();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskList2.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskList2.java
new file mode 100644
index 0000000..3d82170
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/DsTaskList2.java
@@ -0,0 +1,631 @@
+package com.ruoyi.buss.domain;
+
+import java.util.Date;
+import com.fasterxml.jackson.annotation.JsonFormat;
+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;
+
+/**
+ * 浠诲姟鍒楄〃淇℃伅瀵硅薄 ds_task_list
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public class DsTaskList2 extends BaseEntity
+{
+    private static final long serialVersionUID = 1L;
+
+    /**  */
+    @Excel(name = "")
+    private Long PKID;
+
+    /**  */
+    @Excel(name = "")
+    private Long taskId;
+
+    /**  */
+    @Excel(name = "")
+    private String shipNo;
+
+    /**  */
+    @Excel(name = "")
+    private String shipType;
+
+    /**  */
+    @Excel(name = "")
+    private Double TONNAGE;
+
+    /**  */
+    @Excel(name = "")
+    private Double draft;
+
+    /**  */
+    @Excel(name = "")
+    private String LEADER;
+
+    /**  */
+    @Excel(name = "")
+    private Long STAFF;
+
+    /**  */
+    @Excel(name = "")
+    private String grpName;
+
+    /**  */
+    @Excel(name = "")
+    private Long LEVEL;
+
+    /**  */
+    @Excel(name = "")
+    private Double LAT;
+
+    /**  */
+    @Excel(name = "")
+    private Double LON;
+
+    /**  */
+    @Excel(name = "")
+    private String delFlag;
+
+    /**  */
+    @Excel(name = "")
+    private Double oilB;
+
+    /**  */
+    @Excel(name = "")
+    private Double oilG;
+
+    /**  */
+    @Excel(name = "")
+    private Double oilA;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoD;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoP;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoS;
+
+    /**  */
+    @Excel(name = "")
+    private Long ammoO;
+
+    /**  */
+    @Excel(name = "")
+    private Double WATER;
+
+    /**  */
+    @Excel(name = "")
+    private Double waterP;
+
+    /**  */
+    @Excel(name = "")
+    private Long FOOD;
+
+    /**  */
+    @Excel(name = "")
+    private Long foodW;
+
+    /**  */
+    @Excel(name = "")
+    private Long foodO;
+
+    /**  */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @Excel(name = "", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date pSTime;
+
+    /**  */
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    @Excel(name = "", width = 30, dateFormat = "yyyy-MM-dd")
+    private Date pETime;
+
+    /**  */
+    @Excel(name = "")
+    private String status;
+
+    /**  */
+    @Excel(name = "")
+    private Long harborId;
+
+    /**  */
+    @Excel(name = "")
+    private String harborName;
+
+    /**  */
+    @Excel(name = "")
+    private Long berthId;
+
+    /**  */
+    @Excel(name = "")
+    private String berthName;
+
+    /**  */
+    @Excel(name = "")
+    private String parkingType;
+
+    private String deptName;
+
+    private Long deptId;
+
+    private String posArea;
+
+    private Double width;
+
+    private String supplySeq;
+
+    private Double dockTime;
+
+    private Double shipLen;
+
+    private int dockIndex;
+
+    private Date tTime;
+
+    private String path;
+
+    public int getDockIndex() {
+        return dockIndex;
+    }
+
+    public void setDockIndex(int dockIndex) {
+        this.dockIndex = dockIndex;
+    }
+
+    public Date gettTime() {
+        return tTime;
+    }
+
+    public void settTime(Date tTime) {
+        this.tTime = tTime;
+    }
+
+    public boolean needRefueling() {
+        return oilB > 0 || oilG > 0 || oilA > 0;
+    }
+
+    public Double getShipLen() {
+        return shipLen;
+    }
+
+    public void setShipLen(Double shipLen) {
+        this.shipLen = shipLen;
+    }
+
+    public Double getDockTime() {
+        return dockTime;
+    }
+
+    public void setDockTime(Double dockTime) {
+        this.dockTime = dockTime;
+    }
+
+    public void setTaskId(Long taskId)
+    {
+        this.taskId = taskId;
+    }
+
+    public Long getTaskId() 
+    {
+        return taskId;
+    }
+
+    public void setShipNo(String shipNo) 
+    {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipNo() 
+    {
+        return shipNo;
+    }
+
+    public void setShipType(String shipType) 
+    {
+        this.shipType = shipType;
+    }
+
+    public String getShipType() 
+    {
+        return shipType;
+    }
+
+    public void setTONNAGE(Double TONNAGE) 
+    {
+        this.TONNAGE = TONNAGE;
+    }
+
+    public Double getTONNAGE() 
+    {
+        return TONNAGE;
+    }
+
+    public void setLEADER(String LEADER) 
+    {
+        this.LEADER = LEADER;
+    }
+
+    public String getLEADER() 
+    {
+        return LEADER;
+    }
+
+    public void setSTAFF(Long STAFF) 
+    {
+        this.STAFF = STAFF;
+    }
+
+    public Long getSTAFF() 
+    {
+        return STAFF;
+    }
+
+    public void setGrpName(String grpName) 
+    {
+        this.grpName = grpName;
+    }
+
+    public String getGrpName() 
+    {
+        return grpName;
+    }
+
+    public void setLEVEL(Long LEVEL) 
+    {
+        this.LEVEL = LEVEL;
+    }
+
+    public Long getLEVEL() 
+    {
+        return LEVEL;
+    }
+
+    public void setLAT(Double LAT) 
+    {
+        this.LAT = LAT;
+    }
+
+    public Double getLAT() 
+    {
+        return LAT;
+    }
+
+    public void setLON(Double LON) 
+    {
+        this.LON = LON;
+    }
+
+    public Double getLON() 
+    {
+        return LON;
+    }
+
+    public void setDelFlag(String delFlag) 
+    {
+        this.delFlag = delFlag;
+    }
+
+    public String getDelFlag() 
+    {
+        return delFlag;
+    }
+
+    public void setOilB(Double oilB) 
+    {
+        this.oilB = oilB;
+    }
+
+    public Double getOilB() 
+    {
+        return oilB;
+    }
+
+    public void setOilG(Double oilG) 
+    {
+        this.oilG = oilG;
+    }
+
+    public Double getOilG() 
+    {
+        return oilG;
+    }
+
+    public void setOilA(Double oilA) 
+    {
+        this.oilA = oilA;
+    }
+
+    public Double getOilA() 
+    {
+        return oilA;
+    }
+
+    public void setAmmoD(Long ammoD) 
+    {
+        this.ammoD = ammoD;
+    }
+
+    public Long getAmmoD() 
+    {
+        return ammoD;
+    }
+
+    public void setAmmoP(Long ammoP) 
+    {
+        this.ammoP = ammoP;
+    }
+
+    public Long getAmmoP() 
+    {
+        return ammoP;
+    }
+
+    public void setAmmoS(Long ammoS) 
+    {
+        this.ammoS = ammoS;
+    }
+
+    public Long getAmmoS() 
+    {
+        return ammoS;
+    }
+
+    public void setAmmoO(Long ammoO) 
+    {
+        this.ammoO = ammoO;
+    }
+
+    public Long getAmmoO() 
+    {
+        return ammoO;
+    }
+
+    public void setWATER(Double WATER) 
+    {
+        this.WATER = WATER;
+    }
+
+    public Double getWATER() 
+    {
+        return WATER;
+    }
+
+    public void setWaterP(Double waterP) 
+    {
+        this.waterP = waterP;
+    }
+
+    public Double getWaterP() 
+    {
+        return waterP;
+    }
+
+    public void setFOOD(Long FOOD) 
+    {
+        this.FOOD = FOOD;
+    }
+
+    public Long getFOOD() 
+    {
+        return FOOD;
+    }
+
+    public void setFoodW(Long foodW) 
+    {
+        this.foodW = foodW;
+    }
+
+    public Long getFoodW() 
+    {
+        return foodW;
+    }
+
+    public void setFoodO(Long foodO) 
+    {
+        this.foodO = foodO;
+    }
+
+    public Long getFoodO() 
+    {
+        return foodO;
+    }
+
+    public void setpSTime(Date pSTime) 
+    {
+        this.pSTime = pSTime;
+    }
+
+    public Date getpSTime() 
+    {
+        return pSTime;
+    }
+
+    public void setpETime(Date pETime) 
+    {
+        this.pETime = pETime;
+    }
+
+    public Date getpETime() 
+    {
+        return pETime;
+    }
+
+    public void setHarborId(Long harborId) 
+    {
+        this.harborId = harborId;
+    }
+
+    public Long getHarborId() 
+    {
+        return harborId;
+    }
+
+    public void setHarborName(String harborName) 
+    {
+        this.harborName = harborName;
+    }
+
+    public String getHarborName() 
+    {
+        return harborName;
+    }
+
+    public void setBerthId(Long berthId) 
+    {
+        this.berthId = berthId;
+    }
+
+    public Long getBerthId() 
+    {
+        return berthId;
+    }
+
+    public void setBerthName(String berthName) 
+    {
+        this.berthName = berthName;
+    }
+
+    public String getBerthName() 
+    {
+        return berthName;
+    }
+
+    public void setParkingType(String parkingType) 
+    {
+        this.parkingType = parkingType;
+    }
+
+    public String getParkingType() 
+    {
+        return parkingType;
+    }
+
+    public void setPKID(Long PKID) 
+    {
+        this.PKID = PKID;
+    }
+
+    public Long getPKID() 
+    {
+        return PKID;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public String getPosArea() {
+        return posArea;
+    }
+
+    public void setPosArea(String posArea) {
+        this.posArea = posArea;
+    }
+
+    public Double getWidth() {
+        return width;
+    }
+
+    public void setWidth(Double width) {
+        this.width = width;
+    }
+
+    public String getSupplySeq() {
+        return supplySeq;
+    }
+
+    public void setSupplySeq(String supplySeq) {
+        this.supplySeq = supplySeq;
+    }
+
+    public Double getDraft() {
+        return draft;
+    }
+
+    public void setDraft(Double draft) {
+        this.draft = draft;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+
+    @Override
+    public String toString() {
+        return "DsTaskList2 =: {" +
+                "PKID=" + PKID +
+                ", taskId=" + taskId +
+                ", shipNo='" + shipNo + '\'' +
+                ", shipType='" + shipType + '\'' +
+                ", TONNAGE=" + TONNAGE +
+                ", DRAFT=" + draft +
+                ", LEADER='" + LEADER + '\'' +
+                ", STAFF=" + STAFF +
+                ", grpName='" + grpName + '\'' +
+                ", LEVEL=" + LEVEL +
+                ", LAT=" + LAT +
+                ", LON=" + LON +
+                ", delFlag='" + delFlag + '\'' +
+                ", oilB=" + oilB +
+                ", oilG=" + oilG +
+                ", oilA=" + oilA +
+                ", ammoD=" + ammoD +
+                ", ammoP=" + ammoP +
+                ", ammoS=" + ammoS +
+                ", ammoO=" + ammoO +
+                ", WATER=" + WATER +
+                ", waterP=" + waterP +
+                ", FOOD=" + FOOD +
+                ", foodW=" + foodW +
+                ", foodO=" + foodO +
+                ", pSTime=" + pSTime +
+                ", pETime=" + pETime +
+                ", STATUS='" + status + '\'' +
+                ", harborId=" + harborId +
+                ", harborName='" + harborName + '\'' +
+                ", berthId=" + berthId +
+                ", berthName='" + berthName + '\'' +
+                ", parkingType='" + parkingType + '\'' +
+                ", deptName='" + deptName + '\'' +
+                ", deptId=" + deptId +
+                ", posArea='" + posArea + '\'' +
+                ", width=" + width +
+                ", supplySeq='" + supplySeq + '\'' +
+                ", dockTime=" + dockTime +
+                ", shipLen=" + shipLen +
+                ", dockIndex=" + dockIndex +
+                ", tTime=" + tTime +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthReqDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthReqDTO.java
new file mode 100644
index 0000000..adec45d
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthReqDTO.java
@@ -0,0 +1,53 @@
+package com.ruoyi.buss.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+@Schema(name = "AllocBerthReqDTO", description = "娉婁綅鍒嗛厤DTO")
+public class AllocBerthReqDTO implements Serializable {
+
+    @Schema(name = "berthids", description = "鍒嗛厤鐨勬硦浣峣d,澶氫釜娉婁綅鐢ㄩ�楀彿鍒嗛殧")
+    private String berthids;
+
+    @Schema(name = "rule", description = "娉婁綅鍒嗛厤绛栫暐")
+    private String rule;
+
+    @Schema(name = "deptId", description = "闇�瑕佽繘琛屽垎閰嶇殑閮ㄩ棬缂栫爜")
+    private Long deptId;
+
+    @Schema(name = "taskId", description = "浠诲姟缂栧彿")
+    private Long taskId;
+
+    public String getBerthids() {
+        return berthids;
+    }
+
+    public void setBerthids(String berthids) {
+        this.berthids = berthids;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthTimeReqDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthTimeReqDTO.java
new file mode 100644
index 0000000..fcf86e2
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocBerthTimeReqDTO.java
@@ -0,0 +1,42 @@
+package com.ruoyi.buss.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+@Schema(name = "AllocBerthTimeReqDTO", description = "娉婁綅鍒嗛厤DTO")
+public class AllocBerthTimeReqDTO implements Serializable {
+
+    @Schema(name = "rule", description = "娉婁綅鍒嗛厤绛栫暐")
+    private String rule;
+
+    @Schema(name = "deptId", description = "闇�瑕佽繘琛屽垎閰嶇殑閮ㄩ棬缂栫爜")
+    private Long deptId;
+
+    @Schema(name = "taskId", description = "浠诲姟缂栧彿")
+    private Long taskId;
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocationReqDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocationReqDTO.java
new file mode 100644
index 0000000..c004fce
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/AllocationReqDTO.java
@@ -0,0 +1,42 @@
+package com.ruoyi.buss.domain.dto;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+@Schema(name = "AllocationReqDTO", description = "鑸拌墖娓彛鍒嗛厤DTO")
+public class AllocationReqDTO implements Serializable {
+
+    @Schema(name = "shipnos", description = "鑸拌墖 鑸峰彿瀛楃涓诧紝澶氫釜鐢ㄩ�楀彿鍒嗛殧",required=true)
+    private String shipnos;
+
+    @Schema(name = "rule", description = "娓彛鍒嗛厤绛栫暐")
+    private String rule;
+
+    @Schema(name = "harborids", description = "娓彛缂栫爜瀛楃涓诧紝澶氫釜鐢ㄩ�楀彿鍒嗛殧")
+    private String harborids;
+
+    public String getShipnos() {
+        return shipnos;
+    }
+
+    public void setShipnos(String shipnos) {
+        this.shipnos = shipnos;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public String getHarborids() {
+        return harborids;
+    }
+
+    public void setHarborids(String harborids) {
+        this.harborids = harborids;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/DsTaskQueryParam.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/DsTaskQueryParam.java
new file mode 100644
index 0000000..9657617
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/DsTaskQueryParam.java
@@ -0,0 +1,75 @@
+package com.ruoyi.buss.domain.dto;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class DsTaskQueryParam implements Serializable {
+
+    private String name;
+    private String type;
+    private String status;
+    private String notes;
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date stime;
+    @JsonFormat(pattern = "yyyy-MM-dd", timezone = "GMT+8")
+    private Date etime;
+    private Long deptId;
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getNotes() {
+        return notes;
+    }
+
+    public void setNotes(String notes) {
+        this.notes = notes;
+    }
+
+    public Date getStime() {
+        return stime;
+    }
+
+    public void setStime(Date stime) {
+        this.stime = stime;
+    }
+
+    public Date getEtime() {
+        return etime;
+    }
+
+    public void setEtime(Date etime) {
+        this.etime = etime;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ShipGroupDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ShipGroupDTO.java
new file mode 100644
index 0000000..0ab24ed
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ShipGroupDTO.java
@@ -0,0 +1,33 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class ShipGroupDTO implements Serializable {
+    private String parkingType;
+    private List<TaskRecordList> dsTaskList;
+
+    public String getParkingType() {
+        return parkingType;
+    }
+
+    public void setParkingType(String parkingType) {
+        this.parkingType = parkingType;
+    }
+
+    public List<TaskRecordList> getDsTaskList() {
+        return dsTaskList;
+    }
+
+    public void setDsTaskList(List<TaskRecordList> dsTaskList) {
+        this.dsTaskList = dsTaskList;
+    }
+
+    @Override
+    public String toString() {
+        return "ShipGroupDTO =锛歿" +
+                "parkingType='" + parkingType + '\'' +
+                ", taskRecordList=" + dsTaskList +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/Subdata.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/Subdata.java
new file mode 100644
index 0000000..7eacfae
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/Subdata.java
@@ -0,0 +1,212 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+
+public class Subdata implements Serializable {
+    private Long pkId;
+    private Long taskId;
+    private String shipNo;
+    private String shipType;
+    private String tonnage;
+    private String supplySeq;
+    private Long oilB;
+    private Long oilG;
+    private Long oilA;
+    private Long ammoD;
+    private Long ammoP;
+    private Long ammoS;
+    private Long ammoO;
+    private Long water;
+    private Long waterP;
+    private Long food;
+    private Long foodW;
+    private Long foodO;
+    private String pSTime;
+    private String pETime;
+
+    public Long getPkId() {
+        return pkId;
+    }
+
+    public void setPkId(Long pkId) {
+        this.pkId = pkId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getShipNo() {
+        return shipNo;
+    }
+
+    public void setShipNo(String shipNo) {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipType() {
+        return shipType;
+    }
+
+    public void setShipType(String shipType) {
+        this.shipType = shipType;
+    }
+
+    public String getTonnage() {
+        return tonnage;
+    }
+
+    public void setTonnage(String tonnage) {
+        this.tonnage = tonnage;
+    }
+
+    public String getSupplySeq() {
+        return supplySeq;
+    }
+
+    public void setSupplySeq(String supplySeq) {
+        this.supplySeq = supplySeq;
+    }
+
+    public Long getOilB() {
+        return oilB;
+    }
+
+    public void setOilB(Long oilB) {
+        this.oilB = oilB;
+    }
+
+    public Long getOilG() {
+        return oilG;
+    }
+
+    public void setOilG(Long oilG) {
+        this.oilG = oilG;
+    }
+
+    public Long getOilA() {
+        return oilA;
+    }
+
+    public void setOilA(Long oilA) {
+        this.oilA = oilA;
+    }
+
+    public Long getAmmoD() {
+        return ammoD;
+    }
+
+    public void setAmmoD(Long ammoD) {
+        this.ammoD = ammoD;
+    }
+
+    public Long getAmmoP() {
+        return ammoP;
+    }
+
+    public void setAmmoP(Long ammoP) {
+        this.ammoP = ammoP;
+    }
+
+    public Long getAmmoS() {
+        return ammoS;
+    }
+
+    public void setAmmoS(Long ammoS) {
+        this.ammoS = ammoS;
+    }
+
+    public Long getAmmoO() {
+        return ammoO;
+    }
+
+    public void setAmmoO(Long ammoO) {
+        this.ammoO = ammoO;
+    }
+
+    public Long getWater() {
+        return water;
+    }
+
+    public void setWater(Long water) {
+        this.water = water;
+    }
+
+    public Long getWaterP() {
+        return waterP;
+    }
+
+    public void setWaterP(Long waterP) {
+        this.waterP = waterP;
+    }
+
+    public Long getFood() {
+        return food;
+    }
+
+    public void setFood(Long food) {
+        this.food = food;
+    }
+
+    public Long getFoodW() {
+        return foodW;
+    }
+
+    public void setFoodW(Long foodW) {
+        this.foodW = foodW;
+    }
+
+    public Long getFoodO() {
+        return foodO;
+    }
+
+    public void setFoodO(Long foodO) {
+        this.foodO = foodO;
+    }
+
+    public String getpSTime() {
+        return pSTime;
+    }
+
+    public void setpSTime(String pSTime) {
+        this.pSTime = pSTime;
+    }
+
+    public String getpETime() {
+        return pETime;
+    }
+
+    public void setpETime(String pETime) {
+        this.pETime = pETime;
+    }
+
+    @Override
+    public String toString() {
+        return "Subdata =: {" +
+                "pkId=" + pkId +
+                ", taskId='" + taskId + '\'' +
+                ", shipNo='" + shipNo + '\'' +
+                ", shipType='" + shipType + '\'' +
+                ", tonnage='" + tonnage + '\'' +
+                ", supplySeq='" + supplySeq + '\'' +
+                ", oilB=" + oilB +
+                ", oilG=" + oilG +
+                ", oilA=" + oilA +
+                ", ammoD=" + ammoD +
+                ", ammoP=" + ammoP +
+                ", ammoS=" + ammoS +
+                ", ammoO=" + ammoO +
+                ", water=" + water +
+                ", waterP=" + waterP +
+                ", food=" + food +
+                ", foodW=" + foodW +
+                ", foodO=" + foodO +
+                ", pSTime='" + pSTime + '\'' +
+                ", pETime='" + pETime + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskQueryParam.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskQueryParam.java
new file mode 100644
index 0000000..a8db1b6
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskQueryParam.java
@@ -0,0 +1,48 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskQueryParam implements Serializable {
+
+    private List<Long> ids;
+
+    private Long deptId;
+
+    private Long taskId;
+
+    private String status;
+
+
+    public List<Long> getIds() {
+        return ids;
+    }
+
+    public void setIds(List<Long> ids) {
+        this.ids = ids;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskRecordList.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskRecordList.java
new file mode 100644
index 0000000..54853d4
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/TaskRecordList.java
@@ -0,0 +1,63 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskRecordList implements Serializable {
+    private Long berthId;
+    private String berthName;
+    private Long harborId;
+    private String harborName;
+    private List<Subdata> subData;
+
+    public Long getBerthId() {
+        return berthId;
+    }
+
+    public void setBerthId(Long berthId) {
+        this.berthId = berthId;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public Long getHarborId() {
+        return harborId;
+    }
+
+    public void setHarborId(Long harborId) {
+        this.harborId = harborId;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public List<Subdata> getSubData() {
+        return subData;
+    }
+
+    public void setSubData(List<Subdata> subData) {
+        this.subData = subData;
+    }
+
+    @Override
+    public String toString() {
+        return "TaskRecordList =: {" +
+                "berthId=" + berthId +
+                ", berthName='" + berthName + '\'' +
+                ", harborId=" + harborId +
+                ", harborName='" + harborName + '\'' +
+                ", subData=" + subData +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdGroupDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdGroupDTO.java
new file mode 100644
index 0000000..3ab5f01
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdGroupDTO.java
@@ -0,0 +1,45 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+
+public class ZdGroupDTO implements Serializable {
+
+    private String berthIds;
+
+    private String berthGroupRule;
+
+    private String taskId;
+
+    public String getBerthIds() {
+        return berthIds;
+    }
+
+    public void setBerthIds(String berthIds) {
+        this.berthIds = berthIds;
+    }
+
+    public String getBerthGroupRule() {
+        return berthGroupRule;
+    }
+
+    public void setBerthGroupRule(String berthGroupRule) {
+        this.berthGroupRule = berthGroupRule;
+    }
+
+    public String getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(String taskId) {
+        this.taskId = taskId;
+    }
+
+    @Override
+    public String toString() {
+        return "ZdGroupDTO =锛� {" +
+                "berthIds='" + berthIds + '\'' +
+                ", berthGroupRule='" + berthGroupRule + '\'' +
+                ", taskId='" + taskId + '\'' +
+                '}';
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdSupplyPlanDTO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdSupplyPlanDTO.java
new file mode 100644
index 0000000..52e4287
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/dto/ZdSupplyPlanDTO.java
@@ -0,0 +1,35 @@
+package com.ruoyi.buss.domain.dto;
+
+import java.io.Serializable;
+
+public class ZdSupplyPlanDTO implements Serializable {
+    private Long taskId;
+
+    private String t1Time;
+
+    private String usedBerthIds;
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getT1Time() {
+        return t1Time;
+    }
+
+    public void setT1Time(String t1Time) {
+        this.t1Time = t1Time;
+    }
+
+    public String getUsedBerthIds() {
+        return usedBerthIds;
+    }
+
+    public void setUsedBerthIds(String usedBerthIds) {
+        this.usedBerthIds = usedBerthIds;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/DsTaskDetailVO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/DsTaskDetailVO.java
new file mode 100644
index 0000000..299fa4e
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/DsTaskDetailVO.java
@@ -0,0 +1,492 @@
+package com.ruoyi.buss.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.ruoyi.buss.domain.DsTaskDetail;
+import com.ruoyi.common.annotation.Excel;
+
+import java.io.Serializable;
+import java.util.Date;
+
+public class DsTaskDetailVO implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private Long PKID;
+    private Long taskId;
+    private Long harborId;
+    private String harborName;
+    private Long berthId;
+    private String berthName;
+    private String parkingType;
+    private String shipNo;
+    private String shipType;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date STIME;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date elecStime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date elecEtime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date waterStime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date waterEtime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date oilStime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date oilEtime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date ammoStime;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date ammoEtime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date matStime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date matEtime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date ETIME;
+
+    private Integer oilTime;
+
+    private Integer ammoTime;
+
+    private Integer matTime;
+    private Integer waterTime;
+    private Integer totalTime;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date t1;
+
+    private String delFlag;
+
+    private String supplySeq;
+
+    private Integer carCount;
+
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date oilApply;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date oilReady;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date ammoTest;
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", timezone = "GMT+8")
+    private Date ammoStart;
+
+    private Double food;
+
+    private Double foodW;
+
+    private Double foodO;
+
+    private Long workGrpId;
+
+    private String workGrpName;
+
+    private Long deptId;
+
+    private Long workMatGrpId;
+
+    private String workMatGrpName;
+
+    public Long getPKID() {
+        return PKID;
+    }
+
+    public void setPKID(Long PKID) {
+        this.PKID = PKID;
+    }
+
+    public Long getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(Long taskId) {
+        this.taskId = taskId;
+    }
+
+    public Long getHarborId() {
+        return harborId;
+    }
+
+    public void setHarborId(Long harborId) {
+        this.harborId = harborId;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public Long getBerthId() {
+        return berthId;
+    }
+
+    public void setBerthId(Long berthId) {
+        this.berthId = berthId;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public String getParkingType() {
+        return parkingType;
+    }
+
+    public void setParkingType(String parkingType) {
+        this.parkingType = parkingType;
+    }
+
+    public String getShipNo() {
+        return shipNo;
+    }
+
+    public void setShipNo(String shipNo) {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipType() {
+        return shipType;
+    }
+
+    public void setShipType(String shipType) {
+        this.shipType = shipType;
+    }
+
+    public Date getSTIME() {
+        return STIME;
+    }
+
+    public void setSTIME(Date STIME) {
+        this.STIME = STIME;
+    }
+
+    public Date getElecStime() {
+        return elecStime;
+    }
+
+    public void setElecStime(Date elecStime) {
+        this.elecStime = elecStime;
+    }
+
+    public Date getElecEtime() {
+        return elecEtime;
+    }
+
+    public void setElecEtime(Date elecEtime) {
+        this.elecEtime = elecEtime;
+    }
+
+    public Date getWaterStime() {
+        return waterStime;
+    }
+
+    public void setWaterStime(Date waterStime) {
+        this.waterStime = waterStime;
+    }
+
+    public Date getWaterEtime() {
+        return waterEtime;
+    }
+
+    public void setWaterEtime(Date waterEtime) {
+        this.waterEtime = waterEtime;
+    }
+
+    public Date getOilStime() {
+        return oilStime;
+    }
+
+    public void setOilStime(Date oilStime) {
+        this.oilStime = oilStime;
+    }
+
+    public Date getOilEtime() {
+        return oilEtime;
+    }
+
+    public void setOilEtime(Date oilEtime) {
+        this.oilEtime = oilEtime;
+    }
+
+    public Date getAmmoStime() {
+        return ammoStime;
+    }
+
+    public void setAmmoStime(Date ammoStime) {
+        this.ammoStime = ammoStime;
+    }
+
+    public Date getAmmoEtime() {
+        return ammoEtime;
+    }
+
+    public void setAmmoEtime(Date ammoEtime) {
+        this.ammoEtime = ammoEtime;
+    }
+
+    public Date getMatStime() {
+        return matStime;
+    }
+
+    public void setMatStime(Date matStime) {
+        this.matStime = matStime;
+    }
+
+    public Date getMatEtime() {
+        return matEtime;
+    }
+
+    public void setMatEtime(Date matEtime) {
+        this.matEtime = matEtime;
+    }
+
+    public Date getETIME() {
+        return ETIME;
+    }
+
+    public void setETIME(Date ETIME) {
+        this.ETIME = ETIME;
+    }
+
+    public Integer getOilTime() {
+        return oilTime;
+    }
+
+    public void setOilTime(Integer oilTime) {
+        this.oilTime = oilTime;
+    }
+
+    public Integer getAmmoTime() {
+        return ammoTime;
+    }
+
+    public void setAmmoTime(Integer ammoTime) {
+        this.ammoTime = ammoTime;
+    }
+
+    public Integer getMatTime() {
+        return matTime;
+    }
+
+    public void setMatTime(Integer matTime) {
+        this.matTime = matTime;
+    }
+
+    public Integer getWaterTime() {
+        return waterTime;
+    }
+
+    public void setWaterTime(Integer waterTime) {
+        this.waterTime = waterTime;
+    }
+
+    public Integer getTotalTime() {
+        return totalTime;
+    }
+
+    public void setTotalTime(Integer totalTime) {
+        this.totalTime = totalTime;
+    }
+
+    public Date getT1() {
+        return t1;
+    }
+
+    public void setT1(Date t1) {
+        this.t1 = t1;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getSupplySeq() {
+        return supplySeq;
+    }
+
+    public void setSupplySeq(String supplySeq) {
+        this.supplySeq = supplySeq;
+    }
+
+    public Integer getCarCount() {
+        return carCount;
+    }
+
+    public void setCarCount(Integer carCount) {
+        this.carCount = carCount;
+    }
+
+    public Date getOilApply() {
+        return oilApply;
+    }
+
+    public void setOilApply(Date oilApply) {
+        this.oilApply = oilApply;
+    }
+
+    public Date getOilReady() {
+        return oilReady;
+    }
+
+    public void setOilReady(Date oilReady) {
+        this.oilReady = oilReady;
+    }
+
+    public Date getAmmoTest() {
+        return ammoTest;
+    }
+
+    public void setAmmoTest(Date ammoTest) {
+        this.ammoTest = ammoTest;
+    }
+
+    public Date getAmmoStart() {
+        return ammoStart;
+    }
+
+    public void setAmmoStart(Date ammoStart) {
+        this.ammoStart = ammoStart;
+    }
+
+    public Double getFood() {
+        return food;
+    }
+
+    public void setFood(Double food) {
+        this.food = food;
+    }
+
+    public Double getFoodW() {
+        return foodW;
+    }
+
+    public void setFoodW(Double foodW) {
+        this.foodW = foodW;
+    }
+
+    public Double getFoodO() {
+        return foodO;
+    }
+
+    public void setFoodO(Double foodO) {
+        this.foodO = foodO;
+    }
+
+    public Long getWorkGrpId() {
+        return workGrpId;
+    }
+
+    public void setWorkGrpId(Long workGrpId) {
+        this.workGrpId = workGrpId;
+    }
+
+    public String getWorkGrpName() {
+        return workGrpName;
+    }
+
+    public void setWorkGrpName(String workGrpName) {
+        this.workGrpName = workGrpName;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public Long getWorkMatGrpId() {
+        return workMatGrpId;
+    }
+
+    public void setWorkMatGrpId(Long workMatGrpId) {
+        this.workMatGrpId = workMatGrpId;
+    }
+
+    public String getWorkMatGrpName() {
+        return workMatGrpName;
+    }
+
+    public void setWorkMatGrpName(String workMatGrpName) {
+        this.workMatGrpName = workMatGrpName;
+    }
+
+    public DsTaskDetailVO(Long PKID, Long taskId) {
+        this.PKID = PKID;
+        this.taskId = taskId;
+    }
+
+    public DsTaskDetailVO(DsTaskDetail detail) {
+        this.PKID = detail.getPKID();
+        this.taskId = detail.getTaskId();
+        this.harborId = detail.getHarborId();
+        this.harborName = detail.getHarborName();
+        this.berthId = detail.getBerthId();
+        this.berthName = detail.getBerthName();
+        this.parkingType = detail.getParkingType();
+        this.shipNo = detail.getShipNo();
+        this.shipType = detail.getShipType();
+        this.STIME = detail.getSTIME();
+
+        if (detail.getElecStime() != null) {
+            this.elecStime = new Date(detail.getT1().getTime() + detail.getElecStime() * 3600000);
+        }
+        if (detail.getElecEtime() != null) {
+            this.elecEtime = new Date(detail.getT1().getTime() + detail.getElecEtime() * 3600000);
+        }
+        if (detail.getWaterStime() != null) {
+            this.waterStime = new Date(detail.getT1().getTime() + detail.getWaterStime() * 3600000);
+        }
+        if (detail.getWaterEtime() != null) {
+            this.waterEtime = new Date(detail.getT1().getTime() + detail.getWaterEtime() * 3600000);
+        }
+        if (detail.getOilStime() != null) {
+            this.oilStime = new Date(detail.getT1().getTime() + detail.getOilStime() * 3600000);
+        }
+        if (detail.getOilEtime() != null) {
+            this.oilEtime = new Date(detail.getT1().getTime() + detail.getOilEtime() * 3600000);
+        }
+        if (detail.getAmmoStime() != null) {
+            this.ammoStime = new Date(detail.getT1().getTime() + detail.getAmmoStime() * 3600000);
+        }
+        if (detail.getAmmoEtime() != null) {
+            this.ammoEtime = new Date(detail.getT1().getTime() + detail.getAmmoEtime() * 3600000);
+        }
+        if (detail.getMatStime() != null) {
+            this.matStime = new Date(detail.getT1().getTime() + detail.getMatStime() * 3600000);
+        }
+        if (detail.getMatEtime() != null) {
+            this.matEtime = new Date(detail.getT1().getTime() + detail.getMatEtime() * 3600000);
+        }
+        this.ETIME = detail.getETIME();
+        this.oilTime = detail.getOilTime();
+        this.ammoTime = detail.getAmmoTime();
+        this.matTime = detail.getMatTime();
+        this.waterTime = detail.getWaterTime();
+        this.totalTime = detail.getTotalTime();
+        this.t1 = detail.getT1();
+        this.delFlag = detail.getDelFlag();
+        this.supplySeq = detail.getSupplySeq();
+        this.carCount = detail.getCarCount();
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/MatReqVO.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/MatReqVO.java
new file mode 100644
index 0000000..905342f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/MatReqVO.java
@@ -0,0 +1,11 @@
+package com.ruoyi.buss.domain.vo;
+
+import java.io.Serializable;
+
+public class MatReqVO implements Serializable {
+
+    private String content;
+
+    private String result;
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/RfIdVo.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/RfIdVo.java
new file mode 100644
index 0000000..c8a5232
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/RfIdVo.java
@@ -0,0 +1,43 @@
+package com.ruoyi.buss.domain.vo;
+
+import java.io.Serializable;
+
+public class RfIdVo implements Serializable {
+
+    private Integer id;
+    private String name;
+    private String path;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    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 RfIdVo() {
+    }
+
+    public RfIdVo(Integer id, String name, String path) {
+        this.id = id;
+        this.name = name;
+        this.path = path;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssess.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssess.java
new file mode 100644
index 0000000..8c7739f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssess.java
@@ -0,0 +1,28 @@
+package com.ruoyi.buss.domain.vo;
+
+import com.ruoyi.buss.domain.DsEffectAssess;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskAssess implements Serializable {
+    private DsEffectAssess assess;
+    private List<DsEffectAssessList> list;
+
+    public DsEffectAssess getAssess() {
+        return assess;
+    }
+
+    public void setAssess(DsEffectAssess assess) {
+        this.assess = assess;
+    }
+
+    public List<DsEffectAssessList> getList() {
+        return list;
+    }
+
+    public void setList(List<DsEffectAssessList> list) {
+        this.list = list;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssessHis.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssessHis.java
new file mode 100644
index 0000000..e2b1ea7
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskAssessHis.java
@@ -0,0 +1,29 @@
+package com.ruoyi.buss.domain.vo;
+
+import com.ruoyi.buss.domain.DsEffectAssess;
+import com.ruoyi.buss.domain.DsEffectAssessHis;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskAssessHis implements Serializable {
+    private DsEffectAssess assess;
+    private List<DsEffectAssessHis> list;
+
+    public DsEffectAssess getAssess() {
+        return assess;
+    }
+
+    public void setAssess(DsEffectAssess assess) {
+        this.assess = assess;
+    }
+
+    public List<DsEffectAssessHis> getList() {
+        return list;
+    }
+
+    public void setList(List<DsEffectAssessHis> list) {
+        this.list = list;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskListStatis.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskListStatis.java
new file mode 100644
index 0000000..02f177b
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskListStatis.java
@@ -0,0 +1,40 @@
+package com.ruoyi.buss.domain.vo;
+
+import com.ruoyi.buss.domain.DmHarbor2;
+import com.ruoyi.buss.domain.DsTaskList2;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskListStatis implements Serializable {
+
+    private DmHarbor2 harbor;
+
+    private List<DsTaskList2> tasks;
+
+    private DsTaskList2 statis;
+
+    public DmHarbor2 getHarbor() {
+        return harbor;
+    }
+
+    public void setHarbor(DmHarbor2 harbor) {
+        this.harbor = harbor;
+    }
+
+    public List<DsTaskList2> getTasks() {
+        return tasks;
+    }
+
+    public void setTasks(List<DsTaskList2> tasks) {
+        this.tasks = tasks;
+    }
+
+    public DsTaskList2 getStatis() {
+        return statis;
+    }
+
+    public void setStatis(DsTaskList2 statis) {
+        this.statis = statis;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlace.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlace.java
new file mode 100644
index 0000000..56df541
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlace.java
@@ -0,0 +1,317 @@
+package com.ruoyi.buss.domain.vo;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+@Schema(name = "TaskPlace", description = "鐮佸ご鍦哄湴缁熺")
+public class TaskPlace implements Serializable {
+
+    private Long berthId;
+
+    private String berthName;
+
+    private String type;
+
+    private Double t1;
+
+    private Double t2;
+
+    private Double t3;
+
+    private Double t4;
+
+    private Double t5;
+
+    private Double t6;
+
+    private Double t7;
+
+    private Double t8;
+
+    private Double t9;
+
+    private Double t10;
+
+    private Double t11;
+
+    private Double t12;
+
+    private Double t13;
+
+    private Double t14;
+
+    private Double t15;
+
+    private Double t16;
+
+    private Double t17;
+
+    private Double t18;
+
+    private Double t19;
+
+    private Double t20;
+
+    private Double t21;
+
+    private Double t22;
+
+    private Double t23;
+
+    private Double t24;
+
+    public Long getBerthId() {
+        return berthId;
+    }
+
+    public void setBerthId(Long berthId) {
+        this.berthId = berthId;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public Double getT1() {
+        return t1;
+    }
+
+    public void setT1(Double t1) {
+        this.t1 = t1;
+    }
+
+    public Double getT2() {
+        return t2;
+    }
+
+    public void setT2(Double t2) {
+        this.t2 = t2;
+    }
+
+    public Double getT3() {
+        return t3;
+    }
+
+    public void setT3(Double t3) {
+        this.t3 = t3;
+    }
+
+    public Double getT4() {
+        return t4;
+    }
+
+    public void setT4(Double t4) {
+        this.t4 = t4;
+    }
+
+    public Double getT5() {
+        return t5;
+    }
+
+    public void setT5(Double t5) {
+        this.t5 = t5;
+    }
+
+    public Double getT6() {
+        return t6;
+    }
+
+    public void setT6(Double t6) {
+        this.t6 = t6;
+    }
+
+    public Double getT7() {
+        return t7;
+    }
+
+    public void setT7(Double t7) {
+        this.t7 = t7;
+    }
+
+    public Double getT8() {
+        return t8;
+    }
+
+    public void setT8(Double t8) {
+        this.t8 = t8;
+    }
+
+    public Double getT9() {
+        return t9;
+    }
+
+    public void setT9(Double t9) {
+        this.t9 = t9;
+    }
+
+    public Double getT10() {
+        return t10;
+    }
+
+    public void setT10(Double t10) {
+        this.t10 = t10;
+    }
+
+    public Double getT11() {
+        return t11;
+    }
+
+    public void setT11(Double t11) {
+        this.t11 = t11;
+    }
+
+    public Double getT12() {
+        return t12;
+    }
+
+    public void setT12(Double t12) {
+        this.t12 = t12;
+    }
+
+    public Double getT13() {
+        return t13;
+    }
+
+    public void setT13(Double t13) {
+        this.t13 = t13;
+    }
+
+    public Double getT14() {
+        return t14;
+    }
+
+    public void setT14(Double t14) {
+        this.t14 = t14;
+    }
+
+    public Double getT15() {
+        return t15;
+    }
+
+    public void setT15(Double t15) {
+        this.t15 = t15;
+    }
+
+    public Double getT16() {
+        return t16;
+    }
+
+    public void setT16(Double t16) {
+        this.t16 = t16;
+    }
+
+    public Double getT17() {
+        return t17;
+    }
+
+    public void setT17(Double t17) {
+        this.t17 = t17;
+    }
+
+    public Double getT18() {
+        return t18;
+    }
+
+    public void setT18(Double t18) {
+        this.t18 = t18;
+    }
+
+    public Double getT19() {
+        return t19;
+    }
+
+    public void setT19(Double t19) {
+        this.t19 = t19;
+    }
+
+    public Double getT20() {
+        return t20;
+    }
+
+    public void setT20(Double t20) {
+        this.t20 = t20;
+    }
+
+    public Double getT21() {
+        return t21;
+    }
+
+    public void setT21(Double t21) {
+        this.t21 = t21;
+    }
+
+    public Double getT22() {
+        return t22;
+    }
+
+    public void setT22(Double t22) {
+        this.t22 = t22;
+    }
+
+    public Double getT23() {
+        return t23;
+    }
+
+    public void setT23(Double t23) {
+        this.t23 = t23;
+    }
+
+    public Double getT24() {
+        return t24;
+    }
+
+    public void setT24(Double t24) {
+        this.t24 = t24;
+    }
+
+    public TaskPlace() {
+    }
+
+    public TaskPlace(Long berthId, String berthName, String type) {
+        this.berthId = berthId;
+        this.berthName = berthName;
+        this.type = type;
+    }
+
+    public void setTimeSlot(String timeSlot, Double value) {
+        switch (timeSlot) {
+            case "t1": this.t1 = value; break;
+            case "t2": this.t2 = value; break;
+            case "t3": this.t3 = value; break;
+            case "t4": this.t4 = value; break;
+            case "t5": this.t5 = value; break;
+            case "t6": this.t6 = value; break;
+            case "t7": this.t7 = value; break;
+            case "t8": this.t8 = value; break;
+            case "t9": this.t9 = value; break;
+            case "t10": this.t10 = value; break;
+            case "t11": this.t11 = value; break;
+            case "t12": this.t12 = value; break;
+            case "t13": this.t13 = value; break;
+            case "t14": this.t14 = value; break;
+            case "t15": this.t15 = value; break;
+            case "t16": this.t16 = value; break;
+            case "t17": this.t17 = value; break;
+            case "t18": this.t18 = value; break;
+            case "t19": this.t19 = value; break;
+            case "t20": this.t20 = value; break;
+            case "t21": this.t21 = value; break;
+            case "t22": this.t22 = value; break;
+            case "t23": this.t23 = value; break;
+            case "t24": this.t24 = value; break;
+        }
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanList.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanList.java
new file mode 100644
index 0000000..596905f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanList.java
@@ -0,0 +1,10 @@
+package com.ruoyi.buss.domain.vo;
+
+import java.io.Serializable;
+
+public class TaskPlanList implements Serializable {
+
+    private String type;
+    private Long berthId;
+    private String berthName;
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatis.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatis.java
new file mode 100644
index 0000000..766f6ac
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatis.java
@@ -0,0 +1,49 @@
+package com.ruoyi.buss.domain.vo;
+
+import com.ruoyi.buss.domain.DsTaskDetail;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskPlanStatis implements Serializable {
+
+    private String  harborName;
+
+    private String berthName;
+
+    private String berthStrategy;
+
+    private List<DsTaskDetail> shipInfo;
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public String getBerthStrategy() {
+        return berthStrategy;
+    }
+
+    public void setBerthStrategy(String berthStrategy) {
+        this.berthStrategy = berthStrategy;
+    }
+
+    public List<DsTaskDetail> getShipInfo() {
+        return shipInfo;
+    }
+
+    public void setShipInfo(List<DsTaskDetail> shipInfo) {
+        this.shipInfo = shipInfo;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatisTime.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatisTime.java
new file mode 100644
index 0000000..f0082b8
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/domain/vo/TaskPlanStatisTime.java
@@ -0,0 +1,47 @@
+package com.ruoyi.buss.domain.vo;
+
+import java.io.Serializable;
+import java.util.List;
+
+public class TaskPlanStatisTime implements Serializable {
+
+    private String  harborName;
+
+    private String berthName;
+
+    private String berthStrategy;
+
+    private List<DsTaskDetailVO> shipInfo;
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public String getBerthStrategy() {
+        return berthStrategy;
+    }
+
+    public void setBerthStrategy(String berthStrategy) {
+        this.berthStrategy = berthStrategy;
+    }
+
+    public List<DsTaskDetailVO> getShipInfo() {
+        return shipInfo;
+    }
+
+    public void setShipInfo(List<DsTaskDetailVO> shipInfo) {
+        this.shipInfo = shipInfo;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmBerth2Mapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmBerth2Mapper.java
new file mode 100644
index 0000000..89234af
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmBerth2Mapper.java
@@ -0,0 +1,87 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmBerth2;
+
+/**
+ * 娉婁綅淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DmBerth2Mapper
+{
+    /**
+     * 鏌ヨ娉婁綅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 娉婁綅淇℃伅
+     */
+    public DmBerth2 selectDmBerthByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthList(DmBerth2 dmBerth2);
+
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     *
+     * @param harborIds 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthByHarborIds(List<Long> harborIds);
+
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃(鍙煡璇㈢姸鎬佷负姝e父鐨�)
+     *
+     * @param harborIds 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthByHarborIdsAndStatus(List<Long> harborIds);
+
+    /**
+     * 鏂板娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmBerth(DmBerth2 dmBerth2);
+
+    /**
+     * 淇敼娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmBerth(DmBerth2 dmBerth2);
+
+    /**
+     * 鍒犻櫎娉婁綅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmBerthByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎娉婁綅淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmBerthByPKIDs(String[] PKIDs);
+
+    /**
+     * 鏍规嵁娉婁綅ID搴忓垪鏌ヨ娉婁綅淇℃伅闆嗗悎
+     *
+     * @param berthIds 娉婁綅ID搴忓垪
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> getDmBerthListByIds(String berthIds);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmDdConfigMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmDdConfigMapper.java
new file mode 100644
index 0000000..ca007f1
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmDdConfigMapper.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmDdConfig;
+
+/**
+ * 璋冮厤閰嶇疆淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DmDdConfigMapper 
+{
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 璋冮厤閰嶇疆淇℃伅
+     */
+    public DmDdConfig selectDmDdConfigByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅鍒楄〃
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 璋冮厤閰嶇疆淇℃伅闆嗗悎
+     */
+    public List<DmDdConfig> selectDmDdConfigList(DmDdConfig dmDdConfig);
+
+    /**
+     * 鏂板璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmDdConfig(DmDdConfig dmDdConfig);
+
+    /**
+     * 淇敼璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmDdConfig(DmDdConfig dmDdConfig);
+
+    /**
+     * 鍒犻櫎璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmDdConfigByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmDdConfigByPKIDs(String[] PKIDs);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmHarbor2Mapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmHarbor2Mapper.java
new file mode 100644
index 0000000..b1e4c48
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmHarbor2Mapper.java
@@ -0,0 +1,70 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmHarbor2;
+
+/**
+ * 娓彛淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DmHarbor2Mapper
+{
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    public DmHarbor2 selectDmHarborByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor2> selectDmHarborList(DmHarbor2 dmHarbor2);
+
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     *
+     * @param list 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor2> selectDmHarborByPKIDs(List<Long> list);
+
+    /**
+     * 鏂板娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmHarbor(DmHarbor2 dmHarbor2);
+
+    /**
+     * 淇敼娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmHarbor(DmHarbor2 dmHarbor2);
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPKIDs(String[] PKIDs);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmWarshipMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmWarshipMapper.java
new file mode 100644
index 0000000..281d273
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DmWarshipMapper.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmWarship;
+
+/**
+ * 鑸拌墖淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DmWarshipMapper 
+{
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 鑸拌墖淇℃伅
+     */
+    public DmWarship selectDmWarshipByShipNo(String shipNo);
+
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅鍒楄〃
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 鑸拌墖淇℃伅闆嗗悎
+     */
+    public List<DmWarship> selectDmWarshipList(DmWarship dmWarship);
+
+    /**
+     * 鏂板鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmWarship(DmWarship dmWarship);
+
+    /**
+     * 淇敼鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmWarship(DmWarship dmWarship);
+
+    /**
+     * 鍒犻櫎鑸拌墖淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmWarshipByShipNo(String shipNo);
+
+    /**
+     * 鎵归噺鍒犻櫎鑸拌墖淇℃伅
+     * 
+     * @param shipNos 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmWarshipByShipNos(String[] shipNos);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessHisMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessHisMapper.java
new file mode 100644
index 0000000..82c3fce
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessHisMapper.java
@@ -0,0 +1,69 @@
+package com.ruoyi.buss.mapper;
+
+import com.ruoyi.buss.domain.DsEffectAssessHis;
+
+import java.util.List;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匨apper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface DsEffectAssessHisMapper 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    public DsEffectAssessHis selectDsEffectAssessHisByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯呴泦鍚�
+     */
+    public List<DsEffectAssessHis> selectDsEffectAssessHisList(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessHisByPKID(String PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessHisByPKIDs(String[] PKIDs);
+
+    /**
+     * 鏍规嵁浠诲姟ID 鍜岄儴闂↖D 鍒犻櫎瀵瑰簲璇勪及淇℃伅
+     * @param his
+     * @return
+     */
+    public int deleteDsEffectAssessHisByTaskIdAndDeptId(DsEffectAssessHis his);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessListMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessListMapper.java
new file mode 100644
index 0000000..e0ec25d
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessListMapper.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匨apper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface DsEffectAssessListMapper 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    public DsEffectAssessList selectDsEffectAssessListByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯呴泦鍚�
+     */
+    public List<DsEffectAssessList> selectDsEffectAssessListList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssessList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssessList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessListByPKID(String PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessListByPKIDs(String[] PKIDs);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessMapper.java
new file mode 100644
index 0000000..7e50ea0
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsEffectAssessMapper.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsEffectAssess;
+
+/**
+ * 鑳芥晥璇勪及Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface DsEffectAssessMapper 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 鑳芥晥璇勪及
+     */
+    public DsEffectAssess selectDsEffectAssessByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及鍒楄〃
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 鑳芥晥璇勪及闆嗗悎
+     */
+    public List<DsEffectAssess> selectDsEffectAssessList(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 鏂板鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssess(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 淇敼鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssess(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessByPKID(String PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessByPKIDs(String[] PKIDs);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsMatDispatchMapper2.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsMatDispatchMapper2.java
new file mode 100644
index 0000000..e3bf647
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsMatDispatchMapper2.java
@@ -0,0 +1,68 @@
+package com.ruoyi.buss.mapper;
+
+import com.ruoyi.buss.domain.DsMatDispatch2;
+
+import java.util.List;
+
+/**
+ * 鐗╄祫璺ㄦ腐璋冪敤Mapper 鎺ュ彛
+ */
+public interface DsMatDispatchMapper2 {
+
+    /**
+     * 鏌ヨ鐗╄祫璺ㄦ腐璋冪敤淇℃伅
+     * @param dsMatDispatch2
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchList(DsMatDispatch2 dsMatDispatch2);
+
+
+    /**
+     * 鏌ヨ闇�瑕佸鎵圭殑鐗╄祫璺ㄦ腐璋冪敤淇℃伅
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchForApply();
+
+    /**
+     * 鑾峰彇閮ㄩ棬缂栫爜鍜岀姸鎬佽幏鍙栦换鍔″垪琛�
+     * @param dsMatDispatch2
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchByDeptId(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 鏌ヨ鐗╄祫璺ㄦ腐璋冪敤鍒楄〃
+     * @param id
+     * @return
+     */
+    public DsMatDispatch2 selectDsMatDispatchById(Long id);
+
+    /**
+     * 鏂板鐗╄祫璺ㄦ腐璋冪敤
+     * @param dsMatDispatch2
+     * @return
+     */
+    public int insertDsMatDispatch(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 淇敼鐗╄祫璺ㄦ腐璋冪敤
+     * @param dsMatDispatch2
+     * @return
+     */
+    public int updateDsMatDispatch(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 鍒犻櫎鐗╄祫璺ㄦ腐璋冪敤
+     * @param id
+     * @return
+     */
+    public int deleteDsMatDispatchById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎鐗╄祫璺ㄦ腐璋冪敤
+     * @param ids
+     * @return
+     */
+    public int deleteDsMatDispatchByIds(String ids);
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskDetailMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskDetailMapper.java
new file mode 100644
index 0000000..a358071
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskDetailMapper.java
@@ -0,0 +1,94 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsTaskDetail;
+
+/**
+ * 浠诲姟璋冮厤璇︽儏淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DsTaskDetailMapper 
+{
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    public DsTaskDetail selectDsTaskDetailByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectDsTaskDetailList(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 鏌ヨ宀告儏浠诲姟璋冮厤鍒楄〃
+     *
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectAQTaskDetailList(Long deptId);
+
+
+    /**
+     * 鏌ヨ褰撳墠宀告儏浠诲姟璋冮厤鍒楄〃
+     *
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectAQCurTaskDetailList(Long deptId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岄儴闂ㄧ紪鐮佽幏鍙栬皟搴﹁鎯�
+     * @param taskid
+     * @param deptid
+     * @return
+     */
+    public List<DsTaskDetail> selectDsTaskDetailByTaskId(Long taskid, Long deptid);
+
+    /**
+     * 鏂板浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTaskDetail(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 淇敼浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTaskDetail(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskDetailByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskDetailByPKIDs(String[] PKIDs);
+
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岀爜澶碔D鑾峰彇璋冨害璇︽儏
+     * @param taskid
+     * @param harborIds
+     * @return
+     */
+    public List<DsTaskDetail> selectDsTaskDetailByTaskIdAndHarborIds(Long taskid, String harborIds);
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskList2Mapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskList2Mapper.java
new file mode 100644
index 0000000..f47d4b7
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskList2Mapper.java
@@ -0,0 +1,140 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.TaskQueryParam;
+
+/**
+ * 浠诲姟鍒楄〃淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DsTaskList2Mapper
+{
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectDsTaskListByTaskId(Long taskId);
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅V2
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListV2();
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskList();
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅 骞惰繃婊よ埛鍙�
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNo(String[] shipnos);
+
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅 骞惰繃婊よ埛鍙�
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNoV2(String[] shipnos);
+
+    /**
+     * 鏍规嵁浠诲姟鎵�灞為儴闂ㄦ煡璇换鍔″垪琛�
+     *
+     * @param param
+     * @return 浠诲姟鍒楄〃淇℃伅闆嗗悎
+     */
+    public List<DsTaskList2> selectDsTaskListByParam(TaskQueryParam param);
+
+    /**
+     * 鏍规嵁PKIDS鏁扮粍鏌ヨ瀵瑰簲鐨勮埌鑹囦俊鎭�
+     * @param pkids
+     * @return
+     */
+    public List<DsTaskList2> selectDsTaskListByPkids(List<Long> pkids);
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public DsTaskList2 selectDsTaskListByPKID(Long taskId);
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 浠诲姟鍒楄〃淇℃伅闆嗗悎
+     */
+    public List<DsTaskList2> selectDsTaskListList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 鏂板浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTaskList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 淇敼浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTaskList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 鍒犻櫎浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskListByTaskId(Long taskId);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskListByTaskIds(String[] taskIds);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岄儴闂↖D鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> getDsTaskListByTaskIdAndDeptId(DsTaskList2 dsTaskList2);
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID銆佷换鍔D鍜屾硦浣岻D鏌ヨDsTaskList2鏁版嵁闆嗗悎
+     * @param deptId
+     * @param taskId
+     * @param berthId
+     * @return
+     */
+    public List<DsTaskList2> getDsTaskListForSupplyPlan(Long deptId, Long taskId, Long berthId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜屾硦浣岻Ds鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param taskId
+     * @param berthIds
+     * @return
+     */
+    public List<DsTaskList2> selectDsTaskListListByTaskIdAndBerthds(Long taskId, String berthIds);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskMapper.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskMapper.java
new file mode 100644
index 0000000..44d0d72
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/mapper/DsTaskMapper.java
@@ -0,0 +1,76 @@
+package com.ruoyi.buss.mapper;
+
+import java.util.Date;
+import java.util.List;
+import com.ruoyi.buss.domain.DsTask;
+import com.ruoyi.buss.domain.dto.DsTaskQueryParam;
+
+/**
+ * 浠诲姟淇℃伅Mapper鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface DsTaskMapper 
+{
+
+    /**
+     * 鑾峰彇鏈�澶х殑浠诲姟ID
+     * @return
+     */
+    public Long selectMaxTaskId();
+    /**
+     * 鏌ヨ浠诲姟淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 浠诲姟淇℃伅
+     */
+    public DsTask selectDsTaskByPKID(Long PKID);
+
+    /**
+     * 鏍规嵁鏃ユ湡浠ュ強鎻忚堪鏌ヨ鍘嗗彶浠诲姟
+     * @param param
+     * @return
+     */
+    public List<DsTask> selectDsTaskListByParam(DsTaskQueryParam param);
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅鍒楄〃
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 浠诲姟淇℃伅闆嗗悎
+     */
+    public List<DsTask> selectDsTaskList(DsTask dsTask);
+
+    /**
+     * 鏂板浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTask(DsTask dsTask);
+
+    /**
+     * 淇敼浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTask(DsTask dsTask);
+
+    /**
+     * 鍒犻櫎浠诲姟淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskByPKIDs(String[] PKIDs);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmBerth2Service.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmBerth2Service.java
new file mode 100644
index 0000000..90bda60
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmBerth2Service.java
@@ -0,0 +1,85 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmBerth2;
+
+/**
+ * 娉婁綅淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDmBerth2Service
+{
+    /**
+     * 鏌ヨ娉婁綅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 娉婁綅淇℃伅
+     */
+    public DmBerth2 selectDmBerthByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     *
+     * @param harborIds 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthByHarborIds(List<Long> harborIds);
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃(鍙煡璇㈢姸鎬佷负姝e父鐨�)
+     *
+     * @param harborIds 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthByHarborIdsAndStatus(List<Long> harborIds);
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅闆嗗悎
+     */
+    public List<DmBerth2> selectDmBerthList(DmBerth2 dmBerth2);
+
+    /**
+     * 鏂板娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmBerth(DmBerth2 dmBerth2);
+
+    /**
+     * 淇敼娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmBerth(DmBerth2 dmBerth2);
+
+    /**
+     * 鎵归噺鍒犻櫎娉婁綅淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑娉婁綅淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmBerthByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎娉婁綅淇℃伅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmBerthByPKID(Long PKID);
+
+    /**
+     * 鏍规嵁娉婁綅ID搴忓垪鏌ヨ娉婁綅淇℃伅闆嗗悎
+     *
+     * @param berthIds 娉婁綅ID搴忓垪锛屼互閫楀彿鍒嗛殧
+     * @return
+     */
+    public List<DmBerth2> getDmBerthListByIds(String berthIds);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmDdConfigService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmDdConfigService.java
new file mode 100644
index 0000000..1b0e600
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmDdConfigService.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmDdConfig;
+
+/**
+ * 璋冮厤閰嶇疆淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDmDdConfigService 
+{
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 璋冮厤閰嶇疆淇℃伅
+     */
+    public DmDdConfig selectDmDdConfigByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅鍒楄〃
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 璋冮厤閰嶇疆淇℃伅闆嗗悎
+     */
+    public List<DmDdConfig> selectDmDdConfigList(DmDdConfig dmDdConfig);
+
+    /**
+     * 鏂板璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmDdConfig(DmDdConfig dmDdConfig);
+
+    /**
+     * 淇敼璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmDdConfig(DmDdConfig dmDdConfig);
+
+    /**
+     * 鎵归噺鍒犻櫎璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑璋冮厤閰嶇疆淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmDdConfigByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎璋冮厤閰嶇疆淇℃伅淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmDdConfigByPKID(Long PKID);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmHarbor2Service.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmHarbor2Service.java
new file mode 100644
index 0000000..934fc32
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmHarbor2Service.java
@@ -0,0 +1,69 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmHarbor2;
+
+/**
+ * 娓彛淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDmHarbor2Service
+{
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    public DmHarbor2 selectDmHarborByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor2> selectDmHarborList(DmHarbor2 dmHarbor2);
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     *
+     * @param list 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor2> selectDmHarborByPKIDs(List<Long> list);
+
+    /**
+     * 鏂板娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmHarbor(DmHarbor2 dmHarbor2);
+
+    /**
+     * 淇敼娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmHarbor(DmHarbor2 dmHarbor2);
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑娓彛淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPKID(Long PKID);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmWarshipService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmWarshipService.java
new file mode 100644
index 0000000..1e2ebf4
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDmWarshipService.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DmWarship;
+
+/**
+ * 鑸拌墖淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDmWarshipService 
+{
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 鑸拌墖淇℃伅
+     */
+    public DmWarship selectDmWarshipByShipNo(String shipNo);
+
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅鍒楄〃
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 鑸拌墖淇℃伅闆嗗悎
+     */
+    public List<DmWarship> selectDmWarshipList(DmWarship dmWarship);
+
+    /**
+     * 鏂板鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmWarship(DmWarship dmWarship);
+
+    /**
+     * 淇敼鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmWarship(DmWarship dmWarship);
+
+    /**
+     * 鎵归噺鍒犻櫎鑸拌墖淇℃伅
+     * 
+     * @param shipNos 闇�瑕佸垹闄ょ殑鑸拌墖淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmWarshipByShipNos(String shipNos);
+
+    /**
+     * 鍒犻櫎鑸拌墖淇℃伅淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmWarshipByShipNo(String shipNo);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessHisService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessHisService.java
new file mode 100644
index 0000000..e08d9ba
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessHisService.java
@@ -0,0 +1,78 @@
+package com.ruoyi.buss.service;
+
+import com.ruoyi.buss.domain.DsEffectAssessHis;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+import java.util.List;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匰ervice鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface IDsEffectAssessHisService 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    public DsEffectAssessHis selectDsEffectAssessHisByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯呴泦鍚�
+     */
+    public List<DsEffectAssessHis> selectDsEffectAssessHisList(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及椤硅鎯呬富閿泦鍚�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessHisByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯呬俊鎭�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessHisByPKID(String PKID);
+
+    /**
+     * 鏍规嵁閮ㄩ棬鍜�
+     * @param assessHis
+     * @return
+     */
+    public int deleteDsEffectAssessHisByTaskIdAndDeptId(DsEffectAssessHis assessHis);
+
+
+    /**
+     * 鏇存柊褰撳墠浠诲姟璇勪及鏁板��
+     * @param assessHisList
+     * @return
+     */
+    public int updateEffectAssessHisList(List<DsEffectAssessHis> assessHisList);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessListService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessListService.java
new file mode 100644
index 0000000..4ec6710
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessListService.java
@@ -0,0 +1,61 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匰ervice鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface IDsEffectAssessListService 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    public DsEffectAssessList selectDsEffectAssessListByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯呴泦鍚�
+     */
+    public List<DsEffectAssessList> selectDsEffectAssessListList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssessList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssessList(DsEffectAssessList dsEffectAssessList);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及椤硅鎯呬富閿泦鍚�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessListByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯呬俊鎭�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessListByPKID(String PKID);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessService.java
new file mode 100644
index 0000000..72a184c
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsEffectAssessService.java
@@ -0,0 +1,69 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsEffectAssess;
+
+/**
+ * 鑳芥晥璇勪及Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+public interface IDsEffectAssessService 
+{
+    /**
+     * 鏌ヨ鑳芥晥璇勪及
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 鑳芥晥璇勪及
+     */
+    public DsEffectAssess selectDsEffectAssessByPKID(String PKID);
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及鍒楄〃
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 鑳芥晥璇勪及闆嗗悎
+     */
+    public List<DsEffectAssess> selectDsEffectAssessList(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 鏂板鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    public int insertDsEffectAssess(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 淇敼鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    public int updateDsEffectAssess(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 淇敼鑳芥晥璇勪及
+     *
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    public int updateOrInsertDsEffectAssess(DsEffectAssess dsEffectAssess);
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及淇℃伅
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsEffectAssessByPKID(String PKID);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsMatDispatch2Service.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsMatDispatch2Service.java
new file mode 100644
index 0000000..489febc
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsMatDispatch2Service.java
@@ -0,0 +1,64 @@
+package com.ruoyi.buss.service;
+
+import com.ruoyi.buss.domain.DsMatDispatch2;
+
+import java.util.List;
+
+public interface IDsMatDispatch2Service {
+
+    /**
+     * 鏌ヨ鐗╄祫璺ㄦ腐璋冪敤淇℃伅
+     * @param dsMatDispatch2
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchList(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 鏌ヨ闇�瑕佸鎵圭殑鐗╄祫璺ㄦ腐璋冪敤淇℃伅
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchForApply();
+
+    /**
+     * 鑾峰彇閮ㄩ棬缂栫爜鍜岀姸鎬佽幏鍙栦换鍔″垪琛�
+     * @param deptId
+     * @return
+     */
+    public List<DsMatDispatch2> selectDsMatDispatchByDeptId(Long deptId, String status);
+
+
+    /**
+     * 鏌ヨ鐗╄祫璺ㄦ腐璋冪敤鍒楄〃
+     * @param id
+     * @return
+     */
+    public DsMatDispatch2 selectDsMatDispatchById(Long id);
+
+    /**
+     * 鏂板鐗╄祫璺ㄦ腐璋冪敤
+     * @param dsMatDispatch2
+     * @return
+     */
+    public int insertDsMatDispatch(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 淇敼鐗╄祫璺ㄦ腐璋冪敤
+     * @param dsMatDispatch2
+     * @return
+     */
+    public int updateDsMatDispatch(DsMatDispatch2 dsMatDispatch2);
+
+    /**
+     * 鍒犻櫎鐗╄祫璺ㄦ腐璋冪敤
+     * @param id
+     * @return
+     */
+    public int deleteDsMatDispatchById(Long id);
+
+    /**
+     * 鎵归噺鍒犻櫎鐗╄祫璺ㄦ腐璋冪敤
+     * @param ids
+     * @return
+     */
+    public int deleteDsMatDispatchByIds(String ids);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskDetailService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskDetailService.java
new file mode 100644
index 0000000..359ce4d
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskDetailService.java
@@ -0,0 +1,102 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsTaskDetail;
+
+/**
+ * 浠诲姟璋冮厤璇︽儏淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDsTaskDetailService 
+{
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    public DsTaskDetail selectDsTaskDetailByPKID(Long PKID);
+
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectDsTaskDetailList(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岄儴闂ㄧ紪鐮佽幏鍙栬皟搴﹁鎯�
+     * @param taskid
+     * @param deptid
+     * @return
+     */
+    public List<DsTaskDetail> selectDsTaskDetailByTaskId(Long taskid, Long deptid);
+
+
+    /**
+     * 鏌ヨ宀告儏浠诲姟璋冮厤鍒楄〃
+     *
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectAQTaskDetailList(Long deptId);
+
+    /**
+     * 鏌ヨ褰撳墠宀告儏浠诲姟璋冮厤鍒楄〃
+     *
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅闆嗗悎
+     */
+    public List<DsTaskDetail> selectAQCurTaskDetailList(Long deptId);
+
+    /**
+     * 鏂板浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTaskDetail(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 淇敼浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTaskDetail(DsTaskDetail dsTaskDetail);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskDetailByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskDetailByPKID(Long PKID);
+
+    /**
+     * 鎵归噺鏇存柊浠诲姟璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetailList 浠诲姟璇︽儏淇℃伅鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchUpdateDsTaskDetail(List<DsTaskDetail> dsTaskDetailList);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岀爜澶碔D鑾峰彇璋冨害璇︽儏
+     * @param taskid
+     * @param harborIds
+     * @return
+     */
+    public List<DsTaskDetail> selectDsTaskDetailByTaskIdAndHarborIds(Long taskid, String harborIds);
+
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskList2Service.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskList2Service.java
new file mode 100644
index 0000000..01b3971
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskList2Service.java
@@ -0,0 +1,151 @@
+package com.ruoyi.buss.service;
+
+import java.util.List;
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.TaskQueryParam;
+
+/**
+ * 浠诲姟鍒楄〃淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDsTaskList2Service
+{
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param taskId 浠诲姟鍒楄〃淇℃伅
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectDsTaskListByTaskId(Long taskId);
+
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅V2
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListV2();
+
+    /**
+     * 鏌ヨ褰撳墠闇�瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅
+     *
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public List<DsTaskList2> selectCurrentDsTaskList();
+
+
+    /**
+     * 璇㈠綋鍓嶉渶瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅 骞惰繃婊よ埛鍙�
+     * @param shipnos
+     * @return
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNo(String[] shipnos);
+
+    /**
+     * 璇㈠綋鍓嶉渶瑕佺‘瀹氱殑鑸拌墖鍒楄〃淇℃伅 骞惰繃婊よ埛鍙�
+     * @param shipnos
+     * @return
+     */
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNoV2(String[] shipnos);
+
+    /**
+     * 鏍规嵁PKIDS鏁扮粍鏌ヨ瀵瑰簲鐨勮埌鑹囦俊鎭�
+     * @param pkids
+     * @return
+     */
+    public List<DsTaskList2> selectDsTaskListByPkids(List<Long> pkids);
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param pkid 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    public DsTaskList2 selectDsTaskListByPkid(Long  pkid);
+
+
+    /**
+     * 鏍规嵁浠诲姟鎵�灞為儴闂ㄦ煡璇换鍔″垪琛�
+     *
+     * @param param
+     * @return 浠诲姟鍒楄〃淇℃伅闆嗗悎
+     */
+    public List<DsTaskList2> selectDsTaskListByParam(TaskQueryParam param);
+
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 浠诲姟鍒楄〃淇℃伅闆嗗悎
+     */
+    public List<DsTaskList2> selectDsTaskListList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 鏂板浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTaskList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 淇敼浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTaskList(DsTaskList2 dsTaskList2);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑浠诲姟鍒楄〃淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskListByTaskIds(String taskIds);
+
+    /**
+     * 鍒犻櫎浠诲姟鍒楄〃淇℃伅淇℃伅
+     * 
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskListByTaskId(Long taskId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岄儴闂↖D鏌ヨ浠诲姟鍒楄〃淇℃伅
+     * @param taskId
+     * @param deptId
+     * @return
+     */
+    public List<DsTaskList2> getDsTaskListByTaskIdAndDeptId(Long taskId, Long deptId);
+
+    /**
+     * 鏍规嵁閮ㄩ棬ID銆佷换鍔D鍜屾硦浣岻D鏌ヨDsTaskList2鏁版嵁闆嗗悎
+     * @param deptId
+     * @param taskId
+     * @param berthId
+     * @return
+     */
+    public List<DsTaskList2> getDsTaskListForSupplyPlan(Long deptId, Long taskId, Long berthId);
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜屾硦浣岻Ds鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param taskId
+     * @param berthIds
+     * @return
+     */
+    public List<DsTaskList2> selectDsTaskListListByTaskIdAndBerthds(Long taskId, String berthIds);
+
+    /**
+     * 鎵归噺鏇存柊浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2List 浠诲姟鍒楄〃淇℃伅鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchUpdateDsTaskList(List<DsTaskList2> dsTaskList2List);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskService.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskService.java
new file mode 100644
index 0000000..ca23fac
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/IDsTaskService.java
@@ -0,0 +1,76 @@
+package com.ruoyi.buss.service;
+
+import java.util.Date;
+import java.util.List;
+import com.ruoyi.buss.domain.DsTask;
+import com.ruoyi.buss.domain.dto.DsTaskQueryParam;
+
+/**
+ * 浠诲姟淇℃伅Service鎺ュ彛
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+public interface IDsTaskService 
+{
+    /**
+     * 鑾峰彇鏈�澶х殑浠诲姟ID
+     * @return
+     */
+    public Long selectMaxTaskId();
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 浠诲姟淇℃伅
+     */
+    public DsTask selectDsTaskByPKID(Long PKID);
+
+    /**
+     * 鏍规嵁鏃ユ湡浠ュ強鎻忚堪鏌ヨ鍘嗗彶浠诲姟
+     * @param param
+     * @return
+     */
+    public List<DsTask> selectDsTaskListByParam(DsTaskQueryParam param);
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅鍒楄〃
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 浠诲姟淇℃伅闆嗗悎
+     */
+    public List<DsTask> selectDsTaskList(DsTask dsTask);
+
+    /**
+     * 鏂板浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDsTask(DsTask dsTask);
+
+    /**
+     * 淇敼浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDsTask(DsTask dsTask);
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑浠诲姟淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskByPKIDs(String PKIDs);
+
+    /**
+     * 鍒犻櫎浠诲姟淇℃伅淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDsTaskByPKID(Long PKID);
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmBerthService2Impl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmBerthService2Impl.java
new file mode 100644
index 0000000..9e3e047
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmBerthService2Impl.java
@@ -0,0 +1,119 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.buss.domain.DmBerth2;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DmBerth2Mapper;
+import com.ruoyi.buss.service.IDmBerth2Service;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 娉婁綅淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DmBerthService2Impl implements IDmBerth2Service
+{
+    @Autowired
+    private DmBerth2Mapper dmBerthMapper;
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 娉婁綅淇℃伅
+     */
+    @Override
+    public DmBerth2 selectDmBerthByPKID(Long PKID)
+    {
+        return dmBerthMapper.selectDmBerthByPKID(PKID);
+    }
+
+    @Override
+    public List<DmBerth2> selectDmBerthByHarborIds(List<Long> harborIds) {
+        return dmBerthMapper.selectDmBerthByHarborIds(harborIds);
+    }
+
+    @Override
+    public List<DmBerth2> selectDmBerthByHarborIdsAndStatus(List<Long> harborIds) {
+        return dmBerthMapper.selectDmBerthByHarborIdsAndStatus(harborIds);
+    }
+
+    /**
+     * 鏌ヨ娉婁綅淇℃伅鍒楄〃
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 娉婁綅淇℃伅
+     */
+    @Override
+    public List<DmBerth2> selectDmBerthList(DmBerth2 dmBerth2)
+    {
+        return dmBerthMapper.selectDmBerthList(dmBerth2);
+    }
+
+    /**
+     * 鏂板娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDmBerth(DmBerth2 dmBerth2)
+    {
+        dmBerth2.setCreateTime(DateUtils.getNowDate());
+        return dmBerthMapper.insertDmBerth(dmBerth2);
+    }
+
+    /**
+     * 淇敼娉婁綅淇℃伅
+     * 
+     * @param dmBerth2 娉婁綅淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDmBerth(DmBerth2 dmBerth2)
+    {
+        dmBerth2.setUpdateTime(DateUtils.getNowDate());
+        return dmBerthMapper.updateDmBerth(dmBerth2);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娉婁綅淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑娉婁綅淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmBerthByPKIDs(String PKIDs)
+    {
+        return dmBerthMapper.deleteDmBerthByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎娉婁綅淇℃伅淇℃伅
+     * 
+     * @param PKID 娉婁綅淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmBerthByPKID(Long PKID)
+    {
+        return dmBerthMapper.deleteDmBerthByPKID(PKID);
+    }
+
+    /**
+     * 鏍规嵁娉婁綅ID搴忓垪鏌ヨ娉婁綅淇℃伅闆嗗悎
+     *
+     * @param berthIds 娉婁綅ID搴忓垪锛屼互閫楀彿鍒嗛殧
+     * @return
+     */
+    @Override
+    public List<DmBerth2> getDmBerthListByIds(String berthIds) {
+        return dmBerthMapper.getDmBerthListByIds("(" + berthIds + ")");
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmDdConfigServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmDdConfigServiceImpl.java
new file mode 100644
index 0000000..e23b877
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmDdConfigServiceImpl.java
@@ -0,0 +1,94 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DmDdConfigMapper;
+import com.ruoyi.buss.domain.DmDdConfig;
+import com.ruoyi.buss.service.IDmDdConfigService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 璋冮厤閰嶇疆淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DmDdConfigServiceImpl implements IDmDdConfigService 
+{
+    @Autowired
+    private DmDdConfigMapper dmDdConfigMapper;
+
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 璋冮厤閰嶇疆淇℃伅
+     */
+    @Override
+    public DmDdConfig selectDmDdConfigByPKID(Long PKID)
+    {
+        return dmDdConfigMapper.selectDmDdConfigByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ璋冮厤閰嶇疆淇℃伅鍒楄〃
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 璋冮厤閰嶇疆淇℃伅
+     */
+    @Override
+    public List<DmDdConfig> selectDmDdConfigList(DmDdConfig dmDdConfig)
+    {
+        return dmDdConfigMapper.selectDmDdConfigList(dmDdConfig);
+    }
+
+    /**
+     * 鏂板璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDmDdConfig(DmDdConfig dmDdConfig)
+    {
+        return dmDdConfigMapper.insertDmDdConfig(dmDdConfig);
+    }
+
+    /**
+     * 淇敼璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param dmDdConfig 璋冮厤閰嶇疆淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDmDdConfig(DmDdConfig dmDdConfig)
+    {
+        return dmDdConfigMapper.updateDmDdConfig(dmDdConfig);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎璋冮厤閰嶇疆淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmDdConfigByPKIDs(String PKIDs)
+    {
+        return dmDdConfigMapper.deleteDmDdConfigByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎璋冮厤閰嶇疆淇℃伅淇℃伅
+     * 
+     * @param PKID 璋冮厤閰嶇疆淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmDdConfigByPKID(Long PKID)
+    {
+        return dmDdConfigMapper.deleteDmDdConfigByPKID(PKID);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmHarbor2ServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmHarbor2ServiceImpl.java
new file mode 100644
index 0000000..2b675ee
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmHarbor2ServiceImpl.java
@@ -0,0 +1,103 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.buss.domain.DmHarbor2;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DmHarbor2Mapper;
+import com.ruoyi.buss.service.IDmHarbor2Service;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 娓彛淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DmHarbor2ServiceImpl implements IDmHarbor2Service
+{
+    @Autowired
+    private DmHarbor2Mapper dmHarborMapper;
+
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    @Override
+    public DmHarbor2 selectDmHarborByPKID(Long PKID)
+    {
+        return dmHarborMapper.selectDmHarborByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 娓彛淇℃伅
+     */
+    @Override
+    public List<DmHarbor2> selectDmHarborList(DmHarbor2 dmHarbor2)
+    {
+        return dmHarborMapper.selectDmHarborList(dmHarbor2);
+    }
+
+    @Override
+    public List<DmHarbor2> selectDmHarborByPKIDs(List<Long> list) {
+        return dmHarborMapper.selectDmHarborByPKIDs(list);
+    }
+
+    /**
+     * 鏂板娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDmHarbor(DmHarbor2 dmHarbor2)
+    {
+        dmHarbor2.setCreateTime(DateUtils.getNowDate());
+        return dmHarborMapper.insertDmHarbor(dmHarbor2);
+    }
+
+    /**
+     * 淇敼娓彛淇℃伅
+     * 
+     * @param dmHarbor2 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDmHarbor(DmHarbor2 dmHarbor2)
+    {
+        dmHarbor2.setUpdateTime(DateUtils.getNowDate());
+        return dmHarborMapper.updateDmHarbor(dmHarbor2);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmHarborByPKIDs(String PKIDs)
+    {
+        return dmHarborMapper.deleteDmHarborByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅淇℃伅
+     * 
+     * @param PKID 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmHarborByPKID(Long PKID)
+    {
+        return dmHarborMapper.deleteDmHarborByPKID(PKID);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmWarshipServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmWarshipServiceImpl.java
new file mode 100644
index 0000000..f2caac1
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DmWarshipServiceImpl.java
@@ -0,0 +1,97 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DmWarshipMapper;
+import com.ruoyi.buss.domain.DmWarship;
+import com.ruoyi.buss.service.IDmWarshipService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 鑸拌墖淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DmWarshipServiceImpl implements IDmWarshipService 
+{
+    @Autowired
+    private DmWarshipMapper dmWarshipMapper;
+
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 鑸拌墖淇℃伅
+     */
+    @Override
+    public DmWarship selectDmWarshipByShipNo(String shipNo)
+    {
+        return dmWarshipMapper.selectDmWarshipByShipNo(shipNo);
+    }
+
+    /**
+     * 鏌ヨ鑸拌墖淇℃伅鍒楄〃
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 鑸拌墖淇℃伅
+     */
+    @Override
+    public List<DmWarship> selectDmWarshipList(DmWarship dmWarship)
+    {
+        return dmWarshipMapper.selectDmWarshipList(dmWarship);
+    }
+
+    /**
+     * 鏂板鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDmWarship(DmWarship dmWarship)
+    {
+        dmWarship.setCreateTime(DateUtils.getNowDate());
+        return dmWarshipMapper.insertDmWarship(dmWarship);
+    }
+
+    /**
+     * 淇敼鑸拌墖淇℃伅
+     * 
+     * @param dmWarship 鑸拌墖淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDmWarship(DmWarship dmWarship)
+    {
+        dmWarship.setUpdateTime(DateUtils.getNowDate());
+        return dmWarshipMapper.updateDmWarship(dmWarship);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鑸拌墖淇℃伅
+     * 
+     * @param shipNos 闇�瑕佸垹闄ょ殑鑸拌墖淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmWarshipByShipNos(String shipNos)
+    {
+        return dmWarshipMapper.deleteDmWarshipByShipNos(Convert.toStrArray(shipNos));
+    }
+
+    /**
+     * 鍒犻櫎鑸拌墖淇℃伅淇℃伅
+     * 
+     * @param shipNo 鑸拌墖淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmWarshipByShipNo(String shipNo)
+    {
+        return dmWarshipMapper.deleteDmWarshipByShipNo(shipNo);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessHisServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessHisServiceImpl.java
new file mode 100644
index 0000000..1a4ea2e
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessHisServiceImpl.java
@@ -0,0 +1,120 @@
+package com.ruoyi.buss.service.impl;
+
+import com.ruoyi.buss.domain.DsEffectAssessHis;
+import com.ruoyi.buss.mapper.DsEffectAssessHisMapper;
+import com.ruoyi.buss.service.IDsEffectAssessHisService;
+import com.ruoyi.common.core.text.Convert;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匰ervice涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+@Service
+public class DsEffectAssessHisServiceImpl implements IDsEffectAssessHisService
+{
+    @Autowired
+    private DsEffectAssessHisMapper dsEffectAssessHisMapper;
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    @Override
+    public DsEffectAssessHis selectDsEffectAssessHisByPKID(String PKID)
+    {
+        return dsEffectAssessHisMapper.selectDsEffectAssessHisByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    @Override
+    public List<DsEffectAssessHis> selectDsEffectAssessHisList(DsEffectAssessHis dsEffectAssessHis)
+    {
+        return dsEffectAssessHisMapper.selectDsEffectAssessHisList(dsEffectAssessHis);
+    }
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis)
+    {
+        dsEffectAssessHis.setCreateTime(DateUtils.getNowDate());
+        return dsEffectAssessHisMapper.insertDsEffectAssessHis(dsEffectAssessHis);
+    }
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessHis 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsEffectAssessHis(DsEffectAssessHis dsEffectAssessHis)
+    {
+        dsEffectAssessHis.setUpdateTime(DateUtils.getNowDate());
+        return dsEffectAssessHisMapper.updateDsEffectAssessHis(dsEffectAssessHis);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessHisByPKIDs(String PKIDs)
+    {
+        return dsEffectAssessHisMapper.deleteDsEffectAssessHisByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯呬俊鎭�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessHisByPKID(String PKID)
+    {
+        return dsEffectAssessHisMapper.deleteDsEffectAssessHisByPKID(PKID);
+    }
+
+    @Override
+    public int deleteDsEffectAssessHisByTaskIdAndDeptId(DsEffectAssessHis assessHis) {
+        return dsEffectAssessHisMapper.insertDsEffectAssessHis(assessHis);
+    }
+
+    @Override
+    public int updateEffectAssessHisList(List<DsEffectAssessHis> assessHisList) {
+        if(null != assessHisList && assessHisList.size() > 0){
+            DsEffectAssessHis his = assessHisList.get(0);
+
+            // 鏌ョ湅褰撳墠鏄惁鏈夋暟鍊硷紝 濡傛灉鏈夊垯鍏堝垹闄�
+            dsEffectAssessHisMapper.deleteDsEffectAssessHisByTaskIdAndDeptId(his);
+
+            // 鎻掑叆褰撳墠鏁板��
+            for(DsEffectAssessHis tmpHis : assessHisList){
+                dsEffectAssessHisMapper.insertDsEffectAssessHis(tmpHis);
+            }
+            return 1;
+        }
+        return 0;
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessListServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessListServiceImpl.java
new file mode 100644
index 0000000..f4a7a70
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessListServiceImpl.java
@@ -0,0 +1,97 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DsEffectAssessListMapper;
+import com.ruoyi.buss.domain.DsEffectAssessList;
+import com.ruoyi.buss.service.IDsEffectAssessListService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 鑳芥晥璇勪及椤硅鎯匰ervice涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+@Service
+public class DsEffectAssessListServiceImpl implements IDsEffectAssessListService 
+{
+    @Autowired
+    private DsEffectAssessListMapper dsEffectAssessListMapper;
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    @Override
+    public DsEffectAssessList selectDsEffectAssessListByPKID(String PKID)
+    {
+        return dsEffectAssessListMapper.selectDsEffectAssessListByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及椤硅鎯呭垪琛�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 鑳芥晥璇勪及椤硅鎯�
+     */
+    @Override
+    public List<DsEffectAssessList> selectDsEffectAssessListList(DsEffectAssessList dsEffectAssessList)
+    {
+        return dsEffectAssessListMapper.selectDsEffectAssessListList(dsEffectAssessList);
+    }
+
+    /**
+     * 鏂板鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsEffectAssessList(DsEffectAssessList dsEffectAssessList)
+    {
+        dsEffectAssessList.setCreateTime(DateUtils.getNowDate());
+        return dsEffectAssessListMapper.insertDsEffectAssessList(dsEffectAssessList);
+    }
+
+    /**
+     * 淇敼鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param dsEffectAssessList 鑳芥晥璇勪及椤硅鎯�
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsEffectAssessList(DsEffectAssessList dsEffectAssessList)
+    {
+        dsEffectAssessList.setUpdateTime(DateUtils.getNowDate());
+        return dsEffectAssessListMapper.updateDsEffectAssessList(dsEffectAssessList);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及椤硅鎯�
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessListByPKIDs(String PKIDs)
+    {
+        return dsEffectAssessListMapper.deleteDsEffectAssessListByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及椤硅鎯呬俊鎭�
+     * 
+     * @param PKID 鑳芥晥璇勪及椤硅鎯呬富閿�
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessListByPKID(String PKID)
+    {
+        return dsEffectAssessListMapper.deleteDsEffectAssessListByPKID(PKID);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessServiceImpl.java
new file mode 100644
index 0000000..b0f539f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsEffectAssessServiceImpl.java
@@ -0,0 +1,118 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DsEffectAssessMapper;
+import com.ruoyi.buss.domain.DsEffectAssess;
+import com.ruoyi.buss.service.IDsEffectAssessService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 鑳芥晥璇勪及Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-24
+ */
+@Service
+public class DsEffectAssessServiceImpl implements IDsEffectAssessService 
+{
+    @Autowired
+    private DsEffectAssessMapper dsEffectAssessMapper;
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 鑳芥晥璇勪及
+     */
+    @Override
+    public DsEffectAssess selectDsEffectAssessByPKID(String PKID)
+    {
+        return dsEffectAssessMapper.selectDsEffectAssessByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ鑳芥晥璇勪及鍒楄〃
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 鑳芥晥璇勪及
+     */
+    @Override
+    public List<DsEffectAssess> selectDsEffectAssessList(DsEffectAssess dsEffectAssess)
+    {
+        return dsEffectAssessMapper.selectDsEffectAssessList(dsEffectAssess);
+    }
+
+    /**
+     * 鏂板鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsEffectAssess(DsEffectAssess dsEffectAssess)
+    {
+        dsEffectAssess.setCreateTime(DateUtils.getNowDate());
+        return dsEffectAssessMapper.insertDsEffectAssess(dsEffectAssess);
+    }
+
+    /**
+     * 淇敼鑳芥晥璇勪及
+     * 
+     * @param dsEffectAssess 鑳芥晥璇勪及
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsEffectAssess(DsEffectAssess dsEffectAssess)
+    {
+        dsEffectAssess.setUpdateTime(DateUtils.getNowDate());
+        return dsEffectAssessMapper.updateDsEffectAssess(dsEffectAssess);
+    }
+
+    @Override
+    public int updateOrInsertDsEffectAssess(DsEffectAssess dsEffectAssess) {
+        if(null != dsEffectAssess && null != dsEffectAssess.getTaskId() && null != dsEffectAssess.getDeptId() && null != dsEffectAssess.getSCORE()){
+            DsEffectAssess assess = new DsEffectAssess();
+            assess.setDeptId(dsEffectAssess.getDeptId());
+            assess.setTaskId(dsEffectAssess.getTaskId());
+
+            List<DsEffectAssess> assessList = dsEffectAssessMapper.selectDsEffectAssessList(assess);
+            if(null != assessList && assessList.size() > 0){
+                DsEffectAssess tmpAssess = assessList.get(0);
+                tmpAssess.setSCORE(dsEffectAssess.getSCORE());
+                return dsEffectAssessMapper.updateDsEffectAssess(tmpAssess);
+            }
+            else{
+                return dsEffectAssessMapper.insertDsEffectAssess(dsEffectAssess);
+            }
+        }
+        return 0;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鑳芥晥璇勪及
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑鑳芥晥璇勪及涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessByPKIDs(String PKIDs)
+    {
+        return dsEffectAssessMapper.deleteDsEffectAssessByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎鑳芥晥璇勪及淇℃伅
+     * 
+     * @param PKID 鑳芥晥璇勪及涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsEffectAssessByPKID(String PKID)
+    {
+        return dsEffectAssessMapper.deleteDsEffectAssessByPKID(PKID);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsMatDispatch2ServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsMatDispatch2ServiceImpl.java
new file mode 100644
index 0000000..7fc6b5e
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsMatDispatch2ServiceImpl.java
@@ -0,0 +1,65 @@
+package com.ruoyi.buss.service.impl;
+
+import com.ruoyi.buss.domain.DsMatDispatch2;
+import com.ruoyi.buss.mapper.DsMatDispatchMapper2;
+import com.ruoyi.buss.service.IDsMatDispatch2Service;
+import com.ruoyi.common.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+@Service
+public class DsMatDispatch2ServiceImpl implements IDsMatDispatch2Service {
+
+    @Autowired
+    private DsMatDispatchMapper2 dsMatDispatchMapper;
+
+    @Override
+    public List<DsMatDispatch2> selectDsMatDispatchList(DsMatDispatch2 dsMatDispatch2) {
+        return dsMatDispatchMapper.selectDsMatDispatchList(dsMatDispatch2);
+    }
+
+    @Override
+    public List<DsMatDispatch2> selectDsMatDispatchForApply() {
+        return dsMatDispatchMapper.selectDsMatDispatchForApply();
+    }
+
+    @Override
+    public List<DsMatDispatch2> selectDsMatDispatchByDeptId(Long deptId, String status) {
+        DsMatDispatch2 dsMatDispatch2 = new DsMatDispatch2();
+        if(null != deptId){
+            dsMatDispatch2.setResHarborId(deptId.toString());
+        }
+        if(StringUtils.isNotBlank(status)){
+            dsMatDispatch2.setStatus(status);
+        }
+        return dsMatDispatchMapper.selectDsMatDispatchByDeptId(dsMatDispatch2);
+    }
+
+
+    @Override
+    public DsMatDispatch2 selectDsMatDispatchById(Long id) {
+        return dsMatDispatchMapper.selectDsMatDispatchById(id);
+    }
+
+    @Override
+    public int insertDsMatDispatch(DsMatDispatch2 dsMatDispatch2) {
+        return dsMatDispatchMapper.insertDsMatDispatch(dsMatDispatch2);
+    }
+
+    @Override
+    public int updateDsMatDispatch(DsMatDispatch2 dsMatDispatch2) {
+        return dsMatDispatchMapper.updateDsMatDispatch(dsMatDispatch2);
+    }
+
+    @Override
+    public int deleteDsMatDispatchById(Long id) {
+        return dsMatDispatchMapper.deleteDsMatDispatchById(id);
+    }
+
+    @Override
+    public int deleteDsMatDispatchByIds(String ids) {
+        return dsMatDispatchMapper.deleteDsMatDispatchByIds(ids);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskDetailServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskDetailServiceImpl.java
new file mode 100644
index 0000000..ba741cb
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskDetailServiceImpl.java
@@ -0,0 +1,132 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DsTaskDetailMapper;
+import com.ruoyi.buss.domain.DsTaskDetail;
+import com.ruoyi.buss.service.IDsTaskDetailService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 浠诲姟璋冮厤璇︽儏淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DsTaskDetailServiceImpl implements IDsTaskDetailService 
+{
+    @Autowired
+    private DsTaskDetailMapper dsTaskDetailMapper;
+
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Override
+    public DsTaskDetail selectDsTaskDetailByPKID(Long PKID)
+    {
+        return dsTaskDetailMapper.selectDsTaskDetailByPKID(PKID);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 浠诲姟璋冮厤璇︽儏淇℃伅
+     */
+    @Override
+    public List<DsTaskDetail> selectDsTaskDetailList(DsTaskDetail dsTaskDetail)
+    {
+        return dsTaskDetailMapper.selectDsTaskDetailList(dsTaskDetail);
+    }
+
+    @Override
+    public List<DsTaskDetail> selectDsTaskDetailByTaskId(Long taskid, Long deptid) {
+        return dsTaskDetailMapper.selectDsTaskDetailByTaskId(taskid, deptid);
+    }
+
+    @Override
+    public List<DsTaskDetail> selectAQTaskDetailList(Long deptId) {
+        return dsTaskDetailMapper.selectAQTaskDetailList(deptId);
+    }
+
+    @Override
+    public List<DsTaskDetail> selectAQCurTaskDetailList(Long deptId) {
+        return dsTaskDetailMapper.selectAQCurTaskDetailList(deptId);
+    }
+
+    /**
+     * 鏂板浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsTaskDetail(DsTaskDetail dsTaskDetail)
+    {
+        dsTaskDetail.setCreateTime(DateUtils.getNowDate());
+        return dsTaskDetailMapper.insertDsTaskDetail(dsTaskDetail);
+    }
+
+    /**
+     * 淇敼浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param dsTaskDetail 浠诲姟璋冮厤璇︽儏淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsTaskDetail(DsTaskDetail dsTaskDetail)
+    {
+        dsTaskDetail.setUpdateTime(DateUtils.getNowDate());
+        return dsTaskDetailMapper.updateDsTaskDetail(dsTaskDetail);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskDetailByPKIDs(String PKIDs)
+    {
+        return dsTaskDetailMapper.deleteDsTaskDetailByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟璋冮厤璇︽儏淇℃伅淇℃伅
+     * 
+     * @param PKID 浠诲姟璋冮厤璇︽儏淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskDetailByPKID(Long PKID)
+    {
+        return dsTaskDetailMapper.deleteDsTaskDetailByPKID(PKID);
+    }
+
+    @Override
+    public int batchUpdateDsTaskDetail(List<DsTaskDetail> dsTaskDetailList) {
+        int rows = 0;
+        for (DsTaskDetail dsTaskDetail : dsTaskDetailList) {
+            dsTaskDetail.setUpdateTime(DateUtils.getNowDate());
+            rows += dsTaskDetailMapper.updateDsTaskDetail(dsTaskDetail);
+        }
+        return rows;
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岀爜澶碔D鑾峰彇璋冨害璇︽儏
+     * @param taskid
+     * @param harborIds
+     * @return
+     */
+    public List<DsTaskDetail> selectDsTaskDetailByTaskIdAndHarborIds(Long taskid, String harborIds){
+        return dsTaskDetailMapper.selectDsTaskDetailByTaskIdAndHarborIds(taskid, harborIds);
+    }
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskList2ServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskList2ServiceImpl.java
new file mode 100644
index 0000000..07cc151
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskList2ServiceImpl.java
@@ -0,0 +1,180 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.List;
+
+import com.ruoyi.buss.domain.DsTaskList2;
+import com.ruoyi.buss.domain.dto.TaskQueryParam;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DsTaskList2Mapper;
+import com.ruoyi.buss.service.IDsTaskList2Service;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 浠诲姟鍒楄〃淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DsTaskList2ServiceImpl implements IDsTaskList2Service
+{
+    @Autowired
+    private DsTaskList2Mapper dsTaskListMapper;
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    @Override
+    public List<DsTaskList2> selectDsTaskListByTaskId(Long taskId)
+    {
+        return dsTaskListMapper.selectDsTaskListByTaskId(taskId);
+    }
+
+    @Override
+    public List<DsTaskList2> selectCurrentDsTaskListV2() {
+        return dsTaskListMapper.selectCurrentDsTaskListV2();
+    }
+
+    @Override
+    public List<DsTaskList2> selectCurrentDsTaskList() {
+        return dsTaskListMapper.selectCurrentDsTaskList();
+    }
+
+    @Override
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNo(String[] shipnos) {
+        return dsTaskListMapper.selectCurrentDsTaskListWithShipNo(shipnos);
+    }
+
+    @Override
+    public List<DsTaskList2> selectCurrentDsTaskListWithShipNoV2(String[] shipnos) {
+        return dsTaskListMapper.selectCurrentDsTaskListWithShipNoV2(shipnos);
+    }
+
+    @Override
+    public List<DsTaskList2> selectDsTaskListByPkids(List<Long> pkids) {
+        return dsTaskListMapper.selectDsTaskListByPkids(pkids);
+    }
+
+    @Override
+    public DsTaskList2 selectDsTaskListByPkid(Long pkid) {
+        return dsTaskListMapper.selectDsTaskListByPKID(pkid);
+    }
+
+    @Override
+    public List<DsTaskList2> selectDsTaskListByParam(TaskQueryParam param) {
+        return dsTaskListMapper.selectDsTaskListByParam(param);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟鍒楄〃淇℃伅鍒楄〃
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 浠诲姟鍒楄〃淇℃伅
+     */
+    @Override
+    public List<DsTaskList2> selectDsTaskListList(DsTaskList2 dsTaskList2)
+    {
+        return dsTaskListMapper.selectDsTaskListList(dsTaskList2);
+    }
+
+    /**
+     * 鏂板浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsTaskList(DsTaskList2 dsTaskList2)
+    {
+        dsTaskList2.setCreateTime(DateUtils.getNowDate());
+        return dsTaskListMapper.insertDsTaskList(dsTaskList2);
+    }
+
+    /**
+     * 淇敼浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param dsTaskList2 浠诲姟鍒楄〃淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsTaskList(DsTaskList2 dsTaskList2)
+    {
+        dsTaskList2.setUpdateTime(DateUtils.getNowDate());
+        return dsTaskListMapper.updateDsTaskList(dsTaskList2);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟鍒楄〃淇℃伅
+     * 
+     * @param taskIds 闇�瑕佸垹闄ょ殑浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskListByTaskIds(String taskIds)
+    {
+        return dsTaskListMapper.deleteDsTaskListByTaskIds(Convert.toStrArray(taskIds));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟鍒楄〃淇℃伅淇℃伅
+     * 
+     * @param taskId 浠诲姟鍒楄〃淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskListByTaskId(Long taskId)
+    {
+        return dsTaskListMapper.deleteDsTaskListByTaskId(taskId);
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜岄儴闂↖D鏌ヨ浠诲姟鍒楄〃淇℃伅
+     * @param taskId
+     * @param deptId
+     */
+    public List<DsTaskList2> getDsTaskListByTaskIdAndDeptId(Long taskId, Long deptId)
+    {
+        DsTaskList2 dsTaskList2 = new DsTaskList2();
+        dsTaskList2.setTaskId(taskId);
+        dsTaskList2.setDeptId(deptId);
+        return dsTaskListMapper.getDsTaskListByTaskIdAndDeptId(dsTaskList2);
+    }
+
+    /**
+     *
+     * @param deptId
+     * @param taskId
+     * @param berthId
+     * @return
+     */
+    public List<DsTaskList2> getDsTaskListForSupplyPlan(Long deptId, Long taskId, Long berthId){
+        return dsTaskListMapper.getDsTaskListForSupplyPlan(deptId, taskId, berthId);
+    }
+
+    /**
+     * 鏍规嵁浠诲姟ID鍜屾硦浣岻Ds鏌ヨ浠诲姟鍒楄〃淇℃伅
+     *
+     * @param taskId
+     * @param berthIds
+     * @return
+     */
+    public List<DsTaskList2> selectDsTaskListListByTaskIdAndBerthds(Long taskId, String berthIds){
+        return dsTaskListMapper.selectDsTaskListListByTaskIdAndBerthds(taskId, "(" + berthIds + ")");
+    }
+
+    @Override
+    public int batchUpdateDsTaskList(List<DsTaskList2> dsTaskList2List) {
+        int rows = 0;
+        for (DsTaskList2 dsTaskList2 : dsTaskList2List) {
+            dsTaskList2.setUpdateTime(DateUtils.getNowDate());
+            rows += dsTaskListMapper.updateDsTaskList(dsTaskList2);
+        }
+        return rows;
+    }
+
+}
diff --git a/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskServiceImpl.java b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskServiceImpl.java
new file mode 100644
index 0000000..1add27f
--- /dev/null
+++ b/ruoyi-buss/src/main/java/com/ruoyi/buss/service/impl/DsTaskServiceImpl.java
@@ -0,0 +1,110 @@
+package com.ruoyi.buss.service.impl;
+
+import java.util.Date;
+import java.util.List;
+
+import com.ruoyi.buss.domain.dto.DsTaskQueryParam;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.buss.mapper.DsTaskMapper;
+import com.ruoyi.buss.domain.DsTask;
+import com.ruoyi.buss.service.IDsTaskService;
+import com.ruoyi.common.core.text.Convert;
+
+/**
+ * 浠诲姟淇℃伅Service涓氬姟灞傚鐞�
+ * 
+ * @author lx
+ * @date 2025-03-14
+ */
+@Service
+public class DsTaskServiceImpl implements IDsTaskService
+{
+    @Autowired
+    private DsTaskMapper dsTaskMapper;
+
+    @Override
+    public Long selectMaxTaskId() {
+        return dsTaskMapper.selectMaxTaskId();
+    }
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 浠诲姟淇℃伅
+     */
+    @Override
+    public DsTask selectDsTaskByPKID(Long PKID)
+    {
+        return dsTaskMapper.selectDsTaskByPKID(PKID);
+    }
+
+    @Override
+    public List<DsTask> selectDsTaskListByParam(DsTaskQueryParam param) {
+        return dsTaskMapper.selectDsTaskListByParam(param);
+    }
+
+    /**
+     * 鏌ヨ浠诲姟淇℃伅鍒楄〃
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 浠诲姟淇℃伅
+     */
+    @Override
+    public List<DsTask> selectDsTaskList(DsTask dsTask)
+    {
+        return dsTaskMapper.selectDsTaskList(dsTask);
+    }
+
+    /**
+     * 鏂板浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDsTask(DsTask dsTask)
+    {
+        dsTask.setCreateTime(DateUtils.getNowDate());
+        return dsTaskMapper.insertDsTask(dsTask);
+    }
+
+    /**
+     * 淇敼浠诲姟淇℃伅
+     * 
+     * @param dsTask 浠诲姟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDsTask(DsTask dsTask)
+    {
+        dsTask.setUpdateTime(DateUtils.getNowDate());
+        return dsTaskMapper.updateDsTask(dsTask);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎浠诲姟淇℃伅
+     * 
+     * @param PKIDs 闇�瑕佸垹闄ょ殑浠诲姟淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskByPKIDs(String PKIDs)
+    {
+        return dsTaskMapper.deleteDsTaskByPKIDs(Convert.toStrArray(PKIDs));
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟淇℃伅淇℃伅
+     * 
+     * @param PKID 浠诲姟淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDsTaskByPKID(Long PKID)
+    {
+        return dsTaskMapper.deleteDsTaskByPKID(PKID);
+    }
+}
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DmBerth2Mapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DmBerth2Mapper.xml
new file mode 100644
index 0000000..6efbcde
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DmBerth2Mapper.xml
@@ -0,0 +1,145 @@
+<?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.buss.mapper.DmBerth2Mapper">
+    
+    <resultMap type="com.ruoyi.buss.domain.DmBerth2" id="DmBerthResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="NAME"    column="NAME"    />
+        <result property="harborId"    column="HARBOR_ID"    />
+        <result property="harborName"    column="HARBOR_NAME"    />
+        <result property="berthLen"    column="BERTH_LEN"    />
+        <result property="DEPTH"    column="DEPTH"    />
+        <result property="STATUS"    column="STATUS"    />
+        <result property="orderNum"    column="ORDER_NUM"    />
+        <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="deptId"    column="DEPT_ID"    />
+        <result property="path"    column="PATH"    />
+    </resultMap>
+
+    <sql id="selectDmBerthVo">
+        select PKID, NAME, HARBOR_ID, HARBOR_NAME, BERTH_LEN, DEPTH, STATUS, ORDER_NUM, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, DEPT_ID, PATH from dm_berth
+    </sql>
+
+    <select id="selectDmBerthList" parameterType="com.ruoyi.buss.domain.DmBerth2" resultMap="DmBerthResult">
+        <include refid="selectDmBerthVo"/>
+        <where>  
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="NAME != null  and NAME != ''"> and NAME like concat('%', #{NAME}, '%')</if>
+            <if test="harborId != null "> and HARBOR_ID = #{harborId}</if>
+            <if test="harborName != null  and harborName != ''"> and HARBOR_NAME like concat('%', #{harborName}, '%')</if>
+            <if test="berthLen != null "> and BERTH_LEN = #{berthLen}</if>
+            <if test="DEPTH != null "> and DEPTH = #{DEPTH}</if>
+            <if test="STATUS != null  and STATUS != ''"> and STATUS = #{STATUS}</if>
+            <if test="orderNum != null "> and ORDER_NUM = #{orderNum}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+
+    <select id="selectDmBerthByHarborIds" resultMap="DmBerthResult">
+        <include refid="selectDmBerthVo"/>
+        where HARBOR_ID in
+        <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        order by HARBOR_ID, ORDER_NUM
+    </select>
+
+    <select id="selectDmBerthByHarborIdsAndStatus" resultMap="DmBerthResult">
+        <include refid="selectDmBerthVo"/>
+        where status = '1' and  HARBOR_ID in
+        <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+        order by HARBOR_ID, ORDER_NUM
+    </select>
+
+    <select id="selectDmBerthByPKID" parameterType="Long" resultMap="DmBerthResult">
+        <include refid="selectDmBerthVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <insert id="insertDmBerth" parameterType="com.ruoyi.buss.domain.DmBerth2">
+        insert into dm_berth
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="PKID != null">PKID,</if>
+            <if test="NAME != null">NAME,</if>
+            <if test="harborId != null">HARBOR_ID,</if>
+            <if test="harborName != null">HARBOR_NAME,</if>
+            <if test="berthLen != null">BERTH_LEN,</if>
+            <if test="DEPTH != null">DEPTH,</if>
+            <if test="STATUS != null">STATUS,</if>
+            <if test="orderNum != null">ORDER_NUM,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+            <if test="path != null">PATH,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="PKID != null">#{PKID},</if>
+            <if test="NAME != null">#{NAME},</if>
+            <if test="harborId != null">#{harborId},</if>
+            <if test="harborName != null">#{harborName},</if>
+            <if test="berthLen != null">#{berthLen},</if>
+            <if test="DEPTH != null">#{DEPTH},</if>
+            <if test="STATUS != null">#{STATUS},</if>
+            <if test="orderNum != null">#{orderNum},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="path != null">#{path},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDmBerth" parameterType="com.ruoyi.buss.domain.DmBerth2">
+        update dm_berth
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="NAME != null">NAME = #{NAME},</if>
+            <if test="harborId != null">HARBOR_ID = #{harborId},</if>
+            <if test="harborName != null">HARBOR_NAME = #{harborName},</if>
+            <if test="berthLen != null">BERTH_LEN = #{berthLen},</if>
+            <if test="DEPTH != null">DEPTH = #{DEPTH},</if>
+            <if test="STATUS != null">STATUS = #{STATUS},</if>
+            <if test="orderNum != null">ORDER_NUM = #{orderNum},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="path != null">PATH = #{path},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDmBerthByPKID" parameterType="Long">
+        delete from dm_berth where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDmBerthByPKIDs" parameterType="String">
+        delete from dm_berth where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+    <select id="getDmBerthListByIds" parameterType="java.lang.String" resultMap="DmBerthResult">
+        <include refid="selectDmBerthVo"/>
+        where PKID in ${berthIds} ORDER BY PKID ASC
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DmDdConfigMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DmDdConfigMapper.xml
new file mode 100644
index 0000000..34e7cf5
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DmDdConfigMapper.xml
@@ -0,0 +1,73 @@
+<?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.buss.mapper.DmDdConfigMapper">
+    
+    <resultMap type="DmDdConfig" id="DmDdConfigResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="TYPE"    column="TYPE"    />
+        <result property="UNIT"    column="UNIT"    />
+        <result property="shipType"    column="SHIP_TYPE"    />
+        <result property="TIME"    column="TIME"    />
+    </resultMap>
+
+    <sql id="selectDmDdConfigVo">
+        select PKID, TYPE, UNIT, SHIP_TYPE, TIME from dm_dd_config
+    </sql>
+
+    <select id="selectDmDdConfigList" parameterType="DmDdConfig" resultMap="DmDdConfigResult">
+        <include refid="selectDmDdConfigVo"/>
+        <where>  
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="TYPE != null  and TYPE != ''"> and TYPE = #{TYPE}</if>
+            <if test="UNIT != null  and UNIT != ''"> and UNIT = #{UNIT}</if>
+            <if test="shipType != null  and shipType != ''"> and SHIP_TYPE = #{shipType}</if>
+            <if test="TIME != null "> and TIME = #{TIME}</if>
+        </where>
+    </select>
+    
+    <select id="selectDmDdConfigByPKID" parameterType="Long" resultMap="DmDdConfigResult">
+        <include refid="selectDmDdConfigVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <insert id="insertDmDdConfig" parameterType="DmDdConfig">
+        insert into dm_dd_config
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="TYPE != null">TYPE,</if>
+            <if test="UNIT != null">UNIT,</if>
+            <if test="shipType != null">SHIP_TYPE,</if>
+            <if test="TIME != null">TIME,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="TYPE != null">#{TYPE},</if>
+            <if test="UNIT != null">#{UNIT},</if>
+            <if test="shipType != null">#{shipType},</if>
+            <if test="TIME != null">#{TIME},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDmDdConfig" parameterType="DmDdConfig">
+        update dm_dd_config
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="TYPE != null">TYPE = #{TYPE},</if>
+            <if test="UNIT != null">UNIT = #{UNIT},</if>
+            <if test="shipType != null">SHIP_TYPE = #{shipType},</if>
+            <if test="TIME != null">TIME = #{TIME},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDmDdConfigByPKID" parameterType="Long">
+        delete from dm_dd_config where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDmDdConfigByPKIDs" parameterType="String">
+        delete from dm_dd_config where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DmHarbor2Mapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DmHarbor2Mapper.xml
new file mode 100644
index 0000000..e481f42
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DmHarbor2Mapper.xml
@@ -0,0 +1,175 @@
+<?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.buss.mapper.DmHarbor2Mapper">
+    
+    <resultMap type="com.ruoyi.buss.domain.DmHarbor2" id="DmHarborResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="harborName"    column="HARBOR_NAME"    />
+        <result property="deptId"    column="DEPT_ID"    />
+        <result property="deptName"    column="DEPT_NAME"    />
+        <result property="berthNo"    column="BERTH_NO"    />
+        <result property="oilB"    column="OIL_B"    />
+        <result property="oilG"    column="OIL_G"    />
+        <result property="oilA"    column="OIL_A"    />
+        <result property="ammoD"    column="AMMO_D"    />
+        <result property="ammoP"    column="AMMO_P"    />
+        <result property="ammoS"    column="AMMO_S"    />
+        <result property="remark"    column="remark"    />
+        <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="DOCKNAME"    column="DOCKNAME"    />
+        <result property="WATER"    column="WATER"    />
+        <result property="MATERIAL"    column="MATERIAL"    />
+        <result property="ammoO"    column="AMMO_O"    />
+        <result property="vehicleCount"    column="VEHICLE_COUNT"    />
+        <result property="roadConditions"    column="ROAD_CONDITIONS"    />
+        <result property="draft"    column="DRAFT"    />
+    </resultMap>
+
+    <sql id="selectDmHarborVo">
+        select PKID, HARBOR_NAME, DEPT_ID, DEPT_NAME, BERTH_NO, OIL_B, OIL_G, OIL_A, AMMO_D, AMMO_P, AMMO_S, remark, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, DOCKNAME, WATER, MATERIAL, AMMO_O, VEHICLE_COUNT, ROAD_CONDITIONS, DRAFT  from dm_harbor
+    </sql>
+
+    <select id="selectDmHarborList" parameterType="com.ruoyi.buss.domain.DmHarbor2" resultMap="DmHarborResult">
+        <include refid="selectDmHarborVo"/>
+        <where>  
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="harborName != null  and NAME != ''"> and HARBOR_NAME like concat('%', #{harborName}, '%')</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+            <if test="deptName != null  and deptName != ''"> and DEPT_NAME like concat('%', #{deptName}, '%')</if>
+            <if test="berthNo != null "> and BERTH_NO = #{berthNo}</if>
+            <if test="oilB != null "> and OIL_B = #{oilB}</if>
+            <if test="oilG != null "> and OIL_G = #{oilG}</if>
+            <if test="oilA != null "> and OIL_A = #{oilA}</if>
+            <if test="ammoD != null "> and AMMO_D = #{ammoD}</if>
+            <if test="ammoP != null "> and AMMO_P = #{ammoP}</if>
+            <if test="ammoS != null "> and AMMO_S = #{ammoS}</if>
+            <if test="remark != null  and remark != ''"> and remark = #{remark}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="DOCKNAME != null  and DOCKNAME != ''"> and DOCKNAME like concat('%', #{DOCKNAME}, '%')</if>
+            <if test="WATER != null "> and WATER = #{WATER}</if>
+            <if test="MATERIAL != null "> and MATERIAL = #{MATERIAL}</if>
+            <if test="ammoO != null "> and AMMO_O = #{ammoO}</if>
+        </where>
+    </select>
+    
+    <select id="selectDmHarborByPKID" parameterType="Long" resultMap="DmHarborResult">
+        <include refid="selectDmHarborVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <select id="selectDmHarborByPKIDs" resultMap="DmHarborResult">
+        <include refid="selectDmHarborVo"/>
+        where PKID in
+        <foreach item="item" collection="list" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+
+
+    <insert id="insertDmHarbor" parameterType="com.ruoyi.buss.domain.DmHarbor2">
+        insert into dm_harbor
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="harborName != null">HARBOR_NAME,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+            <if test="deptName != null">DEPT_NAME,</if>
+            <if test="berthNo != null">BERTH_NO,</if>
+            <if test="oilB != null">OIL_B,</if>
+            <if test="oilG != null">OIL_G,</if>
+            <if test="oilA != null">OIL_A,</if>
+            <if test="ammoD != null">AMMO_D,</if>
+            <if test="ammoP != null">AMMO_P,</if>
+            <if test="ammoS != null">AMMO_S,</if>
+            <if test="remark != null">remark,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="DOCKNAME != null">DOCKNAME,</if>
+            <if test="WATER != null">WATER,</if>
+            <if test="MATERIAL != null">MATERIAL,</if>
+            <if test="ammoO != null">AMMO_O,</if>
+            <if test="vehicleCount != null">VEHICLE_COUNT,</if>
+            <if test="roadConditions != null">ROAD_CONDITIONS,</if>
+            <if test="draft != null">DRAFT,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="harborName != null">#{harborName},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="deptName != null">#{deptName},</if>
+            <if test="berthNo != null">#{berthNo},</if>
+            <if test="oilB != null">#{oilB},</if>
+            <if test="oilG != null">#{oilG},</if>
+            <if test="oilA != null">#{oilA},</if>
+            <if test="ammoD != null">#{ammoD},</if>
+            <if test="ammoP != null">#{ammoP},</if>
+            <if test="ammoS != null">#{ammoS},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="DOCKNAME != null">#{DOCKNAME},</if>
+            <if test="WATER != null">#{WATER},</if>
+            <if test="MATERIAL != null">#{MATERIAL},</if>
+            <if test="ammoO != null">#{ammoO},</if>
+            <if test="vehicleCount != null">#{vehicleCount},</if>
+            <if test="roadConditions != null">#{roadConditions},</if>
+            <if test="draft != null">#{draft},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDmHarbor" parameterType="com.ruoyi.buss.domain.DmHarbor2">
+        update dm_harbor
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="harborName != null">NAME = #{harborName},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+            <if test="deptName != null">DEPT_NAME = #{deptName},</if>
+            <if test="berthNo != null">BERTH_NO = #{berthNo},</if>
+            <if test="oilB != null">OIL_B = #{oilB},</if>
+            <if test="oilG != null">OIL_G = #{oilG},</if>
+            <if test="oilA != null">OIL_A = #{oilA},</if>
+            <if test="ammoD != null">AMMO_D = #{ammoD},</if>
+            <if test="ammoP != null">AMMO_P = #{ammoP},</if>
+            <if test="ammoS != null">AMMO_S = #{ammoS},</if>
+            <if test="remark != null">remark = #{remark},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="DOCKNAME != null">DOCKNAME = #{DOCKNAME},</if>
+            <if test="WATER != null">WATER = #{WATER},</if>
+            <if test="MATERIAL != null">MATERIAL = #{MATERIAL},</if>
+            <if test="ammoO != null">AMMO_O = #{ammoO},</if>
+            <if test="vehicleCount != null">VEHICLE_COUNT = #{vehicleCount},</if>
+            <if test="roadConditions != null">ROAD_CONDITIONS = #{roadConditions},</if>
+            <if test="draft != null">DRAFT = #{draft},</if>
+
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDmHarborByPKID" parameterType="Long">
+        delete from dm_harbor where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDmHarborByPKIDs" parameterType="String">
+        delete from dm_harbor where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DmWarshipMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DmWarshipMapper.xml
new file mode 100644
index 0000000..10dd439
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DmWarshipMapper.xml
@@ -0,0 +1,125 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.buss.mapper.DmWarshipMapper">
+    
+    <resultMap type="DmWarship" id="DmWarshipResult">
+        <id property="shipNo"    column="SHIP_NO"    />
+        <result property="shipType"    column="SHIP_TYPE"    />
+        <result property="TONNAGE"    column="TONNAGE"    />
+        <result property="DRAFT"    column="DRAFT"    />
+        <result property="LEADER"    column="LEADER"    />
+        <result property="STAFF"    column="STAFF"    />
+        <result property="grpName"    column="GRP_NAME"    />
+        <result property="LEVEL"    column="LEVEL"    />
+        <result property="LAT"    column="LAT"    />
+        <result property="LON"    column="LON"    />
+        <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"    />
+    </resultMap>
+
+    <sql id="selectDmWarshipVo">
+        select SHIP_NO, SHIP_TYPE, TONNAGE, DRAFT, LEADER, STAFF, GRP_NAME, LEVEL, LAT, LON, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME from dm_warship
+    </sql>
+
+    <select id="selectDmWarshipList" parameterType="DmWarship" resultMap="DmWarshipResult">
+        <include refid="selectDmWarshipVo"/>
+        <where>  
+            <if test="shipNo != null  and shipNo != ''"> and SHIP_NO = #{shipNo}</if>
+            <if test="shipType != null  and shipType != ''"> and SHIP_TYPE = #{shipType}</if>
+            <if test="TONNAGE != null "> and TONNAGE = #{TONNAGE}</if>
+            <if test="DRAFT != null "> and DRAFT = #{DRAFT}</if>
+            <if test="LEADER != null  and LEADER != ''"> and LEADER = #{LEADER}</if>
+            <if test="STAFF != null "> and STAFF = #{STAFF}</if>
+            <if test="grpName != null  and grpName != ''"> and GRP_NAME like concat('%', #{grpName}, '%')</if>
+            <if test="LEVEL != null "> and LEVEL = #{LEVEL}</if>
+            <if test="LAT != null "> and LAT = #{LAT}</if>
+            <if test="LON != null "> and LON = #{LON}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+        </where>
+    </select>
+    
+    <select id="selectDmWarshipByShipNo" parameterType="String" resultMap="DmWarshipResult">
+        <include refid="selectDmWarshipVo"/>
+        where SHIP_NO = #{shipNo}
+    </select>
+
+    <insert id="insertDmWarship" parameterType="DmWarship">
+        insert into dm_warship
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="shipNo != null and shipNo != ''">SHIP_NO,</if>
+            <if test="shipType != null">SHIP_TYPE,</if>
+            <if test="TONNAGE != null">TONNAGE,</if>
+            <if test="DRAFT != null">DRAFT,</if>
+            <if test="LEADER != null">LEADER,</if>
+            <if test="STAFF != null">STAFF,</if>
+            <if test="grpName != null">GRP_NAME,</if>
+            <if test="LEVEL != null">LEVEL,</if>
+            <if test="LAT != null">LAT,</if>
+            <if test="LON != null">LON,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="shipNo != null and shipNo != ''">#{shipNo},</if>
+            <if test="shipType != null">#{shipType},</if>
+            <if test="TONNAGE != null">#{TONNAGE},</if>
+            <if test="DRAFT != null">#{DRAFT},</if>
+            <if test="LEADER != null">#{LEADER},</if>
+            <if test="STAFF != null">#{STAFF},</if>
+            <if test="grpName != null">#{grpName},</if>
+            <if test="LEVEL != null">#{LEVEL},</if>
+            <if test="LAT != null">#{LAT},</if>
+            <if test="LON != null">#{LON},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDmWarship" parameterType="DmWarship">
+        update dm_warship
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="shipType != null">SHIP_TYPE = #{shipType},</if>
+            <if test="TONNAGE != null">TONNAGE = #{TONNAGE},</if>
+            <if test="DRAFT != null">DRAFT = #{DRAFT},</if>
+            <if test="LEADER != null">LEADER = #{LEADER},</if>
+            <if test="STAFF != null">STAFF = #{STAFF},</if>
+            <if test="grpName != null">GRP_NAME = #{grpName},</if>
+            <if test="LEVEL != null">LEVEL = #{LEVEL},</if>
+            <if test="LAT != null">LAT = #{LAT},</if>
+            <if test="LON != null">LON = #{LON},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+        </trim>
+        where SHIP_NO = #{shipNo}
+    </update>
+
+    <delete id="deleteDmWarshipByShipNo" parameterType="String">
+        delete from dm_warship where SHIP_NO = #{shipNo}
+    </delete>
+
+    <delete id="deleteDmWarshipByShipNos" parameterType="String">
+        delete from dm_warship where SHIP_NO in 
+        <foreach item="shipNo" collection="array" open="(" separator="," close=")">
+            #{shipNo}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessHisMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessHisMapper.xml
new file mode 100644
index 0000000..ba4c7e2
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessHisMapper.xml
@@ -0,0 +1,154 @@
+<?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.buss.mapper.DsEffectAssessHisMapper">
+    
+    <resultMap type="DsEffectAssessHis" id="DsEffectAssessHisResult">
+        <result property="PKID"    column="PKID"    />
+        <result property="taskId"    column="TASK_ID"    />
+        <result property="TYPE"    column="TYPE"    />
+        <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"    />
+        <result property="PLAN"    column="PLAN"    />
+        <result property="ITEM"    column="ITEM"    />
+        <result property="itemDetail"    column="ITEM_DETAIL"    />
+        <result property="UNIT"    column="UNIT"    />
+        <result property="CODE"    column="CODE"    />
+        <result property="NORMAL"    column="NORMAL"    />
+        <result property="WEIGHT"    column="WEIGHT"    />
+        <result property="classifyIndex"    column="CLASSIFY_INDEX"    />
+        <result property="classifyWeight"    column="CLASSIFY_WEIGHT"    />
+        <result property="val"    column="VAL"    />
+        <result property="deptId"    column="DEPT_ID"    />
+    </resultMap>
+
+    <sql id="selectDsEffectAssessHisVo">
+        select PKID, TASK_ID, TYPE, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK, PLAN, ITEM, ITEM_DETAIL, UNIT, CODE, NORMAL, WEIGHT, CLASSIFY_INDEX, CLASSIFY_WEIGHT, VAL, DEPT_ID from ds_effect_assess_his
+    </sql>
+
+    <select id="selectDsEffectAssessHisList" parameterType="DsEffectAssessHis" resultMap="DsEffectAssessHisResult">
+        <include refid="selectDsEffectAssessHisVo"/>
+        <where>  
+            <if test="PKID != null  and PKID != ''"> and PKID = #{PKID}</if>
+            <if test="taskId != null  and taskId != ''"> and TASK_ID = #{taskId}</if>
+            <if test="TYPE != null  and TYPE != ''"> and TYPE = #{TYPE}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="remark != null  and REMARK != ''"> and REMARK = #{REMARK}</if>
+            <if test="PLAN != null  and PLAN != ''"> and PLAN = #{PLAN}</if>
+            <if test="ITEM != null  and ITEM != ''"> and ITEM = #{ITEM}</if>
+            <if test="itemDetail != null  and itemDetail != ''"> and ITEM_DETAIL = #{itemDetail}</if>
+            <if test="UNIT != null  and UNIT != ''"> and UNIT = #{UNIT}</if>
+            <if test="CODE != null  and CODE != ''"> and CODE = #{CODE}</if>
+            <if test="NORMAL != null  and NORMAL != ''"> and NORMAL = #{NORMAL}</if>
+            <if test="WEIGHT != null "> and WEIGHT = #{WEIGHT}</if>
+            <if test="classifyIndex != null  and classifyIndex != ''"> and CLASSIFY_INDEX = #{classifyIndex}</if>
+            <if test="classifyWeight != null "> and CLASSIFY_WEIGHT = #{classifyWeight}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsEffectAssessHisByPKID" parameterType="String" resultMap="DsEffectAssessHisResult">
+        <include refid="selectDsEffectAssessHisVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <insert id="insertDsEffectAssessHis" parameterType="DsEffectAssessHis">
+        insert into ds_effect_assess_his
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">PKID,</if>
+            <if test="taskId != null">TASK_ID,</if>
+            <if test="TYPE != null">TYPE,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="remark != null">REMARK,</if>
+            <if test="PLAN != null">PLAN,</if>
+            <if test="ITEM != null">ITEM,</if>
+            <if test="itemDetail != null">ITEM_DETAIL,</if>
+            <if test="UNIT != null">UNIT,</if>
+            <if test="CODE != null">CODE,</if>
+            <if test="NORMAL != null">NORMAL,</if>
+            <if test="WEIGHT != null">WEIGHT,</if>
+            <if test="classifyIndex != null">CLASSIFY_INDEX,</if>
+            <if test="classifyWeight != null">CLASSIFY_WEIGHT,</if>
+            <if test="val != null">VAL,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">#{PKID},</if>
+            <if test="taskId != null">#{taskId},</if>
+            <if test="TYPE != null">#{TYPE},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{REMARK},</if>
+            <if test="PLAN != null">#{PLAN},</if>
+            <if test="ITEM != null">#{ITEM},</if>
+            <if test="itemDetail != null">#{itemDetail},</if>
+            <if test="UNIT != null">#{UNIT},</if>
+            <if test="CODE != null">#{CODE},</if>
+            <if test="NORMAL != null">#{NORMAL},</if>
+            <if test="WEIGHT != null">#{WEIGHT},</if>
+            <if test="classifyIndex != null">#{classifyIndex},</if>
+            <if test="classifyWeight != null">#{classifyWeight},</if>
+            <if test="val != null">#{val},</if>
+            <if test="deptId != null">#{deptId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsEffectAssessHis" parameterType="DsEffectAssessHis">
+        update ds_effect_assess_his
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID = #{taskId},</if>
+            <if test="TYPE != null">TYPE = #{TYPE},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="remark != null">REMARK = #{REMARK},</if>
+            <if test="PLAN != null">PLAN = #{PLAN},</if>
+            <if test="ITEM != null">ITEM = #{ITEM},</if>
+            <if test="itemDetail != null">ITEM_DETAIL = #{itemDetail},</if>
+            <if test="UNIT != null">UNIT = #{UNIT},</if>
+            <if test="CODE != null">CODE = #{CODE},</if>
+            <if test="NORMAL != null">NORMAL = #{NORMAL},</if>
+            <if test="WEIGHT != null">WEIGHT = #{WEIGHT},</if>
+            <if test="classifyIndex != null">CLASSIFY_INDEX = #{classifyIndex},</if>
+            <if test="classifyWeight != null">CLASSIFY_WEIGHT = #{classifyWeight},</if>
+            <if test="val != null">VAL = #{val},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsEffectAssessHisByPKID" parameterType="String">
+        delete from ds_effect_assess_his where PKID = #{PKID}
+    </delete>
+
+
+    <delete id="deleteDsEffectAssessHisByTaskIdAndDeptId" parameterType="DsEffectAssessHis">
+        delete from ds_effect_assess_his where TASK_ID = #{taskId} and DEPT_ID = #{deptId}
+    </delete>
+
+    <delete id="deleteDsEffectAssessHisByPKIDs" parameterType="String">
+        delete from ds_effect_assess_his where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessListMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessListMapper.xml
new file mode 100644
index 0000000..c1e827c
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessListMapper.xml
@@ -0,0 +1,149 @@
+<?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.buss.mapper.DsEffectAssessListMapper">
+    
+    <resultMap type="DsEffectAssessList" id="DsEffectAssessListResult">
+        <result property="PKID"    column="PKID"    />
+        <result property="assessId"    column="ASSESS_ID"    />
+        <result property="TYPE"    column="TYPE"    />
+        <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"    />
+        <result property="PLAN"    column="PLAN"    />
+        <result property="ITEM"    column="ITEM"    />
+        <result property="itemDetail"    column="ITEM_DETAIL"    />
+        <result property="UNIT"    column="UNIT"    />
+        <result property="CODE"    column="CODE"    />
+        <result property="NORMAL"    column="NORMAL"    />
+        <result property="WEIGHT"    column="WEIGHT"    />
+        <result property="classifyIndex"    column="CLASSIFY_INDEX"    />
+        <result property="classifyWeight"    column="CLASSIFY_WEIGHT"    />
+        <result property="val"    column="VAL"    />
+        <result property="deptId"    column="DEPT_ID"    />
+    </resultMap>
+
+    <sql id="selectDsEffectAssessListVo">
+        select PKID, ASSESS_ID, TYPE, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK, PLAN, ITEM, ITEM_DETAIL, UNIT, CODE, NORMAL, WEIGHT, CLASSIFY_INDEX, CLASSIFY_WEIGHT, VAL, DEPT_ID from ds_effect_assess_list
+    </sql>
+
+    <select id="selectDsEffectAssessListList" parameterType="DsEffectAssessList" resultMap="DsEffectAssessListResult">
+        <include refid="selectDsEffectAssessListVo"/>
+        <where>  
+            <if test="PKID != null  and PKID != ''"> and PKID = #{PKID}</if>
+            <if test="assessId != null  and assessId != ''"> and ASSESS_ID = #{assessId}</if>
+            <if test="TYPE != null  and TYPE != ''"> and TYPE = #{TYPE}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="remark != null  and REMARK != ''"> and REMARK = #{REMARK}</if>
+            <if test="PLAN != null  and PLAN != ''"> and PLAN = #{PLAN}</if>
+            <if test="ITEM != null  and ITEM != ''"> and ITEM = #{ITEM}</if>
+            <if test="itemDetail != null  and itemDetail != ''"> and ITEM_DETAIL = #{itemDetail}</if>
+            <if test="UNIT != null  and UNIT != ''"> and UNIT = #{UNIT}</if>
+            <if test="CODE != null  and CODE != ''"> and CODE = #{CODE}</if>
+            <if test="NORMAL != null  and NORMAL != ''"> and NORMAL = #{NORMAL}</if>
+            <if test="WEIGHT != null "> and WEIGHT = #{WEIGHT}</if>
+            <if test="classifyIndex != null  and classifyIndex != ''"> and CLASSIFY_INDEX = #{classifyIndex}</if>
+            <if test="classifyWeight != null "> and CLASSIFY_WEIGHT = #{classifyWeight}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsEffectAssessListByPKID" parameterType="String" resultMap="DsEffectAssessListResult">
+        <include refid="selectDsEffectAssessListVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <insert id="insertDsEffectAssessList" parameterType="DsEffectAssessList">
+        insert into ds_effect_assess_list
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">PKID,</if>
+            <if test="assessId != null">ASSESS_ID,</if>
+            <if test="TYPE != null">TYPE,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="remark != null">REMARK,</if>
+            <if test="PLAN != null">PLAN,</if>
+            <if test="ITEM != null">ITEM,</if>
+            <if test="itemDetail != null">ITEM_DETAIL,</if>
+            <if test="UNIT != null">UNIT,</if>
+            <if test="CODE != null">CODE,</if>
+            <if test="NORMAL != null">NORMAL,</if>
+            <if test="WEIGHT != null">WEIGHT,</if>
+            <if test="classifyIndex != null">CLASSIFY_INDEX,</if>
+            <if test="classifyWeight != null">CLASSIFY_WEIGHT,</if>
+            <if test="val != null">VAL,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">#{PKID},</if>
+            <if test="assessId != null">#{assessId},</if>
+            <if test="TYPE != null">#{TYPE},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{REMARK},</if>
+            <if test="PLAN != null">#{PLAN},</if>
+            <if test="ITEM != null">#{ITEM},</if>
+            <if test="itemDetail != null">#{itemDetail},</if>
+            <if test="UNIT != null">#{UNIT},</if>
+            <if test="CODE != null">#{CODE},</if>
+            <if test="NORMAL != null">#{NORMAL},</if>
+            <if test="WEIGHT != null">#{WEIGHT},</if>
+            <if test="classifyIndex != null">#{classifyIndex},</if>
+            <if test="classifyWeight != null">#{classifyWeight},</if>
+            <if test="val != null">#{VAL},</if>
+            <if test="deptId != null">#{deptId},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsEffectAssessList" parameterType="DsEffectAssessList">
+        update ds_effect_assess_list
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="assessId != null">ASSESS_ID = #{assessId},</if>
+            <if test="TYPE != null">TYPE = #{TYPE},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="remark != null">REMARK = #{REMARK},</if>
+            <if test="PLAN != null">PLAN = #{PLAN},</if>
+            <if test="ITEM != null">ITEM = #{ITEM},</if>
+            <if test="itemDetail != null">ITEM_DETAIL = #{itemDetail},</if>
+            <if test="UNIT != null">UNIT = #{UNIT},</if>
+            <if test="CODE != null">CODE = #{CODE},</if>
+            <if test="NORMAL != null">NORMAL = #{NORMAL},</if>
+            <if test="WEIGHT != null">WEIGHT = #{WEIGHT},</if>
+            <if test="classifyIndex != null">CLASSIFY_INDEX = #{classifyIndex},</if>
+            <if test="classifyWeight != null">CLASSIFY_WEIGHT = #{classifyWeight},</if>
+            <if test="val != null">VAL = #{val},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsEffectAssessListByPKID" parameterType="String">
+        delete from ds_effect_assess_list where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDsEffectAssessListByPKIDs" parameterType="String">
+        delete from ds_effect_assess_list where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessMapper.xml
new file mode 100644
index 0000000..8fdc6cb
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsEffectAssessMapper.xml
@@ -0,0 +1,104 @@
+<?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.buss.mapper.DsEffectAssessMapper">
+    
+    <resultMap type="DsEffectAssess" id="DsEffectAssessResult">
+        <result property="PKID"    column="PKID"    />
+        <result property="taskId"    column="TASK_ID"    />
+        <result property="SCORE"    column="SCORE"    />
+        <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"    />
+        <result property="deptId"    column="DEPT_ID"    />
+        <result property="type"    column="TYPE"    />
+    </resultMap>
+
+    <sql id="selectDsEffectAssessVo">
+        select PKID, TASK_ID, SCORE, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK, DEPT_ID,TYPE from ds_effect_assess
+    </sql>
+
+    <select id="selectDsEffectAssessList" parameterType="DsEffectAssess" resultMap="DsEffectAssessResult">
+        <include refid="selectDsEffectAssessVo"/>
+        <where>  
+            <if test="PKID != null  and PKID != ''"> and PKID = #{PKID}</if>
+            <if test="taskId != null  and taskId != ''"> and TASK_ID = #{taskId}</if>
+            <if test="SCORE != null "> and SCORE = #{SCORE}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="remark != null  and remark != ''"> and REMARK = #{REMARK}</if>
+            <if test="deptId != null  and deptId != ''"> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsEffectAssessByPKID" parameterType="String" resultMap="DsEffectAssessResult">
+        <include refid="selectDsEffectAssessVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <insert id="insertDsEffectAssess" parameterType="DsEffectAssess">
+        insert into ds_effect_assess
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">PKID,</if>
+            <if test="taskId != null">TASK_ID,</if>
+            <if test="SCORE != null">SCORE,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="remark != null">REMARK,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+            <if test="type != null">TYPE,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="PKID != null and PKID != ''">#{PKID},</if>
+            <if test="taskId != null">#{taskId},</if>
+            <if test="SCORE != null">#{SCORE},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{REMARK},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="type != null">#{type},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsEffectAssess" parameterType="DsEffectAssess">
+        update ds_effect_assess
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID = #{taskId},</if>
+            <if test="SCORE != null">SCORE = #{SCORE},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="remark != null">REMARK = #{REMARK},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+            <if test="type != null">TYPE = #{type},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsEffectAssessByPKID" parameterType="String">
+        delete from ds_effect_assess where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDsEffectAssessByPKIDs" parameterType="String">
+        delete from ds_effect_assess where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsMatDispatchMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsMatDispatchMapper.xml
new file mode 100644
index 0000000..6e207bb
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsMatDispatchMapper.xml
@@ -0,0 +1,136 @@
+<?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.buss.mapper.DsMatDispatchMapper2">
+
+    <resultMap type="DsMatDispatch2" id="DsMatDispatchResult">
+        <result property="id" column="ID" />
+        <result property="resHarborId" column="RES_HARBOR_ID" />
+        <result property="resHarborName" column="RES_HARBOR_NAME" />
+        <result property="desHarborId" column="DES_HARBOR_ID" />
+        <result property="desHarborName" column="DES_HARBOR_NAME" />
+        <result property="content" column="CONTENT" />
+        <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"    />
+        <result property="status" column="STATUS" />
+        <result property="applyBy" column="APPLY_BY" />
+        <result property="applyTime" column="APPLY_TIME" />
+        <result property="applyResult" column="APPLY_RESULT" />
+        <result property="applyContent" column="APPLY_CONTENT" />
+    </resultMap>
+
+    <sql id="selectDsMatDispatchVo">
+        select ID,RES_HARBOR_ID,RES_HARBOR_NAME,DES_HARBOR_ID,DES_HARBOR_NAME,CONTENT,DEL_FLAG,CREATE_BY,CREATE_TIME,UPDATE_BY,UPDATE_TIME,REMARK,STATUS,APPLY_BY,APPLY_TIME,APPLY_RESULT, APPLY_CONTENT from DS_MAT_DISPATCH
+    </sql>
+
+    <select id="selectDsMatDispatchList" parameterType="DsMatDispatch2" resultMap="DsMatDispatchResult">
+        <include refid="selectDsMatDispatchVo" />
+        <where>
+            <if test="id != null and id != ''"> and ID = #{ID}</if>
+            <if test="resHarborId != null and resHarborId != ''"> and RES_HARBOR_ID = #{resHarborId}  </if>
+            <if test="resHarborName != null and resHarborName != ''"> and RES_HARBOR_NAME = #{resHarborName}</if>
+            <if test="desHarborId != null and desHarborId != ''"> and DES_HARBOR_ID = #{desHarborId} </if>
+            <if test="desHarborName != null and desHarborName != ''"> and DES_HARBOR_NAME = #{desHarborName} </if>
+            <if test="content != null and content != ''"> and CONTENT like concat('%', #{content}, '%') </if>
+            <if test="status != null and status != ''"> and STATUS = #{status} </if>
+            <if test="applyBy != null and applyBy != '' "> and APPLY_BY = #{applyBy} </if>
+            <if test="applyTime != null and applyTime != ''"> and APPLY_TIME = #{applyTime} </if>
+            <if test="applyResult != null and applyResult != '' "> and APPLY_RESULT like concat('%', #{applyResult}, '%') </if>
+            <if test="applyContent != null and applyContent != '' "> and APPLY_CONTENT like concat('%', #{applyContent}, '%') </if>
+        </where>
+    </select>
+
+    <select id="selectDsMatDispatchByDeptId" parameterType="DsMatDispatch2" resultMap="DsMatDispatchResult">
+        <include refid="selectDsMatDispatchVo" />
+        <where>
+            <if test="resHarborId != null and resHarborId != ''"> and (RES_HARBOR_ID = #{resHarborId} or DES_HARBOR_ID = #{resHarborId} )   </if>
+            <if test="status != null and status != ''"> and STATUS = #{status} </if>
+        </where>
+    </select>
+
+    <select id="selectDsMatDispatchById" parameterType="Long" resultMap="DsMatDispatchResult" >
+        <include refid="selectDsMatDispatchVo" />
+        where ID = #{id}
+    </select>
+
+    <select id="selectDsMatDispatchForApply" resultMap="DsMatDispatchResult" >
+        <include refid="selectDsMatDispatchVo" />
+        where STATUS != '1' ORDER BY CREATE_TIME DESC
+    </select>
+
+    <insert id="insertDsMatDispatch" parameterType="DsMatDispatch2">
+        insert into DS_MAT_DISPATCH
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="id != null">ID,</if>
+            <if test="resHarborId != null">RES_HARBOR_ID,</if>
+            <if test="resHarborName != null">RES_HARBOR_NAME,</if>
+            <if test="desHarborId != null">DES_HARBIR_ID,</if>
+            <if test="desHarborName != null">DES_HARBOR_NAME,</if>
+            <if test="content != null">CONTENT,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="remark != null">REMARK,</if>
+            <if test="status != null">STATUS,</if>
+            <if test="applyBy != null">APPLY_BY,</if>
+            <if test="applyTime != null">APPLY_TIME,</if>
+            <if test="applyResult != null">APPLY_RESULT,</if>
+            <if test="applyContent != null">APPLY_CONTENT,</if>
+        </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="id != null">#{id},</if>
+            <if test="resHarborId != null">#{resHarborId},</if>
+            <if test="resHarborName != null">#{resHarborName},</if>
+            <if test="desHarborId != null">#{desHarborId},</if>
+            <if test="desHarborName != null">#{desHarborName},</if>
+            <if test="content != null">#{content},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="status != null">#{status},</if>
+            <if test="applyBy != null">#{applyBy},</if>
+            <if test="applyTime != null">#{applyTime},</if>
+            <if test="applyResult != null">#{applyResult},</if>
+            <if test="applyContent != null">#{applyContent},</if>
+        </trim>
+    </insert>
+
+    <update id="updateDsMatDispatch" parameterType="DsMatDispatch2">
+        update DS_MAT_DISPATCH
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="resHarborId != null"> RES_HARBOR_ID = #{resHarborId},</if>
+            <if test="resHarborName != null"> RES_HARBOR_NAME = #{resHarborName},</if>
+            <if test="desHarborId != null"> DES_HARBOR_ID = #{desHarborId},</if>
+            <if test="desHarborName != null"> DES_HARBOR_NAME = #{desHarborName},</if>
+            <if test="content != null"> CONTENT = #{content},</if>
+            <if test="updateBy != null"> UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null"> UPDATE_TIME = #{updateTime},</if>
+            <if test="remark != null"> REMARK = #{remark},</if>
+            <if test="status != null"> STATUS = #{status},</if>
+            <if test="applyBy != null"> APPLY_BY = #{applyBy}, </if>
+            <if test="applyTime != null"> APPLY_TIME = #{applyTime},</if>
+            <if test="applyResult != null"> APPLY_RESULT = #{applyResult},</if>
+            <if test="applyContent != null"> APPLY_CONTENT = #{applyContent},</if>
+        </trim>
+        where ID = #{id}
+    </update>
+
+    <delete id="deleteDsMatDispatchById" parameterType="Long" >
+        delete from DS_MAT_DISPATCH where ID = #{id}
+    </delete>
+
+    <delete id="deleteDsMatDispatchByIds" parameterType="String">
+        delete from DS_MAT_DISPATCH where ID in
+        <foreach item="id" collection="array" open="(" separator="," close=")">
+            #{id}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsTaskDetailMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskDetailMapper.xml
new file mode 100644
index 0000000..113a3cc
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskDetailMapper.xml
@@ -0,0 +1,304 @@
+<?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.buss.mapper.DsTaskDetailMapper">
+    
+    <resultMap type="DsTaskDetail" id="DsTaskDetailResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="taskId"    column="TASK_ID"    />
+        <result property="harborId"    column="HARBOR_ID"    />
+        <result property="harborName"    column="HARBOR_NAME"    />
+        <result property="berthId"    column="BERTH_ID"    />
+        <result property="berthName"    column="BERTH_NAME"    />
+        <result property="parkingType"    column="PARKING_TYPE"    />
+        <result property="shipNo"    column="SHIP_NO"    />
+        <result property="shipType"    column="SHIP_TYPE"    />
+        <result property="STIME"    column="STIME"    />
+        <result property="elecStime"    column="ELEC_STIME"    />
+        <result property="elecEtime"    column="ELEC_ETIME"    />
+        <result property="waterStime"    column="WATER_STIME"    />
+        <result property="waterEtime"    column="WATER_ETIME"    />
+        <result property="oilStime"    column="OIL_STIME"    />
+        <result property="oilEtime"    column="OIL_ETIME"    />
+        <result property="ammoStime"    column="AMMO_STIME"    />
+        <result property="ammoEtime"    column="AMMO_ETIME"    />
+        <result property="matStime"    column="MAT_STIME"    />
+        <result property="matEtime"    column="MAT_ETIME"    />
+        <result property="ETIME"    column="ETIME"    />
+        <result property="oilTime"    column="OIL_TIME"    />
+        <result property="ammoTime"    column="AMMO_TIME"    />
+        <result property="matTime"    column="MAT_TIME"    />
+        <result property="waterTime"    column="WATER_TIME"    />
+        <result property="totalTime"    column="TOTAL_TIME"    />
+        <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="t1"    column="T1"    />
+        <result property="supplySeq"    column="SUPPLY_SEQ"    />
+        <result property="carCount"    column="CAR_COUNT"    />
+        <result property="oilApply"    column="OIL_APPLY"    />
+        <result property="oilReady"    column="OIL_READY"    />
+        <result property="ammoTest"    column="AMMO_TEST"    />
+        <result property="ammoStart"    column="AMMO_START"    />
+        <result property="food"    column="FOOD"    />
+        <result property="foodW"    column="FOOD_W"    />
+        <result property="foodO"    column="FOOD_O"    />
+        <result property="workGrpId"    column="WORK_GRP_ID"    />
+        <result property="workGrpName"    column="WORK_GRP_NAME"    />
+        <result property="deptId"    column="DEPT_ID"    />
+        <result property="workMatGrpId"    column="WORK_MAT_GRP_ID"    />
+        <result property="workMatGrpName"    column="WORK_MAT_GRP_NAME"    />
+        <result property="path"    column="PATH"    />
+    </resultMap>
+
+    <sql id="selectDsTaskDetailVo">
+        select PKID, TASK_ID, HARBOR_ID, HARBOR_NAME, BERTH_ID, BERTH_NAME, PARKING_TYPE, SHIP_NO, SHIP_TYPE, STIME, ELEC_STIME, ELEC_ETIME, WATER_STIME, WATER_ETIME, OIL_STIME, OIL_ETIME, AMMO_STIME, AMMO_ETIME, MAT_STIME, MAT_ETIME, ETIME, OIL_TIME, AMMO_TIME, MAT_TIME, WATER_TIME, TOTAL_TIME, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, T1, SUPPLY_SEQ, CAR_COUNT, OIL_APPLY, OIL_READY, AMMO_TEST, AMMO_START, FOOD, FOOD_W, FOOD_O, WORK_GRP_ID, WORK_GRP_NAME, DEPT_ID, WORK_MAT_GRP_ID, WORK_MAT_GRP_NAME, PATH from ds_task_detail
+    </sql>
+
+    <select id="selectDsTaskDetailList" parameterType="DsTaskDetail" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        <where>  
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="taskId != null "> and TASK_ID = #{taskId}</if>
+            <if test="harborId != null "> and HARBOR_ID = #{harborId}</if>
+            <if test="harborName != null  and harborName != ''"> and HARBOR_NAME like concat('%', #{harborName}, '%')</if>
+            <if test="berthId != null "> and BERTH_ID = #{berthId}</if>
+            <if test="berthName != null  and berthName != ''"> and BERTH_NAME like concat('%', #{berthName}, '%')</if>
+            <if test="parkingType != null  and parkingType != ''"> and PARKING_TYPE = #{parkingType}</if>
+            <if test="shipNo != null  and shipNo != ''"> and SHIP_NO = #{shipNo}</if>
+            <if test="shipType != null  and shipType != ''"> and SHIP_TYPE = #{shipType}</if>
+            <if test="STIME != null "> and STIME = #{STIME}</if>
+            <if test="elecStime != null "> and ELEC_STIME = #{elecStime}</if>
+            <if test="elecEtime != null "> and ELEC_ETIME = #{elecEtime}</if>
+            <if test="waterStime != null "> and WATER_STIME = #{waterStime}</if>
+            <if test="waterEtime != null "> and WATER_ETIME = #{waterEtime}</if>
+            <if test="oilStime != null "> and OIL_STIME = #{oilStime}</if>
+            <if test="oilEtime != null "> and OIL_ETIME = #{oilEtime}</if>
+            <if test="ammoStime != null "> and AMMO_STIME = #{ammoStime}</if>
+            <if test="ammoEtime != null "> and AMMO_ETIME = #{ammoEtime}</if>
+            <if test="matStime != null "> and MAT_STIME = #{matStime}</if>
+            <if test="matEtime != null "> and MAT_ETIME = #{matEtime}</if>
+            <if test="ETIME != null "> and ETIME = #{ETIME}</if>
+            <if test="oilTime != null "> and OIL_TIME = #{oilTime}</if>
+            <if test="ammoTime != null "> and AMMO_TIME = #{ammoTime}</if>
+            <if test="matTime != null "> and MAT_TIME = #{matTime}</if>
+            <if test="waterTime != null "> and WATER_TIME = #{waterTime}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="t1 != null "> and T1 = #{t1}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsTaskDetailByPKID" parameterType="Long" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <select id="selectAQTaskDetailList" parameterType="Long" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        where TASK_ID in (select top 1 a.pkid from DS_TASK a where a.STATUS = '2' and a.CREATE_TIME >= TRUNC(SYSDATE-1) order by a.pkid desc)
+        and harbor_id in (select c.pkid from DM_HARBOR c where c.DEPT_ID = #{deptId} )
+    </select>
+
+    <select id="selectAQCurTaskDetailList" parameterType="Long" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        where TASK_ID in (select top 1 a.task_id from DS_TASK_LIST a where a.STATUS = '2' and A.DEPT_ID = #{deptId} order by a.TASK_ID desc)
+        and harbor_id in (select c.pkid from DM_HARBOR c where c.DEPT_ID = #{deptId} )
+    </select>
+
+    <select id="selectDsTaskDetailByTaskId" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        <where>
+            <if test="taskid != null "> and TASK_ID = #{taskid}</if>
+            <if test="deptid != null "> and DEPT_ID = #{deptid}</if>
+        </where>
+    </select>
+
+    <select id="selectDsMatDispatchByDeptId" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        <where>
+            <if test="taskid != null "> and TASK_ID = #{taskid}</if>
+            <if test="deptid != null "> and DEPT_ID = #{deptid}</if>
+        </where>
+    </select>
+
+
+    <insert id="insertDsTaskDetail" parameterType="DsTaskDetail">
+        insert into ds_task_detail
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID,</if>
+            <if test="harborId != null">HARBOR_ID,</if>
+            <if test="harborName != null">HARBOR_NAME,</if>
+            <if test="berthId != null">BERTH_ID,</if>
+            <if test="berthName != null">BERTH_NAME,</if>
+            <if test="parkingType != null">PARKING_TYPE,</if>
+            <if test="shipNo != null">SHIP_NO,</if>
+            <if test="shipType != null">SHIP_TYPE,</if>
+            <if test="STIME != null">STIME,</if>
+            <if test="elecStime != null">ELEC_STIME,</if>
+            <if test="elecEtime != null">ELEC_ETIME,</if>
+            <if test="waterStime != null">WATER_STIME,</if>
+            <if test="waterEtime != null">WATER_ETIME,</if>
+            <if test="oilStime != null">OIL_STIME,</if>
+            <if test="oilEtime != null">OIL_ETIME,</if>
+            <if test="ammoStime != null">AMMO_STIME,</if>
+            <if test="ammoEtime != null">AMMO_ETIME,</if>
+            <if test="matStime != null">MAT_STIME,</if>
+            <if test="matEtime != null">MAT_ETIME,</if>
+            <if test="ETIME != null">ETIME,</if>
+            <if test="oilTime != null">OIL_TIME,</if>
+            <if test="ammoTime != null">AMMO_TIME,</if>
+            <if test="matTime != null">MAT_TIME,</if>
+            <if test="waterTime != null">WATER_TIME,</if>
+            <if test="totalTime != null "> and TOTAL_TIME = #{totalTime}</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="t1 != null">T1,</if>
+            <if test="supplySeq != null">SUPPLY_SEQ,</if>
+            <if test="carCount != null">CAR_COUNT,</if>
+            <if test="oilApply != null">OIL_APPLY,</if>
+            <if test="oilReady != null">OIL_READY,</if>
+            <if test="ammoTest != null">AMMO_TEST,</if>
+            <if test="ammoStart != null">AMMO_START,</if>
+            <if test="food != null">FOOD,</if>
+            <if test="foodW != null">FOOD_W,</if>
+            <if test="foodO != null">FOOD_O,</if>
+            <if test="workGrpId != null">WORK_GRP_ID,</if>
+            <if test="workGrpName != null">WORK_GRP_NAME,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+            <if test="workGrpId != null">WORK_MAT_GRP_ID,</if>
+            <if test="workGrpName != null">WORK_MAT_GRP_NAME,</if>
+            <if test="path != null">PATH,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">#{taskId},</if>
+            <if test="harborId != null">#{harborId},</if>
+            <if test="harborName != null">#{harborName},</if>
+            <if test="berthId != null">#{berthId},</if>
+            <if test="berthName != null">#{berthName},</if>
+            <if test="parkingType != null">#{parkingType},</if>
+            <if test="shipNo != null">#{shipNo},</if>
+            <if test="shipType != null">#{shipType},</if>
+            <if test="STIME != null">#{STIME},</if>
+            <if test="elecStime != null">#{elecStime},</if>
+            <if test="elecEtime != null">#{elecEtime},</if>
+            <if test="waterStime != null">#{waterStime},</if>
+            <if test="waterEtime != null">#{waterEtime},</if>
+            <if test="oilStime != null">#{oilStime},</if>
+            <if test="oilEtime != null">#{oilEtime},</if>
+            <if test="ammoStime != null">#{ammoStime},</if>
+            <if test="ammoEtime != null">#{ammoEtime},</if>
+            <if test="matStime != null">#{matStime},</if>
+            <if test="matEtime != null">#{matEtime},</if>
+            <if test="ETIME != null">#{ETIME},</if>
+            <if test="oilTime != null">#{oilTime},</if>
+            <if test="ammoTime != null">#{ammoTime},</if>
+            <if test="matTime != null">#{matTime},</if>
+            <if test="waterTime != null">#{waterTime},</if>
+            <if test="totalTime != null">#{totalTime},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="t1 != null">#{t1},</if>
+            <if test="supplySeq != null">#{supplySeq},</if>
+            <if test="carCount != null">#{carCount},</if>
+            <if test="oilApply != null">#{oilApply},</if>
+            <if test="oilReady != null">#{oilReady},</if>
+            <if test="ammoTest != null">#{ammoTest},</if>
+            <if test="ammoStart != null">#{ammoStart},</if>
+            <if test="food != null">#{food},</if>
+            <if test="foodW != null">#{foodW},</if>
+            <if test="foodO != null">#{foodO},</if>
+            <if test="workGrpId != null">#{workGrpId},</if>
+            <if test="workGrpName != null">#{workGrpName},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="workGrpId != null">#{workMatGrpId},</if>
+            <if test="workGrpName != null">#{workMatGrpName},</if>
+            <if test="path != null">#{path},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsTaskDetail" parameterType="DsTaskDetail">
+        update ds_task_detail
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID = #{taskId},</if>
+            <if test="harborId != null">HARBOR_ID = #{harborId},</if>
+            <if test="harborName != null">HARBOR_NAME = #{harborName},</if>
+            <if test="berthId != null">BERTH_ID = #{berthId},</if>
+            <if test="berthName != null">BERTH_NAME = #{berthName},</if>
+            <if test="parkingType != null">PARKING_TYPE = #{parkingType},</if>
+            <if test="shipNo != null">SHIP_NO = #{shipNo},</if>
+            <if test="shipType != null">SHIP_TYPE = #{shipType},</if>
+            <if test="STIME != null">STIME = #{STIME},</if>
+            <if test="elecStime != null">ELEC_STIME = #{elecStime},</if>
+            <if test="elecEtime != null">ELEC_ETIME = #{elecEtime},</if>
+            <if test="waterStime != null">WATER_STIME = #{waterStime},</if>
+            <if test="waterEtime != null">WATER_ETIME = #{waterEtime},</if>
+            <if test="oilStime != null">OIL_STIME = #{oilStime},</if>
+            <if test="oilEtime != null">OIL_ETIME = #{oilEtime},</if>
+            <if test="ammoStime != null">AMMO_STIME = #{ammoStime},</if>
+            <if test="ammoEtime != null">AMMO_ETIME = #{ammoEtime},</if>
+            <if test="matStime != null">MAT_STIME = #{matStime},</if>
+            <if test="matEtime != null">MAT_ETIME = #{matEtime},</if>
+            <if test="ETIME != null">ETIME = #{ETIME},</if>
+            <if test="oilTime != null">OIL_TIME = #{oilTime},</if>
+            <if test="ammoTime != null">AMMO_TIME = #{ammoTime},</if>
+            <if test="matTime != null">MAT_TIME = #{matTime},</if>
+            <if test="waterTime != null">WATER_TIME = #{waterTime},</if>
+            <if test="totalTime != null ">TOTAL_TIME = #{totalTime},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="t1 != null">T1 = #{t1},</if>
+            <if test="supplySeq != null">SUPPLY_SEQ = #{supplySeq},</if>
+            <if test="carCount != null">CAR_COUNT = #{carCount},</if>
+            <if test="oilApply != null">OIL_APPLY = #{oilApply},</if>
+            <if test="oilReady != null">OIL_READY = #{oilReady},</if>
+            <if test="ammoTest != null">AMMO_TEST = #{ammoTest},</if>
+            <if test="ammoStart != null">AMMO_START = #{ammoStart},</if>
+            <if test="food != null">FOOD = #{food},</if>
+            <if test="foodW != null">FOOD_W = #{foodW},</if>
+            <if test="foodO != null">FOOD_O = #{foodO},</if>
+            <if test="workGrpId != null">WORK_GRP_ID = #{workGrpId},</if>
+            <if test="workGrpName != null">WORK_GRP_NAME = #{workGrpName},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+            <if test="workMatGrpId != null">WORK_MAT_GRP_ID = #{workMatGrpId},</if>
+            <if test="workMatGrpName != null">WORK_MAT_GRP_NAME = #{workMatGrpName},</if>
+            <if test="path != null">PATH = #{path},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsTaskDetailByPKID" parameterType="Long">
+        delete from ds_task_detail where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDsTaskDetailByPKIDs" parameterType="String">
+        delete from ds_task_detail where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+    <select id="selectDsTaskDetailByTaskIdAndHarborIds" resultMap="DsTaskDetailResult">
+        <include refid="selectDsTaskDetailVo"/>
+        <where>
+            <if test="taskid != null "> and TASK_ID = #{taskid}</if>
+            <if test="harborIds != null "> and HARBOR_ID IN ${harborIds}</if>
+        </where>
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsTaskList2Mapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskList2Mapper.xml
new file mode 100644
index 0000000..81249bc
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskList2Mapper.xml
@@ -0,0 +1,352 @@
+<?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.buss.mapper.DsTaskList2Mapper">
+    
+    <resultMap type="com.ruoyi.buss.domain.DsTaskList2" id="DsTaskListResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="taskId"    column="TASK_ID"    />
+        <result property="shipNo"    column="SHIP_NO"    />
+        <result property="shipType"    column="SHIP_TYPE"    />
+        <result property="TONNAGE"    column="TONNAGE"    />
+        <result property="draft"    column="DRAFT"    />
+        <result property="LEADER"    column="LEADER"    />
+        <result property="STAFF"    column="STAFF"    />
+        <result property="grpName"    column="GRP_NAME"    />
+        <result property="LEVEL"    column="LEVEL"    />
+        <result property="LAT"    column="LAT"    />
+        <result property="LON"    column="LON"    />
+        <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="oilB"    column="OIL_B"    />
+        <result property="oilG"    column="OIL_G"    />
+        <result property="oilA"    column="OIL_A"    />
+        <result property="ammoD"    column="AMMO_D"    />
+        <result property="ammoP"    column="AMMO_P"    />
+        <result property="ammoS"    column="AMMO_S"    />
+        <result property="ammoO"    column="AMMO_O"    />
+        <result property="WATER"    column="WATER"    />
+        <result property="waterP"    column="WATER_P"    />
+        <result property="FOOD"    column="FOOD"    />
+        <result property="foodW"    column="FOOD_W"    />
+        <result property="foodO"    column="FOOD_O"    />
+        <result property="pSTime"    column="P_S_TIME"    />
+        <result property="pETime"    column="P_E_TIME"    />
+        <result property="status"    column="STATUS"    />
+        <result property="harborId"    column="HARBOR_ID"    />
+        <result property="harborName"    column="HARBOR_NAME"    />
+        <result property="berthId"    column="BERTH_ID"    />
+        <result property="berthName"    column="BERTH_NAME"    />
+        <result property="parkingType"    column="PARKING_TYPE"    />
+        <result property="deptId"    column="DEPT_ID"    />
+        <result property="deptName"    column="DEPT_NAME"    />
+        <result property="posArea"    column="POS_AREA"    />
+        <result property="remark"    column="REMARK"    />
+        <result property="shipLen"    column="SHIP_LEN"    />
+        <result property="dockTime"    column="DOCK_TIME"    />
+        <result property="dockIndex"    column="DOCK_INDEX"    />
+        <result property="path"    column="PATH"    />
+    </resultMap>
+
+    <sql id="selectDsTaskListVo">
+        select TASK_ID, SHIP_NO, SHIP_TYPE, TONNAGE, DRAFT, LEADER, STAFF, GRP_NAME, LEVEL, LAT, LON, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, OIL_B, OIL_G, OIL_A, AMMO_D, AMMO_P, AMMO_S, AMMO_O, WATER, WATER_P, FOOD, FOOD_W, FOOD_O, P_S_TIME, P_E_TIME, STATUS, HARBOR_ID, HARBOR_NAME, BERTH_ID, BERTH_NAME, PARKING_TYPE, PKID, DEPT_ID, DEPT_NAME, POS_AREA, REMARK, SHIP_LEN, DOCK_TIME, DOCK_INDEX, PATH from ds_task_list
+    </sql>
+
+    <select id="selectDsTaskListList" parameterType="com.ruoyi.buss.domain.DsTaskList2" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        <where>  
+            <if test="taskId != null "> and TASK_ID = #{taskId}</if>
+            <if test="shipNo != null  and shipNo != ''"> and SHIP_NO = #{shipNo}</if>
+            <if test="shipType != null  and shipType != ''"> and SHIP_TYPE = #{shipType}</if>
+            <if test="TONNAGE != null "> and TONNAGE = #{TONNAGE}</if>
+            <if test="draft != null "> and DRAFT = #{draft}</if>
+            <if test="LEADER != null  and LEADER != ''"> and LEADER = #{LEADER}</if>
+            <if test="STAFF != null "> and STAFF = #{STAFF}</if>
+            <if test="grpName != null  and grpName != ''"> and GRP_NAME like concat('%', #{grpName}, '%')</if>
+            <if test="LEVEL != null "> and LEVEL = #{LEVEL}</if>
+            <if test="LAT != null "> and LAT = #{LAT}</if>
+            <if test="LON != null "> and LON = #{LON}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="oilB != null "> and OIL_B = #{oilB}</if>
+            <if test="oilG != null "> and OIL_G = #{oilG}</if>
+            <if test="oilA != null "> and OIL_A = #{oilA}</if>
+            <if test="ammoD != null "> and AMMO_D = #{ammoD}</if>
+            <if test="ammoP != null "> and AMMO_P = #{ammoP}</if>
+            <if test="ammoS != null "> and AMMO_S = #{ammoS}</if>
+            <if test="ammoO != null "> and AMMO_O = #{ammoO}</if>
+            <if test="WATER != null "> and WATER = #{WATER}</if>
+            <if test="waterP != null "> and WATER_P = #{waterP}</if>
+            <if test="FOOD != null "> and FOOD = #{FOOD}</if>
+            <if test="foodW != null "> and FOOD_W = #{foodW}</if>
+            <if test="foodO != null "> and FOOD_O = #{foodO}</if>
+            <if test="pSTime != null "> and P_S_TIME = #{pSTime}</if>
+            <if test="pETime != null "> and P_E_TIME = #{pETime}</if>
+            <if test="status != null  and status != ''"> and STATUS = #{status}</if>
+            <if test="harborId != null "> and HARBOR_ID = #{harborId}</if>
+            <if test="harborName != null  and harborName != ''"> and HARBOR_NAME like concat('%', #{harborName}, '%')</if>
+            <if test="berthId != null "> and BERTH_ID = #{berthId}</if>
+            <if test="berthName != null  and berthName != ''"> and BERTH_NAME like concat('%', #{berthName}, '%')</if>
+            <if test="parkingType != null  and parkingType != ''"> and PARKING_TYPE = #{parkingType}</if>
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+            <if test="deptName != null "> and DEPT_NAME = #{deptName}</if>
+            <if test="path != null "> and PATH = #{path}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsTaskListByTaskId" parameterType="Long" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where TASK_ID = #{taskId}
+    </select>
+
+    <select id="selectDsTaskListByParam" parameterType="com.ruoyi.buss.domain.dto.TaskQueryParam" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        <where>
+            <if test="taskId != null "> and TASK_ID = #{taskId}</if>
+            <if test="deptId != null "> and DEPT_ID = #{deptId}</if>
+            <if test="status != null  and status != ''"> and STATUS = #{status}</if>
+            <if test="ids != null and ids.length > 0 ">
+             and PKID in
+                <foreach collection="ids" item="item" index="index" open="(" separator="," close=")">
+                    #{item}
+                </foreach>
+             </if>
+        </where>
+    </select>
+
+    <select id="selectDsTaskListByPKID" parameterType="Long" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where PKID = #{pkid}
+    </select>
+
+    <select id="selectCurrentDsTaskList" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where TASK_ID is null and CREATE_TIME >= TRUNC(SYSDATE - 1)
+    </select>
+
+    <select id="selectCurrentDsTaskListV2" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where TASK_ID is null
+    </select>
+
+    <select id="selectCurrentDsTaskListWithShipNoV2" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where TASK_ID is null and SHIP_NO in
+        <foreach collection="array" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+
+    <select id="selectCurrentDsTaskListWithShipNo" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where TASK_ID is null and CREATE_TIME >= TRUNC(SYSDATE - 1) and SHIP_NO in
+        <foreach collection="array" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+
+    <select id="selectDsTaskListByPkids" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        where PKID in
+        <foreach collection="list" item="item" index="index" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </select>
+
+    <insert id="insertDsTaskList" parameterType="com.ruoyi.buss.domain.DsTaskList2">
+        insert into ds_task_list
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID,</if>
+            <if test="shipNo != null">SHIP_NO,</if>
+            <if test="shipType != null">SHIP_TYPE,</if>
+            <if test="TONNAGE != null">TONNAGE,</if>
+            <if test="draft != null">DRAFT,</if>
+            <if test="LEADER != null">LEADER,</if>
+            <if test="STAFF != null">STAFF,</if>
+            <if test="grpName != null">GRP_NAME,</if>
+            <if test="LEVEL != null">LEVEL,</if>
+            <if test="LAT != null">LAT,</if>
+            <if test="LON != null">LON,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="oilB != null">OIL_B,</if>
+            <if test="oilG != null">OIL_G,</if>
+            <if test="oilA != null">OIL_A,</if>
+            <if test="ammoD != null">AMMO_D,</if>
+            <if test="ammoP != null">AMMO_P,</if>
+            <if test="ammoS != null">AMMO_S,</if>
+            <if test="ammoO != null">AMMO_O,</if>
+            <if test="WATER != null">WATER,</if>
+            <if test="waterP != null">WATER_P,</if>
+            <if test="FOOD != null">FOOD,</if>
+            <if test="foodW != null">FOOD_W,</if>
+            <if test="foodO != null">FOOD_O,</if>
+            <if test="pSTime != null">P_S_TIME,</if>
+            <if test="pETime != null">P_E_TIME,</if>
+            <if test="status != null">STATUS,</if>
+            <if test="harborId != null">HARBOR_ID,</if>
+            <if test="harborName != null">HARBOR_NAME,</if>
+            <if test="berthId != null">BERTH_ID,</if>
+            <if test="berthName != null">BERTH_NAME,</if>
+            <if test="parkingType != null">PARKING_TYPE,</if>
+            <if test="deptId != null">DEPT_ID,</if>
+            <if test="deptName != null">DEPT_NAME,</if>
+            <if test="posArea != null">POS_AREA,</if>
+            <if test="shipLen != null">SHIP_LEN,</if>
+            <if test="supplySeq != null">SUPPLY_SEQ,</if>
+            <if test="dockTime != null">DOCK_TIME,</if>
+            <if test="dockIndex != null">DOCK_INDEX,</if>
+            <if test="path != null">PATH,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="taskId != null">#{taskId},</if>
+            <if test="shipNo != null">#{shipNo},</if>
+            <if test="shipType != null">#{shipType},</if>
+            <if test="TONNAGE != null">#{TONNAGE},</if>
+            <if test="draft != null">#{draft},</if>
+            <if test="LEADER != null">#{LEADER},</if>
+            <if test="STAFF != null">#{STAFF},</if>
+            <if test="grpName != null">#{grpName},</if>
+            <if test="LEVEL != null">#{LEVEL},</if>
+            <if test="LAT != null">#{LAT},</if>
+            <if test="LON != null">#{LON},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="oilB != null">#{oilB},</if>
+            <if test="oilG != null">#{oilG},</if>
+            <if test="oilA != null">#{oilA},</if>
+            <if test="ammoD != null">#{ammoD},</if>
+            <if test="ammoP != null">#{ammoP},</if>
+            <if test="ammoS != null">#{ammoS},</if>
+            <if test="ammoO != null">#{ammoO},</if>
+            <if test="WATER != null">#{WATER},</if>
+            <if test="waterP != null">#{waterP},</if>
+            <if test="FOOD != null">#{FOOD},</if>
+            <if test="foodW != null">#{foodW},</if>
+            <if test="foodO != null">#{foodO},</if>
+            <if test="pSTime != null">#{pSTime},</if>
+            <if test="pETime != null">#{pETime},</if>
+            <if test="status != null">#{status},</if>
+            <if test="harborId != null">#{harborId},</if>
+            <if test="harborName != null">#{harborName},</if>
+            <if test="berthId != null">#{berthId},</if>
+            <if test="berthName != null">#{berthName},</if>
+            <if test="parkingType != null">#{parkingType},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="deptName != null">#{deptName},</if>
+            <if test="posArea != null">#{posArea},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="shipLen != null">#{shipLen},</if>
+            <if test="supplySeq != null">#{supplySeq},</if>
+            <if test="dockTime != null">#{dockTime},</if>
+            <if test="dockIndex != null">#{dockIndex},</if>
+            <if test="path != null">#{path},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsTaskList" parameterType="com.ruoyi.buss.domain.DsTaskList2">
+        update ds_task_list
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="taskId != null">TASK_ID = #{taskId},</if>
+            <if test="shipNo != null">SHIP_NO = #{shipNo},</if>
+            <if test="shipType != null">SHIP_TYPE = #{shipType},</if>
+            <if test="TONNAGE != null">TONNAGE = #{TONNAGE},</if>
+            <if test="draft != null">DRAFT = #{draft},</if>
+            <if test="LEADER != null">LEADER = #{LEADER},</if>
+            <if test="STAFF != null">STAFF = #{STAFF},</if>
+            <if test="grpName != null">GRP_NAME = #{grpName},</if>
+            <if test="LEVEL != null">LEVEL = #{LEVEL},</if>
+            <if test="LAT != null">LAT = #{LAT},</if>
+            <if test="LON != null">LON = #{LON},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="oilB != null">OIL_B = #{oilB},</if>
+            <if test="oilG != null">OIL_G = #{oilG},</if>
+            <if test="oilA != null">OIL_A = #{oilA},</if>
+            <if test="ammoD != null">AMMO_D = #{ammoD},</if>
+            <if test="ammoP != null">AMMO_P = #{ammoP},</if>
+            <if test="ammoS != null">AMMO_S = #{ammoS},</if>
+            <if test="ammoO != null">AMMO_O = #{ammoO},</if>
+            <if test="WATER != null">WATER = #{WATER},</if>
+            <if test="waterP != null">WATER_P = #{waterP},</if>
+            <if test="FOOD != null">FOOD = #{FOOD},</if>
+            <if test="foodW != null">FOOD_W = #{foodW},</if>
+            <if test="foodO != null">FOOD_O = #{foodO},</if>
+            <if test="pSTime != null">P_S_TIME = #{pSTime},</if>
+            <if test="pETime != null">P_E_TIME = #{pETime},</if>
+            <if test="status != null">STATUS = #{status},</if>
+            <if test="harborId != null">HARBOR_ID = #{harborId},</if>
+            <if test="harborName != null">HARBOR_NAME = #{harborName},</if>
+            <if test="berthId != null">BERTH_ID = #{berthId},</if>
+            <if test="berthName != null">BERTH_NAME = #{berthName},</if>
+            <if test="parkingType != null">PARKING_TYPE = #{parkingType},</if>
+            <if test="deptId != null">DEPT_ID = #{deptId},</if>
+            <if test="deptName != null">DEPT_NAME = #{deptName},</if>
+            <if test="posArea != null">POS_AREA = #{posArea},</if>
+            <if test="remark != null">REMARK = #{remark},</if>
+            <if test="shipLen != null">SHIP_LEN = #{shipLen},</if>
+            <if test="supplySeq != null">SUPPLY_SEQ = #{supplySeq},</if>
+            <if test="dockTime != null">DOCK_TIME = #{dockTime},</if>
+            <if test="dockIndex != null">DOCK_INDEX = #{dockIndex},</if>
+            <if test="path != null">PATH = #{path},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsTaskListByTaskId" parameterType="Long">
+        delete from ds_task_list where TASK_ID = #{taskId}
+    </delete>
+
+    <delete id="deleteDsTaskListByPKID" parameterType="Long">
+        delete from ds_task_list where PKID = #{pkid}
+    </delete>
+
+    <delete id="deleteDsTaskListByTaskIds" parameterType="String">
+        delete from ds_task_list where TASK_ID in 
+        <foreach item="taskId" collection="array" open="(" separator="," close=")">
+            #{taskId}
+        </foreach>
+    </delete>
+
+    <delete id="deleteDsTaskListByPKIDs" parameterType="String">
+        delete from ds_task_list where PKID in
+        <foreach item="item" collection="list" open="(" separator="," close=")">
+            #{item}
+        </foreach>
+    </delete>
+
+    <select id="getDsTaskListByTaskIdAndDeptId" parameterType="com.ruoyi.buss.domain.DsTaskList2" resultMap="DsTaskListResult">
+        <include refid="selectDsTaskListVo"/>
+        <where>
+            <if test="taskId != null ">TASK_ID = #{taskId}</if>
+            <if test="deptId!= null  and deptId!= ''"> and DEPT_ID = #{deptId}</if>
+        </where>
+    </select>
+
+    <select id="getDsTaskListForSupplyPlan" resultMap="DsTaskListResult">
+        select a.*
+        from DS_TASK_LIST a, DM_BERTH b where a.BERTH_ID = b.PKID and a.TASK_ID = ${taskId} and a.DEPT_ID = ${deptId} and a.BERTH_ID = ${berthId}
+    </select>
+
+    <select id="selectDsTaskListListByTaskIdAndBerthds" resultMap="DsTaskListResult">
+        SELECT a.*
+        FROM DS_TASK_LIST WHERE TASK_ID = ${taskId} AND a.BERTH_ID IN ${berthIds}
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/mapper/buss/DsTaskMapper.xml b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskMapper.xml
new file mode 100644
index 0000000..7c65fd1
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/mapper/buss/DsTaskMapper.xml
@@ -0,0 +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.buss.mapper.DsTaskMapper">
+    
+    <resultMap type="DsTask" id="DsTaskResult">
+        <id property="PKID"    column="PKID"    />
+        <result property="NAME"    column="NAME"    />
+        <result property="TYPE"    column="TYPE"    />
+        <result property="NOTES"    column="NOTES"    />
+        <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="status"    column="STATUS"    />
+    </resultMap>
+
+    <sql id="selectDsTaskVo">
+        select PKID, NAME, TYPE, NOTES, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, STATUS from ds_task
+    </sql>
+
+    <select id="selectDsTaskListByParam" parameterType="com.ruoyi.buss.domain.dto.DsTaskQueryParam" resultMap="DsTaskResult">
+        <include refid="selectDsTaskVo"/>
+        <where>
+            <if test="name != null  and name != ''"> and NAME like concat('%', #{name}, '%') </if>
+            <if test="type != null  and type != ''"> and TYPE = #{type} </if>
+            <if test="notes != null  and notes != ''"> and NOTES like concat('%', #{notes}, '%') </if>
+            <if test="stime != null"> and CREATE_TIME >= #{stime} </if>
+            <if test="etime != null"> and CREATE_TIME &lt;= #{etime} </if>
+            <if test="status != null and status != ''"> and STATUS = #{status} </if>
+            <if test="deptId != null and deptId != ''">
+                and PKID in (select DISTINCT TASK_ID from DS_TASK_LIST where DEPT_ID = #{deptId} )
+            </if>
+        </where>
+    </select>
+
+    <select id="selectDsTaskList" parameterType="DsTask" resultMap="DsTaskResult">
+        <include refid="selectDsTaskVo"/>
+        <where>  
+            <if test="PKID != null "> and PKID = #{PKID}</if>
+            <if test="NAME != null  and NAME != ''"> and NAME like concat('%', #{NAME}, '%')</if>
+            <if test="TYPE != null  and TYPE != ''"> and TYPE = #{TYPE}</if>
+            <if test="NOTES != null  and NOTES != ''"> and NOTES = #{NOTES}</if>
+            <if test="delFlag != null  and delFlag != ''"> and DEL_FLAG = #{delFlag}</if>
+            <if test="createBy != null  and createBy != ''"> and CREATE_BY = #{createBy}</if>
+            <if test="createTime != null "> and CREATE_TIME = #{createTime}</if>
+            <if test="updateBy != null  and updateBy != ''"> and UPDATE_BY = #{updateBy}</if>
+            <if test="updateTime != null "> and UPDATE_TIME = #{updateTime}</if>
+            <if test="status != null "> and STATUS = #{status}</if>
+        </where>
+    </select>
+    
+    <select id="selectDsTaskByPKID" parameterType="Long" resultMap="DsTaskResult">
+        <include refid="selectDsTaskVo"/>
+        where PKID = #{PKID}
+    </select>
+
+    <select id="selectMaxTaskId" resultType="java.lang.Long">
+        select max(PKID) from DS_TASK
+    </select>
+
+    <insert id="insertDsTask" parameterType="DsTask" useGeneratedKeys="true" keyColumn="PKID" keyProperty="PKID">
+        insert into ds_task
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="NAME != null">NAME,</if>
+            <if test="TYPE != null">TYPE,</if>
+            <if test="NOTES != null">NOTES,</if>
+            <if test="delFlag != null">DEL_FLAG,</if>
+            <if test="createBy != null">CREATE_BY,</if>
+            <if test="createTime != null">CREATE_TIME,</if>
+            <if test="updateBy != null">UPDATE_BY,</if>
+            <if test="updateTime != null">UPDATE_TIME,</if>
+            <if test="status != null">STATUS,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="NAME != null">#{NAME},</if>
+            <if test="TYPE != null">#{TYPE},</if>
+            <if test="NOTES != null">#{NOTES},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="status != null">#{status},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDsTask" parameterType="DsTask">
+        update ds_task
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="NAME != null">NAME = #{NAME},</if>
+            <if test="TYPE != null">TYPE = #{TYPE},</if>
+            <if test="NOTES != null">NOTES = #{NOTES},</if>
+            <if test="delFlag != null">DEL_FLAG = #{delFlag},</if>
+            <if test="createBy != null">CREATE_BY = #{createBy},</if>
+            <if test="createTime != null">CREATE_TIME = #{createTime},</if>
+            <if test="updateBy != null">UPDATE_BY = #{updateBy},</if>
+            <if test="updateTime != null">UPDATE_TIME = #{updateTime},</if>
+            <if test="status != null">STATUS = #{status},</if>
+        </trim>
+        where PKID = #{PKID}
+    </update>
+
+    <delete id="deleteDsTaskByPKID" parameterType="Long">
+        delete from ds_task where PKID = #{PKID}
+    </delete>
+
+    <delete id="deleteDsTaskByPKIDs" parameterType="String">
+        delete from ds_task where PKID in 
+        <foreach item="PKID" collection="array" open="(" separator="," close=")">
+            #{PKID}
+        </foreach>
+    </delete>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/assess/add.html b/ruoyi-buss/src/main/resources/templates/buss/assess/add.html
new file mode 100644
index 0000000..9972ce6
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/assess/add.html
@@ -0,0 +1,65 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板鑳芥晥璇勪及')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-assess-add">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="PKID" class="form-control" required></textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="taskId" class="form-control"></textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="SCORE" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/assess"
+        $("#form-assess-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-assess-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/assess/assess.html b/ruoyi-buss/src/main/resources/templates/buss/assess/assess.html
new file mode 100644
index 0000000..dd0b3d6
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/assess/assess.html
@@ -0,0 +1,137 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('鑳芥晥璇勪及鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="SCORE"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="REMARK"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:assess:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:assess:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:assess:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:assess:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:assess:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:assess:remove')}]];
+        var prefix = ctx + "buss/assess";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "鑳芥晥璇勪及",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'taskId',
+                    title: ''
+                },
+                {
+                    field: 'SCORE',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    field: 'REMARK',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/assess/edit.html b/ruoyi-buss/src/main/resources/templates/buss/assess/edit.html
new file mode 100644
index 0000000..9b878a3
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/assess/edit.html
@@ -0,0 +1,66 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼鑳芥晥璇勪及')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-assess-edit" th:object="${dsEffectAssess}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="PKID" class="form-control" required>[[*{PKID}]]</textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="taskId" class="form-control">[[*{taskId}]]</textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="SCORE" th:field="*{SCORE}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" th:field="*{REMARK}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/assess";
+        $("#form-assess-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-assess-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/berth/add.html b/ruoyi-buss/src/main/resources/templates/buss/berth/add.html
new file mode 100644
index 0000000..ef47cb7
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/berth/add.html
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板娉婁綅淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-berth-add">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthLen" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DEPTH" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="orderNum" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/berth"
+        $("#form-berth-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-berth-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/berth/berth.html b/ruoyi-buss/src/main/resources/templates/buss/berth/berth.html
new file mode 100644
index 0000000..01b9312
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/berth/berth.html
@@ -0,0 +1,173 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('娉婁綅淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="NAME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthLen"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="DEPTH"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="orderNum"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:berth:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:berth:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:berth:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:berth:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:berth:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:berth:remove')}]];
+        var prefix = ctx + "buss/berth";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "娉婁綅淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'NAME',
+                    title: ''
+                },
+                {
+                    field: 'harborId',
+                    title: ''
+                },
+                {
+                    field: 'harborName',
+                    title: ''
+                },
+                {
+                    field: 'berthLen',
+                    title: ''
+                },
+                {
+                    field: 'DEPTH',
+                    title: ''
+                },
+                {
+                    field: 'STATUS',
+                    title: ''
+                },
+                {
+                    field: 'orderNum',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/berth/edit.html b/ruoyi-buss/src/main/resources/templates/buss/berth/edit.html
new file mode 100644
index 0000000..4e34b2a
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/berth/edit.html
@@ -0,0 +1,90 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼娉婁綅淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-berth-edit" th:object="${dmBerth2}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" th:field="*{NAME}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" th:field="*{harborId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" th:field="*{harborName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthLen" th:field="*{berthLen}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DEPTH" th:field="*{DEPTH}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="orderNum" th:field="*{orderNum}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/berth";
+        $("#form-berth-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-berth-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/config/add.html b/ruoyi-buss/src/main/resources/templates/buss/config/add.html
new file mode 100644
index 0000000..b2fdb6a
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/config/add.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板璋冮厤閰嶇疆淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-config-add">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="UNIT" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TIME" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/config"
+        $("#form-config-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-config-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/config/config.html b/ruoyi-buss/src/main/resources/templates/buss/config/config.html
new file mode 100644
index 0000000..d3c4552
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/config/config.html
@@ -0,0 +1,113 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('璋冮厤閰嶇疆淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="UNIT"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="TIME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="REMARK"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:config:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:config:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:config:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:config:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:config:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:config:remove')}]];
+        var prefix = ctx + "buss/config";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "璋冮厤閰嶇疆淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'TYPE',
+                    title: ''
+                },
+                {
+                    field: 'UNIT',
+                    title: ''
+                },
+                {
+                    field: 'shipType',
+                    title: ''
+                },
+                {
+                    field: 'TIME',
+                    title: ''
+                },
+                {
+                    field: 'REMARK',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/config/edit.html b/ruoyi-buss/src/main/resources/templates/buss/config/edit.html
new file mode 100644
index 0000000..b202f2f
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/config/edit.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼璋冮厤閰嶇疆淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-config-edit" th:object="${dmDdConfig}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="UNIT" th:field="*{UNIT}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TIME" th:field="*{TIME}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" th:field="*{REMARK}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/config";
+        $("#form-config-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-config-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/detail/add.html b/ruoyi-buss/src/main/resources/templates/buss/detail/add.html
new file mode 100644
index 0000000..e8cdd28
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/detail/add.html
@@ -0,0 +1,327 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板浠诲姟璋冮厤璇︽儏淇℃伅')" />
+    <th:block th:include="include :: datetimepicker-css" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-detail-add">
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="taskId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="STIME" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="elecStime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="elecEtime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="waterStime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="waterEtime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="oilStime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="oilEtime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ammoStime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ammoEtime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="matStime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="matEtime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ETIME" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilTime" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoTime" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="matTime" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="waterTime" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <th:block th:include="include :: datetimepicker-js" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/detail"
+        $("#form-detail-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-detail-add').serialize());
+            }
+        }
+
+        $("input[name='STIME']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='elecStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='elecEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='waterStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='waterEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='oilStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='oilEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ammoStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ammoEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='matStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='matEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ETIME']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/detail/detail.html b/ruoyi-buss/src/main/resources/templates/buss/detail/detail.html
new file mode 100644
index 0000000..850198e
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/detail/detail.html
@@ -0,0 +1,305 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('浠诲姟璋冮厤璇︽儏淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="taskId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="shipNo"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="STIME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="elecStime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="elecEtime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="waterStime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="waterEtime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="oilStime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="oilEtime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="ammoStime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="ammoEtime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="matStime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="matEtime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="ETIME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="matTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="waterTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:detail:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:detail:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:detail:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:detail:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:detail:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:detail:remove')}]];
+        var prefix = ctx + "buss/detail";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "浠诲姟璋冮厤璇︽儏淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'taskId',
+                    title: ''
+                },
+                {
+                    field: 'harborId',
+                    title: ''
+                },
+                {
+                    field: 'harborName',
+                    title: ''
+                },
+                {
+                    field: 'berthId',
+                    title: ''
+                },
+                {
+                    field: 'berthName',
+                    title: ''
+                },
+                {
+                    field: 'parkingType',
+                    title: ''
+                },
+                {
+                    field: 'shipNo',
+                    title: ''
+                },
+                {
+                    field: 'shipType',
+                    title: ''
+                },
+                {
+                    field: 'STIME',
+                    title: ''
+                },
+                {
+                    field: 'elecStime',
+                    title: ''
+                },
+                {
+                    field: 'elecEtime',
+                    title: ''
+                },
+                {
+                    field: 'waterStime',
+                    title: ''
+                },
+                {
+                    field: 'waterEtime',
+                    title: ''
+                },
+                {
+                    field: 'oilStime',
+                    title: ''
+                },
+                {
+                    field: 'oilEtime',
+                    title: ''
+                },
+                {
+                    field: 'ammoStime',
+                    title: ''
+                },
+                {
+                    field: 'ammoEtime',
+                    title: ''
+                },
+                {
+                    field: 'matStime',
+                    title: ''
+                },
+                {
+                    field: 'matEtime',
+                    title: ''
+                },
+                {
+                    field: 'ETIME',
+                    title: ''
+                },
+                {
+                    field: 'oilTime',
+                    title: ''
+                },
+                {
+                    field: 'ammoTime',
+                    title: ''
+                },
+                {
+                    field: 'matTime',
+                    title: ''
+                },
+                {
+                    field: 'waterTime',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/detail/edit.html b/ruoyi-buss/src/main/resources/templates/buss/detail/edit.html
new file mode 100644
index 0000000..d774b24
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/detail/edit.html
@@ -0,0 +1,328 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼浠诲姟璋冮厤璇︽儏淇℃伅')" />
+    <th:block th:include="include :: datetimepicker-css" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-detail-edit" th:object="${dsTaskDetail}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="taskId" th:field="*{taskId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" th:field="*{harborId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" th:field="*{harborName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthId" th:field="*{berthId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthName" th:field="*{berthName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" th:field="*{shipNo}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="STIME" th:value="${#dates.format(dsTaskDetail.STIME, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="elecStime" th:value="${#dates.format(dsTaskDetail.elecStime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="elecEtime" th:value="${#dates.format(dsTaskDetail.elecEtime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="waterStime" th:value="${#dates.format(dsTaskDetail.waterStime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="waterEtime" th:value="${#dates.format(dsTaskDetail.waterEtime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="oilStime" th:value="${#dates.format(dsTaskDetail.oilStime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="oilEtime" th:value="${#dates.format(dsTaskDetail.oilEtime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ammoStime" th:value="${#dates.format(dsTaskDetail.ammoStime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ammoEtime" th:value="${#dates.format(dsTaskDetail.ammoEtime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="matStime" th:value="${#dates.format(dsTaskDetail.matStime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="matEtime" th:value="${#dates.format(dsTaskDetail.matEtime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="ETIME" th:value="${#dates.format(dsTaskDetail.ETIME, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilTime" th:field="*{oilTime}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoTime" th:field="*{ammoTime}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="matTime" th:field="*{matTime}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="waterTime" th:field="*{waterTime}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <th:block th:include="include :: datetimepicker-js" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/detail";
+        $("#form-detail-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-detail-edit').serialize());
+            }
+        }
+
+        $("input[name='STIME']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='elecStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='elecEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='waterStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='waterEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='oilStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='oilEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ammoStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ammoEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='matStime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='matEtime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='ETIME']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/harbor/add.html b/ruoyi-buss/src/main/resources/templates/buss/harbor/add.html
new file mode 100644
index 0000000..ad7f37e
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/harbor/add.html
@@ -0,0 +1,161 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板娓彛淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-harbor-add">
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="deptId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="deptName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthNo" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilB" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilG" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilA" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoD" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoP" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoS" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="REMARK" class="form-control"></textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DOCKNAME" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="WATER" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="MATERIAL" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoO" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/harbor"
+        $("#form-harbor-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-harbor-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/harbor/edit.html b/ruoyi-buss/src/main/resources/templates/buss/harbor/edit.html
new file mode 100644
index 0000000..1aa7d81
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/harbor/edit.html
@@ -0,0 +1,162 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼娓彛淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-harbor-edit" th:object="${dmHarbor2}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" th:field="*{NAME}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="deptId" th:field="*{deptId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="deptName" th:field="*{deptName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthNo" th:field="*{berthNo}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilB" th:field="*{oilB}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilG" th:field="*{oilG}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilA" th:field="*{oilA}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoD" th:field="*{ammoD}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoP" th:field="*{ammoP}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoS" th:field="*{ammoS}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <textarea name="REMARK" class="form-control">[[*{REMARK}]]</textarea>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DOCKNAME" th:field="*{DOCKNAME}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="WATER" th:field="*{WATER}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="MATERIAL" th:field="*{MATERIAL}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoO" th:field="*{ammoO}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/harbor";
+        $("#form-harbor-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-harbor-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/harbor/harbor.html b/ruoyi-buss/src/main/resources/templates/buss/harbor/harbor.html
new file mode 100644
index 0000000..889ed8d
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/harbor/harbor.html
@@ -0,0 +1,237 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('娓彛淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="NAME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="deptId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="deptName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthNo"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilB"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilG"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilA"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoD"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoP"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoS"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="DOCKNAME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="WATER"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="MATERIAL"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoO"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:harbor:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:harbor:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:harbor:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:harbor:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:harbor:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:harbor:remove')}]];
+        var prefix = ctx + "buss/harbor";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "娓彛淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'NAME',
+                    title: ''
+                },
+                {
+                    field: 'deptId',
+                    title: ''
+                },
+                {
+                    field: 'deptName',
+                    title: ''
+                },
+                {
+                    field: 'berthNo',
+                    title: ''
+                },
+                {
+                    field: 'oilB',
+                    title: ''
+                },
+                {
+                    field: 'oilG',
+                    title: ''
+                },
+                {
+                    field: 'oilA',
+                    title: ''
+                },
+                {
+                    field: 'ammoD',
+                    title: ''
+                },
+                {
+                    field: 'ammoP',
+                    title: ''
+                },
+                {
+                    field: 'ammoS',
+                    title: ''
+                },
+                {
+                    field: 'REMARK',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    field: 'DOCKNAME',
+                    title: ''
+                },
+                {
+                    field: 'WATER',
+                    title: ''
+                },
+                {
+                    field: 'MATERIAL',
+                    title: ''
+                },
+                {
+                    field: 'ammoO',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/list/add.html b/ruoyi-buss/src/main/resources/templates/buss/list/add.html
new file mode 100644
index 0000000..f7e4f4a
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/list/add.html
@@ -0,0 +1,293 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板浠诲姟鍒楄〃淇℃伅')" />
+    <th:block th:include="include :: datetimepicker-css" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-list-add">
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="taskId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TONNAGE" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DRAFT" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEADER" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="STAFF" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="grpName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEVEL" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LAT" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LON" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilB" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilG" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilA" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoD" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoP" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoS" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoO" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="WATER" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="waterP" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="FOOD" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="foodW" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="foodO" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="pSTime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="pETime" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthId" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <th:block th:include="include :: datetimepicker-js" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/list"
+        $("#form-list-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-list-add').serialize());
+            }
+        }
+
+        $("input[name='pSTime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='pETime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/list/edit.html b/ruoyi-buss/src/main/resources/templates/buss/list/edit.html
new file mode 100644
index 0000000..fd67c69
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/list/edit.html
@@ -0,0 +1,294 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼浠诲姟鍒楄〃淇℃伅')" />
+    <th:block th:include="include :: datetimepicker-css" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-list-edit" th:object="${dsTaskList2}">
+            <input name="taskId" th:field="*{taskId}" type="hidden">
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="taskId" th:field="*{taskId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" th:field="*{shipNo}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TONNAGE" th:field="*{TONNAGE}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DRAFT" th:field="*{DRAFT}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEADER" th:field="*{LEADER}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="STAFF" th:field="*{STAFF}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="grpName" th:field="*{grpName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEVEL" th:field="*{LEVEL}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LAT" th:field="*{LAT}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LON" th:field="*{LON}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilB" th:field="*{oilB}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilG" th:field="*{oilG}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="oilA" th:field="*{oilA}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoD" th:field="*{ammoD}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoP" th:field="*{ammoP}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoS" th:field="*{ammoS}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="ammoO" th:field="*{ammoO}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="WATER" th:field="*{WATER}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="waterP" th:field="*{waterP}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="FOOD" th:field="*{FOOD}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="foodW" th:field="*{foodW}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="foodO" th:field="*{foodO}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="pSTime" th:value="${#dates.format(dsTaskList2.pSTime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <div class="input-group date">
+                            <input name="pETime" th:value="${#dates.format(dsTaskList2.pETime, 'yyyy-MM-dd')}" class="form-control" placeholder="yyyy-MM-dd" type="text">
+                            <span class="input-group-addon"><i class="fa fa-calendar"></i></span>
+                        </div>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="REMARK" th:field="*{REMARK}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborId" th:field="*{harborId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="harborName" th:field="*{harborName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthId" th:field="*{berthId}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="berthName" th:field="*{berthName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-4">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <th:block th:include="include :: datetimepicker-js" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/list";
+        $("#form-list-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-list-edit').serialize());
+            }
+        }
+
+        $("input[name='pSTime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+
+        $("input[name='pETime']").datetimepicker({
+            format: "yyyy-mm-dd",
+            minView: "month",
+            autoclose: true
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/list/list.html b/ruoyi-buss/src/main/resources/templates/buss/list/list.html
new file mode 100644
index 0000000..a65df50
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/list/list.html
@@ -0,0 +1,365 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('浠诲姟鍒楄〃淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="taskId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="shipNo"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="TONNAGE"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="DRAFT"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LEADER"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="STAFF"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="grpName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LEVEL"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LAT"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LON"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilB"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilG"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="oilA"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoD"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoP"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoS"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="ammoO"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="WATER"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="waterP"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="FOOD"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="foodW"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="foodO"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="pSTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="pETime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="REMARK"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="harborName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthId"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="berthName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:list:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:list:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:list:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:list:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:list:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:list:remove')}]];
+        var prefix = ctx + "buss/list";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "浠诲姟鍒楄〃淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'taskId',
+                    title: ''
+                },
+                {
+                    field: 'shipNo',
+                    title: ''
+                },
+                {
+                    field: 'shipType',
+                    title: ''
+                },
+                {
+                    field: 'TONNAGE',
+                    title: ''
+                },
+                {
+                    field: 'DRAFT',
+                    title: ''
+                },
+                {
+                    field: 'LEADER',
+                    title: ''
+                },
+                {
+                    field: 'STAFF',
+                    title: ''
+                },
+                {
+                    field: 'grpName',
+                    title: ''
+                },
+                {
+                    field: 'LEVEL',
+                    title: ''
+                },
+                {
+                    field: 'LAT',
+                    title: ''
+                },
+                {
+                    field: 'LON',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    field: 'oilB',
+                    title: ''
+                },
+                {
+                    field: 'oilG',
+                    title: ''
+                },
+                {
+                    field: 'oilA',
+                    title: ''
+                },
+                {
+                    field: 'ammoD',
+                    title: ''
+                },
+                {
+                    field: 'ammoP',
+                    title: ''
+                },
+                {
+                    field: 'ammoS',
+                    title: ''
+                },
+                {
+                    field: 'ammoO',
+                    title: ''
+                },
+                {
+                    field: 'WATER',
+                    title: ''
+                },
+                {
+                    field: 'waterP',
+                    title: ''
+                },
+                {
+                    field: 'FOOD',
+                    title: ''
+                },
+                {
+                    field: 'foodW',
+                    title: ''
+                },
+                {
+                    field: 'foodO',
+                    title: ''
+                },
+                {
+                    field: 'pSTime',
+                    title: ''
+                },
+                {
+                    field: 'pETime',
+                    title: ''
+                },
+                {
+                    field: 'REMARK',
+                    title: ''
+                },
+                {
+                    field: 'STATUS',
+                    title: ''
+                },
+                {
+                    field: 'harborId',
+                    title: ''
+                },
+                {
+                    field: 'harborName',
+                    title: ''
+                },
+                {
+                    field: 'berthId',
+                    title: ''
+                },
+                {
+                    field: 'berthName',
+                    title: ''
+                },
+                {
+                    field: 'parkingType',
+                    title: ''
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.taskId + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.taskId + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/task/add.html b/ruoyi-buss/src/main/resources/templates/buss/task/add.html
new file mode 100644
index 0000000..5256caa
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/task/add.html
@@ -0,0 +1,57 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板浠诲姟淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-task-add">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NOTES" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/task"
+        $("#form-task-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-task-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/task/edit.html b/ruoyi-buss/src/main/resources/templates/buss/task/edit.html
new file mode 100644
index 0000000..b64ea15
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/task/edit.html
@@ -0,0 +1,58 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼浠诲姟淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-task-edit" th:object="${dsTask}">
+            <input name="PKID" th:field="*{PKID}" type="hidden">
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="PKID" th:field="*{PKID}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NAME" th:field="*{NAME}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="NOTES" th:field="*{NOTES}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-12">
+                <div class="form-group">
+                    <label class="col-sm-3 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/task";
+        $("#form-task-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-task-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/task/task.html b/ruoyi-buss/src/main/resources/templates/buss/task/task.html
new file mode 100644
index 0000000..a9505d8
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/task/task.html
@@ -0,0 +1,141 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('浠诲姟淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="PKID"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="NAME"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="NOTES"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:task:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:task:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:task:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:task:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:task:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:task:remove')}]];
+        var prefix = ctx + "buss/task";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "浠诲姟淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'PKID',
+                    title: ''
+                },
+                {
+                    field: 'NAME',
+                    title: ''
+                },
+                {
+                    field: 'TYPE',
+                    title: ''
+                },
+                {
+                    field: 'NOTES',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.PKID + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.PKID + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/warship/add.html b/ruoyi-buss/src/main/resources/templates/buss/warship/add.html
new file mode 100644
index 0000000..734de2e
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/warship/add.html
@@ -0,0 +1,105 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('鏂板鑸拌墖淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-warship-add">
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TONNAGE" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DRAFT" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEADER" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="STAFF" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="grpName" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEVEL" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LAT" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LON" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/warship"
+        $("#form-warship-add").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/add", $('#form-warship-add').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/warship/edit.html b/ruoyi-buss/src/main/resources/templates/buss/warship/edit.html
new file mode 100644
index 0000000..e86edd8
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/warship/edit.html
@@ -0,0 +1,106 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" >
+<head>
+    <th:block th:include="include :: header('淇敼鑸拌墖淇℃伅')" />
+</head>
+<body class="white-bg">
+    <div class="wrapper wrapper-content animated fadeInRight ibox-content">
+        <form class="form-horizontal m" id="form-warship-edit" th:object="${dmWarship}">
+            <input name="shipNo" th:field="*{shipNo}" type="hidden">
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label is-required">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="shipNo" th:field="*{shipNo}" class="form-control" type="text" required>
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="TONNAGE" th:field="*{TONNAGE}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="DRAFT" th:field="*{DRAFT}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEADER" th:field="*{LEADER}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="STAFF" th:field="*{STAFF}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="grpName" th:field="*{grpName}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LEVEL" th:field="*{LEVEL}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LAT" th:field="*{LAT}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="LON" th:field="*{LON}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+            <div class="col-xs-6">
+                <div class="form-group">
+                    <label class="col-sm-4 control-label">锛�</label>
+                    <div class="col-sm-8">
+                        <input name="delFlag" th:field="*{delFlag}" class="form-control" type="text">
+                    </div>
+                </div>
+            </div>
+        </form>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var prefix = ctx + "buss/warship";
+        $("#form-warship-edit").validate({
+            focusCleanup: true
+        });
+
+        function submitHandler() {
+            if ($.validate.form()) {
+                $.operate.save(prefix + "/edit", $('#form-warship-edit').serialize());
+            }
+        }
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/resources/templates/buss/warship/warship.html b/ruoyi-buss/src/main/resources/templates/buss/warship/warship.html
new file mode 100644
index 0000000..6c8f4f4
--- /dev/null
+++ b/ruoyi-buss/src/main/resources/templates/buss/warship/warship.html
@@ -0,0 +1,189 @@
+<!DOCTYPE html>
+<html lang="zh" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
+<head>
+    <th:block th:include="include :: header('鑸拌墖淇℃伅鍒楄〃')" />
+</head>
+<body class="gray-bg">
+     <div class="container-div">
+        <div class="row">
+            <div class="col-sm-12 search-collapse">
+                <form id="formId">
+                    <div class="select-list">
+                        <ul>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="shipNo"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="TONNAGE"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="DRAFT"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LEADER"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="STAFF"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="grpName"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LEVEL"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LAT"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="LON"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="delFlag"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="createBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="createTime"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" name="updateBy"/>
+                            </li>
+                            <li>
+                                <label>锛�</label>
+                                <input type="text" class="time-input" placeholder="璇烽�夋嫨" name="updateTime"/>
+                            </li>
+                            <li>
+                                <a class="btn btn-primary btn-rounded btn-sm" onclick="$.table.search()"><i class="fa fa-search"></i>&nbsp;鎼滅储</a>
+                                <a class="btn btn-warning btn-rounded btn-sm" onclick="$.form.reset()"><i class="fa fa-refresh"></i>&nbsp;閲嶇疆</a>
+                            </li>
+                        </ul>
+                    </div>
+                </form>
+            </div>
+
+            <div class="btn-group-sm" id="toolbar" role="group">
+                <a class="btn btn-success" onclick="$.operate.add()" shiro:hasPermission="buss:warship:add">
+                    <i class="fa fa-plus"></i> 娣诲姞
+                </a>
+                <a class="btn btn-primary single disabled" onclick="$.operate.edit()" shiro:hasPermission="buss:warship:edit">
+                    <i class="fa fa-edit"></i> 淇敼
+                </a>
+                <a class="btn btn-danger multiple disabled" onclick="$.operate.removeAll()" shiro:hasPermission="buss:warship:remove">
+                    <i class="fa fa-remove"></i> 鍒犻櫎
+                </a>
+                <a class="btn btn-warning" onclick="$.table.exportExcel()" shiro:hasPermission="buss:warship:export">
+                    <i class="fa fa-download"></i> 瀵煎嚭
+                </a>
+            </div>
+            <div class="col-sm-12 select-table table-striped">
+                <table id="bootstrap-table"></table>
+            </div>
+        </div>
+    </div>
+    <th:block th:include="include :: footer" />
+    <script th:inline="javascript">
+        var editFlag = [[${@permission.hasPermi('buss:warship:edit')}]];
+        var removeFlag = [[${@permission.hasPermi('buss:warship:remove')}]];
+        var prefix = ctx + "buss/warship";
+
+        $(function() {
+            var options = {
+                url: prefix + "/list",
+                createUrl: prefix + "/add",
+                updateUrl: prefix + "/edit/{id}",
+                removeUrl: prefix + "/remove",
+                exportUrl: prefix + "/export",
+                modalName: "鑸拌墖淇℃伅",
+                columns: [{
+                    checkbox: true
+                },
+                {
+                    field: 'shipNo',
+                    title: ''
+                },
+                {
+                    field: 'shipType',
+                    title: ''
+                },
+                {
+                    field: 'TONNAGE',
+                    title: ''
+                },
+                {
+                    field: 'DRAFT',
+                    title: ''
+                },
+                {
+                    field: 'LEADER',
+                    title: ''
+                },
+                {
+                    field: 'STAFF',
+                    title: ''
+                },
+                {
+                    field: 'grpName',
+                    title: ''
+                },
+                {
+                    field: 'LEVEL',
+                    title: ''
+                },
+                {
+                    field: 'LAT',
+                    title: ''
+                },
+                {
+                    field: 'LON',
+                    title: ''
+                },
+                {
+                    field: 'delFlag',
+                    title: ''
+                },
+                {
+                    field: 'createBy',
+                    title: ''
+                },
+                {
+                    field: 'createTime',
+                    title: ''
+                },
+                {
+                    field: 'updateBy',
+                    title: ''
+                },
+                {
+                    field: 'updateTime',
+                    title: ''
+                },
+                {
+                    title: '鎿嶄綔',
+                    align: 'center',
+                    formatter: function(value, row, index) {
+                        var actions = [];
+                        actions.push('<a class="btn btn-success btn-xs ' + editFlag + '" href="javascript:void(0)" onclick="$.operate.edit(\'' + row.shipNo + '\')"><i class="fa fa-edit"></i>缂栬緫</a> ');
+                        actions.push('<a class="btn btn-danger btn-xs ' + removeFlag + '" href="javascript:void(0)" onclick="$.operate.remove(\'' + row.shipNo + '\')"><i class="fa fa-remove"></i>鍒犻櫎</a>');
+                        return actions.join('');
+                    }
+                }]
+            };
+            $.table.init(options);
+        });
+    </script>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-buss/src/main/ruoyi-buss.iml b/ruoyi-buss/src/main/ruoyi-buss.iml
new file mode 100644
index 0000000..908ad4f
--- /dev/null
+++ b/ruoyi-buss/src/main/ruoyi-buss.iml
@@ -0,0 +1,11 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$">
+      <sourceFolder url="file://$MODULE_DIR$/java" isTestSource="false" />
+    </content>
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml
new file mode 100644
index 0000000..046276e
--- /dev/null
+++ b/ruoyi-common/pom.xml
@@ -0,0 +1,135 @@
+<?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瑙f瀽鍣� -->
+        <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瑙f瀽鍣� -->
+        <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>
+
+        <!-- 瑙f瀽瀹㈡埛绔搷浣滅郴缁熴�佹祻瑙堝櫒绛� -->
+        <dependency>
+            <groupId>eu.bitwalker</groupId>
+            <artifactId>UserAgentUtils</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mybatis</groupId>
+            <artifactId>mybatis-spring</artifactId>
+        </dependency>
+        <!-- spring-doc -->
+        <dependency>
+            <groupId>org.springdoc</groupId>
+            <artifactId>springdoc-openapi-starter-webmvc-ui</artifactId>
+        </dependency>
+        <!-- servlet鍖� -->
+        <dependency>
+            <groupId>jakarta.servlet</groupId>
+            <artifactId>jakarta.servlet-api</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi-common/ruoyi-common.iml b/ruoyi-common/ruoyi-common.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-common/ruoyi-common.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
new file mode 100644
index 0000000..1d6d4f4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Anonymous.java
@@ -0,0 +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
+{
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
new file mode 100644
index 0000000..be49c80
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataScope.java
@@ -0,0 +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 "";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
new file mode 100644
index 0000000..79cd191
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/DataSource.java
@@ -0,0 +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;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
new file mode 100644
index 0000000..765d8e3
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excel.java
@@ -0,0 +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;
+
+/**
+ * 鑷畾涔夊鍑篍xcel鏁版嵁娉ㄨВ
+ * 
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel
+{
+    /**
+     * 瀵煎嚭鏃跺湪excel涓帓搴�
+     */
+    public int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 瀵煎嚭鍒癊xcel涓殑鍚嶅瓧.
+     */
+    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(榛樿涓嶅紑鍚疊igDecimal鏍煎紡鍖�)
+     */
+    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 {};
+
+    /**
+     * 鏄惁浠庡瓧鍏歌鏁版嵁鍒癱ombo,榛樿涓嶈鍙�,濡傝鍙栭渶瑕佽缃甦ictType娉ㄨВ.
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
new file mode 100644
index 0000000..1f1cc81
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Excels.java
@@ -0,0 +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();
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
new file mode 100644
index 0000000..1eb8e49
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Log.java
@@ -0,0 +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 {};
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
new file mode 100644
index 0000000..0f024c7
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RateLimiter.java
@@ -0,0 +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;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
new file mode 100644
index 0000000..b769748
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/RepeatSubmit.java
@@ -0,0 +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;
+
+/**
+ * 鑷畾涔夋敞瑙i槻姝㈣〃鍗曢噸澶嶆彁浜�
+ * 
+ * @author ruoyi
+ *
+ */
+@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/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
new file mode 100644
index 0000000..c0621e9
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/annotation/Sensitive.java
@@ -0,0 +1,24 @@
+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 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;
+
+/**
+ * 鏁版嵁鑴辨晱娉ㄨВ
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+@JacksonAnnotationsInside
+@JsonSerialize(using = SensitiveJsonSerializer.class)
+public @interface Sensitive
+{
+    DesensitizedType desensitizedType();
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
new file mode 100644
index 0000000..731b5bf
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/RuoYiConfig.java
@@ -0,0 +1,145 @@
+package com.ruoyi.common.config;
+
+import org.springframework.beans.factory.annotation.Value;
+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;
+
+    /** json璺緞 */
+    private String json;
+
+    /** rfidUrl璺緞 */
+    private String bussRfidUrl;
+
+    /** 鑾峰彇鍦板潃寮�鍏� */
+    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 String getJson() {
+        return json;
+    }
+
+    public void setJson(String json) {
+        this.json = json;
+    }
+
+    public String getBussRfidUrl() {
+        return bussRfidUrl;
+    }
+
+    public void setBussRfidUrl(String bussRfidUrl) {
+        this.bussRfidUrl = bussRfidUrl;
+    }
+
+    /**
+     * 鑾峰彇瀵煎叆涓婁紶璺緞
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
new file mode 100644
index 0000000..e819a1d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/config/serializer/SensitiveJsonSerializer.java
@@ -0,0 +1,67 @@
+package com.ruoyi.common.config.serializer;
+
+import java.io.IOException;
+import java.util.Objects;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.BeanProperty;
+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;
+
+/**
+ * 鏁版嵁鑴辨晱搴忓垪鍖栬繃婊�
+ *
+ * @author ruoyi
+ */
+public class SensitiveJsonSerializer extends JsonSerializer<String> implements ContextualSerializer
+{
+    private DesensitizedType desensitizedType;
+
+    @Override
+    public void serialize(String value, JsonGenerator gen, SerializerProvider serializers) throws IOException
+    {
+        if (desensitization())
+        {
+            gen.writeString(desensitizedType.desensitizer().apply(value));
+        }
+        else
+        {
+            gen.writeString(value);
+        }
+    }
+
+    @Override
+    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty property)
+            throws JsonMappingException
+    {
+        Sensitive annotation = property.getAnnotation(Sensitive.class);
+        if (Objects.nonNull(annotation) && Objects.equals(String.class, property.getType().getRawClass()))
+        {
+            this.desensitizedType = annotation.desensitizedType();
+            return this;
+        }
+        return prov.findValueSerializer(property.getType(), property);
+    }
+
+    /**
+     * 鏄惁闇�瑕佽劚鏁忓鐞�
+     */
+    private boolean desensitization()
+    {
+        try
+        {
+            LoginUser securityUser = SecurityUtils.getLoginUser();
+            // 绠$悊鍛樹笉鑴辨晱
+            return !securityUser.getUser().isAdmin();
+        }
+        catch (Exception e)
+        {
+            return true;
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
new file mode 100644
index 0000000..0080343
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/CacheConstants.java
@@ -0,0 +1,44 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 缂撳瓨鐨刱ey 甯搁噺
+ * 
+ * @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:";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
new file mode 100644
index 0000000..0c384c6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/Constants.java
@@ -0,0 +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" };
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
new file mode 100644
index 0000000..7d899d4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/GenConstants.java
@@ -0,0 +1,117 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 浠g爜鐢熸垚閫氱敤甯搁噺
+ * 
+ * @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";
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
new file mode 100644
index 0000000..a983c77
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/HttpStatus.java
@@ -0,0 +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;
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
new file mode 100644
index 0000000..62ad815
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/ScheduleConstants.java
@@ -0,0 +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
+    {
+        /**
+         * 姝e父
+         */
+        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/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
new file mode 100644
index 0000000..8dc7faa
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/constant/UserConstants.java
@@ -0,0 +1,81 @@
+package com.ruoyi.common.constant;
+
+/**
+ * 鐢ㄦ埛甯搁噺淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class UserConstants
+{
+    /**
+     * 骞冲彴鍐呯郴缁熺敤鎴风殑鍞竴鏍囧織
+     */
+    public static final String SYS_USER = "SYS_USER";
+
+    /** 姝e父鐘舵�� */
+    public static final String NORMAL = "0";
+
+    /** 寮傚父鐘舵�� */
+    public static final String EXCEPTION = "1";
+
+    /** 鐢ㄦ埛灏佺鐘舵�� */
+    public static final String USER_DISABLE = "1";
+
+    /** 瑙掕壊姝e父鐘舵�� */
+    public static final String ROLE_NORMAL = "0";
+
+    /** 瑙掕壊灏佺鐘舵�� */
+    public static final String ROLE_DISABLE = "1";
+
+    /** 閮ㄩ棬姝e父鐘舵�� */
+    public static final String DEPT_NORMAL = "0";
+
+    /** 閮ㄩ棬鍋滅敤鐘舵�� */
+    public static final String DEPT_DISABLE = "1";
+
+    /** 瀛楀吀姝e父鐘舵�� */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
new file mode 100644
index 0000000..96edd58
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/controller/BaseController.java
@@ -0,0 +1,180 @@
+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.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());
+        rspData.setTotal(list.size());
+        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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
new file mode 100644
index 0000000..a7abfe4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/AjaxResult.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
new file mode 100644
index 0000000..9e4a8ea
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/BaseEntity.java
@@ -0,0 +1,119 @@
+package com.ruoyi.common.core.domain;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
new file mode 100644
index 0000000..ef15802
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/R.java
@@ -0,0 +1,115 @@
+package com.ruoyi.common.core.domain;
+
+import java.io.Serializable;
+import com.ruoyi.common.constant.HttpStatus;
+
+/**
+ * 鍝嶅簲淇℃伅涓讳綋
+ *
+ * @author ruoyi
+ */
+public class R<T> implements Serializable
+{
+    private static final long serialVersionUID = 1L;
+
+    /** 鎴愬姛 */
+    public static final int SUCCESS = HttpStatus.SUCCESS;
+
+    /** 澶辫触 */
+    public static final int FAIL = HttpStatus.ERROR;
+
+    private int code;
+
+    private String msg;
+
+    private T data;
+
+    public static <T> R<T> ok()
+    {
+        return restResult(null, SUCCESS, "鎿嶄綔鎴愬姛");
+    }
+
+    public static <T> R<T> ok(T data)
+    {
+        return restResult(data, SUCCESS, "鎿嶄綔鎴愬姛");
+    }
+
+    public static <T> R<T> ok(T data, String msg)
+    {
+        return restResult(data, SUCCESS, msg);
+    }
+
+    public static <T> R<T> fail()
+    {
+        return restResult(null, FAIL, "鎿嶄綔澶辫触");
+    }
+
+    public static <T> R<T> fail(String msg)
+    {
+        return restResult(null, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(T data)
+    {
+        return restResult(data, FAIL, "鎿嶄綔澶辫触");
+    }
+
+    public static <T> R<T> fail(T data, String msg)
+    {
+        return restResult(data, FAIL, msg);
+    }
+
+    public static <T> R<T> fail(int code, String msg)
+    {
+        return restResult(null, code, msg);
+    }
+
+    private static <T> R<T> restResult(T data, int code, String msg)
+    {
+        R<T> apiResult = new R<>();
+        apiResult.setCode(code);
+        apiResult.setData(data);
+        apiResult.setMsg(msg);
+        return apiResult;
+    }
+
+    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;
+    }
+
+    public T getData()
+    {
+        return data;
+    }
+
+    public void setData(T data)
+    {
+        this.data = data;
+    }
+
+    public static <T> Boolean isError(R<T> ret)
+    {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret)
+    {
+        return R.SUCCESS == ret.getCode();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
new file mode 100644
index 0000000..a180a18
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeEntity.java
@@ -0,0 +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;
+
+    /** 鐖惰彍鍗旾D */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
new file mode 100644
index 0000000..ae25df2
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/TreeSelect.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
new file mode 100644
index 0000000..37236db
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDept.java
@@ -0,0 +1,203 @@
+package com.ruoyi.common.core.domain.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.validation.constraints.Email;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.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;
+
+    /** 鐖堕儴闂↖D */
+    private Long parentId;
+
+    /** 绁栫骇鍒楄〃 */
+    private String ancestors;
+
+    /** 閮ㄩ棬鍚嶇О */
+    private String deptName;
+
+    /** 鏄剧ず椤哄簭 */
+    private Integer orderNum;
+
+    /** 璐熻矗浜� */
+    private String leader;
+
+    /** 鑱旂郴鐢佃瘽 */
+    private String phone;
+
+    /** 閭 */
+    private String email;
+
+    /** 閮ㄩ棬鐘舵��:0姝e父,1鍋滅敤 */
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鐖堕儴闂ㄥ悕绉� */
+    private String parentName;
+    
+    /** 瀛愰儴闂� */
+    private List<SysDept> children = new ArrayList<SysDept>();
+
+    public Long getDeptId()
+    {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId)
+    {
+        this.deptId = deptId;
+    }
+
+    public Long getParentId()
+    {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId)
+    {
+        this.parentId = parentId;
+    }
+
+    public String getAncestors()
+    {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors)
+    {
+        this.ancestors = ancestors;
+    }
+
+    @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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
new file mode 100644
index 0000000..6b035a6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictData.java
@@ -0,0 +1,176 @@
+package com.ruoyi.common.core.domain.entity;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.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;
+
+    /** 鏄惁榛樿锛圷鏄� N鍚︼級 */
+    @Excel(name = "鏄惁榛樿", readConverterExp = "Y=鏄�,N=鍚�")
+    private String isDefault;
+
+    /** 鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    public Long getDictCode()
+    {
+        return dictCode;
+    }
+
+    public void setDictCode(Long dictCode)
+    {
+        this.dictCode = dictCode;
+    }
+
+    public Long getDictSort()
+    {
+        return dictSort;
+    }
+
+    public void setDictSort(Long dictSort)
+    {
+        this.dictSort = dictSort;
+    }
+
+    @NotBlank(message = "瀛楀吀鏍囩涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀鏍囩闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictLabel()
+    {
+        return dictLabel;
+    }
+
+    public void setDictLabel(String dictLabel)
+    {
+        this.dictLabel = dictLabel;
+    }
+
+    @NotBlank(message = "瀛楀吀閿�间笉鑳戒负绌�")
+    @Size(min = 0, max = 100, message = "瀛楀吀閿�奸暱搴︿笉鑳借秴杩�100涓瓧绗�")
+    public String getDictValue()
+    {
+        return dictValue;
+    }
+
+    public void setDictValue(String dictValue)
+    {
+        this.dictValue = dictValue;
+    }
+
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictType()
+    {
+        return dictType;
+    }
+
+    public void setDictType(String dictType)
+    {
+        this.dictType = dictType;
+    }
+
+    @Size(min = 0, max = 100, message = "鏍峰紡灞炴�ч暱搴︿笉鑳借秴杩�100涓瓧绗�")
+    public String getCssClass()
+    {
+        return cssClass;
+    }
+
+    public void setCssClass(String cssClass)
+    {
+        this.cssClass = cssClass;
+    }
+
+    public String getListClass()
+    {
+        return listClass;
+    }
+
+    public void setListClass(String listClass)
+    {
+        this.listClass = listClass;
+    }
+
+    public boolean getDefault()
+    {
+        return UserConstants.YES.equals(this.isDefault);
+    }
+
+    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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
new file mode 100644
index 0000000..ac5d290
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysDictType.java
@@ -0,0 +1,96 @@
+package com.ruoyi.common.core.domain.entity;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.Pattern;
+import jakarta.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姝e父 1鍋滅敤锛� */
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    public Long getDictId()
+    {
+        return dictId;
+    }
+
+    public void setDictId(Long dictId)
+    {
+        this.dictId = dictId;
+    }
+
+    @NotBlank(message = "瀛楀吀鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷鍚嶇О闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    public String getDictName()
+    {
+        return dictName;
+    }
+
+    public void setDictName(String dictName)
+    {
+        this.dictName = dictName;
+    }
+
+    @NotBlank(message = "瀛楀吀绫诲瀷涓嶈兘涓虹┖")
+    @Size(min = 0, max = 100, message = "瀛楀吀绫诲瀷绫诲瀷闀垮害涓嶈兘瓒呰繃100涓瓧绗�")
+    @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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
new file mode 100644
index 0000000..d4ab762
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysMenu.java
@@ -0,0 +1,274 @@
+package com.ruoyi.common.core.domain.entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.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;
+
+    /** 鐖惰彍鍗旾D */
+    private Long parentId;
+
+    /** 鏄剧ず椤哄簭 */
+    private Integer orderNum;
+
+    /** 璺敱鍦板潃 */
+    private String path;
+
+    /** 缁勪欢璺緞 */
+    private String component;
+
+    /** 璺敱鍙傛暟 */
+    private String query;
+
+    /** 璺敱鍚嶇О锛岄粯璁ゅ拰璺敱鍦板潃鐩稿悓鐨勯┘宄版牸寮忥紙娉ㄦ剰锛氬洜涓簐ue3鐗堟湰鐨剅outer浼氬垹闄ゅ悕绉扮浉鍚岃矾鐢憋紝涓洪伩鍏嶅悕瀛楃殑鍐茬獊锛岀壒娈婃儏鍐靛彲浠ヨ嚜瀹氫箟锛� */
+    private String routeName;
+
+    /** 鏄惁涓哄閾撅紙0鏄� 1鍚︼級 */
+    private String isFrame;
+
+    /** 鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級 */
+    private String isCache;
+
+    /** 绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛� */
+    private String menuType;
+
+    /** 鏄剧ず鐘舵�侊紙0鏄剧ず 1闅愯棌锛� */
+    private String visible;
+
+    /** 鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛� */
+    private String status;
+
+    /** 鏉冮檺瀛楃涓� */
+    private String perms;
+
+    /** 鑿滃崟鍥炬爣 */
+    private String icon;
+
+    /** 瀛愯彍鍗� */
+    private 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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
new file mode 100644
index 0000000..2f8ed14
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysRole.java
@@ -0,0 +1,241 @@
+package com.ruoyi.common.core.domain.entity;
+
+import java.util.Set;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.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姝e父 1鍋滅敤锛� */
+    @Excel(name = "瑙掕壊鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
new file mode 100644
index 0000000..25fc65d
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/entity/SysUser.java
@@ -0,0 +1,324 @@
+package com.ruoyi.common.core.domain.entity;
+
+import java.util.Date;
+import java.util.List;
+import jakarta.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姝e父 1鍋滅敤锛� */
+    @Excel(name = "甯愬彿鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    /** 鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛� */
+    private String delFlag;
+
+    /** 鏈�鍚庣櫥褰旾P */
+    @Excel(name = "鏈�鍚庣櫥褰旾P", 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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
new file mode 100644
index 0000000..b5bc8c8
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginBody.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
new file mode 100644
index 0000000..670e6b3
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/LoginUser.java
@@ -0,0 +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;
+    }
+
+    /**
+     * 鎸囧畾鐢ㄦ埛鏄惁瑙i攣,閿佸畾鐨勭敤鎴锋棤娉曡繘琛岃韩浠介獙璇�
+     * 
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
new file mode 100644
index 0000000..868a1fc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/domain/model/RegisterBody.java
@@ -0,0 +1,11 @@
+package com.ruoyi.common.core.domain.model;
+
+/**
+ * 鐢ㄦ埛娉ㄥ唽瀵硅薄
+ * 
+ * @author ruoyi
+ */
+public class RegisterBody extends LoginBody
+{
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java
new file mode 100644
index 0000000..8966cb4
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/PageDomain.java
@@ -0,0 +1,101 @@
+package com.ruoyi.common.core.page;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 鍒嗛〉鏁版嵁
+ * 
+ * @author ruoyi
+ */
+public class PageDomain
+{
+    /** 褰撳墠璁板綍璧峰绱㈠紩 */
+    private Integer pageNum;
+
+    /** 姣忛〉鏄剧ず璁板綍鏁� */
+    private Integer pageSize;
+
+    /** 鎺掑簭鍒� */
+    private String orderByColumn;
+
+    /** 鎺掑簭鐨勬柟鍚慸esc鎴栬�卆sc */
+    private String isAsc = "asc";
+
+    /** 鍒嗛〉鍙傛暟鍚堢悊鍖� */
+    private Boolean reasonable = true;
+
+    public String getOrderBy()
+    {
+        if (StringUtils.isEmpty(orderByColumn))
+        {
+            return "";
+        }
+        return StringUtils.toUnderScoreCase(orderByColumn) + " " + isAsc;
+    }
+
+    public Integer getPageNum()
+    {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum)
+    {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getPageSize()
+    {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize)
+    {
+        this.pageSize = pageSize;
+    }
+
+    public String getOrderByColumn()
+    {
+        return orderByColumn;
+    }
+
+    public void setOrderByColumn(String orderByColumn)
+    {
+        this.orderByColumn = orderByColumn;
+    }
+
+    public String getIsAsc()
+    {
+        return isAsc;
+    }
+
+    public void setIsAsc(String isAsc)
+    {
+        if (StringUtils.isNotEmpty(isAsc))
+        {
+            // 鍏煎鍓嶇鎺掑簭绫诲瀷
+            if ("ascending".equals(isAsc))
+            {
+                isAsc = "asc";
+            }
+            else if ("descending".equals(isAsc))
+            {
+                isAsc = "desc";
+            }
+            this.isAsc = isAsc;
+        }
+    }
+
+    public Boolean getReasonable()
+    {
+        if (StringUtils.isNull(reasonable))
+        {
+            return Boolean.TRUE;
+        }
+        return reasonable;
+    }
+
+    public void setReasonable(Boolean reasonable)
+    {
+        this.reasonable = reasonable;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java
new file mode 100644
index 0000000..847685b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableDataInfo.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
new file mode 100644
index 0000000..a120c30
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/page/TableSupport.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
new file mode 100644
index 0000000..44e80d8
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/redis/RedisCache.java
@@ -0,0 +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銆丼tring銆佸疄浣撶被绛�
+     *
+     * @param key 缂撳瓨鐨勯敭鍊�
+     * @param value 缂撳瓨鐨勫��
+     */
+    public <T> void setCacheObject(final String key, final T value)
+    {
+        redisTemplate.opsForValue().set(key, value);
+    }
+
+    /**
+     * 缂撳瓨鍩烘湰鐨勫璞★紝Integer銆丼tring銆佸疄浣撶被绛�
+     *
+     * @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=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    public boolean expire(final String key, final long timeout)
+    {
+        return expire(key, timeout, TimeUnit.SECONDS);
+    }
+
+    /**
+     * 璁剧疆鏈夋晥鏃堕棿
+     *
+     * @param key Redis閿�
+     * @param timeout 瓒呮椂鏃堕棿
+     * @param unit 鏃堕棿鍗曚綅
+     * @return true=璁剧疆鎴愬姛锛沠alse=璁剧疆澶辫触
+     */
+    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;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨刲ist瀵硅薄
+     *
+     * @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;
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨剆et
+     *
+     * @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);
+        }
+    }
+
+    /**
+     * 鑾峰緱缂撳瓨鐨凪ap
+     *
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
new file mode 100644
index 0000000..84124aa
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/text/CharsetKit.java
@@ -0,0 +1,86 @@
+package com.ruoyi.common.core.text;
+
+import java.nio.charset.Charset;
+import java.nio.charset.StandardCharsets;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 瀛楃闆嗗伐鍏风被
+ * 
+ * @author ruoyi
+ */
+public class CharsetKit
+{
+    /** ISO-8859-1 */
+    public static final String ISO_8859_1 = "ISO-8859-1";
+    /** UTF-8 */
+    public static final String UTF_8 = "UTF-8";
+    /** GBK */
+    public static final String GBK = "GBK";
+
+    /** ISO-8859-1 */
+    public static final Charset CHARSET_ISO_8859_1 = Charset.forName(ISO_8859_1);
+    /** UTF-8 */
+    public static final Charset CHARSET_UTF_8 = Charset.forName(UTF_8);
+    /** GBK */
+    public static final Charset CHARSET_GBK = Charset.forName(GBK);
+
+    /**
+     * 杞崲涓篊harset瀵硅薄
+     * 
+     * @param charset 瀛楃闆嗭紝涓虹┖鍒欒繑鍥為粯璁ゅ瓧绗﹂泦
+     * @return Charset
+     */
+    public static Charset charset(String charset)
+    {
+        return StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset);
+    }
+
+    /**
+     * 杞崲瀛楃涓茬殑瀛楃闆嗙紪鐮�
+     * 
+     * @param source 瀛楃涓�
+     * @param srcCharset 婧愬瓧绗﹂泦锛岄粯璁SO-8859-1
+     * @param destCharset 鐩爣瀛楃闆嗭紝榛樿UTF-8
+     * @return 杞崲鍚庣殑瀛楃闆�
+     */
+    public static String convert(String source, String srcCharset, String destCharset)
+    {
+        return convert(source, Charset.forName(srcCharset), Charset.forName(destCharset));
+    }
+
+    /**
+     * 杞崲瀛楃涓茬殑瀛楃闆嗙紪鐮�
+     * 
+     * @param source 瀛楃涓�
+     * @param srcCharset 婧愬瓧绗﹂泦锛岄粯璁SO-8859-1
+     * @param destCharset 鐩爣瀛楃闆嗭紝榛樿UTF-8
+     * @return 杞崲鍚庣殑瀛楃闆�
+     */
+    public static String convert(String source, Charset srcCharset, Charset destCharset)
+    {
+        if (null == srcCharset)
+        {
+            srcCharset = StandardCharsets.ISO_8859_1;
+        }
+
+        if (null == destCharset)
+        {
+            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/ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java
new file mode 100644
index 0000000..edf9afc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/text/Convert.java
@@ -0,0 +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);
+    }
+
+    /**
+     * 杞崲涓篵yte<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Byte toByte(Object value, Byte defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Byte)
+        {
+            return (Byte) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).byteValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Byte.parseByte(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篵yte<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Byte toByte(Object value)
+    {
+        return toByte(value, null);
+    }
+
+    /**
+     * 杞崲涓篠hort<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Short toShort(Object value, Short defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Short)
+        {
+            return (Short) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).shortValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Short.parseShort(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篠hort<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Short toShort(Object value)
+    {
+        return toShort(value, null);
+    }
+
+    /**
+     * 杞崲涓篘umber<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Number toNumber(Object value, Number defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Number)
+        {
+            return (Number) value;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return NumberFormat.getInstance().parse(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篘umber<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Number toNumber(Object value)
+    {
+        return toNumber(value, null);
+    }
+
+    /**
+     * 杞崲涓篿nt<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Integer toInt(Object value, Integer defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Integer)
+        {
+            return (Integer) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).intValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Integer.parseInt(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篿nt<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer toInt(Object value)
+    {
+        return toInt(value, null);
+    }
+
+    /**
+     * 杞崲涓篒nteger鏁扮粍<br>
+     *
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer[] toIntArray(String str)
+    {
+        return toIntArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篖ong鏁扮粍<br>
+     *
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long[] toLongArray(String str)
+    {
+        return toLongArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篒nteger鏁扮粍<br>
+     *
+     * @param split 鍒嗛殧绗�
+     * @param split 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Integer[] toIntArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Integer[] {};
+        }
+        String[] arr = str.split(split);
+        final Integer[] ints = new Integer[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Integer v = toInt(arr[i], 0);
+            ints[i] = v;
+        }
+        return ints;
+    }
+
+    /**
+     * 杞崲涓篖ong鏁扮粍<br>
+     *
+     * @param split 鍒嗛殧绗�
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long[] toLongArray(String split, String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new Long[] {};
+        }
+        String[] arr = str.split(split);
+        final Long[] longs = new Long[arr.length];
+        for (int i = 0; i < arr.length; i++)
+        {
+            final Long v = toLong(arr[i], null);
+            longs[i] = v;
+        }
+        return longs;
+    }
+
+    /**
+     * 杞崲涓篠tring鏁扮粍<br>
+     *
+     * @param str 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static String[] toStrArray(String str)
+    {
+        if (StringUtils.isEmpty(str))
+        {
+            return new String[] {};
+        }
+        return toStrArray(",", str);
+    }
+
+    /**
+     * 杞崲涓篠tring鏁扮粍<br>
+     *
+     * @param split 鍒嗛殧绗�
+     * @param split 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static String[] toStrArray(String split, String str)
+    {
+        return str.split(split);
+    }
+
+    /**
+     * 杞崲涓簂ong<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Long toLong(Object value, Long defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Long)
+        {
+            return (Long) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).longValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 鏀寔绉戝璁℃暟娉�
+            return new BigDecimal(valueStr.trim()).longValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓簂ong<br>
+     * 濡傛灉缁欏畾鐨勫�间负<code>null</code>锛屾垨鑰呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Long toLong(Object value)
+    {
+        return toLong(value, null);
+    }
+
+    /**
+     * 杞崲涓篸ouble<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Double toDouble(Object value, Double defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Double)
+        {
+            return (Double) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).doubleValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            // 鏀寔绉戝璁℃暟娉�
+            return new BigDecimal(valueStr.trim()).doubleValue();
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篸ouble<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Double toDouble(Object value)
+    {
+        return toDouble(value, null);
+    }
+
+    /**
+     * 杞崲涓篎loat<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Float toFloat(Object value, Float defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Float)
+        {
+            return (Float) value;
+        }
+        if (value instanceof Number)
+        {
+            return ((Number) value).floatValue();
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Float.parseFloat(valueStr.trim());
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篎loat<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Float toFloat(Object value)
+    {
+        return toFloat(value, null);
+    }
+
+    /**
+     * 杞崲涓篵oolean<br>
+     * String鏀寔鐨勫�间负锛歵rue銆乫alse銆亂es銆乷k銆乶o锛�1,0 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static Boolean toBool(Object value, Boolean defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof Boolean)
+        {
+            return (Boolean) value;
+        }
+        String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        valueStr = valueStr.trim().toLowerCase();
+        switch (valueStr)
+        {
+            case "true":
+            case "yes":
+            case "ok":
+            case "1":
+                return true;
+            case "false":
+            case "no":
+            case "0":
+                return false;
+            default:
+                return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篵oolean<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static Boolean toBool(Object value)
+    {
+        return toBool(value, null);
+    }
+
+    /**
+     * 杞崲涓篍num瀵硅薄<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     *
+     * @param clazz Enum鐨凜lass
+     * @param value 鍊�
+     * @param defaultValue 榛樿鍊�
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value, E defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (clazz.isAssignableFrom(value.getClass()))
+        {
+            @SuppressWarnings("unchecked")
+            E myE = (E) value;
+            return myE;
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return Enum.valueOf(clazz, valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓篍num瀵硅薄<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     *
+     * @param clazz Enum鐨凜lass
+     * @param value 鍊�
+     * @return Enum
+     */
+    public static <E extends Enum<E>> E toEnum(Class<E> clazz, Object value)
+    {
+        return toEnum(clazz, value, null);
+    }
+
+    /**
+     * 杞崲涓築igInteger<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static BigInteger toBigInteger(Object value, BigInteger defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigInteger)
+        {
+            return (BigInteger) value;
+        }
+        if (value instanceof Long)
+        {
+            return BigInteger.valueOf((Long) value);
+        }
+        final String valueStr = toStr(value, null);
+        if (StringUtils.isEmpty(valueStr))
+        {
+            return defaultValue;
+        }
+        try
+        {
+            return new BigInteger(valueStr);
+        }
+        catch (Exception e)
+        {
+            return defaultValue;
+        }
+    }
+
+    /**
+     * 杞崲涓築igInteger<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<code>null</code><br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static BigInteger toBigInteger(Object value)
+    {
+        return toBigInteger(value, null);
+    }
+
+    /**
+     * 杞崲涓築igDecimal<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @param defaultValue 杞崲閿欒鏃剁殑榛樿鍊�
+     * @return 缁撴灉
+     */
+    public static BigDecimal toBigDecimal(Object value, BigDecimal defaultValue)
+    {
+        if (value == null)
+        {
+            return defaultValue;
+        }
+        if (value instanceof BigDecimal)
+        {
+            return (BigDecimal) value;
+        }
+        if (value instanceof Long)
+        {
+            return new BigDecimal((Long) value);
+        }
+        if (value instanceof Double)
+        {
+            return 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;
+        }
+    }
+
+    /**
+     * 杞崲涓築igDecimal<br>
+     * 濡傛灉缁欏畾鐨勫�间负绌猴紝鎴栬�呰浆鎹㈠け璐ワ紝杩斿洖榛樿鍊�<br>
+     * 杞崲澶辫触涓嶄細鎶ラ敊
+     *
+     * @param value 琚浆鎹㈢殑鍊�
+     * @return 缁撴灉
+     */
+    public static BigDecimal toBigDecimal(Object value)
+    {
+        return toBigDecimal(value, null);
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     *
+     * @param obj 瀵硅薄
+     * @return 瀛楃涓�
+     */
+    public static String utf8Str(Object obj)
+    {
+        return str(obj, CharsetKit.CHARSET_UTF_8);
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     *
+     * @param obj 瀵硅薄
+     * @param charsetName 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(Object obj, String charsetName)
+    {
+        return str(obj, Charset.forName(charsetName));
+    }
+
+    /**
+     * 灏嗗璞¤浆涓哄瓧绗︿覆<br>
+     * 1銆丅yte鏁扮粍鍜孊yteBuffer浼氳杞崲涓哄搴斿瓧绗︿覆鐨勬暟缁� 2銆佸璞℃暟缁勪細璋冪敤Arrays.toString鏂规硶
+     *
+     * @param obj 瀵硅薄
+     * @param charset 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(Object obj, Charset charset)
+    {
+        if (null == obj)
+        {
+            return null;
+        }
+
+        if (obj instanceof String)
+        {
+            return (String) obj;
+        }
+        else if (obj instanceof byte[])
+        {
+            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();
+    }
+
+    /**
+     * 灏哹yte鏁扮粍杞负瀛楃涓�
+     *
+     * @param bytes byte鏁扮粍
+     * @param charset 瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(byte[] bytes, String charset)
+    {
+        return str(bytes, StringUtils.isEmpty(charset) ? Charset.defaultCharset() : Charset.forName(charset));
+    }
+
+    /**
+     * 瑙g爜瀛楄妭鐮�
+     *
+     * @param data 瀛楃涓�
+     * @param charset 瀛楃闆嗭紝濡傛灉姝ゅ瓧娈典负绌猴紝鍒欒В鐮佺殑缁撴灉鍙栧喅浜庡钩鍙�
+     * @return 瑙g爜鍚庣殑瀛楃涓�
+     */
+    public static String str(byte[] data, Charset charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        if (null == charset)
+        {
+            return new String(data);
+        }
+        return new String(data, charset);
+    }
+
+    /**
+     * 灏嗙紪鐮佺殑byteBuffer鏁版嵁杞崲涓哄瓧绗︿覆
+     *
+     * @param data 鏁版嵁
+     * @param charset 瀛楃闆嗭紝濡傛灉涓虹┖浣跨敤褰撳墠绯荤粺瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(ByteBuffer data, String charset)
+    {
+        if (data == null)
+        {
+            return null;
+        }
+
+        return str(data, Charset.forName(charset));
+    }
+
+    /**
+     * 灏嗙紪鐮佺殑byteBuffer鏁版嵁杞崲涓哄瓧绗︿覆
+     *
+     * @param data 鏁版嵁
+     * @param charset 瀛楃闆嗭紝濡傛灉涓虹┖浣跨敤褰撳墠绯荤粺瀛楃闆�
+     * @return 瀛楃涓�
+     */
+    public static String str(ByteBuffer data, Charset charset)
+    {
+        if (null == charset)
+        {
+            charset = Charset.defaultCharset();
+        }
+        return charset.decode(data).toString();
+    }
+
+    // ----------------------------------------------------------------------- 鍏ㄨ鍗婅杞崲
+    /**
+     * 鍗婅杞叏瑙�
+     *
+     * @param input String.
+     * @return 鍏ㄨ瀛楃涓�.
+     */
+    public static String toSBC(String input)
+    {
+        return toSBC(input, null);
+    }
+
+    /**
+     * 鍗婅杞叏瑙�
+     *
+     * @param input String
+     * @param notConvertSet 涓嶆浛鎹㈢殑瀛楃闆嗗悎
+     * @return 鍏ㄨ瀛楃涓�.
+     */
+    public static String toSBC(String input, Set<Character> notConvertSet)
+    {
+        char[] c = input.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 璺宠繃涓嶆浛鎹㈢殑瀛楃
+                continue;
+            }
+
+            if (c[i] == ' ')
+            {
+                c[i] = '\u3000';
+            }
+            else if (c[i] < '\177')
+            {
+                c[i] = (char) (c[i] + 65248);
+
+            }
+        }
+        return new String(c);
+    }
+
+    /**
+     * 鍏ㄨ杞崐瑙�
+     *
+     * @param input String.
+     * @return 鍗婅瀛楃涓�
+     */
+    public static String toDBC(String input)
+    {
+        return toDBC(input, null);
+    }
+
+    /**
+     * 鏇挎崲鍏ㄨ涓哄崐瑙�
+     *
+     * @param text 鏂囨湰
+     * @param notConvertSet 涓嶆浛鎹㈢殑瀛楃闆嗗悎
+     * @return 鏇挎崲鍚庣殑瀛楃
+     */
+    public static String toDBC(String text, Set<Character> notConvertSet)
+    {
+        char[] c = text.toCharArray();
+        for (int i = 0; i < c.length; i++)
+        {
+            if (null != notConvertSet && notConvertSet.contains(c[i]))
+            {
+                // 璺宠繃涓嶆浛鎹㈢殑瀛楃
+                continue;
+            }
+
+            if (c[i] == '\u3000')
+            {
+                c[i] = ' ';
+            }
+            else if (c[i] > '\uFF00' && c[i] < '\uFF5F')
+            {
+                c[i] = (char) (c[i] - 65248);
+            }
+        }
+        String returnString = new String(c);
+
+        return returnString;
+    }
+
+    /**
+     * 鏁板瓧閲戦澶у啓杞崲 鍏堝啓涓畬鏁寸殑鐒跺悗灏嗗闆舵嬀鏇挎崲鎴愰浂
+     *
+     * @param n 鏁板瓧
+     * @return 涓枃澶у啓鏁板瓧
+     */
+    public static String digitUppercase(double n)
+    {
+        String[] fraction = { "瑙�", "鍒�" };
+        String[] digit = { "闆�", "澹�", "璐�", "鍙�", "鑲�", "浼�", "闄�", "鏌�", "鎹�", "鐜�" };
+        String[][] unit = { { "鍏�", "涓�", "浜�" }, { "", "鎷�", "浣�", "浠�" } };
+
+        String head = n < 0 ? "璐�" : "";
+        n = Math.abs(n);
+
+        String s = "";
+        for (int i = 0; i < fraction.length; i++)
+        {
+            // 浼樺寲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/ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
new file mode 100644
index 0000000..c78ac77
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/core/text/StrFormatter.java
@@ -0,0 +1,92 @@
+package com.ruoyi.common.core.text;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 瀛楃涓叉牸寮忓寲
+ * 
+ * @author ruoyi
+ */
+public class StrFormatter
+{
+    public static final String EMPTY_JSON = "{}";
+    public static final char C_BACKSLASH = '\\';
+    public static final char C_DELIM_START = '{';
+    public static final char C_DELIM_END = '}';
+
+    /**
+     * 鏍煎紡鍖栧瓧绗︿覆<br>
+     * 姝ゆ柟娉曞彧鏄畝鍗曞皢鍗犱綅绗� {} 鎸夌収椤哄簭鏇挎崲涓哄弬鏁�<br>
+     * 濡傛灉鎯宠緭鍑� {} 浣跨敤 \\杞箟 { 鍗冲彲锛屽鏋滄兂杈撳嚭 {} 涔嬪墠鐨� \ 浣跨敤鍙岃浆涔夌 \\\\ 鍗冲彲<br>
+     * 渚嬶細<br>
+     * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     * 
+     * @param strPattern 瀛楃涓叉ā鏉�
+     * @param argArray 鍙傛暟鍒楄〃
+     * @return 缁撴灉
+     */
+    public static String format(final String strPattern, final Object... argArray)
+    {
+        if (StringUtils.isEmpty(strPattern) || StringUtils.isEmpty(argArray))
+        {
+            return strPattern;
+        }
+        final int strPatternLength = strPattern.length();
+
+        // 鍒濆鍖栧畾涔夊ソ鐨勯暱搴︿互鑾峰緱鏇村ソ鐨勬�ц兘
+        StringBuilder sbuf = new StringBuilder(strPatternLength + 50);
+
+        int handledPosition = 0;
+        int delimIndex;// 鍗犱綅绗︽墍鍦ㄤ綅缃�
+        for (int argIndex = 0; argIndex < argArray.length; argIndex++)
+        {
+            delimIndex = strPattern.indexOf(EMPTY_JSON, handledPosition);
+            if (delimIndex == -1)
+            {
+                if (handledPosition == 0)
+                {
+                    return strPattern;
+                }
+                else
+                { // 瀛楃涓叉ā鏉垮墿浣欓儴鍒嗕笉鍐嶅寘鍚崰浣嶇锛屽姞鍏ュ墿浣欓儴鍒嗗悗杩斿洖缁撴灉
+                    sbuf.append(strPattern, handledPosition, strPatternLength);
+                    return sbuf.toString();
+                }
+            }
+            else
+            {
+                if (delimIndex > 0 && strPattern.charAt(delimIndex - 1) == C_BACKSLASH)
+                {
+                    if (delimIndex > 1 && strPattern.charAt(delimIndex - 2) == C_BACKSLASH)
+                    {
+                        // 杞箟绗︿箣鍓嶈繕鏈変竴涓浆涔夌锛屽崰浣嶇渚濇棫鏈夋晥
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                        handledPosition = delimIndex + 2;
+                    }
+                    else
+                    {
+                        // 鍗犱綅绗﹁杞箟
+                        argIndex--;
+                        sbuf.append(strPattern, handledPosition, delimIndex - 1);
+                        sbuf.append(C_DELIM_START);
+                        handledPosition = delimIndex + 1;
+                    }
+                }
+                else
+                {
+                    // 姝e父鍗犱綅绗�
+                    sbuf.append(strPattern, handledPosition, delimIndex);
+                    sbuf.append(Convert.utf8Str(argArray[argIndex]));
+                    handledPosition = delimIndex + 2;
+                }
+            }
+        }
+        // 鍔犲叆鏈�鍚庝竴涓崰浣嶇鍚庢墍鏈夌殑瀛楃
+        sbuf.append(strPattern, handledPosition, strPattern.length());
+
+        return sbuf.toString();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
new file mode 100644
index 0000000..10b7306
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessStatus.java
@@ -0,0 +1,20 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 鎿嶄綔鐘舵��
+ * 
+ * @author ruoyi
+ *
+ */
+public enum BusinessStatus
+{
+    /**
+     * 鎴愬姛
+     */
+    SUCCESS,
+
+    /**
+     * 澶辫触
+     */
+    FAIL,
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
new file mode 100644
index 0000000..f4e7f67
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/BusinessType.java
@@ -0,0 +1,64 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 涓氬姟鎿嶄綔绫诲瀷
+ * 
+ * @author ruoyi
+ */
+public enum BusinessType
+{
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鏂板
+     */
+    INSERT,
+
+    /**
+     * 淇敼
+     */
+    UPDATE,
+
+    /**
+     * 鍒犻櫎
+     */
+    DELETE,
+
+    /**
+     * 鎺堟潈
+     */
+    GRANT,
+
+    /**
+     * 瀵煎嚭
+     */
+    EXPORT,
+
+    /**
+     * 瀵煎叆
+     */
+    IMPORT,
+
+    /**
+     * 寮洪��
+     */
+    FORCE,
+
+    /**
+     * 鐢熸垚浠g爜
+     */
+    GENCODE,
+    
+    /**
+     * 娓呯┖鏁版嵁
+     */
+    CLEAN,
+
+    /**
+     * 鏌ヨ
+     */
+    SELECT,
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
new file mode 100644
index 0000000..0d945be
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DataSourceType.java
@@ -0,0 +1,19 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 鏁版嵁婧�
+ * 
+ * @author ruoyi
+ */
+public enum DataSourceType
+{
+    /**
+     * 涓诲簱
+     */
+    MASTER,
+
+    /**
+     * 浠庡簱
+     */
+    SLAVE
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java
new file mode 100644
index 0000000..07f02ee
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/DesensitizedType.java
@@ -0,0 +1,59 @@
+package com.ruoyi.common.enums;
+
+import java.util.function.Function;
+import com.ruoyi.common.utils.DesensitizedUtil;
+
+/**
+ * 鑴辨晱绫诲瀷
+ *
+ * @author ruoyi
+ */
+public enum DesensitizedType
+{
+    /**
+     * 濮撳悕锛岀2浣嶆槦鍙锋浛鎹�
+     */
+    USERNAME(s -> s.replaceAll("(\\S)\\S(\\S*)", "$1*$2")),
+
+    /**
+     * 瀵嗙爜锛屽叏閮ㄥ瓧绗﹂兘鐢�*浠f浛
+     */
+    PASSWORD(DesensitizedUtil::password),
+
+    /**
+     * 韬唤璇侊紝涓棿10浣嶆槦鍙锋浛鎹�
+     */
+    ID_CARD(s -> s.replaceAll("(\\d{4})\\d{10}(\\d{3}[Xx]|\\d{4})", "$1** **** ****$2")),
+
+    /**
+     * 鎵嬫満鍙凤紝涓棿4浣嶆槦鍙锋浛鎹�
+     */
+    PHONE(s -> s.replaceAll("(\\d{3})\\d{4}(\\d{4})", "$1****$2")),
+
+    /**
+     * 鐢靛瓙閭锛屼粎鏄剧ず绗竴涓瓧姣嶅拰@鍚庨潰鐨勫湴鍧�鏄剧ず锛屽叾浠栨槦鍙锋浛鎹�
+     */
+    EMAIL(s -> s.replaceAll("(^.)[^@]*(@.*$)", "$1****$2")),
+
+    /**
+     * 閾惰鍗″彿锛屼繚鐣欐渶鍚�4浣嶏紝鍏朵粬鏄熷彿鏇挎崲
+     */
+    BANK_CARD(s -> s.replaceAll("\\d{15}(\\d{3})", "**** **** **** **** $1")),
+
+    /**
+     * 杞︾墝鍙风爜锛屽寘鍚櫘閫氳溅杈嗐�佹柊鑳芥簮杞﹁締
+     */
+    CAR_LICENSE(DesensitizedUtil::carLicense);
+
+    private final Function<String, String> desensitizer;
+
+    DesensitizedType(Function<String, String> desensitizer)
+    {
+        this.desensitizer = desensitizer;
+    }
+
+    public Function<String, String> desensitizer()
+    {
+        return desensitizer;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
new file mode 100644
index 0000000..be6f739
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/HttpMethod.java
@@ -0,0 +1,36 @@
+package com.ruoyi.common.enums;
+
+import java.util.HashMap;
+import java.util.Map;
+import org.springframework.lang.Nullable;
+
+/**
+ * 璇锋眰鏂瑰紡
+ *
+ * @author ruoyi
+ */
+public enum HttpMethod
+{
+    GET, HEAD, POST, PUT, PATCH, DELETE, OPTIONS, TRACE;
+
+    private static final Map<String, HttpMethod> mappings = new HashMap<>(16);
+
+    static
+    {
+        for (HttpMethod httpMethod : values())
+        {
+            mappings.put(httpMethod.name(), httpMethod);
+        }
+    }
+
+    @Nullable
+    public static HttpMethod resolve(@Nullable String method)
+    {
+        return (method != null ? mappings.get(method) : null);
+    }
+
+    public boolean matches(String method)
+    {
+        return (this == resolve(method));
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
new file mode 100644
index 0000000..c609fd8
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/LimitType.java
@@ -0,0 +1,20 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 闄愭祦绫诲瀷
+ *
+ * @author ruoyi
+ */
+
+public enum LimitType
+{
+    /**
+     * 榛樿绛栫暐鍏ㄥ眬闄愭祦
+     */
+    DEFAULT,
+
+    /**
+     * 鏍规嵁璇锋眰鑰匢P杩涜闄愭祦
+     */
+    IP
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
new file mode 100644
index 0000000..bdd143c
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/OperatorType.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 鎿嶄綔浜虹被鍒�
+ * 
+ * @author ruoyi
+ */
+public enum OperatorType
+{
+    /**
+     * 鍏跺畠
+     */
+    OTHER,
+
+    /**
+     * 鍚庡彴鐢ㄦ埛
+     */
+    MANAGE,
+
+    /**
+     * 鎵嬫満绔敤鎴�
+     */
+    MOBILE
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java b/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
new file mode 100644
index 0000000..d7ff44a
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/enums/UserStatus.java
@@ -0,0 +1,30 @@
+package com.ruoyi.common.enums;
+
+/**
+ * 鐢ㄦ埛鐘舵��
+ * 
+ * @author ruoyi
+ */
+public enum UserStatus
+{
+    OK("0", "姝e父"), DISABLE("1", "鍋滅敤"), DELETED("2", "鍒犻櫎");
+
+    private final String code;
+    private final String info;
+
+    UserStatus(String code, String info)
+    {
+        this.code = code;
+        this.info = info;
+    }
+
+    public String getCode()
+    {
+        return code;
+    }
+
+    public String getInfo()
+    {
+        return info;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
new file mode 100644
index 0000000..f6ad2ab
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/DemoModeException.java
@@ -0,0 +1,15 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 婕旂ず妯″紡寮傚父
+ * 
+ * @author ruoyi
+ */
+public class DemoModeException extends RuntimeException
+{
+    private static final long serialVersionUID = 1L;
+
+    public DemoModeException()
+    {
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
new file mode 100644
index 0000000..81a71b5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/GlobalException.java
@@ -0,0 +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;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
new file mode 100644
index 0000000..fcc7ab6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/ServiceException.java
@@ -0,0 +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;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
new file mode 100644
index 0000000..980fa46
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/UtilException.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.exception;
+
+/**
+ * 宸ュ叿绫诲紓甯�
+ * 
+ * @author ruoyi
+ */
+public class UtilException extends RuntimeException
+{
+    private static final long serialVersionUID = 8247610319171014183L;
+
+    public UtilException(Throwable e)
+    {
+        super(e.getMessage(), e);
+    }
+
+    public UtilException(String message)
+    {
+        super(message);
+    }
+
+    public UtilException(String message, Throwable throwable)
+    {
+        super(message, throwable);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
new file mode 100644
index 0000000..b55d72e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/base/BaseException.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
new file mode 100644
index 0000000..871f09b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileException.java
@@ -0,0 +1,19 @@
+package com.ruoyi.common.exception.file;
+
+import com.ruoyi.common.exception.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);
+    }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
new file mode 100644
index 0000000..70e0ec9
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileNameLengthLimitExceededException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.file;
+
+/**
+ * 鏂囦欢鍚嶇О瓒呴暱闄愬埗寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class FileNameLengthLimitExceededException extends FileException
+{
+    private static final long serialVersionUID = 1L;
+
+    public FileNameLengthLimitExceededException(int defaultFileNameLength)
+    {
+        super("upload.filename.exceed.length", new Object[] { defaultFileNameLength });
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
new file mode 100644
index 0000000..ec6ab05
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileSizeLimitExceededException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.file;
+
+/**
+ * 鏂囦欢鍚嶅ぇ灏忛檺鍒跺紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class FileSizeLimitExceededException extends FileException
+{
+    private static final long serialVersionUID = 1L;
+
+    public FileSizeLimitExceededException(long defaultMaxSize)
+    {
+        super("upload.exceed.maxSize", new Object[] { defaultMaxSize });
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java
new file mode 100644
index 0000000..f45e7ef
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/FileUploadException.java
@@ -0,0 +1,61 @@
+package com.ruoyi.common.exception.file;
+
+import java.io.PrintStream;
+import java.io.PrintWriter;
+
+/**
+ * 鏂囦欢涓婁紶寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class FileUploadException extends Exception
+{
+
+    private static final long serialVersionUID = 1L;
+
+    private final Throwable cause;
+
+    public FileUploadException()
+    {
+        this(null, null);
+    }
+
+    public FileUploadException(final String msg)
+    {
+        this(msg, null);
+    }
+
+    public FileUploadException(String msg, Throwable cause)
+    {
+        super(msg);
+        this.cause = cause;
+    }
+
+    @Override
+    public void printStackTrace(PrintStream stream)
+    {
+        super.printStackTrace(stream);
+        if (cause != null)
+        {
+            stream.println("Caused by:");
+            cause.printStackTrace(stream);
+        }
+    }
+
+    @Override
+    public void printStackTrace(PrintWriter writer)
+    {
+        super.printStackTrace(writer);
+        if (cause != null)
+        {
+            writer.println("Caused by:");
+            cause.printStackTrace(writer);
+        }
+    }
+
+    @Override
+    public Throwable getCause()
+    {
+        return cause;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
new file mode 100644
index 0000000..011f308
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/file/InvalidExtensionException.java
@@ -0,0 +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);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
new file mode 100644
index 0000000..a567b40
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/job/TaskException.java
@@ -0,0 +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
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java
new file mode 100644
index 0000000..2bf5038
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/BlackListException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 榛戝悕鍗旾P寮傚父绫�
+ * 
+ * @author ruoyi
+ */
+public class BlackListException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public BlackListException()
+    {
+        super("login.blocked", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
new file mode 100644
index 0000000..389dbc7
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 楠岃瘉鐮侀敊璇紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class CaptchaException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaException()
+    {
+        super("user.jcaptcha.error", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
new file mode 100644
index 0000000..85f9486
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/CaptchaExpireException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 楠岃瘉鐮佸け鏁堝紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class CaptchaExpireException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public CaptchaExpireException()
+    {
+        super("user.jcaptcha.expire", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
new file mode 100644
index 0000000..c292d70
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserException.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.exception.user;
+
+import com.ruoyi.common.exception.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);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java
new file mode 100644
index 0000000..eff8181
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserNotExistsException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 鐢ㄦ埛涓嶅瓨鍦ㄥ紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class UserNotExistsException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserNotExistsException()
+    {
+        super("user.not.exists", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
new file mode 100644
index 0000000..a7f3e5f
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordNotMatchException.java
@@ -0,0 +1,16 @@
+package com.ruoyi.common.exception.user;
+
+/**
+ * 鐢ㄦ埛瀵嗙爜涓嶆纭垨涓嶇鍚堣鑼冨紓甯哥被
+ * 
+ * @author ruoyi
+ */
+public class UserPasswordNotMatchException extends UserException
+{
+    private static final long serialVersionUID = 1L;
+
+    public UserPasswordNotMatchException()
+    {
+        super("user.password.not.match", null);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java
new file mode 100644
index 0000000..c887cf1
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/exception/user/UserPasswordRetryLimitExceedException.java
@@ -0,0 +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 });
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java
new file mode 100644
index 0000000..e1e431b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/PropertyPreExcludeFilter.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
new file mode 100644
index 0000000..efeded9
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatableFilter.java
@@ -0,0 +1,52 @@
+package com.ruoyi.common.filter;
+
+import java.io.IOException;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.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()
+    {
+
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
new file mode 100644
index 0000000..5c6ee08
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/RepeatedlyRequestWrapper.java
@@ -0,0 +1,76 @@
+package com.ruoyi.common.filter;
+
+import java.io.BufferedReader;
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletRequestWrapper;
+import com.ruoyi.common.utils.http.HttpHelper;
+import com.ruoyi.common.constant.Constants;
+
+/**
+ * 鏋勫缓鍙噸澶嶈鍙杋nputStream鐨剅equest
+ * 
+ * @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)
+            {
+
+            }
+        };
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
new file mode 100644
index 0000000..7438fc2
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssFilter.java
@@ -0,0 +1,75 @@
+package com.ruoyi.common.filter;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.FilterConfig;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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()
+    {
+
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
new file mode 100644
index 0000000..bf7837b
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/filter/XssHttpServletRequestWrapper.java
@@ -0,0 +1,111 @@
+package com.ruoyi.common.filter;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import jakarta.servlet.ReadListener;
+import jakarta.servlet.ServletInputStream;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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++)
+            {
+                // 闃瞲ss鏀诲嚮鍜岃繃婊ゅ墠鍚庣┖鏍�
+                escapesValues[i] = EscapeUtil.clean(values[i]).trim();
+            }
+            return escapesValues;
+        }
+        return super.getParameterValues(name);
+    }
+
+    @Override
+    public ServletInputStream getInputStream() throws IOException
+    {
+        // 闈瀓son绫诲瀷锛岀洿鎺ヨ繑鍥�
+        if (!isJsonRequest())
+        {
+            return super.getInputStream();
+        }
+
+        // 涓虹┖锛岀洿鎺ヨ繑鍥�
+        String json = IOUtils.toString(super.getInputStream(), "utf-8");
+        if (StringUtils.isEmpty(json))
+        {
+            return super.getInputStream();
+        }
+
+        // xss杩囨护
+        json = EscapeUtil.clean(json).trim();
+        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();
+            }
+        };
+    }
+
+    /**
+     * 鏄惁鏄疛son璇锋眰
+     * 
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java
new file mode 100644
index 0000000..b6326c2
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/Arith.java
@@ -0,0 +1,114 @@
+package com.ruoyi.common.utils;
+
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+
+/**
+ * 绮剧‘鐨勬诞鐐规暟杩愮畻
+ * 
+ * @author ruoyi
+ */
+public class Arith
+{
+
+    /** 榛樿闄ゆ硶杩愮畻绮惧害 */
+    private static final int DEF_DIV_SCALE = 10;
+
+    /** 杩欎釜绫讳笉鑳藉疄渚嬪寲 */
+    private Arith()
+    {
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫姞娉曡繍绠椼��
+     * @param v1 琚姞鏁�
+     * @param v2 鍔犳暟
+     * @return 涓や釜鍙傛暟鐨勫拰
+     */
+    public static double add(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.add(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫噺娉曡繍绠椼��
+     * @param v1 琚噺鏁�
+     * @param v2 鍑忔暟
+     * @return 涓や釜鍙傛暟鐨勫樊
+     */
+    public static double sub(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.subtract(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勪箻娉曡繍绠椼��
+     * @param v1 琚箻鏁�
+     * @param v2 涔樻暟
+     * @return 涓や釜鍙傛暟鐨勭Н
+     */
+    public static double mul(double v1, double v2)
+    {
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        return b1.multiply(b2).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠楋紝褰撳彂鐢熼櫎涓嶅敖鐨勬儏鍐垫椂锛岀簿纭埌
+     * 灏忔暟鐐逛互鍚�10浣嶏紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2)
+    {
+        return div(v1, v2, DEF_DIV_SCALE);
+    }
+
+    /**
+     * 鎻愪緵锛堢浉瀵癸級绮剧‘鐨勯櫎娉曡繍绠椼�傚綋鍙戠敓闄や笉灏界殑鎯呭喌鏃讹紝鐢眘cale鍙傛暟鎸�
+     * 瀹氱簿搴︼紝浠ュ悗鐨勬暟瀛楀洓鑸嶄簲鍏ャ��
+     * @param v1 琚櫎鏁�
+     * @param v2 闄ゆ暟
+     * @param scale 琛ㄧず琛ㄧず闇�瑕佺簿纭埌灏忔暟鐐逛互鍚庡嚑浣嶃��
+     * @return 涓や釜鍙傛暟鐨勫晢
+     */
+    public static double div(double v1, double v2, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b1 = new BigDecimal(Double.toString(v1));
+        BigDecimal b2 = new BigDecimal(Double.toString(v2));
+        if (b1.compareTo(BigDecimal.ZERO) == 0)
+        {
+            return BigDecimal.ZERO.doubleValue();
+        }
+        return b1.divide(b2, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+
+    /**
+     * 鎻愪緵绮剧‘鐨勫皬鏁颁綅鍥涜垗浜斿叆澶勭悊銆�
+     * @param v 闇�瑕佸洓鑸嶄簲鍏ョ殑鏁板瓧
+     * @param scale 灏忔暟鐐瑰悗淇濈暀鍑犱綅
+     * @return 鍥涜垗浜斿叆鍚庣殑缁撴灉
+     */
+    public static double round(double v, int scale)
+    {
+        if (scale < 0)
+        {
+            throw new IllegalArgumentException(
+                    "The scale must be a positive integer or zero");
+        }
+        BigDecimal b = new BigDecimal(Double.toString(v));
+        BigDecimal one = BigDecimal.ONE;
+        return b.divide(one, scale, RoundingMode.HALF_UP).doubleValue();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
new file mode 100644
index 0000000..fb2ae21
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DateUtils.java
@@ -0,0 +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();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鏃ユ湡, 榛樿鏍煎紡涓簓yyy-MM-dd
+     * 
+     * @return String
+     */
+    public static String getDate()
+    {
+        return dateTimeNow(YYYY_MM_DD);
+    }
+
+    public static final String getTime()
+    {
+        return dateTimeNow(YYYY_MM_DD_HH_MM_SS);
+    }
+
+    public static final String dateTimeNow()
+    {
+        return dateTimeNow(YYYYMMDDHHMMSS);
+    }
+
+    public static final String dateTimeNow(final String format)
+    {
+        return parseDateToStr(format, new Date());
+    }
+
+    public static final String dateTime(final Date date)
+    {
+        return parseDateToStr(YYYY_MM_DD, date);
+    }
+
+    public static final String parseDateToStr(final String format, final Date date)
+    {
+        return new SimpleDateFormat(format).format(date);
+    }
+
+    public static final Date dateTime(final String format, final String ts)
+    {
+        try
+        {
+            return new SimpleDateFormat(format).parse(ts);
+        }
+        catch (ParseException e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�2018/08/08
+     */
+    public static final String datePath()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyy/MM/dd");
+    }
+
+    /**
+     * 鏃ユ湡璺緞 鍗冲勾/鏈�/鏃� 濡�20180808
+     */
+    public static final String dateTime()
+    {
+        Date now = new Date();
+        return DateFormatUtils.format(now, "yyyyMMdd");
+    }
+
+    /**
+     * 鏃ユ湡鍨嬪瓧绗︿覆杞寲涓烘棩鏈� 鏍煎紡
+     */
+    public static Date parseDate(Object str)
+    {
+        if (str == null)
+        {
+            return null;
+        }
+        try
+        {
+            return parseDate(str.toString(), parsePatterns);
+        }
+        catch (ParseException e)
+        {
+            return null;
+        }
+    }
+
+    /**
+     * 鑾峰彇鏈嶅姟鍣ㄥ惎鍔ㄦ椂闂�
+     */
+    public static Date getServerStartDate()
+    {
+        long time = ManagementFactory.getRuntimeMXBean().getStartTime();
+        return new Date(time);
+    }
+
+    /**
+     * 璁$畻鐩稿樊澶╂暟
+     */
+    public static 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/ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
new file mode 100644
index 0000000..f8a4c02
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DesensitizedUtil.java
@@ -0,0 +1,49 @@
+package com.ruoyi.common.utils;
+
+/**
+ * 鑴辨晱宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class DesensitizedUtil
+{
+    /**
+     * 瀵嗙爜鐨勫叏閮ㄥ瓧绗﹂兘鐢�*浠f浛锛屾瘮濡傦細******
+     *
+     * @param password 瀵嗙爜
+     * @return 鑴辨晱鍚庣殑瀵嗙爜
+     */
+    public static String password(String password)
+    {
+        if (StringUtils.isBlank(password))
+        {
+            return StringUtils.EMPTY;
+        }
+        return StringUtils.repeat('*', password.length());
+    }
+
+    /**
+     * 杞︾墝涓棿鐢�*浠f浛锛屽鏋滄槸閿欒鐨勮溅鐗岋紝涓嶅鐞�
+     *
+     * @param carLicense 瀹屾暣鐨勮溅鐗屽彿
+     * @return 鑴辨晱鍚庣殑杞︾墝
+     */
+    public static String carLicense(String carLicense)
+    {
+        if (StringUtils.isBlank(carLicense))
+        {
+            return StringUtils.EMPTY;
+        }
+        // 鏅�氳溅鐗�
+        if (carLicense.length() == 7)
+        {
+            carLicense = StringUtils.hide(carLicense, 3, 6);
+        }
+        else if (carLicense.length() == 8)
+        {
+            // 鏂拌兘婧愯溅鐗�
+            carLicense = StringUtils.hide(carLicense, 3, 7);
+        }
+        return carLicense;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
new file mode 100644
index 0000000..f198462
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/DictUtils.java
@@ -0,0 +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 缂撳瓨閿甼ey
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java
new file mode 100644
index 0000000..214e4a0
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ExceptionUtil.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java
new file mode 100644
index 0000000..0de30c6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/LogUtils.java
@@ -0,0 +1,18 @@
+package com.ruoyi.common.utils;
+
+/**
+ * 澶勭悊骞惰褰曟棩蹇楁枃浠�
+ * 
+ * @author ruoyi
+ */
+public class LogUtils
+{
+    public static String getBlock(Object msg)
+    {
+        if (msg == null)
+        {
+            msg = "";
+        }
+        return "[" + msg.toString() + "]";
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java
new file mode 100644
index 0000000..7dac75a
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/MessageUtils.java
@@ -0,0 +1,26 @@
+package com.ruoyi.common.utils;
+
+import org.springframework.context.MessageSource;
+import org.springframework.context.i18n.LocaleContextHolder;
+import com.ruoyi.common.utils.spring.SpringUtils;
+
+/**
+ * 鑾峰彇i18n璧勬簮鏂囦欢
+ * 
+ * @author ruoyi
+ */
+public class MessageUtils
+{
+    /**
+     * 鏍规嵁娑堟伅閿拰鍙傛暟 鑾峰彇娑堟伅 濮旀墭缁檚pring messageSource
+     *
+     * @param code 娑堟伅閿�
+     * @param args 鍙傛暟
+     * @return 鑾峰彇鍥介檯鍖栫炕璇戝��
+     */
+    public static String message(String code, Object... args)
+    {
+        MessageSource messageSource = SpringUtils.getBean(MessageSource.class);
+        return messageSource.getMessage(code, args, LocaleContextHolder.getLocale());
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
new file mode 100644
index 0000000..e814b69
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/PageUtils.java
@@ -0,0 +1,32 @@
+package com.ruoyi.common.utils;
+
+import com.ruoyi.common.core.page.PageDomain;
+import com.ruoyi.common.core.page.TableSupport;
+import com.ruoyi.common.utils.sql.SqlUtil;
+
+/**
+ * 鍒嗛〉宸ュ叿绫�
+ *
+ * @author ruoyi
+ */
+public class PageUtils {
+//    public class PageUtils extends PageHelper {
+    /**
+     * 璁剧疆璇锋眰鍒嗛〉鏁版嵁
+     */
+    public static void startPage() {
+        PageDomain pageDomain = TableSupport.buildPageRequest();
+        Integer pageNum = pageDomain.getPageNum();
+        Integer pageSize = pageDomain.getPageSize();
+        String orderBy = SqlUtil.escapeOrderBySql(pageDomain.getOrderBy());
+        Boolean reasonable = pageDomain.getReasonable();
+//        PageHelper.startPage(pageNum, pageSize, orderBy).setReasonable(reasonable);
+    }
+
+    /**
+     * 娓呯悊鍒嗛〉鐨勭嚎绋嬪彉閲�
+     */
+    public static void clearPage() {
+        //PageHelper.clearPage();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
new file mode 100644
index 0000000..0d3ac5f
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/SecurityUtils.java
@@ -0,0 +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));
+    }
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
new file mode 100644
index 0000000..5635db7
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ServletUtils.java
@@ -0,0 +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 jakarta.servlet.ServletRequest;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.servlet.http.HttpServletResponse;
+import jakarta.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();
+        }
+    }
+
+    /**
+     * 鏄惁鏄疉jax寮傛璇锋眰
+     * 
+     * @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;
+        }
+    }
+
+    /**
+     * 鍐呭瑙g爜
+     * 
+     * @param str 鍐呭
+     * @return 瑙g爜鍚庣殑鍐呭
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
new file mode 100644
index 0000000..25c2886
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/StringUtils.java
@@ -0,0 +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;
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狢ollection鏄惁涓虹┖锛� 鍖呭惈List锛孲et锛孮ueue
+     * 
+     * @param coll 瑕佸垽鏂殑Collection
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Collection<?> coll)
+    {
+        return isNull(coll) || coll.isEmpty();
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狢ollection鏄惁闈炵┖锛屽寘鍚獿ist锛孲et锛孮ueue
+     * 
+     * @param coll 瑕佸垽鏂殑Collection
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Collection<?> coll)
+    {
+        return !isEmpty(coll);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚︿负绌�
+     * 
+     * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+     ** @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Object[] objects)
+    {
+        return isNull(objects) || (objects.length == 0);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃暟缁勬槸鍚﹂潪绌�
+     * 
+     * @param objects 瑕佸垽鏂殑瀵硅薄鏁扮粍
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Object[] objects)
+    {
+        return !isEmpty(objects);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+     * 
+     * @param map 瑕佸垽鏂殑Map
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(Map<?, ?> map)
+    {
+        return isNull(map) || map.isEmpty();
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓狹ap鏄惁涓虹┖
+     * 
+     * @param map 瑕佸垽鏂殑Map
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotEmpty(Map<?, ?> map)
+    {
+        return !isEmpty(map);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓虹┖涓�
+     * 
+     * @param str String
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isEmpty(String str)
+    {
+        return isNull(str) || NULLSTR.equals(str.trim());
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓瓧绗︿覆鏄惁涓洪潪绌轰覆
+     * 
+     * @param str String
+     * @return true锛氶潪绌轰覆 false锛氱┖涓�
+     */
+    public static boolean isNotEmpty(String str)
+    {
+        return !isEmpty(str);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚︿负绌�
+     * 
+     * @param object Object
+     * @return true锛氫负绌� false锛氶潪绌�
+     */
+    public static boolean isNull(Object object)
+    {
+        return object == null;
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚﹂潪绌�
+     * 
+     * @param object Object
+     * @return true锛氶潪绌� false锛氱┖
+     */
+    public static boolean isNotNull(Object object)
+    {
+        return !isNull(object);
+    }
+
+    /**
+     * * 鍒ゆ柇涓�涓璞℃槸鍚︽槸鏁扮粍绫诲瀷锛圝ava鍩烘湰鍨嬪埆鐨勬暟缁勶級
+     * 
+     * @param object 瀵硅薄
+     * @return true锛氭槸鏁扮粍 false锛氫笉鏄暟缁�
+     */
+    public static boolean isArray(Object object)
+    {
+        return isNotNull(object) && object.getClass().isArray();
+    }
+
+    /**
+     * 鍘荤┖鏍�
+     */
+    public static String trim(String str)
+    {
+        return (str == null ? "" : str.trim());
+    }
+
+    /**
+     * 鏇挎崲鎸囧畾瀛楃涓茬殑鎸囧畾鍖洪棿鍐呭瓧绗︿负"*"
+     *
+     * @param str 瀛楃涓�
+     * @param 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>
+     * 閫氬父浣跨敤锛歠ormat("this is {} for {}", "a", "b") -> this is a for b<br>
+     * 杞箟{}锛� format("this is \\{} for {}", "a", "b") -> this is \{} for a<br>
+     * 杞箟\锛� format("this is \\\\{} for {}", "a", "b") -> this is \a for b<br>
+     * 
+     * @param template 鏂囨湰妯℃澘锛岃鏇挎崲鐨勯儴鍒嗙敤 {} 琛ㄧず
+     * @param params 鍙傛暟鍊�
+     * @return 鏍煎紡鍖栧悗鐨勬枃鏈�
+     */
+    public static String format(String template, Object... params)
+    {
+        if (isEmpty(params) || isEmpty(template))
+        {
+            return template;
+        }
+        return StrFormatter.format(template, params);
+    }
+
+    /**
+     * 鏄惁涓篽ttp(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;
+    }
+
+    /**
+     * 鍒ゆ柇缁欏畾鐨刢ollection鍒楄〃涓槸鍚﹀寘鍚暟缁刟rray 鍒ゆ柇缁欏畾鐨勬暟缁刟rray涓槸鍚﹀寘鍚粰瀹氱殑鍏冪礌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;
+    }
+
+    /**
+     * 灏嗕笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆杞崲涓洪┘宄板紡銆傚鏋滆浆鎹㈠墠鐨勪笅鍒掔嚎澶у啓鏂瑰紡鍛藉悕鐨勫瓧绗︿覆涓虹┖锛屽垯杩斿洖绌哄瓧绗︿覆銆� 渚嬪锛欻ELLO_WORLD->HelloWorld
+     * 
+     * @param name 杞崲鍓嶇殑涓嬪垝绾垮ぇ鍐欐柟寮忓懡鍚嶇殑瀛楃涓�
+     * @return 杞崲鍚庣殑椹煎嘲寮忓懡鍚嶇殑瀛楃涓�
+     */
+    public static String convertToCamelCase(String name)
+    {
+        StringBuilder result = new StringBuilder();
+        // 蹇�熸鏌�
+        if (name == null || name.isEmpty())
+        {
+            // 娌″繀瑕佽浆鎹�
+            return "";
+        }
+        else if (!name.contains("_"))
+        {
+            // 涓嶅惈涓嬪垝绾匡紝浠呭皢棣栧瓧姣嶅ぇ鍐�
+            return name.substring(0, 1).toUpperCase() + name.substring(1);
+        }
+        // 鐢ㄤ笅鍒掔嚎灏嗗師濮嬪瓧绗︿覆鍒嗗壊
+        String[] camels = name.split("_");
+        for (String camel : camels)
+        {
+            // 璺宠繃鍘熷瀛楃涓蹭腑寮�澶淬�佺粨灏剧殑涓嬫崲绾挎垨鍙岄噸涓嬪垝绾�
+            if (camel.isEmpty())
+            {
+                continue;
+            }
+            // 棣栧瓧姣嶅ぇ鍐�
+            result.append(camel.substring(0, 1).toUpperCase());
+            result.append(camel.substring(1).toLowerCase());
+        }
+        return result.toString();
+    }
+
+    /**
+     * 椹煎嘲寮忓懡鍚嶆硶
+     * 渚嬪锛歶ser_name->userName
+     */
+    public static String toCamelCase(String s)
+    {
+        if (s == null)
+        {
+            return null;
+        }
+        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锛屽垯鍙繚鐣� 鏈�鍚巗ize涓瓧绗︺��
+     * 
+     * @param num 鏁板瓧瀵硅薄
+     * @param size 瀛楃涓叉寚瀹氶暱搴�
+     * @return 杩斿洖鏁板瓧鐨勫瓧绗︿覆鏍煎紡锛岃瀛楃涓蹭负鎸囧畾闀垮害銆�
+     */
+    public static final String padl(final Number num, final int size)
+    {
+        return padl(num.toString(), size, '0');
+    }
+
+    /**
+     * 瀛楃涓插乏琛ラ綈銆傚鏋滃師濮嬪瓧绗︿覆s闀垮害澶т簬size锛屽垯鍙繚鐣欐渶鍚巗ize涓瓧绗︺��
+     * 
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
new file mode 100644
index 0000000..71fe6d5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/Threads.java
@@ -0,0 +1,99 @@
+package com.ruoyi.common.utils;
+
+import java.util.concurrent.CancellationException;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 绾跨▼鐩稿叧宸ュ叿绫�.
+ * 
+ * @author ruoyi
+ */
+public class Threads
+{
+    private static final Logger logger = LoggerFactory.getLogger(Threads.class);
+
+    /**
+     * sleep绛夊緟,鍗曚綅涓烘绉�
+     */
+    public static void sleep(long milliseconds)
+    {
+        try
+        {
+            Thread.sleep(milliseconds);
+        }
+        catch (InterruptedException e)
+        {
+            return;
+        }
+    }
+
+    /**
+     * 鍋滄绾跨▼姹�
+     * 鍏堜娇鐢╯hutdown, 鍋滄鎺ユ敹鏂颁换鍔″苟灏濊瘯瀹屾垚鎵�鏈夊凡瀛樺湪浠诲姟.
+     * 濡傛灉瓒呮椂, 鍒欒皟鐢╯hutdownNow, 鍙栨秷鍦╳orkQueue涓璓ending鐨勪换鍔�,骞朵腑鏂墍鏈夐樆濉炲嚱鏁�.
+     * 濡傛灉浠嶇劧瓒呮檪锛屽墖寮峰埗閫�鍑�.
+     * 鍙﹀鍦╯hutdown鏃剁嚎绋嬫湰韬璋冪敤涓柇鍋氫簡澶勭悊.
+     */
+    public static void shutdownAndAwaitTermination(ExecutorService pool)
+    {
+        if (pool != null && !pool.isShutdown())
+        {
+            pool.shutdown();
+            try
+            {
+                if (!pool.awaitTermination(120, TimeUnit.SECONDS))
+                {
+                    pool.shutdownNow();
+                    if (!pool.awaitTermination(120, TimeUnit.SECONDS))
+                    {
+                        logger.info("Pool did not terminate");
+                    }
+                }
+            }
+            catch (InterruptedException ie)
+            {
+                pool.shutdownNow();
+                Thread.currentThread().interrupt();
+            }
+        }
+    }
+
+    /**
+     * 鎵撳嵃绾跨▼寮傚父淇℃伅
+     */
+    public static void printException(Runnable r, Throwable t)
+    {
+        if (t == null && r instanceof Future<?>)
+        {
+            try
+            {
+                Future<?> future = (Future<?>) r;
+                if (future.isDone())
+                {
+                    future.get();
+                }
+            }
+            catch (CancellationException ce)
+            {
+                t = ce;
+            }
+            catch (ExecutionException ee)
+            {
+                t = ee.getCause();
+            }
+            catch (InterruptedException ie)
+            {
+                Thread.currentThread().interrupt();
+            }
+        }
+        if (t != null)
+        {
+            logger.error(t.getMessage(), t);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java
new file mode 100644
index 0000000..4463662
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanUtils.java
@@ -0,0 +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();
+        }
+    }
+
+    /**
+     * 鑾峰彇瀵硅薄鐨剆etter鏂规硶銆�
+     * 
+     * @param obj 瀵硅薄
+     * @return 瀵硅薄鐨剆etter鏂规硶鍒楄〃
+     */
+    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;
+    }
+
+    /**
+     * 鑾峰彇瀵硅薄鐨刧etter鏂规硶銆�
+     * 
+     * @param obj 瀵硅薄
+     * @return 瀵硅薄鐨刧etter鏂规硶鍒楄〃
+     */
+
+    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;
+    }
+
+    /**
+     * 妫�鏌ean鏂规硶鍚嶄腑鐨勫睘鎬у悕鏄惁鐩哥瓑銆�<br>
+     * 濡俫etName()鍜宻etName()灞炴�у悕涓�鏍凤紝getName()鍜宻etAge()灞炴�у悕涓嶄竴鏍枫��
+     * 
+     * @param m1 鏂规硶鍚�1
+     * @param m2 鏂规硶鍚�2
+     * @return 灞炴�у悕涓�鏍疯繑鍥瀟rue锛屽惁鍒欒繑鍥瀎alse
+     */
+
+    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/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
new file mode 100644
index 0000000..898aca5
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/bean/BeanValidators.java
@@ -0,0 +1,24 @@
+package com.ruoyi.common.utils.bean;
+
+import java.util.Set;
+import jakarta.validation.ConstraintViolation;
+import jakarta.validation.ConstraintViolationException;
+import jakarta.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);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
new file mode 100644
index 0000000..68130b9
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileTypeUtils.java
@@ -0,0 +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;
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
new file mode 100644
index 0000000..a71bb45
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUploadUtils.java
@@ -0,0 +1,277 @@
+package com.ruoyi.common.utils.file;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Paths;
+import java.util.ArrayList;
+import java.util.List;
+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;
+    }
+
+    /**
+     * 鍒犻櫎鍗曚釜鏂囦欢
+     *
+     */
+    public static boolean deleteFile(String filePath){
+        boolean flag = false;
+        File file = new File(filePath);
+        // 璺緞涓烘枃浠朵笖涓嶄负绌哄垯杩涜鍒犻櫎
+        if (file.isFile() && file.exists())
+        {
+            flag = file.delete();
+        }
+        return flag;
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎鏂囦欢
+     *
+     */
+//    public static List<String> deleteFiles(List<String> filePaths){
+//        List<String> failedToDelete = new ArrayList<>();
+//        for (String filePath : filePaths){
+//            boolean success = deleteFile(filePath);
+//            if(!success){
+//                failedToDelete.add(filePath);
+//            }
+//        }
+//        return failedToDelete;
+//    }
+
+    /**
+     * 璁$畻鏂囦欢澶у皬锛堝崟浣峂B锛屼繚鐣�4浣嶅皬鏁帮級
+     *
+     */
+    public static String getFileSize(MultipartFile file){
+        long size = file.getSize();
+        double sizeInMB = size / (1024.0 * 1024.0);
+        String sizeStr = String.format("%.4f",sizeInMB);
+        return sizeStr;
+    }
+
+
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
new file mode 100644
index 0000000..2062b75
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/FileUtils.java
@@ -0,0 +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 jakarta.servlet.http.HttpServletRequest;
+import jakarta.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]+";
+
+    /**
+     * 杈撳嚭鎸囧畾鏂囦欢鐨刡yte鏁扮粍
+     * 
+     * @param filePath 鏂囦欢璺緞
+     * @param os 杈撳嚭娴�
+     * @return
+     */
+    public static void writeBytes(String filePath, OutputStream os) throws IOException
+    {
+        FileInputStream fis = null;
+        try
+        {
+            File file = new File(filePath);
+            if (!file.exists())
+            {
+                throw new FileNotFoundException(filePath);
+            }
+            fis = new FileInputStream(file);
+            byte[] b = new byte[1024];
+            int length;
+            while ((length = fis.read(b)) > 0)
+            {
+                os.write(b, 0, length);
+            }
+        }
+        catch (IOException e)
+        {
+            throw e;
+        }
+        finally
+        {
+            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 姝e父 false 闈炴硶
+     */
+    public static boolean isValidFilename(String filename)
+    {
+        return filename.matches(FILENAME_PATTERN);
+    }
+
+    /**
+     * 妫�鏌ユ枃浠舵槸鍚﹀彲涓嬭浇
+     * 
+     * @param resource 闇�瑕佷笅杞界殑鏂囦欢
+     * @return true 姝e父 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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
new file mode 100644
index 0000000..432dfda
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/ImageUtils.java
@@ -0,0 +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);
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
new file mode 100644
index 0000000..1014949
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/file/MimeTypeUtils.java
@@ -0,0 +1,63 @@
+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",
+            // 瑙嗛鏍煎紡
+            "swf", "flv","mp4", "avi", "rmvb",
+            //闊抽鏍煎紡
+            "swf", "flv", "mp3", "wav", "wma", "wmv", "mid", "avi", "mpg", "asf", "rm", "rmvb",
+            //妯″瀷鏍煎紡
+            "glb","gltf",
+            // 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/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
new file mode 100644
index 0000000..f52e83e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/EscapeUtil.java
@@ -0,0 +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);
+    }
+
+    /**
+     * 娓呴櫎鎵�鏈塇TML鏍囩锛屼絾鏄笉鍒犻櫎鏍囩鍐呯殑鍐呭
+     * 
+     * @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瑙g爜
+     * 
+     * @param content 琚浆涔夌殑鍐呭
+     * @return 瑙g爜鍚庣殑瀛楃涓�
+     */
+    public static String decode(String content)
+    {
+        if (StringUtils.isEmpty(content))
+        {
+            return content;
+        }
+
+        StringBuilder tmp = new StringBuilder(content.length());
+        int lastPos = 0, pos = 0;
+        char ch;
+        while (lastPos < content.length())
+        {
+            pos = content.indexOf("%", lastPos);
+            if (pos == lastPos)
+            {
+                if (content.charAt(pos + 1) == 'u')
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 2, pos + 6), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 6;
+                }
+                else
+                {
+                    ch = (char) Integer.parseInt(content.substring(pos + 1, pos + 3), 16);
+                    tmp.append(ch);
+                    lastPos = pos + 3;
+                }
+            }
+            else
+            {
+                if (pos == -1)
+                {
+                    tmp.append(content.substring(lastPos));
+                    lastPos = content.length();
+                }
+                else
+                {
+                    tmp.append(content.substring(lastPos, pos));
+                    lastPos = pos;
+                }
+            }
+        }
+        return tmp.toString();
+    }
+
+    public static void main(String[] args)
+    {
+        String html = "<script>alert(1);</script>";
+        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/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
new file mode 100644
index 0000000..ebff3fd
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/html/HTMLFilter.java
@@ -0,0 +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;锛岄槻姝son鏍煎紡鏃犳晥 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/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java
new file mode 100644
index 0000000..401f25a
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpHelper.java
@@ -0,0 +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 jakarta.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();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
new file mode 100644
index 0000000..ee97c2c
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/http/HttpUtils.java
@@ -0,0 +1,357 @@
+package com.ruoyi.common.utils.http;
+
+import java.io.*;
+import java.net.*;
+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 鍙戦�丟ET鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendGet(String url)
+    {
+        return sendGet(url, StringUtils.EMPTY);
+    }
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丟ET鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @param param 璇锋眰鍙傛暟锛岃姹傚弬鏁板簲璇ユ槸 name1=value1&name2=value2 鐨勫舰寮忋��
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendGet(String url, String param)
+    {
+        return sendGet(url, param, Constants.UTF8);
+    }
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丟ET鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @param param 璇锋眰鍙傛暟锛岃姹傚弬鏁板簲璇ユ槸 name1=value1&name2=value2 鐨勫舰寮忋��
+     * @param contentType 缂栫爜绫诲瀷
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    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 鍙戦�丳OST鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @param param 璇锋眰鍙傛暟锛岃姹傚弬鏁板簲璇ユ槸 name1=value1&name2=value2 鐨勫舰寮忋��
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendPost(String url, String param)
+    {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            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();
+    }
+
+    /**
+     * 鍚戞寚瀹� URL 鍙戦�丳OST鏂规硶鐨勮姹�
+     *
+     * @param url 鍙戦�佽姹傜殑 URL
+     * @return 鎵�浠h〃杩滅▼璧勬簮鐨勫搷搴旂粨鏋�
+     */
+    public static String sendJsonPost(String url, String jsonString)
+    {
+        PrintWriter out = null;
+        BufferedReader in = null;
+        StringBuilder result = new StringBuilder();
+        try
+        {
+            log.info("sendPost - {}", url);
+            URL realUrl = new URL(url);
+            HttpURLConnection conn = (HttpURLConnection)realUrl.openConnection();
+
+            conn.setRequestMethod("POST");
+            conn.setRequestProperty("Content-Type", "application/json;charset=UTF-8");
+            conn.setRequestProperty("Accept", "*/*");
+//            conn.setRequestProperty("connection", "Keep-Alive");
+//            conn.setRequestProperty("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
+            conn.setDoOutput(true);
+            conn.setDoInput(true);
+            try(OutputStream os = conn.getOutputStream()){
+                byte[] input = jsonString.getBytes("utf-8");
+                os.write(input, 0, input.length);
+            }
+
+            int responseCode = conn.getResponseCode();
+            if(responseCode == HttpURLConnection.HTTP_OK){
+                try(BufferedReader br = new BufferedReader(
+                        new InputStreamReader(conn.getInputStream(), "utf-8")
+                )){
+                    String responseLine;
+                    while ((responseLine = br.readLine()) != null){
+                        result.append(responseLine.trim());
+                    }
+                    System.out.println(result.toString());
+                }
+            }
+            conn.disconnect();
+//            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=" + jsonString, e);
+        }
+        catch (SocketTimeoutException e)
+        {
+            log.error("璋冪敤HttpUtils.sendPost SocketTimeoutException, url=" + url + ",param=" + jsonString, e);
+        }
+        catch (IOException e)
+        {
+            log.error("璋冪敤HttpUtils.sendPost IOException, url=" + url + ",param=" + jsonString, e);
+        }
+        catch (Exception e)
+        {
+            log.error("璋冪敤HttpsUtil.sendPost Exception, url=" + url + ",param=" + jsonString, e);
+        }
+        finally
+        {
+            try
+            {
+                if (out != null)
+                {
+                    out.close();
+                }
+                if (in != null)
+                {
+                    in.close();
+                }
+            }
+            catch (IOException ex)
+            {
+                log.error("璋冪敤in.close Exception, url=" + url + ",param=" + jsonString, 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/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
new file mode 100644
index 0000000..edfe419
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/AddressUtils.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
new file mode 100644
index 0000000..a376416
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/ip/IpUtils.java
@@ -0,0 +1,382 @@
+package com.ruoyi.common.utils.ip;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import jakarta.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 + ")";
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疘P
+     * 
+     * @return IP鍦板潃
+     */
+    public static String getIpAddr()
+    {
+        return getIpAddr(ServletUtils.getRequest());
+    }
+
+    /**
+     * 鑾峰彇瀹㈡埛绔疘P
+     * 
+     * @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;
+        }
+    }
+
+    /**
+     * 灏咺Pv4鍦板潃杞崲鎴愬瓧鑺�
+     * 
+     * @param text IPv4鍦板潃
+     * @return byte 瀛楄妭
+     */
+    public static byte[] textToNumericFormatV4(String text)
+    {
+        if (text.length() == 0)
+        {
+            return null;
+        }
+
+        byte[] bytes = new byte[4];
+        String[] elements = text.split("\\.", -1);
+        try
+        {
+            long l;
+            int i;
+            switch (elements.length)
+            {
+                case 1:
+                    l = Long.parseLong(elements[0]);
+                    if ((l < 0L) || (l > 4294967295L))
+                    {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l >> 24 & 0xFF);
+                    bytes[1] = (byte) (int) ((l & 0xFFFFFF) >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 2:
+                    l = Integer.parseInt(elements[0]);
+                    if ((l < 0L) || (l > 255L))
+                    {
+                        return null;
+                    }
+                    bytes[0] = (byte) (int) (l & 0xFF);
+                    l = Integer.parseInt(elements[1]);
+                    if ((l < 0L) || (l > 16777215L))
+                    {
+                        return null;
+                    }
+                    bytes[1] = (byte) (int) (l >> 16 & 0xFF);
+                    bytes[2] = (byte) (int) ((l & 0xFFFF) >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 3:
+                    for (i = 0; i < 2; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                        {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    l = Integer.parseInt(elements[2]);
+                    if ((l < 0L) || (l > 65535L))
+                    {
+                        return null;
+                    }
+                    bytes[2] = (byte) (int) (l >> 8 & 0xFF);
+                    bytes[3] = (byte) (int) (l & 0xFF);
+                    break;
+                case 4:
+                    for (i = 0; i < 4; ++i)
+                    {
+                        l = Integer.parseInt(elements[i]);
+                        if ((l < 0L) || (l > 255L))
+                        {
+                            return null;
+                        }
+                        bytes[i] = (byte) (int) (l & 0xFF);
+                    }
+                    break;
+                default:
+                    return null;
+            }
+        }
+        catch (NumberFormatException e)
+        {
+            return null;
+        }
+        return bytes;
+    }
+
+    /**
+     * 鑾峰彇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 鑾峰緱鐨処P鍦板潃
+     * @return 绗竴涓潪unknown IP鍦板潃
+     */
+    public static String getMultistageReverseProxyIp(String ip)
+    {
+        // 澶氱骇鍙嶅悜浠g悊妫�娴�
+        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);
+    }
+
+    /**
+     * 妫�娴嬬粰瀹氬瓧绗︿覆鏄惁涓烘湭鐭ワ紝澶氱敤浜庢娴婬TTP璇锋眰鐩稿叧
+     *
+     * @param checkString 琚娴嬬殑瀛楃涓�
+     * @return 鏄惁鏈煡
+     */
+    public static boolean isUnknown(String checkString)
+    {
+        return StringUtils.isBlank(checkString) || "unknown".equalsIgnoreCase(checkString);
+    }
+
+    /**
+     * 鏄惁涓篒P
+     */
+    public static boolean isIP(String ip)
+    {
+        return StringUtils.isNotBlank(ip) && ip.matches(REGX_IP);
+    }
+
+    /**
+     * 鏄惁涓篒P锛屾垨 *涓洪棿闅旂殑閫氶厤绗﹀湴鍧�
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
new file mode 100644
index 0000000..ccab288
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelHandlerAdapter.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
new file mode 100644
index 0000000..5fb8255
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/poi/ExcelUtil.java
@@ -0,0 +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 jakarta.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;
+
+    /**
+     * 瀵煎嚭绫诲瀷锛圗XPORT:瀵煎嚭鏁版嵁锛汭MPORT锛氬鍏ユā鏉匡級
+     */
+    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++;
+        }
+    }
+
+    /**
+     * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist
+     * 
+     * @param is 杈撳叆娴�
+     * @return 杞崲鍚庨泦鍚�
+     */
+    public List<T> importExcel(InputStream is)
+    {
+        return importExcel(is, 0);
+    }
+
+    /**
+     * 瀵筫xcel琛ㄥ崟榛樿绗竴涓储寮曞悕杞崲鎴恖ist
+     * 
+     * @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;
+    }
+
+    /**
+     * 瀵筫xcel琛ㄥ崟鎸囧畾琛ㄦ牸绱㈠紩鍚嶈浆鎹㈡垚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涓猻heet
+        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)
+        {
+            // 瀹氫箟涓�涓猰ap鐢ㄤ簬瀛樻斁excel鍒楃殑搴忓彿鍜宖ield.
+            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);
+                }
+            }
+            // 鏈夋暟鎹椂鎵嶅鐞� 寰楀埌绫荤殑鎵�鏈塮ield.
+            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.getDeclaredConstructor().newInstance() : entity);
+                    // 浠巑ap涓緱鍒板搴斿垪鐨刦ield.
+                    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;
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @param list 瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @return 缁撴灉
+     */
+    public AjaxResult exportExcel(List<T> list, String sheetName)
+    {
+        return exportExcel(list, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @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();
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @param response 杩斿洖鏁版嵁
+     * @param list 瀵煎嚭鏁版嵁闆嗗悎
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @return 缁撴灉
+     */
+    public void exportExcel(HttpServletResponse response, List<T> list, String sheetName)
+    {
+        exportExcel(response, list, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @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);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @return 缁撴灉
+     */
+    public AjaxResult importTemplateExcel(String sheetName)
+    {
+        return importTemplateExcel(sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @param title 鏍囬
+     * @return 缁撴灉
+     */
+    public AjaxResult importTemplateExcel(String sheetName, String title)
+    {
+        this.init(null, sheetName, title, Type.IMPORT);
+        return exportExcel();
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @param sheetName 宸ヤ綔琛ㄧ殑鍚嶇О
+     * @return 缁撴灉
+     */
+    public void importTemplateExcel(HttpServletResponse response, String sheetName)
+    {
+        importTemplateExcel(response, sheetName, StringUtils.EMPTY);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @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);
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @return 缁撴灉
+     */
+    public void exportExcel(HttpServletResponse response)
+    {
+        try
+        {
+            writeSheet();
+            wb.write(response.getOutputStream());
+        }
+        catch (Exception e)
+        {
+            log.error("瀵煎嚭Excel寮傚父{}", e.getMessage());
+        }
+        finally
+        {
+            IOUtils.closeQuietly(wb);
+        }
+    }
+
+    /**
+     * 瀵筶ist鏁版嵁婧愬皢鍏堕噷闈㈢殑鏁版嵁瀵煎叆鍒癳xcel琛ㄥ崟
+     * 
+     * @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);
+        }
+    }
+
+    /**
+     * 鍒涘缓鍐欏叆鏁版嵁鍒癝heet
+     */
+    public void writeSheet()
+    {
+        // 鍙栧嚭涓�鍏辨湁澶氬皯涓猻heet.
+        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瀛楃浣滀负鍓嶇紑锛岄槻姝SV娉ㄥ叆銆�
+            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);
+    }
+
+    /**
+     * 瑙f瀽瀵煎嚭鍊� 0=鐢�,1=濂�,2=鏈煡
+     * 
+     * @param propertyValue 鍙傛暟鍊�
+     * @param converterExp 缈昏瘧娉ㄨВ
+     * @param separator 鍒嗛殧绗�
+     * @return 瑙f瀽鍚庡��
+     */
+    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);
+    }
+
+    /**
+     * 鍙嶅悜瑙f瀽鍊� 鐢�=0,濂�=1,鏈煡=2
+     * 
+     * @param propertyValue 鍙傛暟鍊�
+     * @param converterExp 缈昏瘧娉ㄨВ
+     * @param separator 鍒嗛殧绗�
+     * @return 瑙f瀽鍚庡��
+     */
+    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);
+    }
+
+    /**
+     * 瑙f瀽瀛楀吀鍊�
+     * 
+     * @param dictValue 瀛楀吀鍊�
+     * @param dictType 瀛楀吀绫诲瀷
+     * @param separator 鍒嗛殧绗�
+     * @return 瀛楀吀鏍囩
+     */
+    public static String convertDictByExp(String dictValue, String dictType, String separator)
+    {
+        return DictUtils.getDictLabel(dictType, dictValue, separator);
+    }
+
+    /**
+     * 鍙嶅悜瑙f瀽鍊煎瓧鍏稿��
+     * 
+     * @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().getDeclaredConstructor().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锛塖tring锛寁alue:鍥剧墖娴丳ictureData
+     */
+    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锛塖tring锛寁alue:鍥剧墖娴丳ictureData
+     */
+    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/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
new file mode 100644
index 0000000..b19953e
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/reflect/ReflectUtils.java
@@ -0,0 +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, 琚獳OP杩囩殑鐪熷疄绫荤瓑宸ュ叿鍑芥暟.
+ * 
+ * @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淇グ绗�, 涓嶇粡杩噂etter鍑芥暟.
+     */
+    @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淇グ绗�, 涓嶇粡杩噑etter鍑芥暟.
+     */
+    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);
+        }
+    }
+
+    /**
+     * 寰幆鍚戜笂杞瀷, 鑾峰彇瀵硅薄鐨凞eclaredField, 骞跺己鍒惰缃负鍙闂�.
+     * 濡傚悜涓婅浆鍨嬪埌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;
+    }
+
+    /**
+     * 寰幆鍚戜笂杞瀷, 鑾峰彇瀵硅薄鐨凞eclaredMethod,骞跺己鍒惰缃负鍙闂�.
+     * 濡傚悜涓婅浆鍨嬪埌Object浠嶆棤娉曟壘鍒�, 杩斿洖null.
+     * 鍖归厤鍑芥暟鍚�+鍙傛暟绫诲瀷銆�
+     * 鐢ㄤ簬鏂规硶闇�瑕佽澶氭璋冪敤鐨勬儏鍐�. 鍏堜娇鐢ㄦ湰鍑芥暟鍏堝彇寰桵ethod,鐒跺悗璋冪敤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;
+    }
+
+    /**
+     * 寰幆鍚戜笂杞瀷, 鑾峰彇瀵硅薄鐨凞eclaredMethod,骞跺己鍒惰缃负鍙闂�.
+     * 濡傚悜涓婅浆鍨嬪埌Object浠嶆棤娉曟壘鍒�, 杩斿洖null.
+     * 鍙尮閰嶅嚱鏁板悕銆�
+     * 鐢ㄤ簬鏂规硶闇�瑕佽澶氭璋冪敤鐨勬儏鍐�. 鍏堜娇鐢ㄦ湰鍑芥暟鍏堝彇寰桵ethod,鐒跺悗璋冪敤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鐨凷ecurityManager鎶辨�ㄣ��
+     */
+    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鐨凷ecurityManager鎶辨�ㄣ��
+     */
+    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瀹氫箟涓0鏄庣殑娉涘瀷鍙傛暟鐨勭被鍨�, 娉ㄦ剰娉涘瀷蹇呴』瀹氫箟鍦ㄧ埗绫诲
+     * 濡傛棤娉曟壘鍒�, 杩斿洖Object.class.
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> Class<T> getClassGenricType(final Class clazz)
+    {
+        return getClassGenricType(clazz, 0);
+    }
+
+    /**
+     * 閫氳繃鍙嶅皠, 鑾峰緱Class瀹氫箟涓0鏄庣殑鐖剁被鐨勬硾鍨嬪弬鏁扮殑绫诲瀷.
+     * 濡傛棤娉曟壘鍒�, 杩斿洖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;
+
+    }
+
+    /**
+     * 灏嗗弽灏勬椂鐨刢hecked exception杞崲涓簎nchecked 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/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java
new file mode 100644
index 0000000..ca1cd92
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Base64.java
@@ -0,0 +1,291 @@
+package com.ruoyi.common.utils.sign;
+
+/**
+ * Base64宸ュ叿绫�
+ * 
+ * @author ruoyi
+ */
+public final class Base64
+{
+    static private final int     BASELENGTH           = 128;
+    static private final int     LOOKUPLENGTH         = 64;
+    static private final int     TWENTYFOURBITGROUP   = 24;
+    static private final int     EIGHTBIT             = 8;
+    static private final int     SIXTEENBIT           = 16;
+    static private final int     FOURBYTE             = 4;
+    static private final int     SIGN                 = -128;
+    static private final char    PAD                  = '=';
+    static final private byte[]  base64Alphabet       = new byte[BASELENGTH];
+    static final private char[]  lookUpBase64Alphabet = new char[LOOKUPLENGTH];
+
+    static
+    {
+        for (int i = 0; i < BASELENGTH; ++i)
+        {
+            base64Alphabet[i] = -1;
+        }
+        for (int i = 'Z'; i >= 'A'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'A');
+        }
+        for (int i = 'z'; i >= 'a'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - 'a' + 26);
+        }
+
+        for (int i = '9'; i >= '0'; i--)
+        {
+            base64Alphabet[i] = (byte) (i - '0' + 52);
+        }
+
+        base64Alphabet['+'] = 62;
+        base64Alphabet['/'] = 63;
+
+        for (int i = 0; i <= 25; i++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('A' + i);
+        }
+
+        for (int i = 26, j = 0; i <= 51; i++, j++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('a' + j);
+        }
+
+        for (int i = 52, j = 0; i <= 61; i++, j++)
+        {
+            lookUpBase64Alphabet[i] = (char) ('0' + j);
+        }
+        lookUpBase64Alphabet[62] = (char) '+';
+        lookUpBase64Alphabet[63] = (char) '/';
+    }
+
+    private static boolean isWhiteSpace(char octect)
+    {
+        return (octect == 0x20 || octect == 0xd || octect == 0xa || octect == 0x9);
+    }
+
+    private static boolean isPad(char octect)
+    {
+        return (octect == PAD);
+    }
+
+    private static boolean isData(char octect)
+    {
+        return (octect < BASELENGTH && base64Alphabet[octect] != -1);
+    }
+
+    /**
+     * Encodes hex octects into Base64
+     *
+     * @param binaryData Array containing binaryData
+     * @return Encoded Base64 array
+     */
+    public static String encode(byte[] binaryData)
+    {
+        if (binaryData == null)
+        {
+            return null;
+        }
+
+        int lengthDataBits = binaryData.length * EIGHTBIT;
+        if (lengthDataBits == 0)
+        {
+            return "";
+        }
+
+        int fewerThan24bits = lengthDataBits % TWENTYFOURBITGROUP;
+        int numberTriplets = lengthDataBits / TWENTYFOURBITGROUP;
+        int numberQuartet = fewerThan24bits != 0 ? numberTriplets + 1 : numberTriplets;
+        char encodedData[] = null;
+
+        encodedData = new char[numberQuartet * 4];
+
+        byte k = 0, l = 0, b1 = 0, b2 = 0, b3 = 0;
+
+        int encodedIndex = 0;
+        int dataIndex = 0;
+
+        for (int i = 0; i < numberTriplets; i++)
+        {
+            b1 = binaryData[dataIndex++];
+            b2 = binaryData[dataIndex++];
+            b3 = binaryData[dataIndex++];
+
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+            byte val3 = ((b3 & SIGN) == 0) ? (byte) (b3 >> 6) : (byte) ((b3) >> 6 ^ 0xfc);
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[(l << 2) | val3];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[b3 & 0x3f];
+        }
+
+        // form integral number of 6-bit groups
+        if (fewerThan24bits == EIGHTBIT)
+        {
+            b1 = binaryData[dataIndex];
+            k = (byte) (b1 & 0x03);
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[k << 4];
+            encodedData[encodedIndex++] = PAD;
+            encodedData[encodedIndex++] = PAD;
+        }
+        else if (fewerThan24bits == SIXTEENBIT)
+        {
+            b1 = binaryData[dataIndex];
+            b2 = binaryData[dataIndex + 1];
+            l = (byte) (b2 & 0x0f);
+            k = (byte) (b1 & 0x03);
+
+            byte val1 = ((b1 & SIGN) == 0) ? (byte) (b1 >> 2) : (byte) ((b1) >> 2 ^ 0xc0);
+            byte val2 = ((b2 & SIGN) == 0) ? (byte) (b2 >> 4) : (byte) ((b2) >> 4 ^ 0xf0);
+
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val1];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[val2 | (k << 4)];
+            encodedData[encodedIndex++] = lookUpBase64Alphabet[l << 2];
+            encodedData[encodedIndex++] = PAD;
+        }
+        return new String(encodedData);
+    }
+
+    /**
+     * Decodes Base64 data into octects
+     *
+     * @param encoded string containing Base64 data
+     * @return Array containind decoded data.
+     */
+    public static byte[] decode(String encoded)
+    {
+        if (encoded == null)
+        {
+            return null;
+        }
+
+        char[] base64Data = encoded.toCharArray();
+        // remove white spaces
+        int len = removeWhiteSpace(base64Data);
+
+        if (len % FOURBYTE != 0)
+        {
+            return null;// should be divisible by four
+        }
+
+        int numberQuadruple = (len / FOURBYTE);
+
+        if (numberQuadruple == 0)
+        {
+            return new byte[0];
+        }
+
+        byte decodedData[] = null;
+        byte b1 = 0, b2 = 0, b3 = 0, b4 = 0;
+        char d1 = 0, d2 = 0, d3 = 0, d4 = 0;
+
+        int i = 0;
+        int encodedIndex = 0;
+        int dataIndex = 0;
+        decodedData = new byte[(numberQuadruple) * 3];
+
+        for (; i < numberQuadruple - 1; i++)
+        {
+
+            if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++]))
+                    || !isData((d3 = base64Data[dataIndex++])) || !isData((d4 = base64Data[dataIndex++])))
+            {
+                return null;
+            } // if found "no data" just return null
+
+            b1 = base64Alphabet[d1];
+            b2 = base64Alphabet[d2];
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+        }
+
+        if (!isData((d1 = base64Data[dataIndex++])) || !isData((d2 = base64Data[dataIndex++])))
+        {
+            return null;// if found "no data" just return null
+        }
+
+        b1 = base64Alphabet[d1];
+        b2 = base64Alphabet[d2];
+
+        d3 = base64Data[dataIndex++];
+        d4 = base64Data[dataIndex++];
+        if (!isData((d3)) || !isData((d4)))
+        {// Check if they are PAD characters
+            if (isPad(d3) && isPad(d4))
+            {
+                if ((b2 & 0xf) != 0)// last 4 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 1];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex] = (byte) (b1 << 2 | b2 >> 4);
+                return tmp;
+            }
+            else if (!isPad(d3) && isPad(d4))
+            {
+                b3 = base64Alphabet[d3];
+                if ((b3 & 0x3) != 0)// last 2 bits should be zero
+                {
+                    return null;
+                }
+                byte[] tmp = new byte[i * 3 + 2];
+                System.arraycopy(decodedData, 0, tmp, 0, i * 3);
+                tmp[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+                tmp[encodedIndex] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+                return tmp;
+            }
+            else
+            {
+                return null;
+            }
+        }
+        else
+        { // No PAD e.g 3cQl
+            b3 = base64Alphabet[d3];
+            b4 = base64Alphabet[d4];
+            decodedData[encodedIndex++] = (byte) (b1 << 2 | b2 >> 4);
+            decodedData[encodedIndex++] = (byte) (((b2 & 0xf) << 4) | ((b3 >> 2) & 0xf));
+            decodedData[encodedIndex++] = (byte) (b3 << 6 | b4);
+
+        }
+        return decodedData;
+    }
+
+    /**
+     * remove WhiteSpace from MIME containing encoded Base64 data.
+     *
+     * @param data the byte array of base64 data (with WS)
+     * @return the new length
+     */
+    private static int removeWhiteSpace(char[] data)
+    {
+        if (data == null)
+        {
+            return 0;
+        }
+
+        // count characters that's not whitespace
+        int newSize = 0;
+        int len = data.length;
+        for (int i = 0; i < len; i++)
+        {
+            if (!isWhiteSpace(data[i]))
+            {
+                data[newSize++] = data[i];
+            }
+        }
+        return newSize;
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java
new file mode 100644
index 0000000..c1c58db
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sign/Md5Utils.java
@@ -0,0 +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;
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
new file mode 100644
index 0000000..f290ec3
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/spring/SpringUtils.java
@@ -0,0 +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绠$悊鐜涓幏鍙朾ean
+ * 
+ * @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);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷涓簉equiredType鐨勫璞�
+     *
+     * @param clz
+     * @return
+     * @throws org.springframework.beans.BeansException
+     *
+     */
+    public static <T> T getBean(Class<T> clz) throws BeansException
+    {
+        T result = (T) beanFactory.getBean(clz);
+        return result;
+    }
+
+    /**
+     * 濡傛灉BeanFactory鍖呭惈涓�涓笌鎵�缁欏悕绉板尮閰嶇殑bean瀹氫箟锛屽垯杩斿洖true
+     *
+     * @param name
+     * @return boolean
+     */
+    public static boolean containsBean(String name)
+    {
+        return beanFactory.containsBean(name);
+    }
+
+    /**
+     * 鍒ゆ柇浠ョ粰瀹氬悕瀛楁敞鍐岀殑bean瀹氫箟鏄竴涓猻ingleton杩樻槸涓�涓猵rototype銆� 濡傛灉涓庣粰瀹氬悕瀛楃浉搴旂殑bean瀹氫箟娌℃湁琚壘鍒帮紝灏嗕細鎶涘嚭涓�涓紓甯革紙NoSuchBeanDefinitionException锛�
+     *
+     * @param name
+     * @return boolean
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static boolean isSingleton(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.isSingleton(name);
+    }
+
+    /**
+     * @param name
+     * @return Class 娉ㄥ唽瀵硅薄鐨勭被鍨�
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static Class<?> getType(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getType(name);
+    }
+
+    /**
+     * 濡傛灉缁欏畾鐨刡ean鍚嶅瓧鍦╞ean瀹氫箟涓湁鍒悕锛屽垯杩斿洖杩欎簺鍒悕
+     *
+     * @param name
+     * @return
+     * @throws org.springframework.beans.factory.NoSuchBeanDefinitionException
+     *
+     */
+    public static String[] getAliases(String name) throws NoSuchBeanDefinitionException
+    {
+        return beanFactory.getAliases(name);
+    }
+
+    /**
+     * 鑾峰彇aop浠g悊瀵硅薄
+     * 
+     * @param invoker
+     * @return
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T getAopProxy(T invoker)
+    {
+        return (T) AopContext.currentProxy();
+    }
+
+    /**
+     * 鑾峰彇褰撳墠鐨勭幆澧冮厤缃紝鏃犻厤缃繑鍥瀗ull
+     *
+     * @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 閰嶇疆鏂囦欢鐨刱ey
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
new file mode 100644
index 0000000..48720dc
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/sql/SqlUtil.java
@@ -0,0 +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娉ㄥ叆椋庨櫓");
+            }
+        }
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java
new file mode 100644
index 0000000..2c84427
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/IdUtils.java
@@ -0,0 +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锛屼娇鐢ㄦ�ц兘鏇村ソ鐨凾hreadLocalRandom鐢熸垚UUID
+     * 
+     * @return 闅忔満UUID
+     */
+    public static String fastUUID()
+    {
+        return UUID.fastUUID().toString();
+    }
+
+    /**
+     * 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎锛屼娇鐢ㄦ�ц兘鏇村ソ鐨凾hreadLocalRandom鐢熸垚UUID
+     * 
+     * @return 绠�鍖栫殑UUID锛屽幓鎺変簡妯嚎
+     */
+    public static String fastSimpleUUID()
+    {
+        return UUID.fastUUID().toString(true);
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
new file mode 100644
index 0000000..bf99611
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/Seq.java
@@ -0,0 +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宸﹁ˉ榻恖ength浣嶆暟
+     * 
+     * @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/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
new file mode 100644
index 0000000..a5585d6
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/utils/uuid/UUID.java
@@ -0,0 +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();
+    }
+
+    /** 姝UID鐨勬渶楂�64鏈夋晥浣� */
+    private final long mostSigBits;
+
+    /** 姝UID鐨勬渶浣�64鏈夋晥浣� */
+    private final long leastSigBits;
+
+    /**
+     * 绉佹湁鏋勯��
+     * 
+     * @param data 鏁版嵁
+     */
+    private UUID(byte[] data)
+    {
+        long msb = 0;
+        long lsb = 0;
+        assert data.length == 16 : "data must be 16 bytes in length";
+        for (int i = 0; i < 8; i++)
+        {
+            msb = (msb << 8) | (data[i] & 0xff);
+        }
+        for (int i = 8; i < 16; i++)
+        {
+            lsb = (lsb << 8) | (data[i] & 0xff);
+        }
+        this.mostSigBits = msb;
+        this.leastSigBits = lsb;
+    }
+
+    /**
+     * 浣跨敤鎸囧畾鐨勬暟鎹瀯閫犳柊鐨� UUID銆�
+     *
+     * @param mostSigBits 鐢ㄤ簬 {@code UUID} 鐨勬渶楂樻湁鏁� 64 浣�
+     * @param leastSigBits 鐢ㄤ簬 {@code UUID} 鐨勬渶浣庢湁鏁� 64 浣�
+     */
+    public UUID(long mostSigBits, long leastSigBits)
+    {
+        this.mostSigBits = mostSigBits;
+        this.leastSigBits = leastSigBits;
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘��
+     * 
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID fastUUID()
+    {
+        return randomUUID(false);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘�� 浣跨敤鍔犲瘑鐨勫己浼殢鏈烘暟鐢熸垚鍣ㄧ敓鎴愯 UUID銆�
+     * 
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID randomUUID()
+    {
+        return randomUUID(true);
+    }
+
+    /**
+     * 鑾峰彇绫诲瀷 4锛堜吉闅忔満鐢熸垚鐨勶級UUID 鐨勯潤鎬佸伐鍘傘�� 浣跨敤鍔犲瘑鐨勫己浼殢鏈烘暟鐢熸垚鍣ㄧ敓鎴愯 UUID銆�
+     * 
+     * @param isSecure 鏄惁浣跨敤{@link SecureRandom}濡傛灉鏄彲浠ヨ幏寰楁洿瀹夊叏鐨勯殢鏈虹爜锛屽惁鍒欏彲浠ュ緱鍒版洿濂界殑鎬ц兘
+     * @return 闅忔満鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID randomUUID(boolean isSecure)
+    {
+        final Random ng = isSecure ? Holder.numberGenerator : getRandom();
+
+        byte[] randomBytes = new byte[16];
+        ng.nextBytes(randomBytes);
+        randomBytes[6] &= 0x0f; /* clear version */
+        randomBytes[6] |= 0x40; /* set to version 4 */
+        randomBytes[8] &= 0x3f; /* clear variant */
+        randomBytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(randomBytes);
+    }
+
+    /**
+     * 鏍规嵁鎸囧畾鐨勫瓧鑺傛暟缁勮幏鍙栫被鍨� 3锛堝熀浜庡悕绉扮殑锛塙UID 鐨勯潤鎬佸伐鍘傘��
+     *
+     * @param name 鐢ㄤ簬鏋勯�� UUID 鐨勫瓧鑺傛暟缁勩��
+     *
+     * @return 鏍规嵁鎸囧畾鏁扮粍鐢熸垚鐨� {@code UUID}
+     */
+    public static UUID nameUUIDFromBytes(byte[] name)
+    {
+        MessageDigest md;
+        try
+        {
+            md = MessageDigest.getInstance("MD5");
+        }
+        catch (NoSuchAlgorithmException nsae)
+        {
+            throw new InternalError("MD5 not supported");
+        }
+        byte[] md5Bytes = md.digest(name);
+        md5Bytes[6] &= 0x0f; /* clear version */
+        md5Bytes[6] |= 0x30; /* set to version 3 */
+        md5Bytes[8] &= 0x3f; /* clear variant */
+        md5Bytes[8] |= 0x80; /* set to IETF variant */
+        return new UUID(md5Bytes);
+    }
+
+    /**
+     * 鏍规嵁 {@link #toString()} 鏂规硶涓弿杩扮殑瀛楃涓叉爣鍑嗚〃绀哄舰寮忓垱寤簕@code UUID}銆�
+     *
+     * @param name 鎸囧畾 {@code UUID} 瀛楃涓�
+     * @return 鍏锋湁鎸囧畾鍊肩殑 {@code UUID}
+     * @throws IllegalArgumentException 濡傛灉 name 涓� {@link #toString} 涓弿杩扮殑瀛楃涓茶〃绀哄舰寮忎笉绗︽姏鍑烘寮傚父
+     *
+     */
+    public static UUID fromString(String name)
+    {
+        String[] components = name.split("-");
+        if (components.length != 5)
+        {
+            throw new IllegalArgumentException("Invalid UUID string: " + name);
+        }
+        for (int i = 0; i < 5; i++)
+        {
+            components[i] = "0x" + components[i];
+        }
+
+        long mostSigBits = Long.decode(components[0]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[1]).longValue();
+        mostSigBits <<= 16;
+        mostSigBits |= Long.decode(components[2]).longValue();
+
+        long leastSigBits = Long.decode(components[3]).longValue();
+        leastSigBits <<= 48;
+        leastSigBits |= Long.decode(components[4]).longValue();
+
+        return new UUID(mostSigBits, leastSigBits);
+    }
+
+    /**
+     * 杩斿洖姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶浣庢湁鏁� 64 浣嶃��
+     *
+     * @return 姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶浣庢湁鏁� 64 浣嶃��
+     */
+    public long getLeastSignificantBits()
+    {
+        return leastSigBits;
+    }
+
+    /**
+     * 杩斿洖姝� UUID 鐨� 128 浣嶅�间腑鐨勬渶楂樻湁鏁� 64 浣嶃��
+     *
+     * @return 姝� UUID 鐨� 128 浣嶅�间腑鏈�楂樻湁鏁� 64 浣嶃��
+     */
+    public long getMostSignificantBits()
+    {
+        return mostSigBits;
+    }
+
+    /**
+     * 涓庢 {@code UUID} 鐩稿叧鑱旂殑鐗堟湰鍙�. 鐗堟湰鍙锋弿杩版 {@code UUID} 鏄浣曠敓鎴愮殑銆�
+     * <p>
+     * 鐗堟湰鍙峰叿鏈変互涓嬪惈鎰�:
+     * <ul>
+     * <li>1 鍩轰簬鏃堕棿鐨� UUID
+     * <li>2 DCE 瀹夊叏 UUID
+     * <li>3 鍩轰簬鍚嶇О鐨� UUID
+     * <li>4 闅忔満鐢熸垚鐨� UUID
+     * </ul>
+     *
+     * @return 姝� {@code UUID} 鐨勭増鏈彿
+     */
+    public int version()
+    {
+        // Version is bits masked by 0x000000000000F000 in MS long
+        return (int) ((mostSigBits >> 12) & 0x0f);
+    }
+
+    /**
+     * 涓庢 {@code UUID} 鐩稿叧鑱旂殑鍙樹綋鍙枫�傚彉浣撳彿鎻忚堪 {@code UUID} 鐨勫竷灞�銆�
+     * <p>
+     * 鍙樹綋鍙峰叿鏈変互涓嬪惈鎰忥細
+     * <ul>
+     * <li>0 涓� NCS 鍚戝悗鍏煎淇濈暀
+     * <li>2 <a href="http://www.ietf.org/rfc/rfc4122.txt">IETF&nbsp;RFC&nbsp;4122</a>(Leach-Salz), 鐢ㄤ簬姝ょ被
+     * <li>6 淇濈暀锛屽井杞悜鍚庡吋瀹�
+     * <li>7 淇濈暀渚涗互鍚庡畾涔変娇鐢�
+     * </ul>
+     *
+     * @return 姝� {@code UUID} 鐩稿叧鑱旂殑鍙樹綋鍙�
+     */
+    public int variant()
+    {
+        // This field is composed of a varying number of bits.
+        // 0 - - Reserved for NCS backward compatibility
+        // 1 0 - The IETF aka Leach-Salz variant (used by this class)
+        // 1 1 0 Reserved, Microsoft backward compatibility
+        // 1 1 1 Reserved for future definition.
+        return (int) ((leastSigBits >>> (64 - (leastSigBits >>> 62))) & (leastSigBits >> 63));
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鑱旂殑鏃堕棿鎴冲�笺��
+     *
+     * <p>
+     * 60 浣嶇殑鏃堕棿鎴冲�兼牴鎹 {@code UUID} 鐨� time_low銆乼ime_mid 鍜� time_hi 瀛楁鏋勯�犮��<br>
+     * 鎵�寰楀埌鐨勬椂闂存埑浠� 100 姣井绉掍负鍗曚綅锛屼粠 UTC锛堥�氱敤鍗忚皟鏃堕棿锛� 1582 骞� 10 鏈� 15 鏃ラ浂鏃跺紑濮嬨��
+     *
+     * <p>
+     * 鏃堕棿鎴冲�间粎鍦ㄥ湪鍩轰簬鏃堕棿鐨� UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆�<br>
+     * 濡傛灉姝� {@code UUID} 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑� UnsupportedOperationException銆�
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� {@code UUID} 涓嶆槸 version 涓� 1 鐨� UUID銆�
+     */
+    public long timestamp() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return (mostSigBits & 0x0FFFL) << 48//
+                | ((mostSigBits >> 16) & 0x0FFFFL) << 32//
+                | mostSigBits >>> 32;
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鑱旂殑鏃堕挓搴忓垪鍊笺��
+     *
+     * <p>
+     * 14 浣嶇殑鏃堕挓搴忓垪鍊兼牴鎹 UUID 鐨� clock_seq 瀛楁鏋勯�犮�俢lock_seq 瀛楁鐢ㄤ簬淇濊瘉鍦ㄥ熀浜庢椂闂寸殑 UUID 涓殑鏃堕棿鍞竴鎬с��
+     * <p>
+     * {@code clockSequence} 鍊间粎鍦ㄥ熀浜庢椂闂寸殑 UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆� 濡傛灉姝� UUID 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑�
+     * UnsupportedOperationException銆�
+     *
+     * @return 姝� {@code UUID} 鐨勬椂閽熷簭鍒�
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� UUID 鐨� version 涓嶄负 1
+     */
+    public int clockSequence() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return (int) ((leastSigBits & 0x3FFF000000000000L) >>> 48);
+    }
+
+    /**
+     * 涓庢 UUID 鐩稿叧鐨勮妭鐐瑰�笺��
+     *
+     * <p>
+     * 48 浣嶇殑鑺傜偣鍊兼牴鎹 UUID 鐨� node 瀛楁鏋勯�犮�傛瀛楁鏃ㄥ湪鐢ㄤ簬淇濆瓨鏈哄櫒鐨� IEEE 802 鍦板潃锛岃鍦板潃鐢ㄤ簬鐢熸垚姝� UUID 浠ヤ繚璇佺┖闂村敮涓�鎬с��
+     * <p>
+     * 鑺傜偣鍊间粎鍦ㄥ熀浜庢椂闂寸殑 UUID锛堝叾 version 绫诲瀷涓� 1锛変腑鎵嶆湁鎰忎箟銆�<br>
+     * 濡傛灉姝� UUID 涓嶆槸鍩轰簬鏃堕棿鐨� UUID锛屽垯姝ゆ柟娉曟姏鍑� UnsupportedOperationException銆�
+     *
+     * @return 姝� {@code UUID} 鐨勮妭鐐瑰��
+     *
+     * @throws UnsupportedOperationException 濡傛灉姝� UUID 鐨� version 涓嶄负 1
+     */
+    public long node() throws UnsupportedOperationException
+    {
+        checkTimeBase();
+        return leastSigBits & 0x0000FFFFFFFFFFFFL;
+    }
+
+    /**
+     * 杩斿洖姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡銆�
+     *
+     * <p>
+     * UUID 鐨勫瓧绗︿覆琛ㄧず褰㈠紡鐢辨 BNF 鎻忚堪锛�
+     * 
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     * 
+     * </blockquote>
+     *
+     * @return 姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡
+     * @see #toString(boolean)
+     */
+    @Override
+    public String toString()
+    {
+        return toString(false);
+    }
+
+    /**
+     * 杩斿洖姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡銆�
+     *
+     * <p>
+     * UUID 鐨勫瓧绗︿覆琛ㄧず褰㈠紡鐢辨 BNF 鎻忚堪锛�
+     * 
+     * <pre>
+     * {@code
+     * UUID                   = <time_low>-<time_mid>-<time_high_and_version>-<variant_and_sequence>-<node>
+     * time_low               = 4*<hexOctet>
+     * time_mid               = 2*<hexOctet>
+     * time_high_and_version  = 2*<hexOctet>
+     * variant_and_sequence   = 2*<hexOctet>
+     * node                   = 6*<hexOctet>
+     * hexOctet               = <hexDigit><hexDigit>
+     * hexDigit               = [0-9a-fA-F]
+     * }
+     * </pre>
+     * 
+     * </blockquote>
+     *
+     * @param isSimple 鏄惁绠�鍗曟ā寮忥紝绠�鍗曟ā寮忎负涓嶅甫'-'鐨刄UID瀛楃涓�
+     * @return 姝@code UUID} 鐨勫瓧绗︿覆琛ㄧ幇褰㈠紡
+     */
+    public String toString(boolean isSimple)
+    {
+        final StringBuilder builder = new StringBuilder(isSimple ? 32 : 36);
+        // time_low
+        builder.append(digits(mostSigBits >> 32, 8));
+        if (!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
+    /**
+     * 杩斿洖鎸囧畾鏁板瓧瀵瑰簲鐨刪ex鍊�
+     * 
+     * @param val 鍊�
+     * @param digits 浣�
+     * @return 鍊�
+     */
+    private static String digits(long val, int digits)
+    {
+        long hi = 1L << (digits * 4);
+        return Long.toHexString(hi | (val & (hi - 1))).substring(1);
+    }
+
+    /**
+     * 妫�鏌ユ槸鍚︿负time-based鐗堟湰UUID
+     */
+    private void checkTimeBase()
+    {
+        if (version() != 1)
+        {
+            throw new UnsupportedOperationException("Not a time-based UUID");
+        }
+    }
+
+    /**
+     * 鑾峰彇{@link SecureRandom}锛岀被鎻愪緵鍔犲瘑鐨勫己闅忔満鏁扮敓鎴愬櫒 (RNG)
+     * 
+     * @return {@link SecureRandom}
+     */
+    public static SecureRandom getSecureRandom()
+    {
+        try
+        {
+            return SecureRandom.getInstance("SHA1PRNG");
+        }
+        catch (NoSuchAlgorithmException e)
+        {
+            throw new UtilException(e);
+        }
+    }
+
+    /**
+     * 鑾峰彇闅忔満鏁扮敓鎴愬櫒瀵硅薄<br>
+     * ThreadLocalRandom鏄疛DK 7涔嬪悗鎻愪緵骞跺彂浜х敓闅忔満鏁帮紝鑳藉瑙e喅澶氫釜绾跨▼鍙戠敓鐨勭珵浜変簤澶恒��
+     * 
+     * @return {@link ThreadLocalRandom}
+     */
+    public static ThreadLocalRandom getRandom()
+    {
+        return ThreadLocalRandom.current();
+    }
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java b/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
new file mode 100644
index 0000000..cb4b408
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/xss/Xss.java
@@ -0,0 +1,27 @@
+package com.ruoyi.common.xss;
+
+import jakarta.validation.Constraint;
+import jakarta.validation.Payload;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * 鑷畾涔墄ss鏍¢獙娉ㄨВ
+ * 
+ * @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 {};
+}
diff --git a/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
new file mode 100644
index 0000000..7c8e4c0
--- /dev/null
+++ b/ruoyi-common/src/main/java/com/ruoyi/common/xss/XssValidator.java
@@ -0,0 +1,39 @@
+package com.ruoyi.common.xss;
+
+import com.ruoyi.common.utils.StringUtils;
+import jakarta.validation.ConstraintValidator;
+import jakarta.validation.ConstraintValidatorContext;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 鑷畾涔墄ss鏍¢獙娉ㄨВ瀹炵幇
+ * 
+ * @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();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-framework/pom.xml b/ruoyi-framework/pom.xml
new file mode 100644
index 0000000..5456102
--- /dev/null
+++ b/ruoyi-framework/pom.xml
@@ -0,0 +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-3-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>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi-framework/ruoyi-framework.iml b/ruoyi-framework/ruoyi-framework.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-framework/ruoyi-framework.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
new file mode 100644
index 0000000..b2337c9
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataScopeAspect.java
@@ -0,0 +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
+                {
+                    // 鏁版嵁鏉冮檺涓轰粎鏈汉涓旀病鏈塽serAlias鍒悕涓嶆煡璇换浣曟暟鎹�
+                    sqlString.append(StringUtils.format(" OR {}.dept_id = 0 ", deptAlias));
+                }
+            }
+            conditions.add(dataScope);
+        }
+
+        // 瑙掕壊閮戒笉鍖呭惈浼犻�掕繃鏉ョ殑鏉冮檺瀛楃锛岃繖涓椂鍊檚qlString涔熶細涓虹┖锛屾墍浠ヨ闄愬埗涓�涓�,涓嶆煡璇换浣曟暟鎹�
+        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/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
new file mode 100644
index 0000000..8c2c9f4
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/DataSourceAspect.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
new file mode 100644
index 0000000..19429c0
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/LogAspect.java
@@ -0,0 +1,254 @@
+package com.ruoyi.framework.aspectj;
+
+import java.util.Collection;
+import java.util.Map;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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());
+        // 鏄惁闇�瑕佷繚瀛榬equest锛屽弬鏁板拰鍊�
+        if (log.isSaveRequestData())
+        {
+            // 鑾峰彇鍙傛暟鐨勪俊鎭紝浼犲叆鍒版暟鎹簱涓��
+            setRequestValue(joinPoint, operLog, log.excludeParamNames());
+        }
+        // 鏄惁闇�瑕佷繚瀛榬esponse锛屽弬鏁板拰鍊�
+        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锛涘惁鍒欒繑鍥瀎alse銆�
+     */
+    @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/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
new file mode 100644
index 0000000..b720bc1
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/aspectj/RateLimiterAspect.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
new file mode 100644
index 0000000..666decb
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ApplicationConfig.java
@@ -0,0 +1,28 @@
+package com.ruoyi.framework.config;
+
+import java.util.TimeZone;
+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绫荤殑鍖呯殑璺緞
+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/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
new file mode 100644
index 0000000..43e78ae
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/CaptchaConfig.java
@@ -0,0 +1,83 @@
+package com.ruoyi.framework.config;
+
+import java.util.Properties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import com.google.code.kaptcha.impl.DefaultKaptcha;
+import com.google.code.kaptcha.util.Config;
+import static com.google.code.kaptcha.Constants.*;
+
+/**
+ * 楠岃瘉鐮侀厤缃�
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class CaptchaConfig
+{
+    @Bean(name = "captchaProducer")
+    public DefaultKaptcha getKaptchaBean()
+    {
+        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+        Properties properties = new Properties();
+        // 鏄惁鏈夎竟妗� 榛樿涓簍rue 鎴戜滑鍙互鑷繁璁剧疆yes锛宯o
+        properties.setProperty(KAPTCHA_BORDER, "yes");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹂鑹� 榛樿涓篊olor.BLACK
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "black");
+        // 楠岃瘉鐮佸浘鐗囧搴� 榛樿涓�200
+        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+        // 楠岃瘉鐮佸浘鐗囬珮搴� 榛樿涓�50
+        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹀ぇ灏� 榛樿涓�40
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "38");
+        // KAPTCHA_SESSION_KEY
+        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCode");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹂暱搴� 榛樿涓�5
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "4");
+        // 楠岃瘉鐮佹枃鏈瓧浣撴牱寮� 榛樿涓簄ew Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+        // 鍥剧墖鏍峰紡 姘寸汗com.google.code.kaptcha.impl.WaterRipple 楸肩溂com.google.code.kaptcha.impl.FishEyeGimpy 闃村奖com.google.code.kaptcha.impl.ShadowGimpy
+        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+        Config config = new Config(properties);
+        defaultKaptcha.setConfig(config);
+        return defaultKaptcha;
+    }
+
+    @Bean(name = "captchaProducerMath")
+    public DefaultKaptcha getKaptchaBeanMath()
+    {
+        DefaultKaptcha defaultKaptcha = new DefaultKaptcha();
+        Properties properties = new Properties();
+        // 鏄惁鏈夎竟妗� 榛樿涓簍rue 鎴戜滑鍙互鑷繁璁剧疆yes锛宯o
+        properties.setProperty(KAPTCHA_BORDER, "yes");
+        // 杈规棰滆壊 榛樿涓篊olor.BLACK
+        properties.setProperty(KAPTCHA_BORDER_COLOR, "105,179,90");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹂鑹� 榛樿涓篊olor.BLACK
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_COLOR, "blue");
+        // 楠岃瘉鐮佸浘鐗囧搴� 榛樿涓�200
+        properties.setProperty(KAPTCHA_IMAGE_WIDTH, "160");
+        // 楠岃瘉鐮佸浘鐗囬珮搴� 榛樿涓�50
+        properties.setProperty(KAPTCHA_IMAGE_HEIGHT, "60");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹀ぇ灏� 榛樿涓�40
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_SIZE, "35");
+        // KAPTCHA_SESSION_KEY
+        properties.setProperty(KAPTCHA_SESSION_CONFIG_KEY, "kaptchaCodeMath");
+        // 楠岃瘉鐮佹枃鏈敓鎴愬櫒
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_IMPL, "com.ruoyi.framework.config.KaptchaTextCreator");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹂棿璺� 榛樿涓�2
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_SPACE, "3");
+        // 楠岃瘉鐮佹枃鏈瓧绗﹂暱搴� 榛樿涓�5
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_CHAR_LENGTH, "6");
+        // 楠岃瘉鐮佹枃鏈瓧浣撴牱寮� 榛樿涓簄ew Font("Arial", 1, fontSize), new Font("Courier", 1, fontSize)
+        properties.setProperty(KAPTCHA_TEXTPRODUCER_FONT_NAMES, "Arial,Courier");
+        // 楠岃瘉鐮佸櫔鐐归鑹� 榛樿涓篊olor.BLACK
+        properties.setProperty(KAPTCHA_NOISE_COLOR, "white");
+        // 骞叉壈瀹炵幇绫�
+        properties.setProperty(KAPTCHA_NOISE_IMPL, "com.google.code.kaptcha.impl.NoNoise");
+        // 鍥剧墖鏍峰紡 姘寸汗com.google.code.kaptcha.impl.WaterRipple 楸肩溂com.google.code.kaptcha.impl.FishEyeGimpy 闃村奖com.google.code.kaptcha.impl.ShadowGimpy
+        properties.setProperty(KAPTCHA_OBSCURIFICATOR_IMPL, "com.google.code.kaptcha.impl.ShadowGimpy");
+        Config config = new Config(properties);
+        defaultKaptcha.setConfig(config);
+        return defaultKaptcha;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
new file mode 100644
index 0000000..d9cb8c5
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/DruidConfig.java
@@ -0,0 +1,126 @@
+package com.ruoyi.framework.config;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Map;
+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.boot3.autoconfigure.DruidDataSourceBuilder;
+import com.alibaba.druid.spring.boot3.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;
+import jakarta.servlet.Filter;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.ServletRequest;
+import jakarta.servlet.ServletResponse;
+
+/**
+ * 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(jakarta.servlet.FilterConfig filterConfig) throws ServletException
+            {
+            }
+            @Override
+            public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
+                    throws IOException, ServletException
+            {
+                chain.doFilter(request, response);
+                // 閲嶇疆缂撳啿鍖猴紝鍝嶅簲澶翠笉浼氳閲嶇疆
+                response.resetBuffer();
+                // 鑾峰彇common.js
+                String text = Utils.readFromResource(filePath);
+                // 姝e垯鏇挎崲banner, 闄ゅ幓搴曢儴鐨勫箍鍛婁俊鎭�
+                text = text.replaceAll("<a.*?banner\"></a><br/>", "");
+                text = text.replaceAll("powered.*?shrek.wang</a>", "");
+                response.getWriter().write(text);
+            }
+            @Override
+            public void destroy()
+            {
+            }
+        };
+        FilterRegistrationBean registrationBean = new FilterRegistrationBean();
+        registrationBean.setFilter(filter);
+        registrationBean.addUrlPatterns(commonJsPattern);
+        return registrationBean;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
new file mode 100644
index 0000000..4adbb7f
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FastJson2JsonRedisSerializer.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
new file mode 100644
index 0000000..fad6bb8
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/FilterConfig.java
@@ -0,0 +1,58 @@
+package com.ruoyi.framework.config;
+
+import java.util.HashMap;
+import java.util.Map;
+import jakarta.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;
+    }
+
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
new file mode 100644
index 0000000..163fd01
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/I18nConfig.java
@@ -0,0 +1,43 @@
+package com.ruoyi.framework.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.servlet.LocaleResolver;
+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;
+
+/**
+ * 璧勬簮鏂囦欢閰嶇疆鍔犺浇
+ * 
+ * @author ruoyi
+ */
+@Configuration
+public class I18nConfig implements WebMvcConfigurer
+{
+    @Bean
+    public LocaleResolver localeResolver()
+    {
+        SessionLocaleResolver slr = new SessionLocaleResolver();
+        // 榛樿璇█
+        slr.setDefaultLocale(Constants.DEFAULT_LOCALE);
+        return slr;
+    }
+
+    @Bean
+    public LocaleChangeInterceptor localeChangeInterceptor()
+    {
+        LocaleChangeInterceptor lci = new LocaleChangeInterceptor();
+        // 鍙傛暟鍚�
+        lci.setParamName("lang");
+        return lci;
+    }
+
+    @Override
+    public void addInterceptors(InterceptorRegistry registry)
+    {
+        registry.addInterceptor(localeChangeInterceptor());
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
new file mode 100644
index 0000000..7f8e1d5
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/KaptchaTextCreator.java
@@ -0,0 +1,68 @@
+package com.ruoyi.framework.config;
+
+import java.util.Random;
+import com.google.code.kaptcha.text.impl.DefaultTextCreator;
+
+/**
+ * 楠岃瘉鐮佹枃鏈敓鎴愬櫒
+ *
+ * @author ruoyi
+ */
+public class KaptchaTextCreator extends DefaultTextCreator
+{
+    private static final String[] CNUMBERS = "0,1,2,3,4,5,6,7,8,9,10".split(",");
+
+    @Override
+    public String getText()
+    {
+        Integer result = 0;
+        Random random = new Random();
+        int x = random.nextInt(10);
+        int y = random.nextInt(10);
+        StringBuilder suChinese = new StringBuilder();
+        int randomoperands = random.nextInt(3);
+        if (randomoperands == 0)
+        {
+            result = x * y;
+            suChinese.append(CNUMBERS[x]);
+            suChinese.append("*");
+            suChinese.append(CNUMBERS[y]);
+        }
+        else if (randomoperands == 1)
+        {
+            if ((x != 0) && y % x == 0)
+            {
+                result = y / x;
+                suChinese.append(CNUMBERS[y]);
+                suChinese.append("/");
+                suChinese.append(CNUMBERS[x]);
+            }
+            else
+            {
+                result = x + y;
+                suChinese.append(CNUMBERS[x]);
+                suChinese.append("+");
+                suChinese.append(CNUMBERS[y]);
+            }
+        }
+        else
+        {
+            if (x >= y)
+            {
+                result = x - y;
+                suChinese.append(CNUMBERS[x]);
+                suChinese.append("-");
+                suChinese.append(CNUMBERS[y]);
+            }
+            else
+            {
+                result = y - x;
+                suChinese.append(CNUMBERS[y]);
+                suChinese.append("-");
+                suChinese.append(CNUMBERS[x]);
+            }
+        }
+        suChinese.append("=?@" + result);
+        return suChinese.toString();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..30479af
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/MybatisPlusConfig.java
@@ -0,0 +1,39 @@
+package com.ruoyi.framework.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.autoconfigure.ConfigurationCustomizer;
+import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import jakarta.annotation.PostConstruct;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.text.SimpleDateFormat;
+import java.util.Collections;
+
+
+@Configuration
+@MapperScan("com.ruoyi.**.mapper")
+public class MybatisPlusConfig {
+    @Bean
+    public PaginationInnerInterceptor paginationInnerInterceptor() {
+        PaginationInnerInterceptor paginationInterceptor = new PaginationInnerInterceptor();
+        // 璁剧疆鏈�澶у崟椤甸檺鍒舵暟閲忥紝榛樿 500 鏉★紝-1 涓嶅彈闄愬埗
+        paginationInterceptor.setMaxLimit(-1L);
+        paginationInterceptor.setDbType(DbType.DM);
+        // 寮�鍚� count 鐨� join 浼樺寲,鍙拡瀵归儴鍒� left join
+        paginationInterceptor.setOptimizeJoin(true);
+        return paginationInterceptor;
+    }
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor(){
+        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
+        mybatisPlusInterceptor.setInterceptors(Collections.singletonList(paginationInnerInterceptor()));
+        return mybatisPlusInterceptor;
+    }
+
+
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
new file mode 100644
index 0000000..3453237
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/RedisConfig.java
@@ -0,0 +1,70 @@
+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
+ */
+@SuppressWarnings("deprecation")
+@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鏉ュ簭鍒楀寲鍜屽弽搴忓垪鍖杛edis鐨刱ey鍊�
+        template.setKeySerializer(new StringRedisSerializer());
+        template.setValueSerializer(serializer);
+
+        // Hash鐨刱ey涔熼噰鐢⊿tringRedisSerializer鐨勫簭鍒楀寲鏂瑰紡
+        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/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
new file mode 100644
index 0000000..74fb93e
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ResourcesConfig.java
@@ -0,0 +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);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
new file mode 100644
index 0000000..1e9e183
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/SecurityConfig.java
@@ -0,0 +1,143 @@
+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鍦板潃锛屽鏋滅敤鎴稩P鍜屽弬鏁板尮閰嶏紝鍒欏彲浠ヨ闂�
+     * 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锛屾墍浠ヤ笉闇�瑕乻ession
+            .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
+            // 娉ㄨВ鏍囪鍏佽鍖垮悕璁块棶鐨剈rl
+            .authorizeHttpRequests((requests) -> {
+                permitAllUrl.getUrls().forEach(url -> requests.requestMatchers(url).permitAll());
+                // 瀵逛簬鐧诲綍login 娉ㄥ唽register 楠岃瘉鐮乧aptchaImage 鍏佽鍖垮悕璁块棶
+                requests.requestMatchers("/login", "/register", "/captchaImage").permitAll()
+                        .requestMatchers("/sendInfo/*").permitAll()
+                        //澶у睆鐩稿叧鎺ュ彛
+                        .requestMatchers("/dp/**").permitAll()
+                        .requestMatchers("/common/**").permitAll()
+                    // 闈欐�佽祫婧愶紝鍙尶鍚嶈闂�
+                    .requestMatchers(HttpMethod.GET, "/", "/*.html", "/**.html", "/**.css", "/**.js", "/profile/**").permitAll()
+                    .requestMatchers("/swagger-ui.html", "/v3/api-docs/**", "/swagger-ui/**", "/druid/**","/doc.html","/webjars/**").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/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java
new file mode 100644
index 0000000..cd8fb09
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ServerConfig.java
@@ -0,0 +1,32 @@
+package com.ruoyi.framework.config;
+
+import jakarta.servlet.http.HttpServletRequest;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.ServletUtils;
+
+/**
+ * 鏈嶅姟鐩稿叧閰嶇疆
+ * 
+ * @author ruoyi
+ */
+@Component
+public class ServerConfig
+{
+    /**
+     * 鑾峰彇瀹屾暣鐨勮姹傝矾寰勶紝鍖呮嫭锛氬煙鍚嶏紝绔彛锛屼笂涓嬫枃璁块棶璺緞
+     * 
+     * @return 鏈嶅姟鍦板潃
+     */
+    public String getUrl()
+    {
+        HttpServletRequest request = ServletUtils.getRequest();
+        return getDomain(request);
+    }
+
+    public static String getDomain(HttpServletRequest request)
+    {
+        StringBuffer url = request.getRequestURL();
+        String contextPath = request.getServletContext().getContextPath();
+        return url.delete(url.length() - request.getRequestURI().length(), url.length()).append(contextPath).toString();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
new file mode 100644
index 0000000..7840141
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/ThreadPoolConfig.java
@@ -0,0 +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);
+            }
+        };
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
new file mode 100644
index 0000000..c8a5c8a
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/DruidProperties.java
@@ -0,0 +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'銆傚鏋渧alidationQuery涓簄ull锛宼estOnBorrow銆乼estOnReturn銆乼estWhileIdle閮戒笉浼氳捣浣滅敤銆�
+         */
+        datasource.setValidationQuery(validationQuery);
+        /** 寤鸿閰嶇疆涓簍rue锛屼笉褰卞搷鎬ц兘锛屽苟涓斾繚璇佸畨鍏ㄦ�с�傜敵璇疯繛鎺ョ殑鏃跺�欐娴嬶紝濡傛灉绌洪棽鏃堕棿澶т簬timeBetweenEvictionRunsMillis锛屾墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堛�� */
+        datasource.setTestWhileIdle(testWhileIdle);
+        /** 鐢宠杩炴帴鏃舵墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堬紝鍋氫簡杩欎釜閰嶇疆浼氶檷浣庢�ц兘銆� */
+        datasource.setTestOnBorrow(testOnBorrow);
+        /** 褰掕繕杩炴帴鏃舵墽琛寁alidationQuery妫�娴嬭繛鎺ユ槸鍚︽湁鏁堬紝鍋氫簡杩欎釜閰嶇疆浼氶檷浣庢�ц兘銆� */
+        datasource.setTestOnReturn(testOnReturn);
+        return datasource;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java
new file mode 100644
index 0000000..277ba3b
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/config/properties/PermitAllUrlProperties.java
@@ -0,0 +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娉ㄨВ鍏佽鍖垮悕璁块棶鐨剈rl
+ * 
+ * @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.getPathPatternsCondition().getPatternValues()) //
+                    .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.getPathPatternsCondition().getPatternValues())
+                    .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/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
new file mode 100644
index 0000000..e70b8cf
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSource.java
@@ -0,0 +1,26 @@
+package com.ruoyi.framework.datasource;
+
+import java.util.Map;
+import javax.sql.DataSource;
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+/**
+ * 鍔ㄦ�佹暟鎹簮
+ * 
+ * @author ruoyi
+ */
+public class DynamicDataSource extends AbstractRoutingDataSource
+{
+    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources)
+    {
+        super.setDefaultTargetDataSource(defaultTargetDataSource);
+        super.setTargetDataSources(targetDataSources);
+        super.afterPropertiesSet();
+    }
+
+    @Override
+    protected Object determineCurrentLookupKey()
+    {
+        return DynamicDataSourceContextHolder.getDataSourceType();
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
new file mode 100644
index 0000000..9770af6
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/datasource/DynamicDataSourceContextHolder.java
@@ -0,0 +1,45 @@
+package com.ruoyi.framework.datasource;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 鏁版嵁婧愬垏鎹㈠鐞�
+ * 
+ * @author ruoyi
+ */
+public class DynamicDataSourceContextHolder
+{
+    public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);
+
+    /**
+     * 浣跨敤ThreadLocal缁存姢鍙橀噺锛孴hreadLocal涓烘瘡涓娇鐢ㄨ鍙橀噺鐨勭嚎绋嬫彁渚涚嫭绔嬬殑鍙橀噺鍓湰锛�
+     * 鎵�浠ユ瘡涓�涓嚎绋嬮兘鍙互鐙珛鍦版敼鍙樿嚜宸辩殑鍓湰锛岃�屼笉浼氬奖鍝嶅叾瀹冪嚎绋嬫墍瀵瑰簲鐨勫壇鏈��
+     */
+    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();
+
+    /**
+     * 璁剧疆鏁版嵁婧愮殑鍙橀噺
+     */
+    public static void setDataSourceType(String dsType)
+    {
+        log.info("鍒囨崲鍒皗}鏁版嵁婧�", dsType);
+        CONTEXT_HOLDER.set(dsType);
+    }
+
+    /**
+     * 鑾峰緱鏁版嵁婧愮殑鍙橀噺
+     */
+    public static String getDataSourceType()
+    {
+        return CONTEXT_HOLDER.get();
+    }
+
+    /**
+     * 娓呯┖鏁版嵁婧愬彉閲�
+     */
+    public static void clearDataSourceType()
+    {
+        CONTEXT_HOLDER.remove();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
new file mode 100644
index 0000000..4e8d20f
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/RepeatSubmitInterceptor.java
@@ -0,0 +1,56 @@
+package com.ruoyi.framework.interceptor;
+
+import java.lang.reflect.Method;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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 闃查噸澶嶆敞瑙e弬鏁�
+     * @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/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
new file mode 100644
index 0000000..c93df50
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/interceptor/impl/SameUrlDataInterceptor.java
@@ -0,0 +1,110 @@
+package com.ruoyi.framework.interceptor.impl;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import jakarta.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鍙傛暟涓虹┖锛岃幏鍙朠arameter鐨勬暟鎹�
+        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());
+
+        // 璇锋眰鍦板潃锛堜綔涓哄瓨鏀綾ache鐨刱ey鍊硷級
+        String url = request.getRequestURI();
+
+        // 鍞竴鍊硷紙娌℃湁娑堟伅澶村垯浣跨敤璇锋眰鍦板潃锛�
+        String submitKey = StringUtils.trimToEmpty(request.getHeader(header));
+
+        // 鍞竴鏍囪瘑锛堟寚瀹歬ey + 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/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
new file mode 100644
index 0000000..7387a02
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/AsyncManager.java
@@ -0,0 +1,55 @@
+package com.ruoyi.framework.manager;
+
+import java.util.TimerTask;
+import java.util.concurrent.ScheduledExecutorService;
+import java.util.concurrent.TimeUnit;
+import com.ruoyi.common.utils.Threads;
+import com.ruoyi.common.utils.spring.SpringUtils;
+
+/**
+ * 寮傛浠诲姟绠$悊鍣�
+ * 
+ * @author ruoyi
+ */
+public class AsyncManager
+{
+    /**
+     * 鎿嶄綔寤惰繜10姣
+     */
+    private final int OPERATE_DELAY_TIME = 10;
+
+    /**
+     * 寮傛鎿嶄綔浠诲姟璋冨害绾跨▼姹�
+     */
+    private ScheduledExecutorService executor = SpringUtils.getBean("scheduledExecutorService");
+
+    /**
+     * 鍗曚緥妯″紡
+     */
+    private AsyncManager(){}
+
+    private static AsyncManager me = new AsyncManager();
+
+    public static AsyncManager me()
+    {
+        return me;
+    }
+
+    /**
+     * 鎵ц浠诲姟
+     * 
+     * @param task 浠诲姟
+     */
+    public void execute(TimerTask task)
+    {
+        executor.schedule(task, OPERATE_DELAY_TIME, TimeUnit.MILLISECONDS);
+    }
+
+    /**
+     * 鍋滄浠诲姟绾跨▼姹�
+     */
+    public void shutdown()
+    {
+        Threads.shutdownAndAwaitTermination(executor);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
new file mode 100644
index 0000000..095b865
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/ShutdownManager.java
@@ -0,0 +1,39 @@
+package com.ruoyi.framework.manager;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+import jakarta.annotation.PreDestroy;
+
+/**
+ * 纭繚搴旂敤閫�鍑烘椂鑳藉叧闂悗鍙扮嚎绋�
+ *
+ * @author ruoyi
+ */
+@Component
+public class ShutdownManager
+{
+    private static final Logger logger = LoggerFactory.getLogger("sys-user");
+
+    @PreDestroy
+    public void destroy()
+    {
+        shutdownAsyncManager();
+    }
+
+    /**
+     * 鍋滄寮傛鎵ц浠诲姟
+     */
+    private void shutdownAsyncManager()
+    {
+        try
+        {
+            logger.info("====鍏抽棴鍚庡彴浠诲姟浠诲姟绾跨▼姹�====");
+            AsyncManager.me().shutdown();
+        }
+        catch (Exception e)
+        {
+            logger.error(e.getMessage(), e);
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
new file mode 100644
index 0000000..267e305
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/manager/factory/AsyncFactory.java
@@ -0,0 +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);
+            }
+        };
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java
new file mode 100644
index 0000000..6c776ce
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/AuthenticationContextHolder.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java
new file mode 100644
index 0000000..5472f3d
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/context/PermissionContextHolder.java
@@ -0,0 +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));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
new file mode 100644
index 0000000..9d2f494
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/filter/JwtAuthenticationTokenFilter.java
@@ -0,0 +1,44 @@
+package com.ruoyi.framework.security.filter;
+
+import java.io.IOException;
+import jakarta.servlet.FilterChain;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
new file mode 100644
index 0000000..e1789f8
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/AuthenticationEntryPointImpl.java
@@ -0,0 +1,34 @@
+package com.ruoyi.framework.security.handle;
+
+import java.io.IOException;
+import java.io.Serializable;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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)));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
new file mode 100644
index 0000000..595bd3f
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/security/handle/LogoutSuccessHandlerImpl.java
@@ -0,0 +1,53 @@
+package com.ruoyi.framework.security.handle;
+
+import java.io.IOException;
+import jakarta.servlet.ServletException;
+import jakarta.servlet.http.HttpServletRequest;
+import jakarta.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"))));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java
new file mode 100644
index 0000000..63b03da
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/Server.java
@@ -0,0 +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);
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
new file mode 100644
index 0000000..a13a66c
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Cpu.java
@@ -0,0 +1,101 @@
+package com.ruoyi.framework.web.domain.server;
+
+import com.ruoyi.common.utils.Arith;
+
+/**
+ * CPU鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Cpu
+{
+    /**
+     * 鏍稿績鏁�
+     */
+    private int cpuNum;
+
+    /**
+     * CPU鎬荤殑浣跨敤鐜�
+     */
+    private double total;
+
+    /**
+     * CPU绯荤粺浣跨敤鐜�
+     */
+    private double sys;
+
+    /**
+     * CPU鐢ㄦ埛浣跨敤鐜�
+     */
+    private double used;
+
+    /**
+     * CPU褰撳墠绛夊緟鐜�
+     */
+    private double wait;
+
+    /**
+     * CPU褰撳墠绌洪棽鐜�
+     */
+    private double free;
+
+    public int getCpuNum()
+    {
+        return cpuNum;
+    }
+
+    public void setCpuNum(int cpuNum)
+    {
+        this.cpuNum = cpuNum;
+    }
+
+    public double getTotal()
+    {
+        return Arith.round(Arith.mul(total, 100), 2);
+    }
+
+    public void setTotal(double total)
+    {
+        this.total = total;
+    }
+
+    public double getSys()
+    {
+        return Arith.round(Arith.mul(sys / total, 100), 2);
+    }
+
+    public void setSys(double sys)
+    {
+        this.sys = sys;
+    }
+
+    public double getUsed()
+    {
+        return Arith.round(Arith.mul(used / total, 100), 2);
+    }
+
+    public void setUsed(double used)
+    {
+        this.used = used;
+    }
+
+    public double getWait()
+    {
+        return Arith.round(Arith.mul(wait / total, 100), 2);
+    }
+
+    public void setWait(double wait)
+    {
+        this.wait = wait;
+    }
+
+    public double getFree()
+    {
+        return Arith.round(Arith.mul(free / total, 100), 2);
+    }
+
+    public void setFree(double free)
+    {
+        this.free = free;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
new file mode 100644
index 0000000..1fdc6ac
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Jvm.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
new file mode 100644
index 0000000..13eec52
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Mem.java
@@ -0,0 +1,61 @@
+package com.ruoyi.framework.web.domain.server;
+
+import com.ruoyi.common.utils.Arith;
+
+/**
+ * 鍏у瓨鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Mem
+{
+    /**
+     * 鍐呭瓨鎬婚噺
+     */
+    private double total;
+
+    /**
+     * 宸茬敤鍐呭瓨
+     */
+    private double used;
+
+    /**
+     * 鍓╀綑鍐呭瓨
+     */
+    private double free;
+
+    public double getTotal()
+    {
+        return Arith.div(total, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setTotal(long total)
+    {
+        this.total = total;
+    }
+
+    public double getUsed()
+    {
+        return Arith.div(used, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setUsed(long used)
+    {
+        this.used = used;
+    }
+
+    public double getFree()
+    {
+        return Arith.div(free, (1024 * 1024 * 1024), 2);
+    }
+
+    public void setFree(long free)
+    {
+        this.free = free;
+    }
+
+    public double getUsage()
+    {
+        return Arith.mul(Arith.div(used, total, 4), 100);
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
new file mode 100644
index 0000000..45d64d9
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/Sys.java
@@ -0,0 +1,84 @@
+package com.ruoyi.framework.web.domain.server;
+
+/**
+ * 绯荤粺鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class Sys
+{
+    /**
+     * 鏈嶅姟鍣ㄥ悕绉�
+     */
+    private String computerName;
+
+    /**
+     * 鏈嶅姟鍣↖p
+     */
+    private String computerIp;
+
+    /**
+     * 椤圭洰璺緞
+     */
+    private String userDir;
+
+    /**
+     * 鎿嶄綔绯荤粺
+     */
+    private String osName;
+
+    /**
+     * 绯荤粺鏋舵瀯
+     */
+    private String osArch;
+
+    public String getComputerName()
+    {
+        return computerName;
+    }
+
+    public void setComputerName(String computerName)
+    {
+        this.computerName = computerName;
+    }
+
+    public String getComputerIp()
+    {
+        return computerIp;
+    }
+
+    public void setComputerIp(String computerIp)
+    {
+        this.computerIp = computerIp;
+    }
+
+    public String getUserDir()
+    {
+        return userDir;
+    }
+
+    public void setUserDir(String userDir)
+    {
+        this.userDir = userDir;
+    }
+
+    public String getOsName()
+    {
+        return osName;
+    }
+
+    public void setOsName(String osName)
+    {
+        this.osName = osName;
+    }
+
+    public String getOsArch()
+    {
+        return osArch;
+    }
+
+    public void setOsArch(String osArch)
+    {
+        this.osArch = osArch;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
new file mode 100644
index 0000000..1320cde
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/domain/server/SysFile.java
@@ -0,0 +1,114 @@
+package com.ruoyi.framework.web.domain.server;
+
+/**
+ * 绯荤粺鏂囦欢鐩稿叧淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class SysFile
+{
+    /**
+     * 鐩樼璺緞
+     */
+    private String dirName;
+
+    /**
+     * 鐩樼绫诲瀷
+     */
+    private String sysTypeName;
+
+    /**
+     * 鏂囦欢绫诲瀷
+     */
+    private String typeName;
+
+    /**
+     * 鎬诲ぇ灏�
+     */
+    private String total;
+
+    /**
+     * 鍓╀綑澶у皬
+     */
+    private String free;
+
+    /**
+     * 宸茬粡浣跨敤閲�
+     */
+    private String used;
+
+    /**
+     * 璧勬簮鐨勪娇鐢ㄧ巼
+     */
+    private double usage;
+
+    public String getDirName()
+    {
+        return dirName;
+    }
+
+    public void setDirName(String dirName)
+    {
+        this.dirName = dirName;
+    }
+
+    public String getSysTypeName()
+    {
+        return sysTypeName;
+    }
+
+    public void setSysTypeName(String sysTypeName)
+    {
+        this.sysTypeName = sysTypeName;
+    }
+
+    public String getTypeName()
+    {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName)
+    {
+        this.typeName = typeName;
+    }
+
+    public String getTotal()
+    {
+        return total;
+    }
+
+    public void setTotal(String total)
+    {
+        this.total = total;
+    }
+
+    public String getFree()
+    {
+        return free;
+    }
+
+    public void setFree(String free)
+    {
+        this.free = free;
+    }
+
+    public String getUsed()
+    {
+        return used;
+    }
+
+    public void setUsed(String used)
+    {
+        this.used = used;
+    }
+
+    public double getUsage()
+    {
+        return usage;
+    }
+
+    public void setUsage(double usage)
+    {
+        this.usage = usage;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
new file mode 100644
index 0000000..1ca0283
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/exception/GlobalExceptionHandler.java
@@ -0,0 +1,145 @@
+package com.ruoyi.framework.web.exception;
+
+import jakarta.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("婕旂ず妯″紡锛屼笉鍏佽鎿嶄綔");
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
new file mode 100644
index 0000000..07d259a
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/PermissionService.java
@@ -0,0 +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));
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
new file mode 100644
index 0000000..6b82043
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysLoginService.java
@@ -0,0 +1,181 @@
+package com.ruoyi.framework.web.service;
+
+import jakarta.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);
+            // 璇ユ柟娉曚細鍘昏皟鐢║serDetailsServiceImpl.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/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
new file mode 100644
index 0000000..6728c7b
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPasswordService.java
@@ -0,0 +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 缂撳瓨閿甼ey
+     */
+    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/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java
new file mode 100644
index 0000000..51c4dd9
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysPermissionService.java
@@ -0,0 +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))
+            {
+                // 澶氳鑹茶缃畃ermissions灞炴�э紝浠ヤ究鏁版嵁鏉冮檺鍖归厤鏉冮檺
+                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/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
new file mode 100644
index 0000000..f2afe31
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/SysRegisterService.java
@@ -0,0 +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();
+        }
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
new file mode 100644
index 0000000..a03ebad
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/TokenService.java
@@ -0,0 +1,231 @@
+package com.ruoyi.framework.web.service;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import jakarta.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);
+                // 瑙f瀽瀵瑰簲鐨勬潈闄愪互鍙婄敤鎴蜂俊鎭�
+                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灏唋oginUser缂撳瓨
+        String userKey = getTokenKey(loginUser.getToken());
+        redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
+    }
+
+    /**
+     * 璁剧疆鐢ㄦ埛浠g悊淇℃伅
+     *
+     * @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());
+    }
+
+    /**
+     * 浠庢暟鎹0鏄庣敓鎴愪护鐗�
+     *
+     * @param claims 鏁版嵁澹版槑
+     * @return 浠ょ墝
+     */
+    private String createToken(Map<String, Object> claims)
+    {
+        String token = Jwts.builder()
+                .setClaims(claims)
+                .signWith(SignatureAlgorithm.HS512, secret).compact();
+        return token;
+    }
+
+    /**
+     * 浠庝护鐗屼腑鑾峰彇鏁版嵁澹版槑
+     *
+     * @param token 浠ょ墝
+     * @return 鏁版嵁澹版槑
+     */
+    private Claims parseToken(String token)
+    {
+        return Jwts.parser()
+                .setSigningKey(secret)
+                .parseClaimsJws(token)
+                .getBody();
+    }
+
+    /**
+     * 浠庝护鐗屼腑鑾峰彇鐢ㄦ埛鍚�
+     *
+     * @param token 浠ょ墝
+     * @return 鐢ㄦ埛鍚�
+     */
+    public String getUsernameFromToken(String token)
+    {
+        Claims claims = parseToken(token);
+        return claims.getSubject();
+    }
+
+    /**
+     * 鑾峰彇璇锋眰token
+     *
+     * @param request
+     * @return token
+     */
+    private String getToken(HttpServletRequest request)
+    {
+        String token = request.getHeader(header);
+        if (StringUtils.isNotEmpty(token) && token.startsWith(Constants.TOKEN_PREFIX))
+        {
+            token = token.replace(Constants.TOKEN_PREFIX, "");
+        }
+        return token;
+    }
+
+    private String getTokenKey(String uuid)
+    {
+        return CacheConstants.LOGIN_TOKEN_KEY + uuid;
+    }
+}
diff --git a/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
new file mode 100644
index 0000000..5dcdf90
--- /dev/null
+++ b/ruoyi-framework/src/main/java/com/ruoyi/framework/web/service/UserDetailsServiceImpl.java
@@ -0,0 +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));
+    }
+}
diff --git a/ruoyi-fuzhou/pom.xml b/ruoyi-fuzhou/pom.xml
new file mode 100644
index 0000000..a4c764d
--- /dev/null
+++ b/ruoyi-fuzhou/pom.xml
@@ -0,0 +1,92 @@
+<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-fuzhou</artifactId>
+    <description>
+        fuzhou绯荤粺妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>3.8.1</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.github.s7connector</groupId>
+            <artifactId>s7connector</artifactId>
+            <version>2.1</version>
+        </dependency>
+        <dependency>
+            <groupId>com.infiniteautomation</groupId>
+            <artifactId>modbus4j</artifactId>
+            <version>3.0.3</version>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xingshuangs</groupId>
+            <artifactId>iot-communication</artifactId>
+            <version>1.5.1</version>
+        </dependency>
+<!--        <dependency>-->
+<!--            <groupId>org.slf4j</groupId>-->
+<!--            <artifactId>slf4j-api</artifactId>-->
+<!--            <version>1.7.25</version>-->
+<!--        </dependency>-->
+<!--        <dependency>-->
+<!--            <groupId>org.slf4j</groupId>-->
+<!--            <artifactId>slf4j-log4j12</artifactId>-->
+<!--            <version>1.7.25</version>-->
+<!--        </dependency>-->
+        <dependency>
+            <groupId>org.rxtx</groupId>
+            <artifactId>rxtx</artifactId>
+            <version>2.1.7</version>
+        </dependency>
+        <dependency>
+            <groupId>com.hikvision.ga</groupId>
+            <artifactId>artemis-http-client</artifactId>
+            <version>1.1.13.RELEASE</version>
+        </dependency>
+
+    </dependencies>
+    <repositories>
+        <repository>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+            <id>ias-snapshots</id>
+            <name>Infinite Automation Snapshot Repository</name>
+            <url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
+        </repository>
+        <repository>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>ias-releases</id>
+            <name>Infinite Automation Release Repository</name>
+            <url>https://maven.mangoautomation.net/repository/ias-release/</url>
+        </repository>
+    </repositories>
+</project>
diff --git a/ruoyi-fuzhou/ruoyi-fuzhou.iml b/ruoyi-fuzhou/ruoyi-fuzhou.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-fuzhou/ruoyi-fuzhou.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/HikConfig.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/HikConfig.java
new file mode 100644
index 0000000..325d494
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/HikConfig.java
@@ -0,0 +1,28 @@
+package com.ruoyi.fuzhou.config;
+
+import com.hikvision.artemis.sdk.ArtemisHttpUtil;
+import com.hikvision.artemis.sdk.config.ArtemisConfig;
+import org.springframework.stereotype.Service;
+
+import java.util.Map;
+
+@Service
+public class HikConfig {
+    private static final String host = "";
+
+    private static final String appKey = "";
+
+    private static final String appSecret = "";
+
+
+    public String hkpost(Map<String, String> path, String body) throws Exception {
+        ArtemisConfig artemisConfig = new ArtemisConfig();
+        artemisConfig.host = "10.1.10.20:443"; // artemis缃戝叧鏈嶅姟鍣╥p绔彛
+        artemisConfig.appKey = "23872378"; // 绉橀挜appkey
+        artemisConfig.appSecret = "aDmXhRBhZrW6ldVHrLhh";// 绉橀挜appSecret
+        String contentType = "application/json";
+        String result = ArtemisHttpUtil.doPostStringArtemis(artemisConfig,path, body, null, null,
+                contentType , null);// post璇锋眰application/json绫诲瀷鍙傛暟
+        return result;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/WebSocketConfig.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/WebSocketConfig.java
new file mode 100644
index 0000000..480f276
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/config/WebSocketConfig.java
@@ -0,0 +1,23 @@
+package com.ruoyi.fuzhou.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+/**
+ * 寮�鍚疻ebSocket鏀寔
+ * @author zhangyy
+ */
+@Configuration
+public class WebSocketConfig {
+    /**
+     * ServerEndpointExporter 浣滅敤
+     * 杩欎釜Bean浼氳嚜鍔ㄦ敞鍐屼娇鐢ˊServerEndpoint娉ㄨВ澹版槑鐨剋ebsocket endpoint
+     * @return
+     */
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/CameraPTZ.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/CameraPTZ.java
new file mode 100644
index 0000000..2db3d95
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/CameraPTZ.java
@@ -0,0 +1,62 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+
+public class CameraPTZ {
+
+    @JsonProperty("cameraIndexCode")
+    private String cameraIndexCode;
+
+    @JsonProperty("action")
+    private Integer action;
+
+    @JsonProperty("command")
+    private String command;
+
+    @JsonProperty("speed")
+    private Integer speed;
+
+    @JsonProperty("presetIndex")
+    private Integer presetIndex;
+
+    public String getCameraIndexCode() {
+        return cameraIndexCode;
+    }
+
+    public void setCameraIndexCode(String cameraIndexCode) {
+        this.cameraIndexCode = cameraIndexCode;
+    }
+
+    public Integer getAction() {
+        return action;
+    }
+
+    public void setAction(Integer action) {
+        this.action = action;
+    }
+
+    public String getCommand() {
+        return command;
+    }
+
+    public void setCommand(String command) {
+        this.command = command;
+    }
+
+    public Integer getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(Integer speed) {
+        this.speed = speed;
+    }
+
+    public Integer getPresetIndex() {
+        return presetIndex;
+    }
+
+    public void setPresetIndex(Integer presetIndex) {
+        this.presetIndex = presetIndex;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpEquipment.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpEquipment.java
new file mode 100644
index 0000000..b72d506
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpEquipment.java
@@ -0,0 +1,306 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ *
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@TableName("DP_EQUIPMENT")
+@Schema( description = "璁惧淇℃伅")
+public class DpEquipment {
+
+    @Schema(title ="涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title ="鎵�灞炴硦浣岻D")
+    @TableField("BE_ID")
+    private Integer beId;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("EQU_NAME")
+    private String equName;
+
+    @Schema(title ="鏇存柊闂撮殧(鍒嗛挓)")
+    @TableField("INTERVAL_TIME")
+    private Integer intervalTime;
+
+    @Schema(title ="鏌ヨ鏃堕棿娈靛ぇ灏�(鍒嗛挓)")
+    @TableField("PERIOD_TIME")
+    private Integer periodTime;
+
+    @Schema(title ="璁惧浜岀骇绫诲瀷")
+    @TableField("EQU_SE_TYPE")
+    private Integer equSeType;
+
+    @Schema(title ="閫氫俊鍗忚")
+    @TableField("PROTOCOL")
+    private String protocol;
+
+    @Schema(title ="娓彛缂栧彿")
+    @TableField("WH_ID")
+    private Integer whId;
+
+    @Schema(title ="缁忓害")
+    @TableField("X")
+    private Double x;
+
+    @Schema(title ="绾害")
+    @TableField("Y")
+    private Double y;
+
+    @Schema(title ="楂樺害")
+    @TableField("Z")
+    private Double z;
+
+    @Schema(title ="妯″瀷瀛楁")
+    @TableField("FIELD_NAME")
+    private String fieldName;
+
+    @Schema(title ="璁惧绫诲瀷ID")
+    @TableField("EQUIPMENT_TYPE_ID")
+    private Integer equipmentTypeId;
+
+    @Schema(title ="璁惧缂栫爜")
+    @TableField("EQU_CODE")
+    private String equCode;
+
+    @Schema(title ="璁惧鐘舵��")
+    @TableField("STATUS")
+    private Integer status;
+
+    @TableField(exist = false)
+    private String typeName;
+
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+
+    @TableField(exist = false)
+    private String whName;
+
+    @TableField(exist = false)
+    private String beName;
+
+    @TableField(exist = false)
+    private String ip;
+
+    @TableField(exist = false)
+    private Integer port;
+
+    @TableField(exist = false)
+    private Byte deviceAddress;
+
+
+//    @TableField(exist = false)
+//    private Integer whId;
+
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public String getEquCode() {
+        return equCode;
+    }
+
+    public void setEquCode(String equCode) {
+        this.equCode = equCode;
+    }
+
+    public Integer getEquipmentTypeId() {
+        return equipmentTypeId;
+    }
+
+    public void setEquipmentTypeId(Integer equipmentTypeId) {
+        this.equipmentTypeId = equipmentTypeId;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public void setFieldName(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+    public Double getX() {
+        return x;
+    }
+
+    public void setX(Double x) {
+        this.x = x;
+    }
+
+    public Double getY() {
+        return y;
+    }
+
+    public void setY(Double y) {
+        this.y = y;
+    }
+
+    public Double getZ() {
+        return z;
+    }
+
+    public void setZ(Double z) {
+        this.z = z;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public String getWhName() {
+        return whName;
+    }
+
+    public void setWhName(String whName) {
+        this.whName = whName;
+    }
+
+    public String getBeName() {
+        return beName;
+    }
+
+    public void setBeName(String beName) {
+        this.beName = beName;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public Integer getWhId() {
+        return whId;
+    }
+
+    public void setWhId(Integer whId) {
+        this.whId = whId;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getBeId() {
+        return beId;
+    }
+
+    public void setBeId(Integer beId) {
+        this.beId = beId;
+    }
+
+    public String getEquName() {
+        return equName;
+    }
+
+    public void setEquName(String equName) {
+        this.equName = equName;
+    }
+
+    public Integer getIntervalTime() {
+        return intervalTime;
+    }
+
+    public void setIntervalTime(Integer intervalTime) {
+        this.intervalTime = intervalTime;
+    }
+
+    public Integer getPeriodTime() {
+        return periodTime;
+    }
+
+    public void setPeriodTime(Integer periodTime) {
+        this.periodTime = periodTime;
+    }
+
+    public Integer getEquSeType() {
+        return equSeType;
+    }
+
+    public void setEquSeType(Integer equSeType) {
+        this.equSeType = equSeType;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getTypeName() {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName) {
+        this.typeName = typeName;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidTask.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidTask.java
new file mode 100644
index 0000000..2aa812f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidTask.java
@@ -0,0 +1,232 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * RFID浠诲姟琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-25
+ */
+@TableName("DP_RFID_TASK")
+@Schema(description = "RFID浠诲姟琛�")
+public class DpRfidTask {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "杞︾墝鍙�")
+    @TableField("CAR")
+    private String car;
+
+    @Schema(title = "杞﹁締鍨嬪彿")
+    @TableField("TYPE")
+    private String type;
+
+    @Schema(title = "椹鹃┒浜�")
+    @TableField("DRIVER")
+    private String driver;
+
+    @Schema(title = "韬唤璇�")
+    @TableField("IDNO")
+    private String idno;
+
+    @Schema(title = "鑱旂郴鏂瑰紡")
+    @TableField("TEL")
+    private String tel;
+
+    @Schema(title = "鏍囩缂栧彿")
+    @TableField("EPC")
+    private String epc;
+
+    @Schema(title = "鏍囪1瑁呰揣2鍗歌揣3杩愯緭")
+    @TableField("OPF")
+    private String opf;
+
+    @Schema(title = "缁戝畾鐗╄祫淇℃伅")
+    private List<OpenWZ> wzData;
+
+    @Schema(title = "缁戝畾鐗╄祫淇℃伅")
+    @TableField("WZ_DATA")
+    private String wzDataStr;
+
+
+    @Schema(title = "缁忚繃鏃堕棿")
+    @TableField(value = "PASS_TIME", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date passTime;
+
+
+    @TableField(exist = false)
+    private Integer equId;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private Double x;
+
+    @TableField(exist = false)
+    private Double y;
+
+    @TableField(exist = false)
+    private Double z;
+
+    public String getWzDataStr() {
+        return wzDataStr;
+    }
+
+    public void setWzDataStr(String wzDataStr) {
+        this.wzDataStr = wzDataStr;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getCar() {
+        return car;
+    }
+
+    public void setCar(String car) {
+        this.car = car;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDriver() {
+        return driver;
+    }
+
+    public void setDriver(String driver) {
+        this.driver = driver;
+    }
+
+    public String getIdno() {
+        return idno;
+    }
+
+    public void setIdno(String idno) {
+        this.idno = idno;
+    }
+
+    public String getTel() {
+        return tel;
+    }
+
+    public void setTel(String tel) {
+        this.tel = tel;
+    }
+
+    public String getEpc() {
+        return epc;
+    }
+
+    public void setEpc(String epc) {
+        this.epc = epc;
+    }
+
+    public String getOpf() {
+        return opf;
+    }
+
+    public void setOpf(String opf) {
+        this.opf = opf;
+    }
+
+    public List<OpenWZ> getWzData() {
+        return wzData;
+    }
+
+    public void setWzData(List<OpenWZ> wzData) {
+        this.wzData = wzData;
+    }
+
+    public Date getPassTime() {
+        return passTime;
+    }
+
+    public void setPassTime(Date passTime) {
+        this.passTime = passTime;
+    }
+
+    public Integer getEquId() {
+        return equId;
+    }
+
+    public void setEquId(Integer equId) {
+        this.equId = equId;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public Double getX() {
+        return x;
+    }
+
+    public void setX(Double x) {
+        this.x = x;
+    }
+
+    public Double getY() {
+        return y;
+    }
+
+    public void setY(Double y) {
+        this.y = y;
+    }
+
+    public Double getZ() {
+        return z;
+    }
+
+    public void setZ(Double z) {
+        this.z = z;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidVehicle.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidVehicle.java
new file mode 100644
index 0000000..619aaa4
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/DpRfidVehicle.java
@@ -0,0 +1,268 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * RFID杞﹁締璁板綍琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-21
+ */
+@TableName("DP_RFID_VEHICLE")
+@Schema(description = "RFID杞﹁締璁板綍琛�")
+public class DpRfidVehicle {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "涓�浣撴満缂栫爜")
+    @TableField("SN")
+    private String sn;
+
+    @Schema(title = "涓�浣撴満IP")
+    @TableField("IP")
+    private String ip;
+
+    @Schema(title = "涓�浣撴満浣嶇疆")
+    @TableField("ADDR")
+    private String addr;
+
+    @Schema(title = "杞︾墝鍙�")
+    @TableField("CAR")
+    private String car;
+
+    @Schema(title = "杞﹁締鍨嬪彿")
+    @TableField("TYPE")
+    private String type;
+
+    @Schema(title = "椹鹃┒浜�")
+    @TableField("DRIVER")
+    private String driver;
+
+    @Schema(title = "韬唤璇�")
+    @TableField("IDNO")
+    private String idno;
+
+    @Schema(title = "鑱旂郴鏂瑰紡")
+    @TableField("TEL")
+    private String tel;
+
+    @Schema(title = "鏍囩缂栧彿")
+    @TableField("EPC")
+    private String epc;
+
+    @Schema(title = "鏍囪1瑁呰揣2鍗歌揣3杩愯緭")
+    @TableField("OPF")
+    private String opf;
+
+    @Schema(title = "缁戝畾鐗╄祫淇℃伅")
+    private List<OpenWZ> wzData;
+
+    @Schema(title = "缁戝畾鐗╄祫淇℃伅")
+    @TableField("WZ_DATA")
+    private String wzDataStr;
+
+
+    @Schema(title = "缁忚繃鏃堕棿")
+    @TableField(value = "PASS_TIME", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date passTime;
+
+
+    @TableField(exist = false)
+    private Integer equId;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private Double x;
+
+    @TableField(exist = false)
+    private Double y;
+
+    @TableField(exist = false)
+    private Double z;
+
+    public String getWzDataStr() {
+        return wzDataStr;
+    }
+
+    public void setWzDataStr(String wzDataStr) {
+        this.wzDataStr = wzDataStr;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getSn() {
+        return sn;
+    }
+
+    public void setSn(String sn) {
+        this.sn = sn;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public String getAddr() {
+        return addr;
+    }
+
+    public void setAddr(String addr) {
+        this.addr = addr;
+    }
+
+    public String getCar() {
+        return car;
+    }
+
+    public void setCar(String car) {
+        this.car = car;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getDriver() {
+        return driver;
+    }
+
+    public void setDriver(String driver) {
+        this.driver = driver;
+    }
+
+    public String getIdno() {
+        return idno;
+    }
+
+    public void setIdno(String idno) {
+        this.idno = idno;
+    }
+
+    public String getTel() {
+        return tel;
+    }
+
+    public void setTel(String tel) {
+        this.tel = tel;
+    }
+
+    public String getEpc() {
+        return epc;
+    }
+
+    public void setEpc(String epc) {
+        this.epc = epc;
+    }
+
+    public String getOpf() {
+        return opf;
+    }
+
+    public void setOpf(String opf) {
+        this.opf = opf;
+    }
+
+    public List<OpenWZ> getWzData() {
+        return wzData;
+    }
+
+    public void setWzData(List<OpenWZ> wzData) {
+        this.wzData = wzData;
+    }
+
+    public Date getPassTime() {
+        return passTime;
+    }
+
+    public void setPassTime(Date passTime) {
+        this.passTime = passTime;
+    }
+
+    public Integer getEquId() {
+        return equId;
+    }
+
+    public void setEquId(Integer equId) {
+        this.equId = equId;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public Double getX() {
+        return x;
+    }
+
+    public void setX(Double x) {
+        this.x = x;
+    }
+
+    public Double getY() {
+        return y;
+    }
+
+    public void setY(Double y) {
+        this.y = y;
+    }
+
+    public Double getZ() {
+        return z;
+    }
+
+    public void setZ(Double z) {
+        this.z = z;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEvent.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEvent.java
new file mode 100644
index 0000000..5476ac7
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEvent.java
@@ -0,0 +1,200 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 娴峰悍鍛婅浜嬩欢
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-25
+ */
+@TableName("HIK_EVENT")
+@Schema(description = "娴峰悍鍛婅浜嬩欢")
+public class HikEvent {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private String id;
+
+    @Schema(title = "鍙戦�佹椂闂�")
+    @TableField(value = "SEND_TIME")
+    private Date sendTime;
+
+    @Schema(title = "鍙戠敓鏃堕棿")
+    @TableField(value = "HAPPEN_TIME")
+    private Date happenTime;
+
+    @Schema(title = "浜嬩欢绫诲瀷ID")
+    @TableField(value = "EVENT_TYPE")
+    private Integer eventType;
+
+    @Schema(title = "缁堢浠g爜")
+    @TableField(value = "SRC_INDEX")
+    private String srcIndex;
+
+    @Schema(title = "缁堢鍚嶇О")
+    @TableField(value = "SRC_NAME")
+    private String srcName;
+
+    @Schema(title = "缁堢绫诲瀷")
+    @TableField(value = "SRC_TYPE")
+    private String srcType;
+
+    @Schema(title = "ip")
+    @TableField(value = "IP_ADDRESS")
+    private String ipAddress;
+
+    @Schema(title = "绔彛")
+    @TableField(value = "PORT_NO")
+    private Integer portNo;
+
+    @Schema(title = "鎽勫儚澶翠唬鐮�")
+    @TableField(value = "CAMERA_INDEX_CODE")
+    private String cameraIndexCode;
+
+    @Schema(title = "鎽勫儚澶翠綅缃�")
+    @TableField(value = "CAMERA_ADDRESS")
+    private String cameraAddress;
+
+    @Schema(title = "鍥剧墖璺緞")
+    @TableField(value = "IMAGE_URL")
+    private String imageUrl;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public Date getSendTime() {
+        return sendTime;
+    }
+
+    public void setSendTime(Date sendTime) {
+        this.sendTime = sendTime;
+    }
+
+    public Date getHappenTime() {
+        return happenTime;
+    }
+
+    public void setHappenTime(Date happenTime) {
+        this.happenTime = happenTime;
+    }
+
+    public Integer getEventType() {
+        return eventType;
+    }
+
+    public void setEventType(Integer eventType) {
+        this.eventType = eventType;
+    }
+
+    public String getSrcIndex() {
+        return srcIndex;
+    }
+
+    public void setSrcIndex(String srcIndex) {
+        this.srcIndex = srcIndex;
+    }
+
+    public String getSrcName() {
+        return srcName;
+    }
+
+    public void setSrcName(String srcName) {
+        this.srcName = srcName;
+    }
+
+    public String getSrcType() {
+        return srcType;
+    }
+
+    public void setSrcType(String srcType) {
+        this.srcType = srcType;
+    }
+
+    public String getIpAddress() {
+        return ipAddress;
+    }
+
+    public void setIpAddress(String ipAddress) {
+        this.ipAddress = ipAddress;
+    }
+
+    public Integer getPortNo() {
+        return portNo;
+    }
+
+    public void setPortNo(Integer portNo) {
+        this.portNo = portNo;
+    }
+
+    public String getCameraIndexCode() {
+        return cameraIndexCode;
+    }
+
+    public void setCameraIndexCode(String cameraIndexCode) {
+        this.cameraIndexCode = cameraIndexCode;
+    }
+
+    public String getCameraAddress() {
+        return cameraAddress;
+    }
+
+    public void setCameraAddress(String cameraAddress) {
+        this.cameraAddress = cameraAddress;
+    }
+
+    public String getImageUrl() {
+        return imageUrl;
+    }
+
+    public void setImageUrl(String imageUrl) {
+        this.imageUrl = imageUrl;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEventObj.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEventObj.java
new file mode 100644
index 0000000..6bc6b9a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/HikEventObj.java
@@ -0,0 +1,40 @@
+package com.ruoyi.fuzhou.domain;
+
+public class HikEventObj {
+    private Integer[] eventTypes;
+    private String eventDest;
+    private Integer subType;
+    private Integer[] eventLvl;
+
+    public Integer[] getEventTypes() {
+        return eventTypes;
+    }
+
+    public void setEventTypes(Integer[] eventTypes) {
+        this.eventTypes = eventTypes;
+    }
+
+    public String getEventDest() {
+        return eventDest;
+    }
+
+    public void setEventDest(String eventDest) {
+        this.eventDest = eventDest;
+    }
+
+    public Integer getSubType() {
+        return subType;
+    }
+
+    public void setSubType(Integer subType) {
+        this.subType = subType;
+    }
+
+    public Integer[] getEventLvl() {
+        return eventLvl;
+    }
+
+    public void setEventLvl(Integer[] eventLvl) {
+        this.eventLvl = eventLvl;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/OpenWZ.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/OpenWZ.java
new file mode 100644
index 0000000..9c5a933
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/OpenWZ.java
@@ -0,0 +1,58 @@
+package com.ruoyi.fuzhou.domain;
+
+public class OpenWZ {
+    private String taskid;
+    private String task;
+    private String code;
+    private String type;
+    private String num;
+    private String epc;
+
+    public String getTaskid() {
+        return taskid;
+    }
+
+    public void setTaskid(String taskid) {
+        this.taskid = taskid;
+    }
+
+    public String getTask() {
+        return task;
+    }
+
+    public void setTask(String task) {
+        this.task = task;
+    }
+
+    public String getCode() {
+        return code;
+    }
+
+    public void setCode(String code) {
+        this.code = code;
+    }
+
+    public String getType() {
+        return type;
+    }
+
+    public void setType(String type) {
+        this.type = type;
+    }
+
+    public String getNum() {
+        return num;
+    }
+
+    public void setNum(String num) {
+        this.num = num;
+    }
+
+    public String getEpc() {
+        return epc;
+    }
+
+    public void setEpc(String epc) {
+        this.epc = epc;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarRule.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarRule.java
new file mode 100644
index 0000000..6c54a71
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarRule.java
@@ -0,0 +1,138 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ * 杞﹁締鏁版嵁鎺ユ敹淇℃伅
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-22
+ */
+@TableName("RECEIVE_CAR_RULE")
+@Schema( description = "杞﹁締鏁版嵁鎺ユ敹淇℃伅")
+public class ReceiveCarRule {
+
+    @Schema(title ="涓婚敭")
+    @TableField("ID")
+    private Long id;
+
+    @Schema(title ="鏁版嵁椤�")
+    @TableField("DATA_NAME")
+    private String dataName;
+
+    @Schema(title ="璧峰瀛楄妭")
+    @TableField("START")
+    private Integer start;
+
+    @Schema(title ="鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private String dataType;
+
+    @Schema(title ="瀛楄妭闀垮害")
+    @TableField("DATA_LENGTH")
+    private Integer dataLength;
+
+    @Schema(title ="瑙勫垯")
+    @TableField("RULE")
+    private String rule;
+
+    @Schema(title ="绮惧害")
+    @TableField("RULE_VALUE")
+    private String ruleValue;
+
+    @Schema(title ="鏁版嵁缂栫爜")
+    @TableField("CAR_CODE")
+    private String carCode;
+
+    @Schema(title ="鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    @Schema(title ="鍋忕Щ閲�")
+    @TableField("OFFSET")
+    private String offset;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDataName() {
+        return dataName;
+    }
+
+    public void setDataName(String dataName) {
+        this.dataName = dataName;
+    }
+
+    public Integer getStart() {
+        return start;
+    }
+
+    public void setStart(Integer start) {
+        this.start = start;
+    }
+
+    public String getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(String dataType) {
+        this.dataType = dataType;
+    }
+
+    public Integer getDataLength() {
+        return dataLength;
+    }
+
+    public void setDataLength(Integer dataLength) {
+        this.dataLength = dataLength;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public String getRuleValue() {
+        return ruleValue;
+    }
+
+    public void setRuleValue(String ruleValue) {
+        this.ruleValue = ruleValue;
+    }
+
+    public String getCarCode() {
+        return carCode;
+    }
+
+    public void setCarCode(String carCode) {
+        this.carCode = carCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+
+    public String getOffset() {
+        return offset;
+    }
+
+    public void setOffset(String offset) {
+        this.offset = offset;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValue.java
new file mode 100644
index 0000000..447f1bb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValue.java
@@ -0,0 +1,295 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-24
+ */
+@TableName("RECEIVE_CAR_VALUE")
+@Schema( description = "宸ュ喌閲囬泦")
+public class ReceiveCarValue {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private String id;
+
+    @Schema(title ="VIN鐮�")
+    @TableField("VIN")
+    private String vin;
+
+    @Schema(title ="鏁版嵁闀垮害")
+    @TableField("LENGTH")
+    private String length;
+
+    @Schema(title ="淇℃伅閲囬泦鏃堕棿")
+    @TableField("DATA_TIME")
+    private String dataTime;
+
+    @Schema(title ="杞﹂��")
+    @TableField("SPEED")
+    private String speed;
+
+    @Schema(title ="澶ф皵鍘嬪姏")
+    @TableField("PRESSURE")
+    private String pressure;
+
+    @Schema(title ="鍙戝姩鏈哄噣杈撳嚭鎵煩")
+    @TableField("TORQUE")
+    private String torque;
+
+    @Schema(title ="鎽╂摝鎵煩")
+    @TableField("FRICTION_TORQUE")
+    private String frictionTorque;
+
+    @Schema(title ="鍙戝姩鏈鸿浆閫�")
+    @TableField("ENGINE_SPEED")
+    private String engineSpeed;
+
+    @Schema(title ="鍙戝姩鏈虹噧鏂欐祦閲�")
+    @TableField("FLOW")
+    private String flow;
+
+    @Schema(title ="SCR涓婃父 NOx 浼犳劅鍣ㄨ緭鍑哄��")
+    @TableField("SCR_UP_NO")
+    private String scrUpNo;
+
+    @Schema(title ="SCR涓嬫父 NOx浼犳劅鍣�")
+    @TableField("SCR_DOWN_NO")
+    private String scrDownNo;
+
+    @Schema(title ="鍙嶅簲鍓備綑閲�")
+    @TableField("LAST")
+    private String last;
+
+    @Schema(title ="鍙戝姩鏈鸿繘姘旈噺")
+    @TableField("ENGINE_IN")
+    private String engineIn;
+
+    @Schema(title ="SCR鍏ュ彛娓╁害")
+    @TableField("SCR_IN_TEMP")
+    private String scrInTemp;
+
+    @Schema(title ="SCR鍑哄彛娓╁害")
+    @TableField("SCR_OUT_TEMP")
+    private String scrOutTemp;
+
+    @Schema(title ="DPF鍘嬪樊")
+    @TableField("DPF_PRESSURE")
+    private String dpfPressure;
+
+    @Schema(title ="鍙戝姩鏈哄喎鍗存恫娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="娌圭娑蹭綅")
+    @TableField("LEVEL")
+    private String level;
+
+    @Schema(title ="瀹氫綅鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+    @Schema(title ="缁忓害")
+    @TableField("LON")
+    private String lon;
+
+    @Schema(title ="绾害")
+    @TableField("LAT")
+    private String lat;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getVin() {
+        return vin;
+    }
+
+    public void setVin(String vin) {
+        this.vin = vin;
+    }
+
+    public String getLength() {
+        return length;
+    }
+
+    public void setLength(String length) {
+        this.length = length;
+    }
+
+    public String getDataTime() {
+        return dataTime;
+    }
+
+    public void setDataTime(String dataTime) {
+        this.dataTime = dataTime;
+    }
+
+    public String getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(String speed) {
+        this.speed = speed;
+    }
+
+    public String getPressure() {
+        return pressure;
+    }
+
+    public void setPressure(String pressure) {
+        this.pressure = pressure;
+    }
+
+    public String getTorque() {
+        return torque;
+    }
+
+    public void setTorque(String torque) {
+        this.torque = torque;
+    }
+
+    public String getFrictionTorque() {
+        return frictionTorque;
+    }
+
+    public void setFrictionTorque(String frictionTorque) {
+        this.frictionTorque = frictionTorque;
+    }
+
+    public String getEngineSpeed() {
+        return engineSpeed;
+    }
+
+    public void setEngineSpeed(String engineSpeed) {
+        this.engineSpeed = engineSpeed;
+    }
+
+    public String getFlow() {
+        return flow;
+    }
+
+    public void setFlow(String flow) {
+        this.flow = flow;
+    }
+
+    public String getScrUpNo() {
+        return scrUpNo;
+    }
+
+    public void setScrUpNo(String scrUpNo) {
+        this.scrUpNo = scrUpNo;
+    }
+
+    public String getScrDownNo() {
+        return scrDownNo;
+    }
+
+    public void setScrDownNo(String scrDownNo) {
+        this.scrDownNo = scrDownNo;
+    }
+
+    public String getLast() {
+        return last;
+    }
+
+    public void setLast(String last) {
+        this.last = last;
+    }
+
+    public String getEngineIn() {
+        return engineIn;
+    }
+
+    public void setEngineIn(String engineIn) {
+        this.engineIn = engineIn;
+    }
+
+    public String getScrInTemp() {
+        return scrInTemp;
+    }
+
+    public void setScrInTemp(String scrInTemp) {
+        this.scrInTemp = scrInTemp;
+    }
+
+    public String getScrOutTemp() {
+        return scrOutTemp;
+    }
+
+    public void setScrOutTemp(String scrOutTemp) {
+        this.scrOutTemp = scrOutTemp;
+    }
+
+    public String getDpfPressure() {
+        return dpfPressure;
+    }
+
+    public void setDpfPressure(String dpfPressure) {
+        this.dpfPressure = dpfPressure;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getLon() {
+        return lon;
+    }
+
+    public void setLon(String lon) {
+        this.lon = lon;
+    }
+
+    public String getLat() {
+        return lat;
+    }
+
+    public void setLat(String lat) {
+        this.lat = lat;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValueFinal.java
new file mode 100644
index 0000000..6700766
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveCarValueFinal.java
@@ -0,0 +1,308 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+
+@TableName("RECEIVE_ELECTRICITY_ANALYSE")
+@Schema(description = "宸ュ喌閲囬泦")
+public class ReceiveCarValueFinal {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private String id;
+
+    @Schema(title ="VIN鐮�")
+    @TableField("VIN")
+    private String vin;
+
+    @Schema(title ="鏁版嵁闀垮害")
+    @TableField("LENGTH")
+    private String length;
+
+    @Schema(title ="淇℃伅閲囬泦鏃堕棿")
+    @TableField("DATA_TIME")
+    private String dataTime;
+
+    @Schema(title ="杞﹂��")
+    @TableField("SPEED")
+    private String speed;
+
+    @Schema(title ="澶ф皵鍘嬪姏")
+    @TableField("PRESSURE")
+    private String pressure;
+
+    @Schema(title ="鍙戝姩鏈哄噣杈撳嚭鎵煩")
+    @TableField("TORQUE")
+    private String torque;
+
+    @Schema(title ="鎽╂摝鎵煩")
+    @TableField("FRICTION_TORQUE")
+    private String frictionTorque;
+
+    @Schema(title ="鍙戝姩鏈鸿浆閫�")
+    @TableField("ENGINE_SPEED")
+    private String engineSpeed;
+
+    @Schema(title ="鍙戝姩鏈虹噧鏂欐祦閲�")
+    @TableField("FLOW")
+    private String flow;
+
+    @Schema(title ="SCR涓婃父 NOx 浼犳劅鍣ㄨ緭鍑哄��")
+    @TableField("SCR_UP_NO")
+    private String scrUpNo;
+
+    @Schema(title ="SCR涓嬫父 NOx浼犳劅鍣�")
+    @TableField("SCR_DOWN_NO")
+    private String scrDownNo;
+
+    @Schema(title ="鍙嶅簲鍓備綑閲�")
+    @TableField("LAST")
+    private String last;
+
+    @Schema(title ="鍙戝姩鏈鸿繘姘旈噺")
+    @TableField("ENGINE_IN")
+    private String engineIn;
+
+    @Schema(title ="SCR鍏ュ彛娓╁害")
+    @TableField("SCR_IN_TEMP")
+    private String scrInTemp;
+
+    @Schema(title ="SCR鍑哄彛娓╁害")
+    @TableField("SCR_OUT_TEMP")
+    private String scrOutTemp;
+
+    @Schema(title ="DPF鍘嬪樊")
+    @TableField("DPF_PRESSURE")
+    private String dpfPressure;
+
+    @Schema(title ="鍙戝姩鏈哄喎鍗存恫娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="娌圭娑蹭綅")
+    @TableField("LEVEL")
+    private String level;
+
+    @Schema(title ="瀹氫綅鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+    @Schema(title ="缁忓害")
+    @TableField("LON")
+    private String lon;
+
+    @Schema(title ="绾害")
+    @TableField("LAT")
+    private String lat;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getVin() {
+        return vin;
+    }
+
+    public void setVin(String vin) {
+        this.vin = vin;
+    }
+
+    public String getLength() {
+        return length;
+    }
+
+    public void setLength(String length) {
+        this.length = length;
+    }
+
+    public String getDataTime() {
+        return dataTime;
+    }
+
+    public void setDataTime(String dataTime) {
+        this.dataTime = dataTime;
+    }
+
+    public String getSpeed() {
+        return speed;
+    }
+
+    public void setSpeed(String speed) {
+        this.speed = speed;
+    }
+
+    public String getPressure() {
+        return pressure;
+    }
+
+    public void setPressure(String pressure) {
+        this.pressure = pressure;
+    }
+
+    public String getTorque() {
+        return torque;
+    }
+
+    public void setTorque(String torque) {
+        this.torque = torque;
+    }
+
+    public String getFrictionTorque() {
+        return frictionTorque;
+    }
+
+    public void setFrictionTorque(String frictionTorque) {
+        this.frictionTorque = frictionTorque;
+    }
+
+    public String getEngineSpeed() {
+        return engineSpeed;
+    }
+
+    public void setEngineSpeed(String engineSpeed) {
+        this.engineSpeed = engineSpeed;
+    }
+
+    public String getFlow() {
+        return flow;
+    }
+
+    public void setFlow(String flow) {
+        this.flow = flow;
+    }
+
+    public String getScrUpNo() {
+        return scrUpNo;
+    }
+
+    public void setScrUpNo(String scrUpNo) {
+        this.scrUpNo = scrUpNo;
+    }
+
+    public String getScrDownNo() {
+        return scrDownNo;
+    }
+
+    public void setScrDownNo(String scrDownNo) {
+        this.scrDownNo = scrDownNo;
+    }
+
+    public String getLast() {
+        return last;
+    }
+
+    public void setLast(String last) {
+        this.last = last;
+    }
+
+    public String getEngineIn() {
+        return engineIn;
+    }
+
+    public void setEngineIn(String engineIn) {
+        this.engineIn = engineIn;
+    }
+
+    public String getScrInTemp() {
+        return scrInTemp;
+    }
+
+    public void setScrInTemp(String scrInTemp) {
+        this.scrInTemp = scrInTemp;
+    }
+
+    public String getScrOutTemp() {
+        return scrOutTemp;
+    }
+
+    public void setScrOutTemp(String scrOutTemp) {
+        this.scrOutTemp = scrOutTemp;
+    }
+
+    public String getDpfPressure() {
+        return dpfPressure;
+    }
+
+    public void setDpfPressure(String dpfPressure) {
+        this.dpfPressure = dpfPressure;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getLevel() {
+        return level;
+    }
+
+    public void setLevel(String level) {
+        this.level = level;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getLon() {
+        return lon;
+    }
+
+    public void setLon(String lon) {
+        this.lon = lon;
+    }
+
+    public String getLat() {
+        return lat;
+    }
+
+    public void setLat(String lat) {
+        this.lat = lat;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityAnalyse.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityAnalyse.java
new file mode 100644
index 0000000..233c21d
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityAnalyse.java
@@ -0,0 +1,285 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹竻娲�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@TableName("RECEIVE_ELECTRICITY_ANALYSE")
+@Schema(description = "鐢佃澶囨暟鎹竻娲�")
+public class ReceiveElectricityAnalyse {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private Long id;
+
+    @Schema(title ="N椤规俯搴�")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="A鐩哥數鍘�")
+    @TableField("VOLTAGE_A")
+    private String voltageA;
+
+    @Schema(title ="B椤圭數鍘�")
+    @TableField("VOLTAGE_B")
+    private String voltageB;
+
+    @Schema(title ="C椤圭數鍘�")
+    @TableField("VOLTAGE_C")
+    private String voltageC;
+
+    @Schema(title ="AB绾跨數鍘�")
+    @TableField("VOLTAGE_AB")
+    private String voltageAb;
+
+    @Schema(title ="BC绾跨數鍘�")
+    @TableField("VOLTAGE_BC")
+    private String voltageBc;
+
+    @Schema(title ="CA绾跨數鍘�")
+    @TableField("VOLTAGE_CA")
+    private String voltageCa;
+
+    @Schema(title ="A鐩哥數娴�")
+    @TableField("CURRENT_A")
+    private String currentA;
+
+    @Schema(title ="B鐩哥數娴�")
+    @TableField("CURRENT_B")
+    private String currentB;
+
+    @Schema(title ="C鐩哥數娴�")
+    @TableField("CURRENT_C")
+    private String currentC;
+
+    @Schema(title ="A鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_A")
+    private String powerA;
+
+    @Schema(title ="B鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_B")
+    private String powerB;
+
+    @Schema(title ="C鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_C")
+    private String powerC;
+
+    @Schema(title ="鎬绘湁鍔熷姛鐜�")
+    @TableField("POWER")
+    private String power;
+
+    @Schema(title ="A鐩告俯搴�")
+    @TableField("TEMP_A")
+    private String tempA;
+
+    @Schema(title ="B鐩告俯搴�")
+    @TableField("TEMP_B")
+    private String tempB;
+
+    @Schema(title ="C鐩告俯搴�")
+    @TableField("TEMP_C")
+    private String tempC;
+
+    @Schema(title ="鎶ヨ鐘舵��")
+    @TableField("WARN_STATUS")
+    private String warnStatus;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(description = "姝e悜鏈夊姛鐢佃兘")
+    @TableField("ZHENG_POWER")
+    private String zhengPower;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVoltageA() {
+        return voltageA;
+    }
+
+    public void setVoltageA(String voltageA) {
+        this.voltageA = voltageA;
+    }
+
+    public String getVoltageB() {
+        return voltageB;
+    }
+
+    public void setVoltageB(String voltageB) {
+        this.voltageB = voltageB;
+    }
+
+    public String getVoltageC() {
+        return voltageC;
+    }
+
+    public void setVoltageC(String voltageC) {
+        this.voltageC = voltageC;
+    }
+
+    public String getVoltageAb() {
+        return voltageAb;
+    }
+
+    public void setVoltageAb(String voltageAb) {
+        this.voltageAb = voltageAb;
+    }
+
+    public String getVoltageBc() {
+        return voltageBc;
+    }
+
+    public void setVoltageBc(String voltageBc) {
+        this.voltageBc = voltageBc;
+    }
+
+    public String getVoltageCa() {
+        return voltageCa;
+    }
+
+    public void setVoltageCa(String voltageCa) {
+        this.voltageCa = voltageCa;
+    }
+
+    public String getCurrentA() {
+        return currentA;
+    }
+
+    public void setCurrentA(String currentA) {
+        this.currentA = currentA;
+    }
+
+    public String getCurrentB() {
+        return currentB;
+    }
+
+    public void setCurrentB(String currentB) {
+        this.currentB = currentB;
+    }
+
+    public String getCurrentC() {
+        return currentC;
+    }
+
+    public void setCurrentC(String currentC) {
+        this.currentC = currentC;
+    }
+
+    public String getPowerA() {
+        return powerA;
+    }
+
+    public void setPowerA(String powerA) {
+        this.powerA = powerA;
+    }
+
+    public String getPowerB() {
+        return powerB;
+    }
+
+    public void setPowerB(String powerB) {
+        this.powerB = powerB;
+    }
+
+    public String getPowerC() {
+        return powerC;
+    }
+
+    public void setPowerC(String powerC) {
+        this.powerC = powerC;
+    }
+
+    public String getPower() {
+        return power;
+    }
+
+    public void setPower(String power) {
+        this.power = power;
+    }
+
+    public String getTempA() {
+        return tempA;
+    }
+
+    public void setTempA(String tempA) {
+        this.tempA = tempA;
+    }
+
+    public String getTempB() {
+        return tempB;
+    }
+
+    public void setTempB(String tempB) {
+        this.tempB = tempB;
+    }
+
+    public String getTempC() {
+        return tempC;
+    }
+
+    public void setTempC(String tempC) {
+        this.tempC = tempC;
+    }
+
+    public String getWarnStatus() {
+        return warnStatus;
+    }
+
+    public void setWarnStatus(String warnStatus) {
+        this.warnStatus = warnStatus;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getZhengPower() {
+        return zhengPower;
+    }
+
+    public void setZhengPower(String zhengPower) {
+        this.zhengPower = zhengPower;
+    }
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityInfo.java
new file mode 100644
index 0000000..5d67c24
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityInfo.java
@@ -0,0 +1,177 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ * 鐢垫暟鎹帴鏀剁鐞�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+
+@TableName("RECEIVE_ELECTRICITY_INFO")
+@Schema( description = "鐢垫暟鎹帴鏀剁鐞�")
+public class ReceiveElectricityInfo {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private Byte deviceAddress;
+
+    @Schema(title ="缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+    @Schema(title ="缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+    @Schema(title ="鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private Byte functionCode;
+
+    @Schema(title ="瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+    @Schema(title ="瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+    @Schema(title ="鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+    @Schema(title ="杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+    @Schema(title ="鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+    @Schema(title ="鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+    @Schema(title ="鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(Byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValue.java
new file mode 100644
index 0000000..5e3e3be
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValue.java
@@ -0,0 +1,283 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@TableName("RECEIVE_ELECTRICITY_VALUE")
+@Schema(description = "鐢佃澶囨暟鎹�")
+public class ReceiveElectricityValue {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title ="N椤规俯搴�")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="A鐩哥數鍘�")
+    @TableField("VOLTAGE_A")
+    private String voltageA;
+
+    @Schema(title ="B椤圭數鍘�")
+    @TableField("VOLTAGE_B")
+    private String voltageB;
+
+    @Schema(title ="C椤圭數鍘�")
+    @TableField("VOLTAGE_C")
+    private String voltageC;
+
+    @Schema(title ="AB绾跨數鍘�")
+    @TableField("VOLTAGE_AB")
+    private String voltageAb;
+
+    @Schema(title ="BC绾跨數鍘�")
+    @TableField("VOLTAGE_BC")
+    private String voltageBc;
+
+    @Schema(title ="CA绾跨數鍘�")
+    @TableField("VOLTAGE_CA")
+    private String voltageCa;
+
+    @Schema(title ="A鐩哥數娴�")
+    @TableField("CURRENT_A")
+    private String currentA;
+
+    @Schema(title ="B鐩哥數娴�")
+    @TableField("CURRENT_B")
+    private String currentB;
+
+    @Schema(title ="C鐩哥數娴�")
+    @TableField("CURRENT_C")
+    private String currentC;
+
+    @Schema(title ="A鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_A")
+    private String powerA;
+
+    @Schema(title ="B鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_B")
+    private String powerB;
+
+    @Schema(title ="C鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_C")
+    private String powerC;
+
+    @Schema(title ="鎬绘湁鍔熷姛鐜�")
+    @TableField("POWER")
+    private String power;
+
+    @Schema(title ="A鐩告俯搴�")
+    @TableField("TEMP_A")
+    private String tempA;
+
+    @Schema(title ="B鐩告俯搴�")
+    @TableField("TEMP_B")
+    private String tempB;
+
+    @Schema(title ="C鐩告俯搴�")
+    @TableField("TEMP_C")
+    private String tempC;
+
+    @Schema(title ="鎶ヨ鐘舵��")
+    @TableField("WARN_STATUS")
+    private String warnStatus;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(description = "姝e悜鏈夊姛鐢佃兘")
+    @TableField("ZHENG_POWER")
+    private String zhengPower;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVoltageA() {
+        return voltageA;
+    }
+
+    public void setVoltageA(String voltageA) {
+        this.voltageA = voltageA;
+    }
+
+    public String getVoltageB() {
+        return voltageB;
+    }
+
+    public void setVoltageB(String voltageB) {
+        this.voltageB = voltageB;
+    }
+
+    public String getVoltageC() {
+        return voltageC;
+    }
+
+    public void setVoltageC(String voltageC) {
+        this.voltageC = voltageC;
+    }
+
+    public String getVoltageAb() {
+        return voltageAb;
+    }
+
+    public void setVoltageAb(String voltageAb) {
+        this.voltageAb = voltageAb;
+    }
+
+    public String getVoltageBc() {
+        return voltageBc;
+    }
+
+    public void setVoltageBc(String voltageBc) {
+        this.voltageBc = voltageBc;
+    }
+
+    public String getVoltageCa() {
+        return voltageCa;
+    }
+
+    public void setVoltageCa(String voltageCa) {
+        this.voltageCa = voltageCa;
+    }
+
+    public String getCurrentA() {
+        return currentA;
+    }
+
+    public void setCurrentA(String currentA) {
+        this.currentA = currentA;
+    }
+
+    public String getCurrentB() {
+        return currentB;
+    }
+
+    public void setCurrentB(String currentB) {
+        this.currentB = currentB;
+    }
+
+    public String getCurrentC() {
+        return currentC;
+    }
+
+    public void setCurrentC(String currentC) {
+        this.currentC = currentC;
+    }
+
+    public String getPowerA() {
+        return powerA;
+    }
+
+    public void setPowerA(String powerA) {
+        this.powerA = powerA;
+    }
+
+    public String getPowerB() {
+        return powerB;
+    }
+
+    public void setPowerB(String powerB) {
+        this.powerB = powerB;
+    }
+
+    public String getPowerC() {
+        return powerC;
+    }
+
+    public void setPowerC(String powerC) {
+        this.powerC = powerC;
+    }
+
+    public String getPower() {
+        return power;
+    }
+
+    public void setPower(String power) {
+        this.power = power;
+    }
+
+    public String getTempA() {
+        return tempA;
+    }
+
+    public void setTempA(String tempA) {
+        this.tempA = tempA;
+    }
+
+    public String getTempB() {
+        return tempB;
+    }
+
+    public void setTempB(String tempB) {
+        this.tempB = tempB;
+    }
+
+    public String getTempC() {
+        return tempC;
+    }
+
+    public void setTempC(String tempC) {
+        this.tempC = tempC;
+    }
+
+    public String getWarnStatus() {
+        return warnStatus;
+    }
+
+    public void setWarnStatus(String warnStatus) {
+        this.warnStatus = warnStatus;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getZhengPower() {
+        return zhengPower;
+    }
+
+    public void setZhengPower(String zhengPower) {
+        this.zhengPower = zhengPower;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValueFinal.java
new file mode 100644
index 0000000..16d825e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveElectricityValueFinal.java
@@ -0,0 +1,297 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+
+@TableName("RECEIVE_ELECTRICITY_VALUE_FINAL")
+@Schema(description = "鐢佃澶囨暟鎹�")
+public class ReceiveElectricityValueFinal {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private BigInteger id;
+
+    @Schema(title ="N椤规俯搴�")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="A鐩哥數鍘�")
+    @TableField("VOLTAGE_A")
+    private String voltageA;
+
+    @Schema(title ="B椤圭數鍘�")
+    @TableField("VOLTAGE_B")
+    private String voltageB;
+
+    @Schema(title ="C椤圭數鍘�")
+    @TableField("VOLTAGE_C")
+    private String voltageC;
+
+    @Schema(title ="AB绾跨數鍘�")
+    @TableField("VOLTAGE_AB")
+    private String voltageAb;
+
+    @Schema(title ="BC绾跨數鍘�")
+    @TableField("VOLTAGE_BC")
+    private String voltageBc;
+
+    @Schema(title ="CA绾跨數鍘�")
+    @TableField("VOLTAGE_CA")
+    private String voltageCa;
+
+    @Schema(title ="A鐩哥數娴�")
+    @TableField("CURRENT_A")
+    private String currentA;
+
+    @Schema(title ="B鐩哥數娴�")
+    @TableField("CURRENT_B")
+    private String currentB;
+
+    @Schema(title ="C鐩哥數娴�")
+    @TableField("CURRENT_C")
+    private String currentC;
+
+    @Schema(title ="A鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_A")
+    private String powerA;
+
+    @Schema(title ="B鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_B")
+    private String powerB;
+
+    @Schema(title ="C鐩告湁鍔熷姛鐜�")
+    @TableField("POWER_C")
+    private String powerC;
+
+    @Schema(title ="鎬绘湁鍔熷姛鐜�")
+    @TableField("POWER")
+    private String power;
+
+    @Schema(title ="A鐩告俯搴�")
+    @TableField("TEMP_A")
+    private String tempA;
+
+    @Schema(title ="B鐩告俯搴�")
+    @TableField("TEMP_B")
+    private String tempB;
+
+    @Schema(title ="C鐩告俯搴�")
+    @TableField("TEMP_C")
+    private String tempC;
+
+    @Schema(title ="鎶ヨ鐘舵��")
+    @TableField("WARN_STATUS")
+    private String warnStatus;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="姝e悜鏈夊姛鐢佃兘")
+    @TableField("ZHENG_POWER")
+    private String zhengPower;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVoltageA() {
+        return voltageA;
+    }
+
+    public void setVoltageA(String voltageA) {
+        this.voltageA = voltageA;
+    }
+
+    public String getVoltageB() {
+        return voltageB;
+    }
+
+    public void setVoltageB(String voltageB) {
+        this.voltageB = voltageB;
+    }
+
+    public String getVoltageC() {
+        return voltageC;
+    }
+
+    public void setVoltageC(String voltageC) {
+        this.voltageC = voltageC;
+    }
+
+    public String getVoltageAb() {
+        return voltageAb;
+    }
+
+    public void setVoltageAb(String voltageAb) {
+        this.voltageAb = voltageAb;
+    }
+
+    public String getVoltageBc() {
+        return voltageBc;
+    }
+
+    public void setVoltageBc(String voltageBc) {
+        this.voltageBc = voltageBc;
+    }
+
+    public String getVoltageCa() {
+        return voltageCa;
+    }
+
+    public void setVoltageCa(String voltageCa) {
+        this.voltageCa = voltageCa;
+    }
+
+    public String getCurrentA() {
+        return currentA;
+    }
+
+    public void setCurrentA(String currentA) {
+        this.currentA = currentA;
+    }
+
+    public String getCurrentB() {
+        return currentB;
+    }
+
+    public void setCurrentB(String currentB) {
+        this.currentB = currentB;
+    }
+
+    public String getCurrentC() {
+        return currentC;
+    }
+
+    public void setCurrentC(String currentC) {
+        this.currentC = currentC;
+    }
+
+    public String getPowerA() {
+        return powerA;
+    }
+
+    public void setPowerA(String powerA) {
+        this.powerA = powerA;
+    }
+
+    public String getPowerB() {
+        return powerB;
+    }
+
+    public void setPowerB(String powerB) {
+        this.powerB = powerB;
+    }
+
+    public String getPowerC() {
+        return powerC;
+    }
+
+    public void setPowerC(String powerC) {
+        this.powerC = powerC;
+    }
+
+    public String getPower() {
+        return power;
+    }
+
+    public void setPower(String power) {
+        this.power = power;
+    }
+
+    public String getTempA() {
+        return tempA;
+    }
+
+    public void setTempA(String tempA) {
+        this.tempA = tempA;
+    }
+
+    public String getTempB() {
+        return tempB;
+    }
+
+    public void setTempB(String tempB) {
+        this.tempB = tempB;
+    }
+
+    public String getTempC() {
+        return tempC;
+    }
+
+    public void setTempC(String tempC) {
+        this.tempC = tempC;
+    }
+
+    public String getWarnStatus() {
+        return warnStatus;
+    }
+
+    public void setWarnStatus(String warnStatus) {
+        this.warnStatus = warnStatus;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getZhengPower() {
+        return zhengPower;
+    }
+
+    public void setZhengPower(String zhengPower) {
+        this.zhengPower = zhengPower;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveInfo.java
new file mode 100644
index 0000000..dce8918
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveInfo.java
@@ -0,0 +1,82 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.io.Serializable;
+
+/**
+ * <p>
+ * 鏁版嵁鎺ユ敹淇℃伅
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-10
+ */
+@TableName("RECEIVE_INFO")
+@Schema(description = "鏁版嵁鎺ユ敹淇℃伅")
+public class ReceiveInfo implements Serializable {
+
+    @Schema(title = "涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title = "鏁版嵁鍐呭")
+    @TableField("CONTENT")
+    private String content;
+
+    @Schema(title = "鍗忚")
+    @TableField("PROTOCOL")
+    private String protocol;
+
+    @Schema(title = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title = "璁惧绫诲瀷")
+    @TableField("DEVICT_TYPE")
+    private Integer deviceType;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getContent() {
+        return content;
+    }
+
+    public void setContent(String content) {
+        this.content = content;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Integer getDeviceType() {
+        return deviceType;
+    }
+
+    public void setDeviceType(Integer deviceType) {
+        this.deviceType = deviceType;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveModuleInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveModuleInfo.java
new file mode 100644
index 0000000..e86f5fb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveModuleInfo.java
@@ -0,0 +1,176 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ * modbus鏁版嵁妯℃澘
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-27
+ */
+@TableName("RECEIVE_MODULE_INFO")
+@Schema(description = "modbus鏁版嵁妯℃澘")
+public class ReceiveModuleInfo {
+
+    @Schema(title = "涓婚敭")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Long id;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private Byte deviceAddress;
+
+    @Schema(title ="缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+    @Schema(title ="缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+    @Schema(title ="鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private Byte functionCode;
+
+    @Schema(title ="瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+    @Schema(title ="瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+    @Schema(title ="鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+    @Schema(title ="杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+    @Schema(title ="鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+    @Schema(title ="鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+    @Schema(title ="鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(Byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilAnalyse.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilAnalyse.java
new file mode 100644
index 0000000..8f1ed20
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilAnalyse.java
@@ -0,0 +1,309 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 娌硅鍒嗘瀽鏁版嵁
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@TableName("RECEIVE_OIL_ANALYSE")
+@Schema( description = "娌硅鍒嗘瀽鏁版嵁")
+public class ReceiveOilAnalyse {
+
+    @Schema(description = "涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private Long id;
+
+    @Schema(description = "璐ㄩ噺娴侀噺")
+    @TableField("QUALITY_FLOW")
+    private String qualityFlow;
+
+    @Schema(description = "瀵嗗害")
+    @TableField("DENSITY")
+    private String density;
+
+    @Schema(description = "娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(description = "浣撶Н娴侀噺")
+    @TableField("VOLUME_FLOW")
+    private String volumeFlow;
+
+    @Schema(description = "浣撶Н璐ㄩ噺")
+    @TableField("VOLUME_QUALITY")
+    private String volumeQuality;
+
+    @Schema(description = "浣撶Н鎬婚噺")
+    @TableField("VOLUME_TOTAL")
+    private String volumeTotal;
+
+    @Schema(description = "鍚按鐜�")
+    @TableField("WATER_RATE")
+    private String waterRate;
+
+    @Schema(description = "绾补璐ㄩ噺绱Н")
+    @TableField("OIL_TOTAL")
+    private String oilTotal;
+
+    @Schema(description = "绾按璐ㄩ噺绱Н")
+    @TableField("WATER_TOTAL")
+    private String waterTotal;
+
+    @Schema(description = "绾补閲忔爣鍑嗘俯搴︿笅")
+    @TableField("OIL_TEMP")
+    private String oilTemp;
+
+    @Schema(description = "绾按閲忔爣鍑嗘俯搴︿笅")
+    @TableField("WATER_TEMP")
+    private String waterTemp;
+
+    @Schema(description = "绾补閲�")
+    @TableField("OIL")
+    private String oil;
+
+    @Schema(description = "绾按閲�")
+    @TableField("WATER")
+    private String water;
+
+    @Schema(description = "娓╄ˉ鍚庢补瀵嗗害")
+    @TableField("TEMP_OIL_DENSITY")
+    private String tempOilDensity;
+
+    @Schema(description = "娓╄ˉ鍚庢按瀵嗗害")
+    @TableField("TEMP_WATER_DENSITY")
+    private String tempWaterDensity;
+
+    @Schema(description = "绾补鐬椂娴侀噺")
+    @TableField("OIL_TIME_FLOW")
+    private String oilTimeFlow;
+
+    @Schema(description = "鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(description = "绱娴侀噺")
+    @TableField("FLOW_TOTAL")
+    private String flowTotal;
+
+    @Schema(description = "璐ㄩ噺鎬婚噺L")
+    @TableField("FLOW_TOTAL_L")
+    private String flowTotalL;
+
+    @Schema(description = "璐ㄩ噺鎬婚噺H")
+    @TableField("FLOW_TOTAL_H")
+    private String flowTotalH;
+
+    @Schema(description = "浣撶Н鎬婚噺L")
+    @TableField("VOLUME_TOTAL_L")
+    private String volumeTotalL;
+
+    @Schema(description = "浣撶Н鎬婚噺H")
+    @TableField("VOLUME_TOTAL_H")
+    private String volumeTotalH;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getQualityFlow() {
+        return qualityFlow;
+    }
+
+    public void setQualityFlow(String qualityFlow) {
+        this.qualityFlow = qualityFlow;
+    }
+
+    public String getDensity() {
+        return density;
+    }
+
+    public void setDensity(String density) {
+        this.density = density;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVolumeFlow() {
+        return volumeFlow;
+    }
+
+    public void setVolumeFlow(String volumeFlow) {
+        this.volumeFlow = volumeFlow;
+    }
+
+    public String getVolumeQuality() {
+        return volumeQuality;
+    }
+
+    public void setVolumeQuality(String volumeQuality) {
+        this.volumeQuality = volumeQuality;
+    }
+
+    public String getVolumeTotal() {
+        return volumeTotal;
+    }
+
+    public void setVolumeTotal(String volumeTotal) {
+        this.volumeTotal = volumeTotal;
+    }
+
+    public String getWaterRate() {
+        return waterRate;
+    }
+
+    public void setWaterRate(String waterRate) {
+        this.waterRate = waterRate;
+    }
+
+    public String getOilTotal() {
+        return oilTotal;
+    }
+
+    public void setOilTotal(String oilTotal) {
+        this.oilTotal = oilTotal;
+    }
+
+    public String getWaterTotal() {
+        return waterTotal;
+    }
+
+    public void setWaterTotal(String waterTotal) {
+        this.waterTotal = waterTotal;
+    }
+
+    public String getOilTemp() {
+        return oilTemp;
+    }
+
+    public void setOilTemp(String oilTemp) {
+        this.oilTemp = oilTemp;
+    }
+
+    public String getWaterTemp() {
+        return waterTemp;
+    }
+
+    public void setWaterTemp(String waterTemp) {
+        this.waterTemp = waterTemp;
+    }
+
+    public String getOil() {
+        return oil;
+    }
+
+    public void setOil(String oil) {
+        this.oil = oil;
+    }
+
+    public String getWater() {
+        return water;
+    }
+
+    public void setWater(String water) {
+        this.water = water;
+    }
+
+    public String getTempOilDensity() {
+        return tempOilDensity;
+    }
+
+    public void setTempOilDensity(String tempOilDensity) {
+        this.tempOilDensity = tempOilDensity;
+    }
+
+    public String getTempWaterDensity() {
+        return tempWaterDensity;
+    }
+
+    public void setTempWaterDensity(String tempWaterDensity) {
+        this.tempWaterDensity = tempWaterDensity;
+    }
+
+    public String getOilTimeFlow() {
+        return oilTimeFlow;
+    }
+
+    public void setOilTimeFlow(String oilTimeFlow) {
+        this.oilTimeFlow = oilTimeFlow;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getFlowTotal() {
+        return flowTotal;
+    }
+
+    public void setFlowTotal(String flowTotal) {
+        this.flowTotal = flowTotal;
+    }
+
+    public String getFlowTotalL() {
+        return flowTotalL;
+    }
+
+    public void setFlowTotalL(String flowTotalL) {
+        this.flowTotalL = flowTotalL;
+    }
+
+    public String getFlowTotalH() {
+        return flowTotalH;
+    }
+
+    public void setFlowTotalH(String flowTotalH) {
+        this.flowTotalH = flowTotalH;
+    }
+
+    public String getVolumeTotalL() {
+        return volumeTotalL;
+    }
+
+    public void setVolumeTotalL(String volumeTotalL) {
+        this.volumeTotalL = volumeTotalL;
+    }
+
+    public String getVolumeTotalH() {
+        return volumeTotalH;
+    }
+
+    public void setVolumeTotalH(String volumeTotalH) {
+        this.volumeTotalH = volumeTotalH;
+    }
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilInfo.java
new file mode 100644
index 0000000..7cd07fb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilInfo.java
@@ -0,0 +1,184 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ * 娌规暟鎹帴鏀剁鐞�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@TableName("RECEIVE_OIL_INFO")
+@Schema(description = "娌规暟鎹帴鏀剁鐞�")
+public class ReceiveOilInfo {
+
+    @Schema(title = "涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title = "鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private byte deviceAddress;
+
+    @Schema(title = "缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+    @Schema(title = "缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+    @Schema(title = "鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private byte functionCode;
+
+    @Schema(title = "瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+    @Schema(title = "瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+    @Schema(title = "鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+    @Schema(title = "杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+    @Schema(title = "鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+    @Schema(title = "鏁版嵁鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+    @Schema(title = "鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(Byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public void setDeviceAddress(byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public void setFunctionCode(byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValue.java
new file mode 100644
index 0000000..a35b342
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValue.java
@@ -0,0 +1,307 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@TableName("RECEIVE_OIL_VALUE")
+@Schema( description = "娌硅澶囧疄鏃舵暟鎹�")
+public class ReceiveOilValue {
+
+    @Schema(description = "涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(description = "璐ㄩ噺娴侀噺")
+    @TableField("QUALITY_FLOW")
+    private String qualityFlow;
+
+    @Schema(description = "瀵嗗害")
+    @TableField("DENSITY")
+    private String density;
+
+    @Schema(description = "娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(description = "浣撶Н娴侀噺")
+    @TableField("VOLUME_FLOW")
+    private String volumeFlow;
+
+    @Schema(description = "浣撶Н璐ㄩ噺")
+    @TableField("VOLUME_QUALITY")
+    private String volumeQuality;
+
+    @Schema(description = "浣撶Н鎬婚噺")
+    @TableField("VOLUME_TOTAL")
+    private String volumeTotal;
+
+    @Schema(description = "鍚按鐜�")
+    @TableField("WATER_RATE")
+    private String waterRate;
+
+    @Schema(description = "绾补璐ㄩ噺绱Н")
+    @TableField("OIL_TOTAL")
+    private String oilTotal;
+
+    @Schema(description = "绾按璐ㄩ噺绱Н")
+    @TableField("WATER_TOTAL")
+    private String waterTotal;
+
+    @Schema(description = "绾补閲忔爣鍑嗘俯搴︿笅")
+    @TableField("OIL_TEMP")
+    private String oilTemp;
+
+    @Schema(description = "绾按閲忔爣鍑嗘俯搴︿笅")
+    @TableField("WATER_TEMP")
+    private String waterTemp;
+
+    @Schema(description = "绾补閲�")
+    @TableField("OIL")
+    private String oil;
+
+    @Schema(description = "绾按閲�")
+    @TableField("WATER")
+    private String water;
+
+    @Schema(description = "娓╄ˉ鍚庢补瀵嗗害")
+    @TableField("TEMP_OIL_DENSITY")
+    private String tempOilDensity;
+
+    @Schema(description = "娓╄ˉ鍚庢按瀵嗗害")
+    @TableField("TEMP_WATER_DENSITY")
+    private String tempWaterDensity;
+
+    @Schema(description = "绾补鐬椂娴侀噺")
+    @TableField("OIL_TIME_FLOW")
+    private String oilTimeFlow;
+
+    @Schema(description = "鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(description = "绱娴侀噺")
+    @TableField("FLOW_TOTAL")
+    private String flowTotal;
+
+    @Schema(description = "璐ㄩ噺鎬婚噺L")
+    @TableField("FLOW_TOTAL_L")
+    private String flowTotalL;
+
+    @Schema(description = "璐ㄩ噺鎬婚噺H")
+    @TableField("FLOW_TOTAL_H")
+    private String flowTotalH;
+
+    @Schema(description = "浣撶Н鎬婚噺L")
+    @TableField("VOLUME_TOTAL_L")
+    private String volumeTotalL;
+
+    @Schema(description = "浣撶Н鎬婚噺H")
+    @TableField("VOLUME_TOTAL_H")
+    private String volumeTotalH;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getQualityFlow() {
+        return qualityFlow;
+    }
+
+    public void setQualityFlow(String qualityFlow) {
+        this.qualityFlow = qualityFlow;
+    }
+
+    public String getDensity() {
+        return density;
+    }
+
+    public void setDensity(String density) {
+        this.density = density;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVolumeFlow() {
+        return volumeFlow;
+    }
+
+    public void setVolumeFlow(String volumeFlow) {
+        this.volumeFlow = volumeFlow;
+    }
+
+    public String getVolumeQuality() {
+        return volumeQuality;
+    }
+
+    public void setVolumeQuality(String volumeQuality) {
+        this.volumeQuality = volumeQuality;
+    }
+
+    public String getVolumeTotal() {
+        return volumeTotal;
+    }
+
+    public void setVolumeTotal(String volumeTotal) {
+        this.volumeTotal = volumeTotal;
+    }
+
+    public String getWaterRate() {
+        return waterRate;
+    }
+
+    public void setWaterRate(String waterRate) {
+        this.waterRate = waterRate;
+    }
+
+    public String getOilTotal() {
+        return oilTotal;
+    }
+
+    public void setOilTotal(String oilTotal) {
+        this.oilTotal = oilTotal;
+    }
+
+    public String getWaterTotal() {
+        return waterTotal;
+    }
+
+    public void setWaterTotal(String waterTotal) {
+        this.waterTotal = waterTotal;
+    }
+
+    public String getOilTemp() {
+        return oilTemp;
+    }
+
+    public void setOilTemp(String oilTemp) {
+        this.oilTemp = oilTemp;
+    }
+
+    public String getWaterTemp() {
+        return waterTemp;
+    }
+
+    public void setWaterTemp(String waterTemp) {
+        this.waterTemp = waterTemp;
+    }
+
+    public String getOil() {
+        return oil;
+    }
+
+    public void setOil(String oil) {
+        this.oil = oil;
+    }
+
+    public String getWater() {
+        return water;
+    }
+
+    public void setWater(String water) {
+        this.water = water;
+    }
+
+    public String getTempOilDensity() {
+        return tempOilDensity;
+    }
+
+    public void setTempOilDensity(String tempOilDensity) {
+        this.tempOilDensity = tempOilDensity;
+    }
+
+    public String getTempWaterDensity() {
+        return tempWaterDensity;
+    }
+
+    public void setTempWaterDensity(String tempWaterDensity) {
+        this.tempWaterDensity = tempWaterDensity;
+    }
+
+    public String getOilTimeFlow() {
+        return oilTimeFlow;
+    }
+
+    public void setOilTimeFlow(String oilTimeFlow) {
+        this.oilTimeFlow = oilTimeFlow;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getFlowTotal() {
+        return flowTotal;
+    }
+
+    public void setFlowTotal(String flowTotal) {
+        this.flowTotal = flowTotal;
+    }
+
+    public String getFlowTotalL() {
+        return flowTotalL;
+    }
+
+    public void setFlowTotalL(String flowTotalL) {
+        this.flowTotalL = flowTotalL;
+    }
+
+    public String getFlowTotalH() {
+        return flowTotalH;
+    }
+
+    public void setFlowTotalH(String flowTotalH) {
+        this.flowTotalH = flowTotalH;
+    }
+
+    public String getVolumeTotalL() {
+        return volumeTotalL;
+    }
+
+    public void setVolumeTotalL(String volumeTotalL) {
+        this.volumeTotalL = volumeTotalL;
+    }
+
+    public String getVolumeTotalH() {
+        return volumeTotalH;
+    }
+
+    public void setVolumeTotalH(String volumeTotalH) {
+        this.volumeTotalH = volumeTotalH;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValueFinal.java
new file mode 100644
index 0000000..8ccf3ed
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveOilValueFinal.java
@@ -0,0 +1,321 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+
+@TableName("RECEIVE_OIL_VALUE_FINAL")
+@Schema(description = "娌硅澶囧疄鏃舵暟鎹�")
+public class ReceiveOilValueFinal {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private BigInteger id;
+
+    @Schema(title ="璐ㄩ噺娴侀噺")
+    @TableField("QUALITY_FLOW")
+    private String qualityFlow;
+
+    @Schema(title ="瀵嗗害")
+    @TableField("DENSITY")
+    private String density;
+
+    @Schema(title ="娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="浣撶Н娴侀噺")
+    @TableField("VOLUME_FLOW")
+    private String volumeFlow;
+
+    @Schema(title ="浣撶Н璐ㄩ噺")
+    @TableField("VOLUME_QUALITY")
+    private String volumeQuality;
+
+    @Schema(title ="浣撶Н鎬婚噺")
+    @TableField("VOLUME_TOTAL")
+    private String volumeTotal;
+
+    @Schema(title ="鍚按鐜�")
+    @TableField("WATER_RATE")
+    private String waterRate;
+
+    @Schema(title ="绾补璐ㄩ噺绱Н")
+    @TableField("OIL_TOTAL")
+    private String oilTotal;
+
+    @Schema(title ="绾按璐ㄩ噺绱Н")
+    @TableField("WATER_TOTAL")
+    private String waterTotal;
+
+    @Schema(title ="绾补閲忔爣鍑嗘俯搴︿笅")
+    @TableField("OIL_TEMP")
+    private String oilTemp;
+
+    @Schema(title ="绾按閲忔爣鍑嗘俯搴︿笅")
+    @TableField("WATER_TEMP")
+    private String waterTemp;
+
+    @Schema(title ="绾补閲�")
+    @TableField("OIL")
+    private String oil;
+
+    @Schema(title ="绾按閲�")
+    @TableField("WATER")
+    private String water;
+
+    @Schema(title ="娓╄ˉ鍚庢补瀵嗗害")
+    @TableField("TEMP_OIL_DENSITY")
+    private String tempOilDensity;
+
+    @Schema(title ="娓╄ˉ鍚庢按瀵嗗害")
+    @TableField("TEMP_WATER_DENSITY")
+    private String tempWaterDensity;
+
+    @Schema(title ="绾补鐬椂娴侀噺")
+    @TableField("OIL_TIME_FLOW")
+    private String oilTimeFlow;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="绱娴侀噺")
+    @TableField("FLOW_TOTAL")
+    private String flowTotal;
+
+    @Schema(title ="璐ㄩ噺鎬婚噺L")
+    @TableField("FLOW_TOTAL_L")
+    private String flowTotalL;
+
+    @Schema(title ="璐ㄩ噺鎬婚噺H")
+    @TableField("FLOW_TOTAL_H")
+    private String flowTotalH;
+
+    @Schema(title ="浣撶Н鎬婚噺L")
+    @TableField("VOLUME_TOTAL_L")
+    private String volumeTotalL;
+
+    @Schema(title ="浣撶Н鎬婚噺H")
+    @TableField("VOLUME_TOTAL_H")
+    private String volumeTotalH;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getQualityFlow() {
+        return qualityFlow;
+    }
+
+    public void setQualityFlow(String qualityFlow) {
+        this.qualityFlow = qualityFlow;
+    }
+
+    public String getDensity() {
+        return density;
+    }
+
+    public void setDensity(String density) {
+        this.density = density;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getVolumeFlow() {
+        return volumeFlow;
+    }
+
+    public void setVolumeFlow(String volumeFlow) {
+        this.volumeFlow = volumeFlow;
+    }
+
+    public String getVolumeQuality() {
+        return volumeQuality;
+    }
+
+    public void setVolumeQuality(String volumeQuality) {
+        this.volumeQuality = volumeQuality;
+    }
+
+    public String getVolumeTotal() {
+        return volumeTotal;
+    }
+
+    public void setVolumeTotal(String volumeTotal) {
+        this.volumeTotal = volumeTotal;
+    }
+
+    public String getWaterRate() {
+        return waterRate;
+    }
+
+    public void setWaterRate(String waterRate) {
+        this.waterRate = waterRate;
+    }
+
+    public String getOilTotal() {
+        return oilTotal;
+    }
+
+    public void setOilTotal(String oilTotal) {
+        this.oilTotal = oilTotal;
+    }
+
+    public String getWaterTotal() {
+        return waterTotal;
+    }
+
+    public void setWaterTotal(String waterTotal) {
+        this.waterTotal = waterTotal;
+    }
+
+    public String getOilTemp() {
+        return oilTemp;
+    }
+
+    public void setOilTemp(String oilTemp) {
+        this.oilTemp = oilTemp;
+    }
+
+    public String getWaterTemp() {
+        return waterTemp;
+    }
+
+    public void setWaterTemp(String waterTemp) {
+        this.waterTemp = waterTemp;
+    }
+
+    public String getOil() {
+        return oil;
+    }
+
+    public void setOil(String oil) {
+        this.oil = oil;
+    }
+
+    public String getWater() {
+        return water;
+    }
+
+    public void setWater(String water) {
+        this.water = water;
+    }
+
+    public String getTempOilDensity() {
+        return tempOilDensity;
+    }
+
+    public void setTempOilDensity(String tempOilDensity) {
+        this.tempOilDensity = tempOilDensity;
+    }
+
+    public String getTempWaterDensity() {
+        return tempWaterDensity;
+    }
+
+    public void setTempWaterDensity(String tempWaterDensity) {
+        this.tempWaterDensity = tempWaterDensity;
+    }
+
+    public String getOilTimeFlow() {
+        return oilTimeFlow;
+    }
+
+    public void setOilTimeFlow(String oilTimeFlow) {
+        this.oilTimeFlow = oilTimeFlow;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getFlowTotal() {
+        return flowTotal;
+    }
+
+    public void setFlowTotal(String flowTotal) {
+        this.flowTotal = flowTotal;
+    }
+
+    public String getFlowTotalL() {
+        return flowTotalL;
+    }
+
+    public void setFlowTotalL(String flowTotalL) {
+        this.flowTotalL = flowTotalL;
+    }
+
+    public String getFlowTotalH() {
+        return flowTotalH;
+    }
+
+    public void setFlowTotalH(String flowTotalH) {
+        this.flowTotalH = flowTotalH;
+    }
+
+    public String getVolumeTotalL() {
+        return volumeTotalL;
+    }
+
+    public void setVolumeTotalL(String volumeTotalL) {
+        this.volumeTotalL = volumeTotalL;
+    }
+
+    public String getVolumeTotalH() {
+        return volumeTotalH;
+    }
+
+    public void setVolumeTotalH(String volumeTotalH) {
+        this.volumeTotalH = volumeTotalH;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSelectRule.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSelectRule.java
new file mode 100644
index 0000000..eeff148
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSelectRule.java
@@ -0,0 +1,83 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+
+/**
+ * <p>
+ * 鏁版嵁娓呮礂瑙勫垯
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-09
+ */
+@TableName("RECEIVE_SELECT_RULE")
+@Schema( description = "鏁版嵁娓呮礂瑙勫垯")
+public class ReceiveSelectRule {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private BigInteger id;
+
+    @Schema(title ="瑙勫垯鍚嶇О")
+    @TableField("RULE_NAME")
+    private String ruleName;
+
+    @Schema(title ="鍙傛暟")
+    @TableField("PARAM")
+    private String param;
+
+    @Schema(title ="瑙勫垯")
+    @TableField("RULE")
+    private String rule;
+
+    @Schema(title ="鍙傛暟鍊�")
+    @TableField("VALUE")
+    private BigDecimal value;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getRuleName() {
+        return ruleName;
+    }
+
+    public void setRuleName(String ruleName) {
+        this.ruleName = ruleName;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public String getRule() {
+        return rule;
+    }
+
+    public void setRule(String rule) {
+        this.rule = rule;
+    }
+
+    public BigDecimal getValue() {
+        return value;
+    }
+
+    public void setValue(BigDecimal value) {
+        this.value = value;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmAnalyse.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmAnalyse.java
new file mode 100644
index 0000000..a19d104
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmAnalyse.java
@@ -0,0 +1,153 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+
+@TableName("RECEIVE_SLM_ANALYSE")
+@Schema(description = "闆疯揪璁惧瀹炴椂鏁版嵁")
+public class ReceiveSlmAnalyse {
+
+    @TableId(value = "ID",  type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+     @Schema(title ="婵�鍏堿璺濊埞璺濈")
+    @TableField("ADIS")
+    private String adis;
+
+     @Schema(title ="婵�鍏塀璺濊埞璺濈")
+    @TableField("BDIS")
+    private String bdis;
+
+     @Schema(title ="A鎷㈤��")
+    @TableField("ASPEED")
+    private String aspeed;
+
+     @Schema(title ="B鎷㈤��")
+    @TableField("BSPEED")
+    private String bspeed;
+
+     @Schema(title ="婵�鍏堿閫熷害鎶ヨ")
+    @TableField("AALARM")
+    private String aalarm;
+
+     @Schema(title ="婵�鍏塀閫熷害鎶ヨ")
+    @TableField("BALARM")
+    private String balarm;
+
+     @Schema(title ="褰撳墠鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+     @Schema(title ="娉婁綅鍚嶇О")
+    @TableField("BERTHNAME")
+    private String berthname;
+
+     @Schema(title ="鑸硅埗鍚嶇О")
+    @TableField("BOATNAME")
+    private String boatname;
+
+     @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getAdis() {
+        return adis;
+    }
+
+    public void setAdis(String adis) {
+        this.adis = adis;
+    }
+
+    public String getBdis() {
+        return bdis;
+    }
+
+    public void setBdis(String bdis) {
+        this.bdis = bdis;
+    }
+
+    public String getAspeed() {
+        return aspeed;
+    }
+
+    public void setAspeed(String aspeed) {
+        this.aspeed = aspeed;
+    }
+
+    public String getBspeed() {
+        return bspeed;
+    }
+
+    public void setBspeed(String bspeed) {
+        this.bspeed = bspeed;
+    }
+
+    public String getAalarm() {
+        return aalarm;
+    }
+
+    public void setAalarm(String aalarm) {
+        this.aalarm = aalarm;
+    }
+
+    public String getBalarm() {
+        return balarm;
+    }
+
+    public void setBalarm(String balarm) {
+        this.balarm = balarm;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getBerthname() {
+        return berthname;
+    }
+
+    public void setBerthname(String berthname) {
+        this.berthname = berthname;
+    }
+
+    public String getBoatname() {
+        return boatname;
+    }
+
+    public void setBoatname(String boatname) {
+        this.boatname = boatname;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmInfo.java
new file mode 100644
index 0000000..c6f21b9
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmInfo.java
@@ -0,0 +1,180 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+
+/**
+ * <p>
+ * 闆疯揪鏁版嵁鎺ユ敹绠$悊
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+
+@TableName("RECEIVE_SLM_INFO")
+@Schema(description = "闆疯揪鏁版嵁鎺ユ敹绠$悊")
+public class ReceiveSlmInfo {
+
+     @Schema(title ="涓婚敭")
+    @TableId(value = "ID",  type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+     @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+     @Schema(title ="鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private byte deviceAddress;
+
+     @Schema(title ="缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+     @Schema(title ="缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+     @Schema(title ="鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private byte functionCode;
+
+     @Schema(title ="瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+     @Schema(title ="瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+     @Schema(title ="鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+     @Schema(title ="杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+     @Schema(title ="鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+     @Schema(title ="鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+     @Schema(title ="鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValue.java
new file mode 100644
index 0000000..bd2af02
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValue.java
@@ -0,0 +1,165 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+
+@TableName("RECEIVE_SLM_VALUE")
+@Schema(description = "闆疯揪璁惧瀹炴椂鏁版嵁")
+public class ReceiveSlmValue {
+
+    @TableId(value = "ID",  type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+     @Schema(title ="婵�鍏堿璺濊埞璺濈")
+    @TableField("ADIS")
+    private String adis;
+
+     @Schema(title ="婵�鍏塀璺濊埞璺濈")
+    @TableField("BDIS")
+    private String bdis;
+
+     @Schema(title ="A鎷㈤��")
+    @TableField("ASPEED")
+    private String aspeed;
+
+     @Schema(title ="B鎷㈤��")
+    @TableField("BSPEED")
+    private String bspeed;
+
+     @Schema(title ="婵�鍏堿閫熷害鎶ヨ")
+    @TableField("AALARM")
+    private String aalarm;
+
+     @Schema(title ="婵�鍏塀閫熷害鎶ヨ")
+    @TableField("BALARM")
+    private String balarm;
+
+     @Schema(title ="褰撳墠鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+     @Schema(title ="娉婁綅鍚嶇О")
+    @TableField("BERTHNAME")
+    private String berthname;
+
+     @Schema(title ="鑸硅埗鍚嶇О")
+    @TableField("BOATNAME")
+    private String boatname;
+
+     @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getAdis() {
+        return adis;
+    }
+
+    public void setAdis(String adis) {
+        this.adis = adis;
+    }
+
+    public String getBdis() {
+        return bdis;
+    }
+
+    public void setBdis(String bdis) {
+        this.bdis = bdis;
+    }
+
+    public String getAspeed() {
+        return aspeed;
+    }
+
+    public void setAspeed(String aspeed) {
+        this.aspeed = aspeed;
+    }
+
+    public String getBspeed() {
+        return bspeed;
+    }
+
+    public void setBspeed(String bspeed) {
+        this.bspeed = bspeed;
+    }
+
+    public String getAalarm() {
+        return aalarm;
+    }
+
+    public void setAalarm(String aalarm) {
+        this.aalarm = aalarm;
+    }
+
+    public String getBalarm() {
+        return balarm;
+    }
+
+    public void setBalarm(String balarm) {
+        this.balarm = balarm;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getBerthname() {
+        return berthname;
+    }
+
+    public void setBerthname(String berthname) {
+        this.berthname = berthname;
+    }
+
+    public String getBoatname() {
+        return boatname;
+    }
+
+    public void setBoatname(String boatname) {
+        this.boatname = boatname;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValueFinal.java
new file mode 100644
index 0000000..3ab4741
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveSlmValueFinal.java
@@ -0,0 +1,165 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+
+@TableName("RECEIVE_SLM_VALUE_FINAL")
+@Schema(description = "闆疯揪璁惧瀹炴椂鏁版嵁")
+public class ReceiveSlmValueFinal {
+
+    @TableId(value = "ID",  type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+    @Schema(title ="婵�鍏堿璺濊埞璺濈")
+    @TableField("ADIS")
+    private String adis;
+
+    @Schema(title ="婵�鍏塀璺濊埞璺濈")
+    @TableField("BDIS")
+    private String bdis;
+
+    @Schema(title ="A鎷㈤��")
+    @TableField("ASPEED")
+    private String aspeed;
+
+    @Schema(title ="B鎷㈤��")
+    @TableField("BSPEED")
+    private String bspeed;
+
+    @Schema(title ="婵�鍏堿閫熷害鎶ヨ")
+    @TableField("AALARM")
+    private String aalarm;
+
+    @Schema(title ="婵�鍏塀閫熷害鎶ヨ")
+    @TableField("BALARM")
+    private String balarm;
+
+    @Schema(title ="褰撳墠鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+    @Schema(title ="娉婁綅鍚嶇О")
+    @TableField("BERTHNAME")
+    private String berthname;
+
+    @Schema(title ="鑸硅埗鍚嶇О")
+    @TableField("BOATNAME")
+    private String boatname;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getAdis() {
+        return adis;
+    }
+
+    public void setAdis(String adis) {
+        this.adis = adis;
+    }
+
+    public String getBdis() {
+        return bdis;
+    }
+
+    public void setBdis(String bdis) {
+        this.bdis = bdis;
+    }
+
+    public String getAspeed() {
+        return aspeed;
+    }
+
+    public void setAspeed(String aspeed) {
+        this.aspeed = aspeed;
+    }
+
+    public String getBspeed() {
+        return bspeed;
+    }
+
+    public void setBspeed(String bspeed) {
+        this.bspeed = bspeed;
+    }
+
+    public String getAalarm() {
+        return aalarm;
+    }
+
+    public void setAalarm(String aalarm) {
+        this.aalarm = aalarm;
+    }
+
+    public String getBalarm() {
+        return balarm;
+    }
+
+    public void setBalarm(String balarm) {
+        this.balarm = balarm;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public String getBerthname() {
+        return berthname;
+    }
+
+    public void setBerthname(String berthname) {
+        this.berthname = berthname;
+    }
+
+    public String getBoatname() {
+        return boatname;
+    }
+
+    public void setBoatname(String boatname) {
+        this.boatname = boatname;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterAnalyse.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterAnalyse.java
new file mode 100644
index 0000000..58b7429
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterAnalyse.java
@@ -0,0 +1,201 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘村垎鏋愭暟鎹�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@TableName("RECEIVE_WATER_ANALYSE")
+@Schema( description = "姘村垎鏋愭暟鎹�")
+public class ReceiveWaterAnalyse {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private Long id;
+
+    @Schema(title ="鐬椂娴侀噺")
+    @TableField("TIME_FLOW")
+    private String timeFlow;
+
+    @Schema(title ="鐬椂娴侀��")
+    @TableField("FLOW_RATE")
+    private String flowRate;
+
+    @Schema(title ="娴侀噺鐧惧垎姣�")
+    @TableField("RATE")
+    private String rate;
+
+    @Schema(title ="娴佷綋鐢靛姣�")
+    @TableField("FLOW_ELECTRICITY")
+    private String flowElectricity;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title = "姘存繁")
+    @TableField("WATER_DEEP")
+    private String waterDeep;
+
+    @Schema(title = "姘村帇")
+    @TableField("WATER_YA")
+    private String waterYa;
+
+    @Schema(title = "姝e悜绱娴侀噺鏁存暟")
+    @TableField("ZHENG_TOTAL")
+    private String zhengTotal;
+
+    @Schema(title = "姝e悜绱鏁板�煎皬鏁�")
+    @TableField("ZHENG_LITLE_TOTAL")
+    private String zhengLitleTotal;
+
+    @Schema(title = "鍙嶅悜绱鏁板�兼暣")
+    @TableField("FAN_TOTAL")
+    private String fanTotal;
+
+    @Schema(title = "鍙嶅悜绱鏁板�煎皬鏁�")
+    @TableField("FAN_LITLE_TOTAL")
+    private String fanLitleTotal;
+
+    @Schema(title = "鐬椂娴侀噺鍗曚綅")
+    @TableField("FLOW_UNIT")
+    private String flowUnit;
+
+    @Schema(title = "绱娴侀噺鍗曚綅")
+    @TableField("TOTAL_UNIT")
+    private String totalUnit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTimeFlow() {
+        return timeFlow;
+    }
+
+    public void setTimeFlow(String timeFlow) {
+        this.timeFlow = timeFlow;
+    }
+
+    public String getFlowRate() {
+        return flowRate;
+    }
+
+    public void setFlowRate(String flowRate) {
+        this.flowRate = flowRate;
+    }
+
+    public String getRate() {
+        return rate;
+    }
+
+    public void setRate(String rate) {
+        this.rate = rate;
+    }
+
+    public String getFlowElectricity() {
+        return flowElectricity;
+    }
+
+    public void setFlowElectricity(String flowElectricity) {
+        this.flowElectricity = flowElectricity;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getWaterDeep() {
+        return waterDeep;
+    }
+
+    public void setWaterDeep(String waterDeep) {
+        this.waterDeep = waterDeep;
+    }
+
+    public String getWaterYa() {
+        return waterYa;
+    }
+
+    public void setWaterYa(String waterYa) {
+        this.waterYa = waterYa;
+    }
+
+    public String getZhengTotal() {
+        return zhengTotal;
+    }
+
+    public void setZhengTotal(String zhengTotal) {
+        this.zhengTotal = zhengTotal;
+    }
+
+    public String getZhengLitleTotal() {
+        return zhengLitleTotal;
+    }
+
+    public void setZhengLitleTotal(String zhengLitleTotal) {
+        this.zhengLitleTotal = zhengLitleTotal;
+    }
+
+    public String getFanTotal() {
+        return fanTotal;
+    }
+
+    public void setFanTotal(String fanTotal) {
+        this.fanTotal = fanTotal;
+    }
+
+    public String getFanLitleTotal() {
+        return fanLitleTotal;
+    }
+
+    public void setFanLitleTotal(String fanLitleTotal) {
+        this.fanLitleTotal = fanLitleTotal;
+    }
+
+    public String getFlowUnit() {
+        return flowUnit;
+    }
+
+    public void setFlowUnit(String flowUnit) {
+        this.flowUnit = flowUnit;
+    }
+
+    public String getTotalUnit() {
+        return totalUnit;
+    }
+
+    public void setTotalUnit(String totalUnit) {
+        this.totalUnit = totalUnit;
+    }
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterInfo.java
new file mode 100644
index 0000000..f0001e9
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterInfo.java
@@ -0,0 +1,181 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+/**
+ * <p>
+ * 姘磋澶囦俊鎭�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@TableName("RECEIVE_WATER_INFO")
+@Schema(description = "姘磋澶囦俊鎭�")
+public class ReceiveWaterInfo {
+
+    @Schema(title = "涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title = "鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private byte deviceAddress;
+
+    @Schema(title = "缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+    @Schema(title = "缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+    @Schema(title = "鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private byte functionCode;
+
+    @Schema(title = "瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+    @Schema(title = "瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+    @Schema(title = "鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+    @Schema(title = "杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+    @Schema(title = "鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+    @Schema(title = "鏁版嵁鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+    @Schema(title = "鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(Byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public void setDeviceAddress(byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public void setFunctionCode(byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValue.java
new file mode 100644
index 0000000..7fb4fb0
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValue.java
@@ -0,0 +1,200 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-13
+ */
+
+@TableName("RECEIVE_WATER_VALUE")
+@Schema( description = "姘村疄鏃舵暟鎹�")
+public class ReceiveWaterValue {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private Long id;
+
+    @Schema(title ="鐬椂娴侀噺")
+    @TableField("TIME_FLOW")
+    private String timeFlow;
+
+    @Schema(title ="鐬椂娴侀��")
+    @TableField("FLOW_RATE")
+    private String flowRate;
+
+    @Schema(title ="娴侀噺鐧惧垎姣�")
+    @TableField("RATE")
+    private String rate;
+
+    @Schema(title ="娴佷綋鐢靛姣�")
+    @TableField("FLOW_ELECTRICITY")
+    private String flowElectricity;
+
+    @Schema(description = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title = "姘存繁")
+    @TableField("WATER_DEEP")
+    private String waterDeep;
+
+    @Schema(title = "姘村帇")
+    @TableField("WATER_YA")
+    private String waterYa;
+
+    @Schema(title = "姝e悜绱娴侀噺鏁存暟")
+    @TableField("ZHENG_TOTAL")
+    private String zhengTotal;
+
+    @Schema(title = "姝e悜绱鏁板�煎皬鏁�")
+    @TableField("ZHENG_LITLE_TOTAL")
+    private String zhengLitleTotal;
+
+    @Schema(title = "鍙嶅悜绱鏁板�兼暣")
+    @TableField("FAN_TOTAL")
+    private String fanTotal;
+
+    @Schema(title = "鍙嶅悜绱鏁板�煎皬鏁�")
+    @TableField("FAN_LITLE_TOTAL")
+    private String fanLitleTotal;
+
+    @Schema(title = "鐬椂娴侀噺鍗曚綅")
+    @TableField("FLOW_UNIT")
+    private String flowUnit;
+
+    @Schema(title = "绱娴侀噺鍗曚綅")
+    @TableField("TOTAL_UNIT")
+    private String totalUnit;
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getTimeFlow() {
+        return timeFlow;
+    }
+
+    public void setTimeFlow(String timeFlow) {
+        this.timeFlow = timeFlow;
+    }
+
+    public String getFlowRate() {
+        return flowRate;
+    }
+
+    public void setFlowRate(String flowRate) {
+        this.flowRate = flowRate;
+    }
+
+    public String getRate() {
+        return rate;
+    }
+
+    public void setRate(String rate) {
+        this.rate = rate;
+    }
+
+    public String getFlowElectricity() {
+        return flowElectricity;
+    }
+
+    public void setFlowElectricity(String flowElectricity) {
+        this.flowElectricity = flowElectricity;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getWaterDeep() {
+        return waterDeep;
+    }
+
+    public void setWaterDeep(String waterDeep) {
+        this.waterDeep = waterDeep;
+    }
+
+    public String getWaterYa() {
+        return waterYa;
+    }
+
+    public void setWaterYa(String waterYa) {
+        this.waterYa = waterYa;
+    }
+
+    public String getZhengTotal() {
+        return zhengTotal;
+    }
+
+    public void setZhengTotal(String zhengTotal) {
+        this.zhengTotal = zhengTotal;
+    }
+
+    public String getZhengLitleTotal() {
+        return zhengLitleTotal;
+    }
+
+    public void setZhengLitleTotal(String zhengLitleTotal) {
+        this.zhengLitleTotal = zhengLitleTotal;
+    }
+
+    public String getFanTotal() {
+        return fanTotal;
+    }
+
+    public void setFanTotal(String fanTotal) {
+        this.fanTotal = fanTotal;
+    }
+
+    public String getFanLitleTotal() {
+        return fanLitleTotal;
+    }
+
+    public void setFanLitleTotal(String fanLitleTotal) {
+        this.fanLitleTotal = fanLitleTotal;
+    }
+
+    public String getFlowUnit() {
+        return flowUnit;
+    }
+
+    public void setFlowUnit(String flowUnit) {
+        this.flowUnit = flowUnit;
+    }
+
+    public String getTotalUnit() {
+        return totalUnit;
+    }
+
+    public void setTotalUnit(String totalUnit) {
+        this.totalUnit = totalUnit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValueFinal.java
new file mode 100644
index 0000000..c271149
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWaterValueFinal.java
@@ -0,0 +1,213 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+
+@TableName("RECEIVE_WATER_VALUE_FINAL")
+@Schema(description = "姘村疄鏃舵暟鎹�")
+public class ReceiveWaterValueFinal {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.INPUT)
+    private BigInteger id;
+
+    @Schema(title ="鐬椂娴侀噺")
+    @TableField("TIME_FLOW")
+    private String timeFlow;
+
+    @Schema(title ="鐬椂娴侀��")
+    @TableField("FLOW_RATE")
+    private String flowRate;
+
+    @Schema(title ="娴侀噺鐧惧垎姣�")
+    @TableField("RATE")
+    private String rate;
+
+    @Schema(title ="娴佷綋鐢靛姣�")
+    @TableField("FLOW_ELECTRICITY")
+    private String flowElectricity;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title ="姘存繁")
+    @TableField("WATER_DEEP")
+    private String waterDeep;
+
+    @Schema(title ="姘村帇")
+    @TableField("WATER_YA")
+    private String waterYa;
+
+    @Schema(title ="姝e悜绱娴侀噺鏁存暟")
+    @TableField("ZHENG_TOTAL")
+    private String zhengTotal;
+
+    @Schema(title ="姝e悜绱鏁板�煎皬鏁�")
+    @TableField("ZHENG_LITLE_TOTAL")
+    private String zhengLitleTotal;
+
+    @Schema(title ="鍙嶅悜绱鏁板�兼暣")
+    @TableField("FAN_TOTAL")
+    private String fanTotal;
+
+    @Schema(title ="鍙嶅悜绱鏁板�煎皬鏁�")
+    @TableField("FAN_LITLE_TOTAL")
+    private String fanLitleTotal;
+
+    @Schema(title ="鐬椂娴侀噺鍗曚綅")
+    @TableField("FLOW_UNIT")
+    private String flowUnit;
+
+    @Schema(title ="绱娴侀噺鍗曚綅")
+    @TableField("TOTAL_UNIT")
+    private String totalUnit;
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getTimeFlow() {
+        return timeFlow;
+    }
+
+    public void setTimeFlow(String timeFlow) {
+        this.timeFlow = timeFlow;
+    }
+
+    public String getFlowRate() {
+        return flowRate;
+    }
+
+    public void setFlowRate(String flowRate) {
+        this.flowRate = flowRate;
+    }
+
+    public String getRate() {
+        return rate;
+    }
+
+    public void setRate(String rate) {
+        this.rate = rate;
+    }
+
+    public String getFlowElectricity() {
+        return flowElectricity;
+    }
+
+    public void setFlowElectricity(String flowElectricity) {
+        this.flowElectricity = flowElectricity;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public String getWaterDeep() {
+        return waterDeep;
+    }
+
+    public void setWaterDeep(String waterDeep) {
+        this.waterDeep = waterDeep;
+    }
+
+    public String getWaterYa() {
+        return waterYa;
+    }
+
+    public void setWaterYa(String waterYa) {
+        this.waterYa = waterYa;
+    }
+
+    public String getZhengTotal() {
+        return zhengTotal;
+    }
+
+    public void setZhengTotal(String zhengTotal) {
+        this.zhengTotal = zhengTotal;
+    }
+
+    public String getZhengLitleTotal() {
+        return zhengLitleTotal;
+    }
+
+    public void setZhengLitleTotal(String zhengLitleTotal) {
+        this.zhengLitleTotal = zhengLitleTotal;
+    }
+
+    public String getFanTotal() {
+        return fanTotal;
+    }
+
+    public void setFanTotal(String fanTotal) {
+        this.fanTotal = fanTotal;
+    }
+
+    public String getFanLitleTotal() {
+        return fanLitleTotal;
+    }
+
+    public void setFanLitleTotal(String fanLitleTotal) {
+        this.fanLitleTotal = fanLitleTotal;
+    }
+
+    public String getFlowUnit() {
+        return flowUnit;
+    }
+
+    public void setFlowUnit(String flowUnit) {
+        this.flowUnit = flowUnit;
+    }
+
+    public String getTotalUnit() {
+        return totalUnit;
+    }
+
+    public void setTotalUnit(String totalUnit) {
+        this.totalUnit = totalUnit;
+    }
+
+    public Date getUpdateTime() {
+        return updateTime;
+    }
+
+    public void setUpdateTime(Date updateTime) {
+        this.updateTime = updateTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherAnalyse.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherAnalyse.java
new file mode 100644
index 0000000..e93b808
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherAnalyse.java
@@ -0,0 +1,119 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘旇薄璁惧鍒嗘瀽鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+
+@TableName("RECEIVE_WEATHER_ANALYSE")
+@Schema( description = "姘旇薄璁惧鍒嗘瀽鏁版嵁")
+public class ReceiveWeatherAnalyse {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+    @Schema(title ="椋庨��")
+    @TableField("WIND_SPEED")
+    private String windSpeed;
+
+    @Schema(title ="椋庡悜")
+    @TableField("WIND_DIRECTION")
+    private String windDirection;
+
+    @Schema(title ="娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="婀垮害")
+    @TableField("HUMIDITY")
+    private String humidity;
+
+    @Schema(title ="澶ф皵鍘�")
+    @TableField("ATMOSPHERIC_PRESSURE")
+    private String atmosphericPressure;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getWindSpeed() {
+        return windSpeed;
+    }
+
+    public void setWindSpeed(String windSpeed) {
+        this.windSpeed = windSpeed;
+    }
+
+    public String getWindDirection() {
+        return windDirection;
+    }
+
+    public void setWindDirection(String windDirection) {
+        this.windDirection = windDirection;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getHumidity() {
+        return humidity;
+    }
+
+    public void setHumidity(String humidity) {
+        this.humidity = humidity;
+    }
+
+    public String getAtmosphericPressure() {
+        return atmosphericPressure;
+    }
+
+    public void setAtmosphericPressure(String atmosphericPressure) {
+        this.atmosphericPressure = atmosphericPressure;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherInfo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherInfo.java
new file mode 100644
index 0000000..643f762
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherInfo.java
@@ -0,0 +1,182 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+
+/**
+ * <p>
+ * 姘旇薄鏁版嵁鎺ユ敹绠$悊
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+
+@TableName("RECEIVE_WEATHER_INFO")
+ @Schema(description = "姘旇薄鏁版嵁鎺ユ敹绠$悊")
+public class ReceiveWeatherInfo {
+
+     @Schema(title ="涓婚敭")
+     @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+     @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+     @Schema(title ="鍦板潃鐮�")
+    @TableField("DEVICE_ADDRESS")
+    private byte deviceAddress;
+
+     @Schema(title ="缃戝叧ip")
+    @TableField("IP")
+    private String ip;
+
+     @Schema(title ="缃戝叧绔彛")
+    @TableField("PORT")
+    private Integer port;
+
+     @Schema(title ="鍔熻兘鐮�")
+    @TableField("FUNCTION_CODE")
+    private byte functionCode;
+
+     @Schema(title ="瀵勫瓨鍣ㄥ湴鍧�")
+    @TableField("REGISTER_ADRESS")
+    private Integer registerAdress;
+
+     @Schema(title ="瀵勫瓨鍣ㄦ暟閲�")
+    @TableField("REGISTER_COUNT")
+    private Integer registerCount;
+
+     @Schema(title ="鏍¢獙鐮�")
+    @TableField("CRC")
+    private Integer crc;
+
+     @Schema(title ="杩斿洖鏁版嵁绫诲瀷")
+    @TableField("DATA_TYPE")
+    private Integer dataType;
+
+     @Schema(title ="鏁版嵁鍚箟")
+    @TableField("PARAM")
+    private String param;
+
+     @Schema(title ="鍚箟缂栫爜")
+    @TableField("PARAM_CODE")
+    private String paramCode;
+
+     @Schema(title ="鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public byte getFunctionCode() {
+        return functionCode;
+    }
+
+    public void setFunctionCode(byte functionCode) {
+        this.functionCode = functionCode;
+    }
+
+    public Integer getRegisterAdress() {
+        return registerAdress;
+    }
+
+    public void setRegisterAdress(Integer registerAdress) {
+        this.registerAdress = registerAdress;
+    }
+
+    public Integer getRegisterCount() {
+        return registerCount;
+    }
+
+    public void setRegisterCount(Integer registerCount) {
+        this.registerCount = registerCount;
+    }
+
+    public Integer getCrc() {
+        return crc;
+    }
+
+    public void setCrc(Integer crc) {
+        this.crc = crc;
+    }
+
+    public Integer getDataType() {
+        return dataType;
+    }
+
+    public void setDataType(Integer dataType) {
+        this.dataType = dataType;
+    }
+
+    public String getParam() {
+        return param;
+    }
+
+    public void setParam(String param) {
+        this.param = param;
+    }
+
+    public String getParamCode() {
+        return paramCode;
+    }
+
+    public void setParamCode(String paramCode) {
+        this.paramCode = paramCode;
+    }
+
+    public String getUnit() {
+        return unit;
+    }
+
+    public void setUnit(String unit) {
+        this.unit = unit;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValue.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValue.java
new file mode 100644
index 0000000..bbd1bdb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValue.java
@@ -0,0 +1,119 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+
+@TableName("RECEIVE_WEATHER_VALUE")
+@Schema( description = "姘旇薄璁惧瀹炴椂鏁版嵁")
+public class ReceiveWeatherValue {
+
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+    @Schema(title ="椋庨��")
+    @TableField("WIND_SPEED")
+    private String windSpeed;
+
+    @Schema(title ="椋庡悜")
+    @TableField("WIND_DIRECTION")
+    private String windDirection;
+
+    @Schema(title ="娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="婀垮害")
+    @TableField("HUMIDITY")
+    private String humidity;
+
+    @Schema(title ="澶ф皵鍘�")
+    @TableField("ATMOSPHERIC_PRESSURE")
+    private String atmosphericPressure;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getWindSpeed() {
+        return windSpeed;
+    }
+
+    public void setWindSpeed(String windSpeed) {
+        this.windSpeed = windSpeed;
+    }
+
+    public String getWindDirection() {
+        return windDirection;
+    }
+
+    public void setWindDirection(String windDirection) {
+        this.windDirection = windDirection;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getHumidity() {
+        return humidity;
+    }
+
+    public void setHumidity(String humidity) {
+        this.humidity = humidity;
+    }
+
+    public String getAtmosphericPressure() {
+        return atmosphericPressure;
+    }
+
+    public void setAtmosphericPressure(String atmosphericPressure) {
+        this.atmosphericPressure = atmosphericPressure;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValueFinal.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValueFinal.java
new file mode 100644
index 0000000..7730a35
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/ReceiveWeatherValueFinal.java
@@ -0,0 +1,119 @@
+package com.ruoyi.fuzhou.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+
+
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+
+@TableName("RECEIVE_WEATHER_VALUE_FINAL")
+@Schema( description = "姘旇薄璁惧瀹炴椂鏁版嵁")
+public class ReceiveWeatherValueFinal {
+    @Schema(title ="涓婚敭")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private BigInteger id;
+
+    @Schema(title ="椋庨��")
+    @TableField("WIND_SPEED")
+    private String windSpeed;
+
+    @Schema(title ="椋庡悜")
+    @TableField("WIND_DIRECTION")
+    private String windDirection;
+
+    @Schema(title ="娓╁害")
+    @TableField("TEMP")
+    private String temp;
+
+    @Schema(title ="婀垮害")
+    @TableField("HUMIDITY")
+    private String humidity;
+
+    @Schema(title ="澶ф皵鍘�")
+    @TableField("ATMOSPHERIC_PRESSURE")
+    private String atmosphericPressure;
+
+    @Schema(title ="鍏ュ簱鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title ="璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    public String getDeviceName() {
+        return deviceName;
+    }
+
+    public void setDeviceName(String deviceName) {
+        this.deviceName = deviceName;
+    }
+
+    public Date getCreateTime() {
+        return createTime;
+    }
+
+    public void setCreateTime(Date createTime) {
+        this.createTime = createTime;
+    }
+
+    public BigInteger getId() {
+        return id;
+    }
+
+    public void setId(BigInteger id) {
+        this.id = id;
+    }
+
+    public String getWindSpeed() {
+        return windSpeed;
+    }
+
+    public void setWindSpeed(String windSpeed) {
+        this.windSpeed = windSpeed;
+    }
+
+    public String getWindDirection() {
+        return windDirection;
+    }
+
+    public void setWindDirection(String windDirection) {
+        this.windDirection = windDirection;
+    }
+
+    public String getTemp() {
+        return temp;
+    }
+
+    public void setTemp(String temp) {
+        this.temp = temp;
+    }
+
+    public String getHumidity() {
+        return humidity;
+    }
+
+    public void setHumidity(String humidity) {
+        this.humidity = humidity;
+    }
+
+    public String getAtmosphericPressure() {
+        return atmosphericPressure;
+    }
+
+    public void setAtmosphericPressure(String atmosphericPressure) {
+        this.atmosphericPressure = atmosphericPressure;
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/DpEquipmentVO.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/DpEquipmentVO.java
new file mode 100644
index 0000000..ba3a1db
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/DpEquipmentVO.java
@@ -0,0 +1,250 @@
+package com.ruoyi.fuzhou.domain.vo;
+
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableField;
+
+public class DpEquipmentVO {
+    private Integer id;
+    private Integer beId;
+    private String equName;
+    private Integer intervalTime;
+    private Integer periodTime;
+    private Integer equSeType;
+    private String protocol;
+    private Integer whId;
+    private Double x;
+    private Double y;
+    private Double z;
+    private String fieldName;
+    private Integer equipmentTypeId;
+    private String equtype;
+    private String description;
+    private String filepath;
+    private String whName;
+    private String beName;
+    private String typeName;
+    private String icon;
+    private String equCode;
+    private Integer status;
+
+    @TableField(exist = false)
+    private String ip;
+
+    @TableField(exist = false)
+    private Integer port;
+
+    @TableField(exist = false)
+    private Byte deviceAddress;
+
+    @TableField(exist = false)
+    private Object dataHis;
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Object getDataHis() {
+        return dataHis;
+    }
+
+    public void setDataHis(Object dataHis) {
+        this.dataHis = dataHis;
+    }
+
+    public String getEquCode() {
+        return equCode;
+    }
+
+    public void setEquCode(String equCode) {
+        this.equCode = equCode;
+    }
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public String getTypeName() {
+        return typeName;
+    }
+
+    public void setTypeName(String typeName) {
+        this.typeName = typeName;
+    }
+
+    public String getWhName() {
+        return whName;
+    }
+
+    public void setWhName(String whName) {
+        this.whName = whName;
+    }
+
+    public String getBeName() {
+        return beName;
+    }
+
+    public void setBeName(String beName) {
+        this.beName = beName;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getBeId() {
+        return beId;
+    }
+
+    public void setBeId(Integer beId) {
+        this.beId = beId;
+    }
+
+    public String getEquName() {
+        return equName;
+    }
+
+    public void setEquName(String equName) {
+        this.equName = equName;
+    }
+
+    public Integer getIntervalTime() {
+        return intervalTime;
+    }
+
+    public void setIntervalTime(Integer intervalTime) {
+        this.intervalTime = intervalTime;
+    }
+
+    public Integer getPeriodTime() {
+        return periodTime;
+    }
+
+    public void setPeriodTime(Integer periodTime) {
+        this.periodTime = periodTime;
+    }
+
+    public Integer getEquSeType() {
+        return equSeType;
+    }
+
+    public void setEquSeType(Integer equSeType) {
+        this.equSeType = equSeType;
+    }
+
+    public String getProtocol() {
+        return protocol;
+    }
+
+    public void setProtocol(String protocol) {
+        this.protocol = protocol;
+    }
+
+    public Integer getWhId() {
+        return whId;
+    }
+
+    public void setWhId(Integer whId) {
+        this.whId = whId;
+    }
+
+    public Double getX() {
+        return x;
+    }
+
+    public void setX(Double x) {
+        this.x = x;
+    }
+
+    public Double getY() {
+        return y;
+    }
+
+    public void setY(Double y) {
+        this.y = y;
+    }
+
+    public Double getZ() {
+        return z;
+    }
+
+    public void setZ(Double z) {
+        this.z = z;
+    }
+
+    public String getFieldName() {
+        return fieldName;
+    }
+
+    public void setFieldName(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+    public Integer getEquipmentTypeId() {
+        return equipmentTypeId;
+    }
+
+    public void setEquipmentTypeId(Integer equipmentTypeId) {
+        this.equipmentTypeId = equipmentTypeId;
+    }
+
+    public String getDescription() {
+        return description;
+    }
+
+    public void setDescription(String description) {
+        this.description = description;
+    }
+
+    public String getEqutype() {
+        return equtype;
+    }
+
+    public void setEqutype(String equtype) {
+        this.equtype = equtype;
+    }
+
+    public String getFilepath() {
+        return filepath;
+    }
+
+    public void setFilepath(String filepath) {
+        this.filepath = filepath;
+    }
+
+    public String getIp() {
+        return ip;
+    }
+
+    public void setIp(String ip) {
+        this.ip = ip;
+    }
+
+    public Integer getPort() {
+        return port;
+    }
+
+    public void setPort(Integer port) {
+        this.port = port;
+    }
+
+    public Byte getDeviceAddress() {
+        return deviceAddress;
+    }
+
+    public void setDeviceAddress(Byte deviceAddress) {
+        this.deviceAddress = deviceAddress;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/QueryAnalysisVO.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/QueryAnalysisVO.java
new file mode 100644
index 0000000..8506f55
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/QueryAnalysisVO.java
@@ -0,0 +1,79 @@
+package com.ruoyi.fuzhou.domain.vo;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.util.Date;
+import java.util.List;
+
+@Schema(description = "鏌ヨ鍒嗘瀽鍏ュ弬")
+public class QueryAnalysisVO {
+
+//    @Schema(title = "璁惧ids")
+//    private List<Integer> ids;
+
+    @Schema(title = "娉婁綅id")
+    private Integer beId;
+
+    @Schema(title = "璁惧绫诲瀷id")
+    private Integer typeId;
+
+    @Schema(title = "寮�濮嬫椂闂�")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date startTime;
+
+    @Schema(title = "缁撴潫鏃堕棿")
+    @JsonFormat(pattern = "yyyy-MM-dd")
+    private Date endTime;
+
+    @Schema(title = "鏌ヨ闂撮殧")
+    private Integer interval;
+
+//    public List<Integer> getIds() {
+//        return ids;
+//    }
+//
+//    public void setIds(List<Integer> ids) {
+//        this.ids = ids;
+//    }
+
+    public Integer getBeId() {
+        return beId;
+    }
+
+    public void setBeId(Integer beId) {
+        this.beId = beId;
+    }
+
+    public Integer getTypeId() {
+        return typeId;
+    }
+
+    public void setTypeId(Integer typeId) {
+        this.typeId = typeId;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getInterval() {
+        return interval;
+    }
+
+    public void setInterval(Integer interval) {
+        this.interval = interval;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/ReceiveValueListVo.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/ReceiveValueListVo.java
new file mode 100644
index 0000000..dda1b92
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/ReceiveValueListVo.java
@@ -0,0 +1,86 @@
+package com.ruoyi.fuzhou.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 娌硅澶囧垪琛ㄦ煡璇㈠叆鍙�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-10
+ */
+@Schema(description = "娌硅澶囧垪琛ㄦ煡璇㈠叆鍙�")
+public class ReceiveValueListVo {
+
+    @Schema(title = "璁惧id")
+    @NotNull(message = "璁惧id涓嶈兘涓虹┖")
+    private Long id;
+
+    @Schema(title = "寮�濮嬫椂闂�")
+    private Date startTime;
+
+    @Schema(title = "缁撴潫鏃堕棿")
+    private Date endTime;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public Date getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(Date startTime) {
+        this.startTime = startTime;
+    }
+
+    public Date getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(Date endTime) {
+        this.endTime = endTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/RfidVehicleVO.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/RfidVehicleVO.java
new file mode 100644
index 0000000..810adee
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/domain/vo/RfidVehicleVO.java
@@ -0,0 +1,33 @@
+package com.ruoyi.fuzhou.domain.vo;
+
+
+
+public class RfidVehicleVO {
+    private String nodeNum;
+    private String startTime;
+    private String endTime;
+
+    public String getNodeNum() {
+        return nodeNum;
+    }
+
+    public void setNodeNum(String nodeNum) {
+        this.nodeNum = nodeNum;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/enums/DataTypeEnum.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/enums/DataTypeEnum.java
new file mode 100644
index 0000000..b403f3e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/enums/DataTypeEnum.java
@@ -0,0 +1,76 @@
+package com.ruoyi.fuzhou.enums;
+
+/**
+ * 鏁版嵁绫诲瀷鏋氫妇
+ */
+public enum DataTypeEnum {
+
+    OIL(1, "娌硅繙绋嬭閲�"),
+
+    LIJIUOIL(12, "鍘﹂棬鍒╂棫娌硅〃"),
+    /**
+     * 鏈帴
+     */
+    LIJIUJUN(13, "瀹佸痉鍒╂棫娌硅〃"),
+    /**
+     * 鏈帴
+     */
+    NIGDETUIYOU(14, "瀹佸痉鍒╂棫閫�娌硅〃"),
+
+
+    WATER_FLOW(2, "鏅鸿兘姘磋〃"),
+
+
+    WATER_YA(10, "鏅鸿兘鍘嬪姏琛�"),
+
+
+    WATER_DEPT(7, "姘存繁浼犳劅鍣�"),
+
+
+    ELECTRICITY(3, "鏅鸿兘鐢佃〃"),
+
+    WEATHER(15, "姘旇薄琛�"),
+
+
+    SLM(16, "婵�鍏夐浄杈捐〃"),
+
+    YDKFM(8, "娌圭數鎺ч榾闂�"),
+
+    GONGKUANG(5, "宸ュ喌閲囬泦");
+
+
+
+    private Integer code;
+    private String name;
+
+    public Integer getCode() {
+        return code;
+    }
+
+    public void setCode(Integer code) {
+        this.code = code;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    DataTypeEnum(Integer code, String name) {
+        this.code = code;
+        this.name = name;
+    }
+
+    public static String of(Integer code) {
+        DataTypeEnum[] values = DataTypeEnum.values();
+        for (DataTypeEnum value : values) {
+            if (value.getCode().equals(code)) {
+                return value.getName();
+            }
+        }
+        return null;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidTaskMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidTaskMapper.java
new file mode 100644
index 0000000..6431527
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidTaskMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.DpRfidTask;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID浠诲姟琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-25
+ */
+@Mapper
+public interface DpRfidTaskMapper extends BaseMapper<DpRfidTask> {
+    List<DpRfidTask> getPageList(DpRfidTask dpRfidTask);
+
+    Integer getTotal(DpRfidTask dpRfidTask);
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidVehicleMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidVehicleMapper.java
new file mode 100644
index 0000000..0e1d065
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/DpRfidVehicleMapper.java
@@ -0,0 +1,27 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.DpRfidVehicle;
+import com.ruoyi.fuzhou.domain.vo.RfidVehicleVO;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID杞﹁締璁板綍琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-21
+ */
+@Mapper
+public interface DpRfidVehicleMapper extends BaseMapper<DpRfidVehicle> {
+
+    List<DpRfidVehicle> getPageList(DpRfidVehicle dpRfidVehicle);
+
+    Integer getTotal(DpRfidVehicle dpRfidVehicle);
+
+    List<DpRfidVehicle> selectRfidVehicle(RfidVehicleVO rfidVehicleVO);
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/EquipmentMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/EquipmentMapper.java
new file mode 100644
index 0000000..e3aa742
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/EquipmentMapper.java
@@ -0,0 +1,35 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.vo.DpEquipmentVO;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Mapper
+public interface EquipmentMapper extends BaseMapper<DpEquipment> {
+
+    List<DpEquipmentVO> getPageList(DpEquipment equipment);
+
+    long getTotal(DpEquipment equipment);
+
+    DpEquipmentVO queryById(Integer id);
+
+    void deleteBy(Integer whId);
+
+    List<DpEquipmentVO> getListByBeId(Integer beId);
+
+    List<DpEquipmentVO> getListByWhId(Integer whId);
+
+    List<DpEquipmentVO> getListByBeIdTypeId(@Param("beId")Integer beId, @Param("typeIds") List<Integer> typeIds);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/HikEventMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/HikEventMapper.java
new file mode 100644
index 0000000..0ca16cd
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/HikEventMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.HikEvent;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娴峰悍鍛婅浜嬩欢 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-25
+ */
+@Mapper
+public interface HikEventMapper extends BaseMapper<HikEvent> {
+
+    List<HikEvent> getPageList(HikEvent hikEvent);
+
+    Integer getTotal(HikEvent hikEvent);
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarRuleMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarRuleMapper.java
new file mode 100644
index 0000000..e872d2e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarRuleMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveCarRule;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 杞﹁締鏁版嵁鎺ユ敹淇℃伅 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-22
+ */
+@Mapper
+public interface ReceiveCarRuleMapper extends BaseMapper<ReceiveCarRule> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueFinalMapper.java
new file mode 100644
index 0000000..587ab25
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueFinalMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Mapper
+public interface ReceiveCarValueFinalMapper extends BaseMapper<ReceiveCarValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueMapper.java
new file mode 100644
index 0000000..657171b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveCarValueMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveCarValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-24
+ */
+@Mapper
+public interface ReceiveCarValueMapper extends BaseMapper<ReceiveCarValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityAnalyseMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityAnalyseMapper.java
new file mode 100644
index 0000000..5ba52d5
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityAnalyseMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityAnalyse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹竻娲� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Mapper
+public interface ReceiveElectricityAnalyseMapper extends BaseMapper<ReceiveElectricityAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityInfoMapper.java
new file mode 100644
index 0000000..de401b9
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityInfoMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鐢垫暟鎹帴鏀剁鐞� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Mapper
+public interface ReceiveElectricityInfoMapper extends BaseMapper<ReceiveElectricityInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueFinalMapper.java
new file mode 100644
index 0000000..344cf2a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueFinalMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Mapper
+public interface ReceiveElectricityValueFinalMapper extends BaseMapper<ReceiveElectricityValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueMapper.java
new file mode 100644
index 0000000..30c5a69
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveElectricityValueMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Mapper
+public interface ReceiveElectricityValueMapper extends BaseMapper<ReceiveElectricityValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveModuleInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveModuleInfoMapper.java
new file mode 100644
index 0000000..42a7c4a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveModuleInfoMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * modbus鏁版嵁妯℃澘 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-27
+ */
+@Mapper
+public interface ReceiveModuleInfoMapper extends BaseMapper<ReceiveModuleInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilAnalyseMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilAnalyseMapper.java
new file mode 100644
index 0000000..6aae826
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilAnalyseMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveOilAnalyse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 娌硅鍒嗘瀽鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Mapper
+public interface ReceiveOilAnalyseMapper extends BaseMapper<ReceiveOilAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilInfoMapper.java
new file mode 100644
index 0000000..fab2ae5
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilInfoMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 娌规暟鎹帴鏀剁鐞� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Mapper
+public interface ReceiveOilInfoMapper extends BaseMapper<ReceiveOilInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueFinalMapper.java
new file mode 100644
index 0000000..0a4e90f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueFinalMapper.java
@@ -0,0 +1,22 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.ReceiveOilValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Mapper
+public interface ReceiveOilValueFinalMapper extends BaseMapper<ReceiveOilValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueMapper.java
new file mode 100644
index 0000000..eba2c96
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveOilValueMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Mapper
+public interface ReceiveOilValueMapper extends BaseMapper<ReceiveOilValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSelectRuleMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSelectRuleMapper.java
new file mode 100644
index 0000000..43d595b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSelectRuleMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveSelectRule;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鏁版嵁娓呮礂瑙勫垯 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-09
+ */
+@Mapper
+public interface ReceiveSelectRuleMapper extends BaseMapper<ReceiveSelectRule> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmAnalyseMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmAnalyseMapper.java
new file mode 100644
index 0000000..d307979
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmAnalyseMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveSlmAnalyse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Mapper
+public interface ReceiveSlmAnalyseMapper extends BaseMapper<ReceiveSlmAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmInfoMapper.java
new file mode 100644
index 0000000..b6f52ef
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmInfoMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveSlmInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 闆疯揪鏁版嵁鎺ユ敹绠$悊 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Mapper
+public interface ReceiveSlmInfoMapper extends BaseMapper<ReceiveSlmInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueFinalMapper.java
new file mode 100644
index 0000000..d574eba
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueFinalMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Mapper
+public interface ReceiveSlmValueFinalMapper extends BaseMapper<ReceiveSlmValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueMapper.java
new file mode 100644
index 0000000..2d96468
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveSlmValueMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveSlmValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Mapper
+public interface ReceiveSlmValueMapper extends BaseMapper<ReceiveSlmValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterAnalyseMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterAnalyseMapper.java
new file mode 100644
index 0000000..d1a0f3f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterAnalyseMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveWaterAnalyse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘村垎鏋愭暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Mapper
+public interface ReceiveWaterAnalyseMapper extends BaseMapper<ReceiveWaterAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterInfoMapper.java
new file mode 100644
index 0000000..4cba9a9
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterInfoMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveWaterInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘磋澶囦俊鎭� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Mapper
+public interface ReceiveWaterInfoMapper extends BaseMapper<ReceiveWaterInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueFinalMapper.java
new file mode 100644
index 0000000..8ebc460
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueFinalMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Mapper
+public interface ReceiveWaterValueFinalMapper extends BaseMapper<ReceiveWaterValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueMapper.java
new file mode 100644
index 0000000..b1e9990
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWaterValueMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-13
+ */
+@Mapper
+public interface ReceiveWaterValueMapper extends BaseMapper<ReceiveWaterValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherAnalyseMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherAnalyseMapper.java
new file mode 100644
index 0000000..3d72f96
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherAnalyseMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherAnalyse;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘旇薄璁惧鍒嗘瀽鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Mapper
+public interface ReceiveWeatherAnalyseMapper extends BaseMapper<ReceiveWeatherAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherInfoMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherInfoMapper.java
new file mode 100644
index 0000000..26e76da
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherInfoMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘旇薄鏁版嵁鎺ユ敹绠$悊 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Mapper
+public interface ReceiveWeatherInfoMapper extends BaseMapper<ReceiveWeatherInfo> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueFinalMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueFinalMapper.java
new file mode 100644
index 0000000..a92adf7
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueFinalMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Mapper
+public interface ReceiveWeatherValueFinalMapper extends BaseMapper<ReceiveWeatherValueFinal> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueMapper.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueMapper.java
new file mode 100644
index 0000000..d46d1c0
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/mapper/ReceiveWeatherValueMapper.java
@@ -0,0 +1,19 @@
+package com.ruoyi.fuzhou.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValue;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Mapper
+public interface ReceiveWeatherValueMapper extends BaseMapper<ReceiveWeatherValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidTaskService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidTaskService.java
new file mode 100644
index 0000000..a3c4a54
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidTaskService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidTask;
+
+/**
+ * <p>
+ * RFID浠诲姟琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-25
+ */
+public interface DpRfidTaskService extends IService<DpRfidTask> {
+    TableDataInfo getPageList(DpRfidTask dpRfidTask);
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidVehicleService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidVehicleService.java
new file mode 100644
index 0000000..db20b96
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/DpRfidVehicleService.java
@@ -0,0 +1,26 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidVehicle;
+import com.ruoyi.fuzhou.domain.vo.RfidVehicleVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID杞﹁締璁板綍琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-21
+ */
+public interface DpRfidVehicleService extends IService<DpRfidVehicle> {
+    TableDataInfo getPageList(DpRfidVehicle dpRfidVehicle);
+
+    List<DpRfidVehicle> selectRfidVehicle(RfidVehicleVO rfidVehicleVO);
+
+    DpRfidVehicle QueryVehicleByTask(String task);
+
+    Integer insert(DpRfidVehicle dpRfidVehicle);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/EquipmentService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/EquipmentService.java
new file mode 100644
index 0000000..56c8c36
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/EquipmentService.java
@@ -0,0 +1,34 @@
+package com.ruoyi.fuzhou.service;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.vo.DpEquipmentVO;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+public interface EquipmentService extends IService<DpEquipment> {
+    List<DpEquipment> getListByType(Integer typeId);
+
+    DpEquipment getEpByField(String field);
+
+    TableDataInfo getPageList(DpEquipment equipment);
+
+    DpEquipmentVO selectById(Integer id);
+
+    List<DpEquipmentVO> getListByBeId(Integer beId);
+
+    List<DpEquipmentVO> getListByWhId(Integer whId);
+
+    List<DpEquipmentVO> getListByBeIdTypeId(Integer beId,List<Integer> typeIds);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/HikService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/HikService.java
new file mode 100644
index 0000000..5245b18
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/HikService.java
@@ -0,0 +1,30 @@
+package com.ruoyi.fuzhou.service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.CameraPTZ;
+import com.ruoyi.fuzhou.domain.HikEvent;
+import com.ruoyi.fuzhou.domain.HikEventObj;
+
+import java.util.Map;
+
+public interface HikService extends IService<HikEvent> {
+    String getCameraPreviewURL(String cameraName) throws Exception;
+
+    String getCameraURL(String cameraIndexCode) throws Exception;
+
+    Map<String,Integer> getCameraOnline(String[] indexCodes);
+
+    JSONObject cameraCommand(CameraPTZ cameraPTZ) throws Exception;
+
+    JSONObject subByEventTypes(HikEventObj hikEventObj) throws Exception;
+
+    JSONObject unSubByEventTypes(HikEventObj hikEventObj) throws Exception;
+
+    JSONObject eventView() throws Exception;
+
+    boolean saveInsert(HikEvent hikEvent);
+
+    TableDataInfo getList(HikEvent hikEvent);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarRuleService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarRuleService.java
new file mode 100644
index 0000000..ce2d446
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarRuleService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveCarRule;
+
+/**
+ * <p>
+ * 杞﹁締鏁版嵁鎺ユ敹淇℃伅 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-22
+ */
+public interface ReceiveCarRuleService extends IService<ReceiveCarRule> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueFinalService.java
new file mode 100644
index 0000000..44ade91
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueFinalService.java
@@ -0,0 +1,36 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+public interface ReceiveCarValueFinalService extends IService<ReceiveCarValueFinal> {
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveCarValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatch(List<ReceiveCarValueFinal> carValueFinals);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveCarValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveCarValueFinal receiveCarValueFinal);
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueService.java
new file mode 100644
index 0000000..4cf8549
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveCarValueService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveCarValue;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-24
+ */
+public interface ReceiveCarValueService extends IService<ReceiveCarValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityAnalyseService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityAnalyseService.java
new file mode 100644
index 0000000..1c2691b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityAnalyseService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityAnalyse;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹竻娲� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+public interface ReceiveElectricityAnalyseService extends IService<ReceiveElectricityAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityInfoService.java
new file mode 100644
index 0000000..b41f451
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityInfoService.java
@@ -0,0 +1,21 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityInfo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鐢垫暟鎹帴鏀剁鐞� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+public interface ReceiveElectricityInfoService extends IService<ReceiveElectricityInfo> {
+
+    void saveElectricity(List<ReceiveElectricityInfo> list, DpEquipment info);
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueFinalService.java
new file mode 100644
index 0000000..d00c49c
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueFinalService.java
@@ -0,0 +1,36 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+public interface ReceiveElectricityValueFinalService extends IService<ReceiveElectricityValueFinal> {
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveElectricityValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatch(List<ReceiveElectricityValueFinal> electricityValueFinals);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveElectricityValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveElectricityValueFinal receiveElectricityValueFinal);
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueService.java
new file mode 100644
index 0000000..e9002f4
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveElectricityValueService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+public interface ReceiveElectricityValueService extends IService<ReceiveElectricityValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveModuleInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveModuleInfoService.java
new file mode 100644
index 0000000..9d99dd8
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveModuleInfoService.java
@@ -0,0 +1,28 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+
+import java.util.Map;
+
+/**
+ * <p>
+ * modbus鏁版嵁妯℃澘 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-27
+ */
+public interface ReceiveModuleInfoService extends IService<ReceiveModuleInfo> {
+
+    void saveByModule(String deviceName, String ip, Integer port, Byte deviceAddress, Integer dataType);
+
+    void removeByModule(String deviceName, Integer dataType);
+
+    DpEquipment getIp(String deviceName, Integer dataType);
+
+    Map<String, Object> getYdkfmStatus(String deviceName) throws Exception;
+
+    Map<String, Object> ctrlYdkfm(String deviceName, Boolean flag) throws Exception;
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilAnalyseService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilAnalyseService.java
new file mode 100644
index 0000000..f5996df
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilAnalyseService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveOilAnalyse;
+
+/**
+ * <p>
+ * 娌硅鍒嗘瀽鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+public interface ReceiveOilAnalyseService extends IService<ReceiveOilAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilInfoService.java
new file mode 100644
index 0000000..7a6fa39
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilInfoService.java
@@ -0,0 +1,27 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娌规暟鎹帴鏀剁鐞� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+public interface ReceiveOilInfoService extends IService<ReceiveOilInfo> {
+
+    void saveOil(List<ReceiveOilInfo> list, DpEquipment info);
+
+    void saveOilLijiuNingde(List<ReceiveOilInfo> list, DpEquipment info);
+
+    void saveLijiuOil(List<ReceiveOilInfo> list, DpEquipment info);
+
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueFinalService.java
new file mode 100644
index 0000000..2920c17
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueFinalService.java
@@ -0,0 +1,37 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveOilValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+
+public interface ReceiveOilValueFinalService extends IService<ReceiveOilValueFinal> {
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveOilValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatch(List<ReceiveOilValueFinal> oilValueFinals);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveOilValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveOilValueFinal receiveOilValueFinal);
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueService.java
new file mode 100644
index 0000000..1652b9b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveOilValueService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+public interface ReceiveOilValueService extends IService<ReceiveOilValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSelectRuleService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSelectRuleService.java
new file mode 100644
index 0000000..5229902
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSelectRuleService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveSelectRule;
+
+/**
+ * <p>
+ * 鏁版嵁娓呮礂瑙勫垯 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-09
+ */
+public interface ReceiveSelectRuleService extends IService<ReceiveSelectRule> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmAnalyseService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmAnalyseService.java
new file mode 100644
index 0000000..315d125
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmAnalyseService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveSlmAnalyse;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+public interface ReceiveSlmAnalyseService extends IService<ReceiveSlmAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmInfoService.java
new file mode 100644
index 0000000..7778057
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmInfoService.java
@@ -0,0 +1,23 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveSlmInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 闆疯揪鏁版嵁鎺ユ敹绠$悊 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+public interface ReceiveSlmInfoService extends IService<ReceiveSlmInfo> {
+
+
+    void saveData(List<ReceiveSlmInfo> list, DpEquipment info);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueFinalService.java
new file mode 100644
index 0000000..1c8d621
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueFinalService.java
@@ -0,0 +1,38 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+public interface ReceiveSlmValueFinalService extends IService<ReceiveSlmValueFinal> {
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveSlmValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatchNew(List<ReceiveSlmValueFinal> receiveSlmValueFinal);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveSlmValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveSlmValueFinal receiveCarValueFinal);
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueService.java
new file mode 100644
index 0000000..060acf4
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveSlmValueService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValue;
+
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+public interface ReceiveSlmValueService extends IService<ReceiveSlmValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterAnalyseService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterAnalyseService.java
new file mode 100644
index 0000000..4f3632d
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterAnalyseService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveWaterAnalyse;
+
+/**
+ * <p>
+ * 姘村垎鏋愭暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+public interface ReceiveWaterAnalyseService extends IService<ReceiveWaterAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterInfoService.java
new file mode 100644
index 0000000..ab8c743
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterInfoService.java
@@ -0,0 +1,25 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveWaterInfo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 姘磋澶囦俊鎭� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+public interface ReceiveWaterInfoService extends IService<ReceiveWaterInfo> {
+
+    void saveWater(List<ReceiveWaterInfo> list, DpEquipment info);
+
+    void saveWaterYa(List<ReceiveWaterInfo> list, DpEquipment info);
+
+    void saveWaterDept(List<ReceiveWaterInfo> list, DpEquipment info);
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueFinalService.java
new file mode 100644
index 0000000..712d49f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueFinalService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+public interface ReceiveWaterValueFinalService extends IService<ReceiveWaterValueFinal> {
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveWaterValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatch(List<ReceiveWaterValueFinal> waterValueFinals);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveWaterValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveWaterValueFinal receiveWaterValueFinal);
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueService.java
new file mode 100644
index 0000000..2e63246
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWaterValueService.java
@@ -0,0 +1,16 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-13
+ */
+public interface ReceiveWaterValueService extends IService<ReceiveWaterValue> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherAnalyseService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherAnalyseService.java
new file mode 100644
index 0000000..16410f9
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherAnalyseService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherAnalyse;
+
+
+/**
+ * <p>
+ * 姘旇薄璁惧鍒嗘瀽鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+public interface ReceiveWeatherAnalyseService extends IService<ReceiveWeatherAnalyse> {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherInfoService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherInfoService.java
new file mode 100644
index 0000000..4605334
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherInfoService.java
@@ -0,0 +1,23 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 姘旇薄鏁版嵁鎺ユ敹绠$悊 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+public interface ReceiveWeatherInfoService extends IService<ReceiveWeatherInfo> {
+
+    void saveData(List<ReceiveWeatherInfo> list, DpEquipment info);
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueFinalService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueFinalService.java
new file mode 100644
index 0000000..e8d47ae
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueFinalService.java
@@ -0,0 +1,37 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+public interface ReceiveWeatherValueFinalService extends IService<ReceiveWeatherValueFinal> {
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<ReceiveWeatherValueFinal> listAll();
+
+    //鎵归噺鎻掑叆
+    Integer saveBatchNew(List<ReceiveWeatherValueFinal> receiveWeatherValueFinal);
+
+    //鏉′欢鏌ヨ
+    List<ReceiveWeatherValueFinal> queryData(ReceiveValueListVo vo);
+
+    //鎵归噺鍒犻櫎
+    Integer deleteBatch(List<Long> ids);
+
+    //淇敼鏇存柊
+    Integer updateDate(ReceiveWeatherValueFinal receiveWeatherValueFinal);
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueService.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueService.java
new file mode 100644
index 0000000..6bff87a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/ReceiveWeatherValueService.java
@@ -0,0 +1,23 @@
+package com.ruoyi.fuzhou.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValue;
+
+import java.util.List;
+
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+public interface ReceiveWeatherValueService extends IService<ReceiveWeatherValue> {
+
+
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidTaskServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidTaskServiceImpl.java
new file mode 100644
index 0000000..4add007
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidTaskServiceImpl.java
@@ -0,0 +1,36 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidTask;
+import com.ruoyi.fuzhou.mapper.DpRfidTaskMapper;
+import com.ruoyi.fuzhou.service.DpRfidTaskService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID浠诲姟琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-25
+ */
+@Service
+public class DpRfidTaskServiceImpl extends ServiceImpl<DpRfidTaskMapper, DpRfidTask> implements DpRfidTaskService {
+
+    @Resource
+    private DpRfidTaskMapper dpRfidTaskMapper;
+
+    @Override
+    public TableDataInfo getPageList(DpRfidTask dpRfidTask) {
+        Integer offset = (dpRfidTask.getPageNum()-1)*dpRfidTask.getPageSize();
+        dpRfidTask.setOffset(offset);
+        List<DpRfidTask> records = dpRfidTaskMapper.getPageList(dpRfidTask);
+        Integer total = dpRfidTaskMapper.getTotal(dpRfidTask);
+        return new TableDataInfo(records,total);
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidVehicleServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidVehicleServiceImpl.java
new file mode 100644
index 0000000..c6e798a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/DpRfidVehicleServiceImpl.java
@@ -0,0 +1,72 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpRfidTask;
+import com.ruoyi.fuzhou.domain.DpRfidVehicle;
+import com.ruoyi.fuzhou.domain.OpenWZ;
+import com.ruoyi.fuzhou.domain.vo.RfidVehicleVO;
+import com.ruoyi.fuzhou.mapper.DpRfidVehicleMapper;
+import com.ruoyi.fuzhou.service.DpRfidVehicleService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * RFID杞﹁締璁板綍琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-21
+ */
+@Service
+public class DpRfidVehicleServiceImpl extends ServiceImpl<DpRfidVehicleMapper, DpRfidVehicle> implements DpRfidVehicleService {
+
+    @Resource
+    private DpRfidVehicleMapper dpRfidVehicleMapper;
+
+    @Override
+    public TableDataInfo getPageList(DpRfidVehicle dpRfidVehicle) {
+        Integer offset = (dpRfidVehicle.getPageNum()-1)*dpRfidVehicle.getPageSize();
+        dpRfidVehicle.setOffset(offset);
+        List<DpRfidVehicle> records = dpRfidVehicleMapper.getPageList(dpRfidVehicle);
+        Integer total = dpRfidVehicleMapper.getTotal(dpRfidVehicle);
+        return new TableDataInfo(records,total);
+    }
+
+    @Override
+    public List<DpRfidVehicle> selectRfidVehicle(RfidVehicleVO rfidVehicleVO){
+        return dpRfidVehicleMapper.selectRfidVehicle(rfidVehicleVO);
+    }
+
+    @Override
+    public DpRfidVehicle QueryVehicleByTask(String task){
+        LambdaQueryWrapper<DpRfidVehicle> rfidVehicleWrapper = new LambdaQueryWrapper<>();
+        rfidVehicleWrapper.like(DpRfidVehicle::getWzData,task).orderByDesc(DpRfidVehicle::getPassTime).last("LIMIT 1");
+
+//        List<DpRfidVehicle> list = dpRfidVehicleMapper.selectList(rfidVehicleWrapper);
+//        if(list.size()>0){
+//            for (DpRfidVehicle dpRfidVehicle : list){
+//                List<OpenWZ> taskList = dpRfidVehicle.getWzData();
+//                if(taskList.size()>0){
+//                    for (DpRfidTask dpRfidTask : taskList){
+//                        String name = dpRfidTask.getType();
+//                        if(name.equals(task)){
+//                            return dpRfidVehicle;
+//                        }
+//                    }
+//                }
+//            }
+//        }
+        return dpRfidVehicleMapper.selectOne(rfidVehicleWrapper);
+    }
+
+    @Override
+    public Integer insert(DpRfidVehicle dpRfidVehicle){
+        return dpRfidVehicleMapper.insert(dpRfidVehicle);
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/EquipmentServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/EquipmentServiceImpl.java
new file mode 100644
index 0000000..296533c
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/EquipmentServiceImpl.java
@@ -0,0 +1,81 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+import com.ruoyi.fuzhou.domain.vo.DpEquipmentVO;
+import com.ruoyi.fuzhou.mapper.EquipmentMapper;
+import com.ruoyi.fuzhou.service.EquipmentService;
+import com.ruoyi.fuzhou.service.ReceiveModuleInfoService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Service
+public class EquipmentServiceImpl extends ServiceImpl<EquipmentMapper, DpEquipment> implements EquipmentService {
+    @Resource
+    private EquipmentMapper dpEquipmentMapper;
+
+    @Resource
+    ReceiveModuleInfoServiceImpl receiveModuleInfoService;
+
+    public DpEquipment getEpByField(String field) {
+        List<DpEquipment> list = list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().eq(DpEquipment::getFieldName, field);
+        }});
+
+        return null == list || list.isEmpty() ? null : list.get(0);
+    }
+
+    public List<DpEquipment> getListByType(Integer typeId) {
+        List<DpEquipment> list = list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().eq(DpEquipment::getEquipmentTypeId, typeId);
+        }});
+
+        return list;
+    }
+
+    @Override
+    public TableDataInfo getPageList(DpEquipment equipment) {
+        if (equipment.getPageNum() != null && equipment.getPageSize() != null) {
+            Integer offset = (equipment.getPageNum() - 1) * equipment.getPageSize();
+            equipment.setOffset(offset);
+            List<DpEquipmentVO> records = dpEquipmentMapper.getPageList(equipment);
+            long total = dpEquipmentMapper.getTotal(equipment);
+            return new TableDataInfo(records, Integer.parseInt(String.valueOf(total)));
+        } else {
+            return null;
+        }
+    }
+
+    @Override
+    public DpEquipmentVO selectById(Integer id) {
+        return dpEquipmentMapper.queryById(id);
+    }
+
+    @Override
+    public List<DpEquipmentVO> getListByBeId(Integer beId){
+        return dpEquipmentMapper.getListByBeId(beId);
+    }
+
+    @Override
+    public List<DpEquipmentVO> getListByWhId(Integer whId){
+        return dpEquipmentMapper.getListByWhId(whId);
+    }
+
+    @Override
+    public List<DpEquipmentVO> getListByBeIdTypeId(Integer beId,List<Integer> typeIds){return dpEquipmentMapper.getListByBeIdTypeId(beId,typeIds);}
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/HikServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/HikServiceImpl.java
new file mode 100644
index 0000000..b7dad76
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/HikServiceImpl.java
@@ -0,0 +1,333 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.fuzhou.config.HikConfig;
+import com.ruoyi.fuzhou.domain.CameraPTZ;
+import com.ruoyi.fuzhou.domain.HikEvent;
+import com.ruoyi.fuzhou.domain.HikEventObj;
+import com.ruoyi.fuzhou.mapper.HikEventMapper;
+import com.ruoyi.fuzhou.service.HikService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.HashMap;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+@Service
+public class HikServiceImpl extends ServiceImpl<HikEventMapper, HikEvent>
+        implements HikService {
+    @Autowired
+    private HikConfig hikConfig;
+    @Autowired
+    private HikEventMapper hikEventMapper;
+
+    @Override
+    public Map<String,Integer> getCameraOnline(String[] indexCodes){
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String onlineApi = ARTEMIS_PATH +
+                "/api/nms/v1/online/camera/get";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", onlineApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+
+        Map<String,Integer> onlineMap = new LinkedHashMap<>();
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("indexCodes", indexCodes);
+        jsonBody.put("pageNo", 1);
+        jsonBody.put("pageSize", 999);
+        String body = jsonBody.toJSONString();
+
+        try {
+            String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+            JSONObject res = JSON.parseObject(result);
+
+            JSONObject data = res.getJSONObject("data");
+            JSONArray jsonArray = data.getJSONArray("list");
+            for (Object object : jsonArray){
+                String objJson = object.toString();
+                JSONObject jsonObject = JSON.parseObject(objJson);
+                if(jsonObject.get("indexCode")!=null && jsonObject.get("online")!=null){
+                    onlineMap.put(jsonObject.getString("indexCode"),jsonObject.getIntValue("online"));
+                }
+            }
+            return onlineMap;
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }
+        return onlineMap;
+    }
+
+    @Override
+    public JSONObject subByEventTypes(HikEventObj hikEventObj) throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String subEventApi = ARTEMIS_PATH +
+                "/api/eventService/v1/eventSubscriptionByEventTypes";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", subEventApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+
+        JSONObject res = new JSONObject();
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("eventTypes",hikEventObj.getEventTypes());
+        jsonBody.put("eventDest", hikEventObj.getEventDest());
+        jsonBody.put("subType", hikEventObj.getSubType());
+        jsonBody.put("eventLvl", hikEventObj.getEventLvl());
+        String body = jsonBody.toJSONString();
+
+        try {
+            String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+            res = JSON.parseObject(result);
+            return res;
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }
+        return res;
+    }
+
+    @Override
+    public JSONObject unSubByEventTypes(HikEventObj hikEventObj) throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String unSubEventApi = ARTEMIS_PATH +
+                "/api/eventService/v1/eventUnSubscriptionByEventTypes";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", unSubEventApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+
+        JSONObject res = new JSONObject();
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("eventTypes",hikEventObj.getEventTypes());
+
+        String body = jsonBody.toJSONString();
+
+        try {
+            String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+            res = JSON.parseObject(result);
+            return res;
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }
+        return res;
+    }
+
+    @Override
+    public JSONObject eventView() throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String eventApi = ARTEMIS_PATH +
+                "/api/eventService/v1/eventSubscriptionView";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", eventApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+
+        JSONObject res = new JSONObject();
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+
+        String body = jsonBody.toJSONString();
+
+        try {
+            String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+            res = JSON.parseObject(result);
+            return res;
+        }catch (Exception e){
+            System.out.println(e.getMessage());
+        }
+        return res;
+    }
+
+    @Override
+    public boolean saveInsert(HikEvent hikEvent){
+        int res =  hikEventMapper.insert(hikEvent);
+        if(res != 0){
+            return true;
+        }else {
+            return false;
+        }
+    }
+
+    @Override
+    public TableDataInfo getList(HikEvent hikEvent) {
+        Integer offset = (hikEvent.getPageNum()-1)*hikEvent.getPageSize();
+        hikEvent.setOffset(offset);
+        List<HikEvent> list = hikEventMapper.getPageList(hikEvent);
+        Integer total = hikEventMapper.getTotal(hikEvent);
+        TableDataInfo tableDataInfo = new TableDataInfo();
+        tableDataInfo.setRows(list);
+        tableDataInfo.setTotal(total);
+        return tableDataInfo;
+    }
+
+    @Override
+    public JSONObject cameraCommand(CameraPTZ cameraPTZ) throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String urlApi = ARTEMIS_PATH +
+                "/api/video/v1/ptzs/controlling";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", urlApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("cameraIndexCode", cameraPTZ.getCameraIndexCode());
+        jsonBody.put("action", cameraPTZ.getAction());
+        jsonBody.put("command", cameraPTZ.getCommand());
+        jsonBody.put("speed", cameraPTZ.getSpeed());
+        jsonBody.put("presetIndex", cameraPTZ.getPresetIndex());
+
+        String body = jsonBody.toJSONString();
+        String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+        JSONObject res = JSON.parseObject(result);
+
+        return res;
+    }
+
+    @Override
+    public String getCameraPreviewURL(String cameraName) throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String previewURLsApi = ARTEMIS_PATH +
+                "/api/video/v2/cameras/previewURLs";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", previewURLsApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+        String cameraIndexCode = getCameraIndexCode(cameraName);
+
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("cameraIndexCode", cameraIndexCode);
+        jsonBody.put("streamType", 0);
+        jsonBody.put("protocol", "ws");
+        jsonBody.put("transmode", 1);
+        jsonBody.put("expand", "transcode=0");
+        String body = jsonBody.toJSONString();
+        String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+        JSONObject res = JSON.parseObject(result);
+
+        JSONObject data = res.getJSONObject("data");
+        String url = data.getString("url");
+
+        return url;
+    }
+
+    private String getCameraIndexCode(String cameraName) throws Exception {
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String previewURLsApi = ARTEMIS_PATH +
+                "/api/resource/v2/camera/search";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", previewURLsApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("name", cameraName);
+        jsonBody.put("pageNo", 1);
+        jsonBody.put("pageSize", 10);
+        String body = jsonBody.toJSONString();
+        String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+        JSONObject res = JSON.parseObject(result);
+        JSONArray array = res.getJSONObject("data").getJSONArray("list");
+        JSONObject data = array.getJSONObject(0);
+        String cameraIndexCode = data.getString("indexCode");
+
+        return cameraIndexCode;
+    }
+
+    @Override
+    public String getCameraURL(String cameraIndexCode) throws Exception{
+        final String ARTEMIS_PATH = "/artemis";
+        /**
+         * STEP3锛氳缃帴鍙g殑URI鍦板潃
+         */
+        final String previewURLsApi = ARTEMIS_PATH +
+                "/api/video/v2/cameras/previewURLs";
+        Map<String, String> path = new HashMap<String, String>(2) {
+            {
+                put("https://", previewURLsApi);//鏍规嵁鐜板満鐜閮ㄧ讲纭鏄痟ttp杩樻槸https
+            }
+        };
+        //缁勮鍙傛暟
+        JSONObject jsonBody = new JSONObject();
+        jsonBody.put("cameraIndexCode", cameraIndexCode);
+        jsonBody.put("streamType", 0);
+        jsonBody.put("protocol", "ws");
+        jsonBody.put("transmode", 1);
+        jsonBody.put("expand", "transcode=0");
+        String body = jsonBody.toJSONString();
+        String result = hikConfig.hkpost(path, body);// post璇锋眰application/json绫诲瀷鍙傛暟
+
+        JSONObject res = JSON.parseObject(result);
+
+        JSONObject data = res.getJSONObject("data");
+        String url = data.getString("url");
+
+        return url;
+    }
+
+//    public static void main(String[] args) {
+//        String ipAddr = "10.3.10.66";
+//        try {
+//            InetAddress address = InetAddress.getByName(ipAddr);
+//            boolean res = address.isReachable(5000);
+//            if(res){
+//                System.out.println(ipAddr+"鑱旈��");
+//            }else {
+//                System.out.println(ipAddr+"涓嶉��");
+//            }
+//        }catch (Exception e){
+//            System.out.println(e.getMessage());
+//        }
+//
+//    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarRuleServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarRuleServiceImpl.java
new file mode 100644
index 0000000..2ee46f2
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarRuleServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveCarRule;
+import com.ruoyi.fuzhou.mapper.ReceiveCarRuleMapper;
+import com.ruoyi.fuzhou.service.ReceiveCarRuleService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 杞﹁締鏁版嵁鎺ユ敹淇℃伅 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-22
+ */
+@Service
+public class ReceiveCarRuleServiceImpl extends ServiceImpl<ReceiveCarRuleMapper, ReceiveCarRule> implements ReceiveCarRuleService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueFinalServiceImpl.java
new file mode 100644
index 0000000..ecc4b4a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueFinalServiceImpl.java
@@ -0,0 +1,82 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveCarValueFinalMapper;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.mapper.ReceiveCarValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveCarValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveCarValueFinalServiceImpl extends ServiceImpl<ReceiveCarValueFinalMapper, ReceiveCarValueFinal> implements ReceiveCarValueFinalService {
+
+    @Autowired
+    private ReceiveCarValueFinalMapper receiveCarValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveCarValueFinal> listAll(){
+        return receiveCarValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatch(List<ReceiveCarValueFinal> carValueFinals){
+        int i = 0;
+        for (ReceiveCarValueFinal receiveCarValueFinal : carValueFinals){
+            QueryWrapper<ReceiveCarValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveCarValueFinal.getId());
+            if(!receiveCarValueFinalMapper.exists(queryWrapper)){
+                receiveCarValueFinalMapper.insert(receiveCarValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveCarValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveCarValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveCarValueFinal::getVin, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveCarValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveCarValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveCarValueFinal::getCreateTime);
+        return receiveCarValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveCarValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveCarValueFinal receiveCarValueFinal){
+        return receiveCarValueFinalMapper.updateById(receiveCarValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveCarValueFinalMapper.selectCount(null);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueServiceImpl.java
new file mode 100644
index 0000000..7bcabb6
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveCarValueServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveCarValue;
+import com.ruoyi.fuzhou.mapper.ReceiveCarValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveCarValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 宸ュ喌閲囬泦 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-24
+ */
+@Service
+public class ReceiveCarValueServiceImpl extends ServiceImpl<ReceiveCarValueMapper, ReceiveCarValue> implements ReceiveCarValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityAnalyseServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityAnalyseServiceImpl.java
new file mode 100644
index 0000000..0279307
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityAnalyseServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityAnalyse;
+import com.ruoyi.fuzhou.mapper.ReceiveElectricityAnalyseMapper;
+import com.ruoyi.fuzhou.service.ReceiveElectricityAnalyseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹竻娲� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Service
+public class ReceiveElectricityAnalyseServiceImpl extends ServiceImpl<ReceiveElectricityAnalyseMapper, ReceiveElectricityAnalyse> implements ReceiveElectricityAnalyseService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityInfoServiceImpl.java
new file mode 100644
index 0000000..89756b7
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityInfoServiceImpl.java
@@ -0,0 +1,91 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityInfo;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+import com.ruoyi.fuzhou.mapper.ReceiveElectricityInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveElectricityInfoService;
+import com.ruoyi.fuzhou.service.ReceiveElectricityValueService;
+import com.ruoyi.fuzhou.utils.electricitymodbus.ModbusElectricityUtils;
+import com.ruoyi.fuzhou.websocket.WebSocketOilServer;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>
+ * 鐢垫暟鎹帴鏀剁鐞� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Service
+public class ReceiveElectricityInfoServiceImpl extends ServiceImpl<ReceiveElectricityInfoMapper, ReceiveElectricityInfo> implements ReceiveElectricityInfoService {
+
+    @Resource
+    private ReceiveElectricityValueService receiveElectricityValueService;
+
+    @Resource
+    private RedisTemplate redisTemplate;
+
+    @Override
+    public void saveElectricity(List<ReceiveElectricityInfo> list, DpEquipment dpEquipment) {
+        JSONObject jsonObject = ModbusElectricityUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveElectricityValue receiveElectricityValue = JSON.toJavaObject(jsonObject, ReceiveElectricityValue.class);
+            receiveElectricityValue.setCreateTime(new Date());
+            receiveElectricityValue.setDeviceName(list.get(0).getDeviceName());
+            if (Math.abs(Double.valueOf(receiveElectricityValue.getCurrentA())) > 0 || Math.abs(Double.valueOf(receiveElectricityValue.getCurrentB())) > 0 ||
+                    Math.abs(Double.valueOf(receiveElectricityValue.getCurrentC())) > 0) {
+                redisTemplate.opsForValue().set("VALUE@" + receiveElectricityValue.getDeviceName(), receiveElectricityValue.getCurrentA()
+                        + receiveElectricityValue.getCurrentB()
+                        + receiveElectricityValue.getCurrentC(), 30, TimeUnit.MINUTES);
+                receiveElectricityValueService.save(receiveElectricityValue);
+            } else {
+                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveElectricityValue.getDeviceName());
+                if (obj == null) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveElectricityValue.getDeviceName(), receiveElectricityValue.getCurrentA()
+                            + receiveElectricityValue.getCurrentB()
+                            + receiveElectricityValue.getCurrentC(), 30, TimeUnit.MINUTES);
+                    receiveElectricityValueService.save(receiveElectricityValue);
+                } else if (!obj.toString().equals(receiveElectricityValue.getCurrentA() + receiveElectricityValue.getCurrentB() + receiveElectricityValue.getCurrentC())) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveElectricityValue.getDeviceName(), receiveElectricityValue.getCurrentA()
+                            + receiveElectricityValue.getCurrentB()
+                            + receiveElectricityValue.getCurrentC(), 30, TimeUnit.MINUTES);
+                    receiveElectricityValueService.save(receiveElectricityValue);
+                }
+            }
+        }
+        //鍒堕�爏ocket鏁版嵁
+//        JSONArray header = new JSONArray();
+//        list.forEach(item -> {
+//            JSONObject head = new JSONObject();
+//            head.put("param", item.getParam());
+//            head.put("paramCode", item.getParamCode());
+//            head.put("unit", item.getUnit());
+//            header.add(head);
+//        });
+//        ReceiveElectricityValue receiveOilValue = receiveElectricityValueService.getOne(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+//            or().eq(ReceiveElectricityValue::getDeviceName, list.get(0).getDeviceName()).orderByDesc(ReceiveElectricityValue::getCreateTime).last("limit 1");
+//        }});
+//        if (receiveOilValue != null) {
+//            JSONObject object = new JSONObject();
+//            object.put("header", header);
+//            object.put("body", JSONObject.parseObject(JSON.toJSONString(receiveOilValue)));
+//            object.put("info", JSONObject.parseObject(JSON.toJSONString(dpEquipment)));
+//            object.put("status", "1");
+//            WebSocketOilServer.sendAllMessage(object.toJSONString());
+//        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueFinalServiceImpl.java
new file mode 100644
index 0000000..26ba33e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueFinalServiceImpl.java
@@ -0,0 +1,80 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveElectricityValueFinalMapper;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValueFinal;
+import com.ruoyi.fuzhou.service.ReceiveElectricityValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveElectricityValueFinalServiceImpl extends ServiceImpl<ReceiveElectricityValueFinalMapper, ReceiveElectricityValueFinal> implements ReceiveElectricityValueFinalService {
+    @Autowired
+    private ReceiveElectricityValueFinalMapper receiveElectricityValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveElectricityValueFinal> listAll(){
+        return receiveElectricityValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatch(List<ReceiveElectricityValueFinal> electricityValueFinals){
+        int i = 0;
+        for (ReceiveElectricityValueFinal receiveElectricityValueFinal : electricityValueFinals){
+            QueryWrapper<ReceiveElectricityValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveElectricityValueFinal.getId());
+            if(!receiveElectricityValueFinalMapper.exists(queryWrapper)){
+                receiveElectricityValueFinalMapper.insert(receiveElectricityValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveElectricityValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveElectricityValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveElectricityValueFinal::getDeviceName, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveElectricityValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveElectricityValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveElectricityValueFinal::getCreateTime);
+        return receiveElectricityValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveElectricityValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveElectricityValueFinal receiveElectricityValueFinal){
+        return receiveElectricityValueFinalMapper.updateById(receiveElectricityValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveElectricityValueFinalMapper.selectCount(null);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueServiceImpl.java
new file mode 100644
index 0000000..4d54d17
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveElectricityValueServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+import com.ruoyi.fuzhou.mapper.ReceiveElectricityValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveElectricityValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 鐢佃澶囨暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-14
+ */
+@Service
+public class ReceiveElectricityValueServiceImpl extends ServiceImpl<ReceiveElectricityValueMapper, ReceiveElectricityValue> implements ReceiveElectricityValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveModuleInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveModuleInfoServiceImpl.java
new file mode 100644
index 0000000..aa10ba8
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveModuleInfoServiceImpl.java
@@ -0,0 +1,296 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.mapper.ReceiveModuleInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveElectricityInfoService;
+import com.ruoyi.fuzhou.service.ReceiveModuleInfoService;
+import com.ruoyi.fuzhou.service.ReceiveOilInfoService;
+import com.ruoyi.fuzhou.service.ReceiveWaterInfoService;
+import com.ruoyi.fuzhou.utils.Modbus4jUtils;
+import com.ruoyi.fuzhou.utils.RtuMasterUtils;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * modbus鏁版嵁妯℃澘 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-27
+ */
+@Service
+public class ReceiveModuleInfoServiceImpl extends ServiceImpl<ReceiveModuleInfoMapper, ReceiveModuleInfo> implements ReceiveModuleInfoService {
+
+    @Resource
+    private ReceiveElectricityInfoService receiveElectricityInfoService;
+
+    @Resource
+    private ReceiveOilInfoService receiveOilInfoService;
+
+    @Resource
+    private ReceiveWaterInfoService receiveWaterInfoService;
+
+    @Override
+    public void saveByModule(String deviceName, String ip, Integer port, Byte deviceAddress, Integer dataType) {
+        if (dataType == null || DataTypeEnum.of(dataType) == null) return;
+
+        List<ReceiveModuleInfo> receiveModuleInfos;
+        if (DataTypeEnum.YDKFM.getCode().equals(dataType)) {
+            receiveModuleInfos = list(new LambdaQueryWrapper<ReceiveModuleInfo>() {{
+                or().eq(ReceiveModuleInfo::getDataType, dataType).eq(ReceiveModuleInfo::getDeviceName, deviceName);
+            }});
+            boolean flag = null == receiveModuleInfos || receiveModuleInfos.isEmpty();
+
+            ReceiveModuleInfo rmi = flag ? new ReceiveModuleInfo() : receiveModuleInfos.get(0);
+            if (flag) rmi.setId(null);
+            rmi.setDeviceAddress(deviceAddress);
+            rmi.setDeviceName(deviceName);
+            rmi.setPort(port);
+            if (StringUtils.isNotEmpty(ip)) rmi.setIp(ip);
+            rmi.setDataType(dataType);
+            rmi.setRegisterCount(1);
+
+            if (flag) save(rmi);
+            else updateById(rmi);
+            return;
+        }
+        receiveModuleInfos = list(new LambdaQueryWrapper<ReceiveModuleInfo>() {{
+            or().eq(ReceiveModuleInfo::getDataType, dataType);
+        }});
+        if (receiveModuleInfos != null && receiveModuleInfos.size() > 0) {
+            if (DataTypeEnum.WATER_DEPT.getCode().equals(dataType) || DataTypeEnum.WATER_YA.getCode().equals(dataType) ||
+                    DataTypeEnum.WATER_FLOW.getCode().equals(dataType)) {
+                List<ReceiveWaterInfo> receiveWaterInfos = new ArrayList<>();
+                ReceiveWaterInfo receiveWaterInfo;
+                for (ReceiveModuleInfo info : receiveModuleInfos
+                ) {
+                    receiveWaterInfo = new ReceiveWaterInfo();
+                    receiveWaterInfo.setDeviceAddress(deviceAddress);
+                    receiveWaterInfo.setDeviceName(deviceName);
+                    receiveWaterInfo.setPort(port);
+                    if (StringUtils.isNotEmpty(ip)) {
+                        receiveWaterInfo.setIp(ip);
+                    }
+                    if (info.getFunctionCode() != null) {
+                        receiveWaterInfo.setFunctionCode(info.getFunctionCode());
+                    }
+                    receiveWaterInfo.setRegisterAdress(info.getRegisterAdress());
+                    receiveWaterInfo.setRegisterCount(info.getRegisterCount());
+                    receiveWaterInfo.setParam(info.getParam());
+                    receiveWaterInfo.setParamCode(info.getParamCode());
+                    receiveWaterInfo.setUnit(info.getUnit());
+                    receiveWaterInfo.setDataType(dataType);
+                    receiveWaterInfos.add(receiveWaterInfo);
+                }
+                receiveWaterInfoService.remove(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                    or().eq(ReceiveWaterInfo::getDeviceName, deviceName);
+                }});
+                receiveWaterInfoService.saveBatch(receiveWaterInfos);
+            } else if (DataTypeEnum.ELECTRICITY.getCode().equals(dataType)) {
+                List<ReceiveElectricityInfo> receiveElectricityInfos = new ArrayList<>();
+                ReceiveElectricityInfo electricityInfo;
+                for (ReceiveModuleInfo info : receiveModuleInfos
+                ) {
+                    electricityInfo = new ReceiveElectricityInfo();
+                    electricityInfo.setDeviceAddress(deviceAddress);
+                    electricityInfo.setDeviceName(deviceName);
+                    electricityInfo.setPort(port);
+                    if (StringUtils.isNotEmpty(ip)) {
+                        electricityInfo.setIp(ip);
+                    }
+                    electricityInfo.setDataType(dataType);
+                    electricityInfo.setFunctionCode(info.getFunctionCode());
+                    electricityInfo.setRegisterAdress(info.getRegisterAdress());
+                    electricityInfo.setRegisterCount(info.getRegisterCount());
+                    electricityInfo.setParam(info.getParam());
+                    electricityInfo.setParamCode(info.getParamCode());
+                    electricityInfo.setUnit(info.getUnit());
+                    receiveElectricityInfos.add(electricityInfo);
+                }
+                receiveElectricityInfoService.remove(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                    or().eq(ReceiveElectricityInfo::getDeviceName, deviceName);
+                }});
+                receiveElectricityInfoService.saveBatch(receiveElectricityInfos);
+            } else if (DataTypeEnum.OIL.getCode().equals(dataType) || DataTypeEnum.LIJIUOIL.getCode().equals(dataType) ||
+                    DataTypeEnum.LIJIUJUN.getCode().equals(dataType) || DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                List<ReceiveOilInfo> receiveOilInfos = new ArrayList<>();
+                ReceiveOilInfo receiveOilInfo;
+                for (ReceiveModuleInfo info : receiveModuleInfos
+                ) {
+                    receiveOilInfo = new ReceiveOilInfo();
+                    receiveOilInfo.setDeviceAddress(deviceAddress);
+                    receiveOilInfo.setDeviceName(deviceName);
+                    receiveOilInfo.setPort(port);
+                    if (StringUtils.isNotEmpty(ip)) {
+                        receiveOilInfo.setIp(ip);
+                    }
+                    receiveOilInfo.setDataType(dataType);
+                    if (info.getFunctionCode() != null) {
+                        receiveOilInfo.setFunctionCode(info.getFunctionCode());
+                    }
+                    receiveOilInfo.setRegisterAdress(info.getRegisterAdress());
+                    receiveOilInfo.setRegisterCount(info.getRegisterCount());
+                    receiveOilInfo.setParam(info.getParam());
+                    receiveOilInfo.setParamCode(info.getParamCode());
+                    receiveOilInfo.setUnit(info.getUnit());
+                    receiveOilInfos.add(receiveOilInfo);
+                }
+                receiveOilInfoService.remove(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                    or().eq(ReceiveOilInfo::getDeviceName, deviceName);
+                }});
+                receiveOilInfoService.saveBatch(receiveOilInfos);
+            }
+        }
+    }
+
+    @Override
+    public void removeByModule(String deviceName, Integer dataType) {
+        if (dataType == null || DataTypeEnum.of(dataType) == null) {
+            return;
+        } else {
+            if (DataTypeEnum.WATER_DEPT.getCode().equals(dataType) || DataTypeEnum.WATER_YA.getCode().equals(dataType) ||
+                    DataTypeEnum.WATER_FLOW.getCode().equals(dataType)) {
+                receiveWaterInfoService.remove(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                    or().eq(ReceiveWaterInfo::getDeviceName, deviceName);
+                }});
+            } else if (DataTypeEnum.ELECTRICITY.getCode().equals(dataType)) {
+                receiveElectricityInfoService.remove(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                    or().eq(ReceiveElectricityInfo::getDeviceName, deviceName);
+                }});
+            } else if (DataTypeEnum.OIL.getCode().equals(dataType) || DataTypeEnum.LIJIUOIL.getCode().equals(dataType) ||
+                    DataTypeEnum.LIJIUJUN.getCode().equals(dataType) || DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                receiveOilInfoService.remove(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                    or().eq(ReceiveOilInfo::getDeviceName, deviceName);
+                }});
+            }
+        }
+    }
+
+    @Override
+    public DpEquipment getIp(String deviceName, Integer dataType) {
+        if (dataType == null || DataTypeEnum.of(dataType) == null) {
+            return new DpEquipment();
+        } else {
+            DpEquipment dpEquipment = new DpEquipment();
+            if (DataTypeEnum.YDKFM.getCode().equals(dataType)) {
+                List<ReceiveModuleInfo> infos = list(new LambdaQueryWrapper<ReceiveModuleInfo>() {{
+                    or().eq(ReceiveModuleInfo::getDeviceName, deviceName);
+                }});
+                if (null == infos || infos.isEmpty()) return dpEquipment;
+                ReceiveModuleInfo rmi = infos.get(0);
+                dpEquipment.setIp(rmi.getIp());
+                dpEquipment.setPort(rmi.getPort());
+                dpEquipment.setDeviceAddress(rmi.getDeviceAddress());
+            }
+            if (DataTypeEnum.WATER_DEPT.getCode().equals(dataType) || DataTypeEnum.WATER_YA.getCode().equals(dataType) ||
+                    DataTypeEnum.WATER_FLOW.getCode().equals(dataType)) {
+                List<ReceiveWaterInfo> receiveWaterInfos = receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                    or().eq(ReceiveWaterInfo::getDeviceName, deviceName);
+                }});
+                for (ReceiveWaterInfo r : receiveWaterInfos
+                ) {
+                    if (StringUtils.isNotEmpty(r.getIp())) {
+                        dpEquipment.setIp(r.getIp());
+                    }
+                    if (r.getPort() != null) {
+                        dpEquipment.setPort(r.getPort());
+                    }
+                    if (r.getDeviceAddress() != null) {
+                        dpEquipment.setDeviceAddress(r.getDeviceAddress());
+                    }
+                }
+            } else if (DataTypeEnum.ELECTRICITY.getCode().equals(dataType)) {
+                List<ReceiveElectricityInfo> receiveElectricityInfos = receiveElectricityInfoService.list(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                    or().eq(ReceiveElectricityInfo::getDeviceName, deviceName);
+                }});
+                for (ReceiveElectricityInfo r : receiveElectricityInfos
+                ) {
+                    if (StringUtils.isNotEmpty(r.getIp())) {
+                        dpEquipment.setIp(r.getIp());
+                    }
+                    if (r.getPort() != null) {
+                        dpEquipment.setPort(r.getPort());
+                    }
+                    if (r.getDeviceAddress() != null) {
+                        dpEquipment.setDeviceAddress(r.getDeviceAddress());
+                    }
+                }
+            } else if (DataTypeEnum.OIL.getCode().equals(dataType) || DataTypeEnum.LIJIUOIL.getCode().equals(dataType) ||
+                    DataTypeEnum.LIJIUJUN.getCode().equals(dataType) || DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                List<ReceiveOilInfo> receiveOilInfos = receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                    or().eq(ReceiveOilInfo::getDeviceName, deviceName);
+                }});
+                for (ReceiveOilInfo r : receiveOilInfos
+                ) {
+                    if (StringUtils.isNotEmpty(r.getIp())) {
+                        dpEquipment.setIp(r.getIp());
+                    }
+                    if (r.getPort() != null) {
+                        dpEquipment.setPort(r.getPort());
+                    }
+                    if (r.getDeviceAddress() != null) {
+                        dpEquipment.setDeviceAddress(r.getDeviceAddress());
+                    }
+                }
+            }
+            return dpEquipment;
+        }
+    }
+
+    @Override
+    public Map<String, Object> getYdkfmStatus(String deviceName) throws Exception {
+        List<ReceiveModuleInfo> infos = list(new LambdaQueryWrapper<ReceiveModuleInfo>() {{
+            or().eq(ReceiveModuleInfo::getDeviceName, deviceName);
+        }});
+        if (null == infos || infos.isEmpty()) throw new Exception("鎵句笉鍒版补鐢垫帶闃�闂�");
+
+        ReceiveModuleInfo rmi = infos.get(0);
+        Map<String, Object> map = new HashMap<>();
+
+        Boolean status;
+        try {
+            //status = RtuMasterUtils.getYdkfmStatus(rmi);
+            status = Modbus4jUtils.getYdkfmStatus(rmi);
+        } catch (Exception ex) {
+            map.put("error", ex.getMessage());
+            status = null;
+        }
+        map.put("status", status);
+
+        return map;
+    }
+
+    @Override
+    public Map<String, Object> ctrlYdkfm(String deviceName, Boolean flag) throws Exception {
+        List<ReceiveModuleInfo> infos = list(new LambdaQueryWrapper<ReceiveModuleInfo>() {{
+            or().eq(ReceiveModuleInfo::getDeviceName, deviceName);
+        }});
+        if (null == infos || infos.isEmpty()) throw new Exception("鎵句笉鍒版补鐢垫帶闃�闂�");
+
+        ReceiveModuleInfo rmi = infos.get(0);
+        Map<String, Object> map = new HashMap<>();
+
+        Boolean status;
+        try {
+            //status = RtuMasterUtils.ctrlYdkfm(rmi, flag);
+            status = Modbus4jUtils.ctrlYdkfm(rmi, flag);
+        } catch (Exception ex) {
+            map.put("error", ex.getMessage());
+            status = null;
+        }
+        map.put("status", status);
+
+        return map;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilAnalyseServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilAnalyseServiceImpl.java
new file mode 100644
index 0000000..f6a633b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilAnalyseServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveOilAnalyse;
+import com.ruoyi.fuzhou.mapper.ReceiveOilAnalyseMapper;
+import com.ruoyi.fuzhou.service.ReceiveOilAnalyseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 娌硅鍒嗘瀽鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Service
+public class ReceiveOilAnalyseServiceImpl extends ServiceImpl<ReceiveOilAnalyseMapper, ReceiveOilAnalyse> implements ReceiveOilAnalyseService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilInfoServiceImpl.java
new file mode 100644
index 0000000..0694291
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilInfoServiceImpl.java
@@ -0,0 +1,130 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+import com.ruoyi.fuzhou.mapper.ReceiveOilInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveOilInfoService;
+import com.ruoyi.fuzhou.service.ReceiveOilValueService;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusOilServerUtils;
+import com.ruoyi.fuzhou.websocket.WebSocketOilServer;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>
+ * 娌规暟鎹帴鏀剁鐞� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Service
+public class ReceiveOilInfoServiceImpl extends ServiceImpl<ReceiveOilInfoMapper, ReceiveOilInfo> implements ReceiveOilInfoService {
+
+    @Resource
+    private ReceiveOilValueService receiveOilValueService;
+
+    @Resource
+    private RedisTemplate redisTemplate;
+
+    @Override
+    public void saveOil(List<ReceiveOilInfo> list, DpEquipment info) {
+        JSONObject jsonObject = ModbusOilServerUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveOilValue receiveOilValue = JSON.toJavaObject(jsonObject, ReceiveOilValue.class);
+            receiveOilValue.setCreateTime(new Date());
+            receiveOilValue.setDeviceName(list.get(0).getDeviceName());
+            if (Math.abs(Double.valueOf(receiveOilValue.getOilTimeFlow())) > 0) {
+                redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+                receiveOilValueService.save(receiveOilValue);
+            } else {
+                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveOilValue.getDeviceName());
+                if (obj == null) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+                    receiveOilValueService.save(receiveOilValue);
+                } else if (!obj.toString().equals(receiveOilValue.getOilTimeFlow())) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+                    receiveOilValueService.save(receiveOilValue);
+                }
+            }
+        }
+        //鍒堕�爏ocket鏁版嵁
+//        JSONArray header = new JSONArray();
+//        list.forEach(item -> {
+//            JSONObject head = new JSONObject();
+//            head.put("param", item.getParam());
+//            head.put("paramCode", item.getParamCode());
+//            head.put("unit", item.getUnit());
+//            header.add(head);
+//        });
+//        ReceiveOilValue receiveOilValue = receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+//            or().eq(ReceiveOilValue::getDeviceName, list.get(0).getDeviceName()).orderByDesc(ReceiveOilValue::getCreateTime).last("limit 1");
+//        }});
+//        if (receiveOilValue != null) {
+//            JSONObject object = new JSONObject();
+//            object.put("header", header);
+//            object.put("body", JSONObject.parseObject(JSON.toJSONString(receiveOilValue)));
+//            object.put("info", JSONObject.parseObject(JSON.toJSONString(info)));
+//            object.put("status", "1");
+////            WebSocketOilServer.sendAllMessage(object.toJSONString());
+//        }
+    }
+
+    @Override
+    public void saveOilLijiuNingde(List<ReceiveOilInfo> list, DpEquipment info) {
+        JSONObject jsonObject = ModbusOilServerUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveOilValue receiveOilValue = JSON.toJavaObject(jsonObject, ReceiveOilValue.class);
+            receiveOilValue.setCreateTime(new Date());
+            receiveOilValue.setDeviceName(list.get(0).getDeviceName());
+            if (Math.abs(Double.valueOf(receiveOilValue.getOilTimeFlow())) > 0 || Math.abs(Double.valueOf(receiveOilValue.getVolumeFlow())) > 0) {
+                redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow() + receiveOilValue.getVolumeFlow(), 30, TimeUnit.MINUTES);
+                receiveOilValueService.save(receiveOilValue);
+            } else {
+                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveOilValue.getDeviceName());
+                if (obj == null) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow() + receiveOilValue.getVolumeFlow(), 30, TimeUnit.MINUTES);
+                    receiveOilValueService.save(receiveOilValue);
+                } else if (!obj.toString().equals(receiveOilValue.getOilTimeFlow() + receiveOilValue.getVolumeFlow())) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow() + receiveOilValue.getVolumeFlow(), 30, TimeUnit.MINUTES);
+                    receiveOilValueService.save(receiveOilValue);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void saveLijiuOil(List<ReceiveOilInfo> list, DpEquipment info) {
+        JSONObject jsonObject = ModbusOilServerUtils.getLijiuValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveOilValue receiveOilValue = JSON.toJavaObject(jsonObject, ReceiveOilValue.class);
+            receiveOilValue.setDeviceName(list.get(0).getDeviceName());
+            receiveOilValue.setCreateTime(new Date());
+            if (Math.abs(Double.valueOf(receiveOilValue.getOilTimeFlow())) > 0) {
+                receiveOilValueService.save(receiveOilValue);
+                redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+            }else {
+                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveOilValue.getDeviceName());
+                if (obj == null) {
+                    receiveOilValueService.save(receiveOilValue);
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+                } else if (!obj.toString().equals(receiveOilValue.getOilTimeFlow())) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+                    receiveOilValueService.save(receiveOilValue);
+                }
+            }
+        }
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueFinalServiceImpl.java
new file mode 100644
index 0000000..f8cc393
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueFinalServiceImpl.java
@@ -0,0 +1,81 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveOilValueFinalMapper;
+import com.ruoyi.fuzhou.domain.ReceiveOilValueFinal;
+import com.ruoyi.fuzhou.service.ReceiveOilValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveOilValueFinalServiceImpl extends ServiceImpl<ReceiveOilValueFinalMapper, ReceiveOilValueFinal> implements ReceiveOilValueFinalService {
+    @Autowired
+    private ReceiveOilValueFinalMapper receiveOilValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveOilValueFinal> listAll(){
+        return receiveOilValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatch(List<ReceiveOilValueFinal> oilValueFinals){
+        int i = 0;
+        for (ReceiveOilValueFinal receiveOilValueFinal : oilValueFinals){
+            QueryWrapper<ReceiveOilValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveOilValueFinal.getId());
+            if(!receiveOilValueFinalMapper.exists(queryWrapper)){
+                receiveOilValueFinalMapper.insert(receiveOilValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveOilValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveOilValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveOilValueFinal::getDeviceName, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveOilValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveOilValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveOilValueFinal::getCreateTime);
+        return receiveOilValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveOilValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveOilValueFinal receiveOilValueFinal){
+        return receiveOilValueFinalMapper.updateById(receiveOilValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveOilValueFinalMapper.selectCount(null);
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueServiceImpl.java
new file mode 100644
index 0000000..0e4d677
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveOilValueServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveOilValue;
+import com.ruoyi.fuzhou.mapper.ReceiveOilValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveOilValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 娌硅澶囧疄鏃舵暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Service
+public class ReceiveOilValueServiceImpl extends ServiceImpl<ReceiveOilValueMapper, ReceiveOilValue> implements ReceiveOilValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSelectRuleServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSelectRuleServiceImpl.java
new file mode 100644
index 0000000..97f49fb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSelectRuleServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveSelectRule;
+import com.ruoyi.fuzhou.mapper.ReceiveSelectRuleMapper;
+import com.ruoyi.fuzhou.service.ReceiveSelectRuleService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 鏁版嵁娓呮礂瑙勫垯 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-09
+ */
+@Service
+public class ReceiveSelectRuleServiceImpl extends ServiceImpl<ReceiveSelectRuleMapper, ReceiveSelectRule> implements ReceiveSelectRuleService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmAnalyseServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmAnalyseServiceImpl.java
new file mode 100644
index 0000000..893ab73
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmAnalyseServiceImpl.java
@@ -0,0 +1,21 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.ReceiveSlmAnalyse;
+import com.ruoyi.fuzhou.mapper.ReceiveSlmAnalyseMapper;
+import com.ruoyi.fuzhou.service.ReceiveSlmAnalyseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Service
+public class ReceiveSlmAnalyseServiceImpl extends ServiceImpl<ReceiveSlmAnalyseMapper, ReceiveSlmAnalyse> implements ReceiveSlmAnalyseService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmInfoServiceImpl.java
new file mode 100644
index 0000000..8fbf5bc
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmInfoServiceImpl.java
@@ -0,0 +1,82 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.mapper.ReceiveSlmInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveSlmInfoService;
+import com.ruoyi.fuzhou.service.ReceiveSlmValueService;
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueService;
+import com.ruoyi.fuzhou.utils.ModbusSlmServerUtils;
+import com.ruoyi.fuzhou.utils.ModbusWeatherServerUtils;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 闆疯揪鏁版嵁鎺ユ敹绠$悊 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Service
+public class ReceiveSlmInfoServiceImpl extends ServiceImpl<ReceiveSlmInfoMapper, ReceiveSlmInfo> implements ReceiveSlmInfoService {
+    @Resource
+    private RedisTemplate redisTemplate;
+
+    @Resource
+    private ReceiveSlmValueService receiveSlmValueService;
+
+    @Override
+    public void saveData(List<ReceiveSlmInfo> list, DpEquipment info) {
+        JSONObject jsonObject = ModbusSlmServerUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+//        JSONObject jsonObject = ModbusWeatherServerUtils.getValueTest(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveSlmValue receiveSlmValue = JSON.toJavaObject(jsonObject, ReceiveSlmValue.class);
+            receiveSlmValue.setCreateTime(new Date());
+            receiveSlmValue.setDeviceName(list.get(0).getDeviceName());
+
+//            if (Math.abs(Double.valueOf(receiveWeatherValue.getOilTimeFlow())) > 0) {
+//                redisTemplate.opsForValue().set("VALUE@" + receiveWeatherValue.getDeviceName(), receiveWeatherValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                receiveWeatherValueService.save(receiveWeatherValue);
+//            } else {
+//                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveOilValue.getDeviceName());
+//                if (obj == null) {
+//                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                    receiveWeatherValueService.save(receiveOilValue);
+//                } else if (!obj.toString().equals(receiveOilValue.getOilTimeFlow())) {
+//                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                    receiveWeatherValueService.save(receiveOilValue);
+//                }
+//            }
+            receiveSlmValueService.save(receiveSlmValue);
+        }
+        //鍒堕�爏ocket鏁版嵁
+//        JSONArray header = new JSONArray();
+//        list.forEach(item -> {
+//            JSONObject head = new JSONObject();
+//            head.put("param", item.getParam());
+//            head.put("paramCode", item.getParamCode());
+//            head.put("unit", item.getUnit());
+//            header.add(head);
+//        });
+//        ReceiveOilValue receiveOilValue = receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+//            or().eq(ReceiveOilValue::getDeviceName, list.get(0).getDeviceName()).orderByDesc(ReceiveOilValue::getCreateTime).last("limit 1");
+//        }});
+//        if (receiveOilValue != null) {
+//            JSONObject object = new JSONObject();
+//            object.put("header", header);
+//            object.put("body", JSONObject.parseObject(JSON.toJSONString(receiveOilValue)));
+//            object.put("info", JSONObject.parseObject(JSON.toJSONString(info)));
+//            object.put("status", "1");
+////            WebSocketOilServer.sendAllMessage(object.toJSONString());
+//        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueFinalServiceImpl.java
new file mode 100644
index 0000000..4218f53
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueFinalServiceImpl.java
@@ -0,0 +1,85 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveCarValueFinalMapper;
+import com.ruoyi.fuzhou.mapper.ReceiveSlmValueFinalMapper;
+import com.ruoyi.fuzhou.service.ReceiveSlmValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveSlmValueFinalServiceImpl extends ServiceImpl<ReceiveSlmValueFinalMapper, ReceiveSlmValueFinal> implements ReceiveSlmValueFinalService {
+
+
+    @Autowired
+    private ReceiveSlmValueFinalMapper receiveSlmValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveSlmValueFinal> listAll(){
+        return receiveSlmValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatchNew(List<ReceiveSlmValueFinal> carValueFinals){
+        int i = 0;
+        for (ReceiveSlmValueFinal receiveCarValueFinal : carValueFinals){
+            QueryWrapper<ReceiveSlmValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveCarValueFinal.getId());
+            if(!receiveSlmValueFinalMapper.exists(queryWrapper)){
+                receiveSlmValueFinalMapper.insert(receiveCarValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveSlmValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveSlmValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveSlmValueFinal::getDeviceName, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveSlmValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveSlmValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveSlmValueFinal::getCreateTime);
+        return receiveSlmValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveSlmValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveSlmValueFinal receiveCarValueFinal){
+        return receiveSlmValueFinalMapper.updateById(receiveCarValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveSlmValueFinalMapper.selectCount(null);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueServiceImpl.java
new file mode 100644
index 0000000..3edbc19
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveSlmValueServiceImpl.java
@@ -0,0 +1,21 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.ReceiveSlmValue;
+import com.ruoyi.fuzhou.mapper.ReceiveSlmValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveSlmValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 闆疯揪璁惧瀹炴椂鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Service
+public class ReceiveSlmValueServiceImpl extends ServiceImpl<ReceiveSlmValueMapper, ReceiveSlmValue> implements ReceiveSlmValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterAnalyseServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterAnalyseServiceImpl.java
new file mode 100644
index 0000000..a955874
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterAnalyseServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveWaterAnalyse;
+import com.ruoyi.fuzhou.mapper.ReceiveWaterAnalyseMapper;
+import com.ruoyi.fuzhou.service.ReceiveWaterAnalyseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 姘村垎鏋愭暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-25
+ */
+@Service
+public class ReceiveWaterAnalyseServiceImpl extends ServiceImpl<ReceiveWaterAnalyseMapper, ReceiveWaterAnalyse> implements ReceiveWaterAnalyseService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterInfoServiceImpl.java
new file mode 100644
index 0000000..7bc3566
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterInfoServiceImpl.java
@@ -0,0 +1,163 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.fuzhou.domain.DpEquipment;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityValue;
+import com.ruoyi.fuzhou.domain.ReceiveWaterInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+import com.ruoyi.fuzhou.mapper.EquipmentMapper;
+import com.ruoyi.fuzhou.mapper.ReceiveWaterInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveWaterInfoService;
+import com.ruoyi.fuzhou.service.ReceiveWaterValueService;
+import com.ruoyi.fuzhou.utils.hj1239.StringToHexUtil;
+import com.ruoyi.fuzhou.utils.waterdept.ModbusWaterDeptUtils;
+import com.ruoyi.fuzhou.utils.watermodbus.ModbusWaterUtils;
+import com.ruoyi.fuzhou.websocket.WebSocketOilServer;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>
+ * 姘磋澶囦俊鎭� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-12
+ */
+@Service
+public class ReceiveWaterInfoServiceImpl extends ServiceImpl<ReceiveWaterInfoMapper, ReceiveWaterInfo> implements ReceiveWaterInfoService {
+
+    @Resource
+    private ReceiveWaterValueService receiveWaterValueService;
+
+    @Resource
+    private EquipmentMapper equipmentMapper;
+
+    @Resource
+    private RedisTemplate redisTemplate;
+
+    @Override
+    public void saveWater(List<ReceiveWaterInfo> list, DpEquipment dpEquipment) {
+        JSONObject jsonObject = ModbusWaterUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveWaterValue receiveWaterValue = JSON.toJavaObject(jsonObject, ReceiveWaterValue.class);
+            receiveWaterValue.setCreateTime(new Date());
+            receiveWaterValue.setDeviceName(list.get(0).getDeviceName());
+            if (Math.abs(Double.valueOf(receiveWaterValue.getTimeFlow())) > 0 || Math.abs(Double.valueOf(receiveWaterValue.getFlowRate())) > 0) {
+                redisTemplate.opsForValue().set("VALUE@" + receiveWaterValue.getDeviceName(), receiveWaterValue.getFlowRate()
+                        + receiveWaterValue.getTimeFlow(), 30, TimeUnit.MINUTES);
+                receiveWaterValueService.save(receiveWaterValue);
+            } else {
+                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveWaterValue.getDeviceName());
+                if (obj == null) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveWaterValue.getDeviceName(), receiveWaterValue.getFlowRate()
+                            + receiveWaterValue.getTimeFlow(), 30, TimeUnit.MINUTES);
+                    receiveWaterValueService.save(receiveWaterValue);
+                } else if (!obj.toString().equals(receiveWaterValue.getFlowRate() + receiveWaterValue.getTimeFlow())) {
+                    redisTemplate.opsForValue().set("VALUE@" + receiveWaterValue.getDeviceName(), receiveWaterValue.getFlowRate()
+                            + receiveWaterValue.getTimeFlow(), 30, TimeUnit.MINUTES);
+                    receiveWaterValueService.save(receiveWaterValue);
+                }
+            }
+        }
+        //鍒堕�爏ocket鏁版嵁
+//        JSONArray header = new JSONArray();
+//        list.forEach(item -> {
+//            JSONObject head = new JSONObject();
+//            head.put("param", item.getParam());
+//            head.put("paramCode", item.getParamCode());
+//            head.put("unit", item.getUnit());
+//            header.add(head);
+//        });
+//        ReceiveWaterValue receiveOilValue = receiveWaterValueService.getOne(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+//            or().eq(ReceiveWaterValue::getDeviceName, list.get(0).getDeviceName()).orderByDesc(ReceiveWaterValue::getCreateTime).last("limit 1");
+//        }});
+//        if (receiveOilValue != null) {
+//            JSONObject object = new JSONObject();
+//            object.put("header", header);
+//            object.put("body", JSONObject.parseObject(JSON.toJSONString(receiveOilValue)));
+//            object.put("info", JSONObject.parseObject(JSON.toJSONString(dpEquipment)));
+//            object.put("status", "1");
+//            WebSocketOilServer.sendAllMessage(object.toJSONString());
+//        }
+    }
+
+    @Override
+    public void saveWaterYa(List<ReceiveWaterInfo> list, DpEquipment info) {
+        JSONObject jsonObject = ModbusWaterUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveWaterValue receiveWaterValue = JSON.toJavaObject(jsonObject, ReceiveWaterValue.class);
+            receiveWaterValue.setCreateTime(new Date());
+            receiveWaterValue.setDeviceName(list.get(0).getDeviceName());
+            receiveWaterValueService.save(receiveWaterValue);
+        }
+    }
+
+    @Override
+    public void saveWaterDept(List<ReceiveWaterInfo> list, DpEquipment info) {
+        for (ReceiveWaterInfo receiveWaterInfo : list
+        ) {
+
+            try{
+                String value = ModbusWaterDeptUtils.getWaterDept(receiveWaterInfo.getIp(), receiveWaterInfo.getPort());
+                Map<String, Double> map = new HashMap<>();
+                if (StringUtils.isNotEmpty(value)) {
+                    String result = StringToHexUtil.convertHexToString(value);
+                    System.out.println("馃摜 鏀跺埌姘存繁璁惧鍝嶅簲: " + result);
+                    String[] resultList = result.split("\\r\\n");
+                    for (int i = 0; i < resultList.length; i++) {
+                        String[] item = resultList[i].split("-");
+                        if (item.length == 2) {
+                            if (map.get(item[0]) == null) {
+                                map.put(item[0], Double.valueOf(item[1]));
+                            } else {
+                                if (Double.valueOf(item[1]) > map.get(item[0])) {
+                                    map.put(item[0], Double.valueOf(item[1]));
+                                }
+                            }
+                        }
+                    }
+                }
+                if (map.size() > 0) {
+                    Set<String> set = map.keySet();
+                    for (String src : set
+                    ) {
+                        DpEquipment equipment = equipmentMapper.selectOne(new LambdaQueryWrapper<DpEquipment>() {{
+                            or().eq(DpEquipment::getFieldName, src);
+                        }});
+                        if (equipment != null) {
+                            ReceiveWaterValue receiveWaterValue = new ReceiveWaterValue();
+                            if (map.get(src) > 5 && map.get(src) < 20) {
+                                receiveWaterValue.setWaterDeep(String.valueOf(String.format("%.3f", map.get(src))));
+                                receiveWaterValue.setCreateTime(new Date());
+                                receiveWaterValue.setDeviceName(String.valueOf(equipment.getId()));
+                                receiveWaterValueService.save(receiveWaterValue);
+                            }else {
+                                receiveWaterValue.setWaterDeep("10");
+                                receiveWaterValue.setCreateTime(new Date());
+                                receiveWaterValue.setDeviceName(String.valueOf(equipment.getId()));
+                                receiveWaterValueService.save(receiveWaterValue);
+                            }
+
+                        }
+                    }
+                }
+            }catch (Exception e){
+                System.out.println("");
+                continue;
+            }
+
+        }
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueFinalServiceImpl.java
new file mode 100644
index 0000000..f7fa835
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueFinalServiceImpl.java
@@ -0,0 +1,80 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveWaterValueFinalMapper;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal;
+import com.ruoyi.fuzhou.service.ReceiveWaterValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-04-25
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveWaterValueFinalServiceImpl extends ServiceImpl<ReceiveWaterValueFinalMapper, ReceiveWaterValueFinal> implements ReceiveWaterValueFinalService {
+    @Autowired
+    private ReceiveWaterValueFinalMapper receiveWaterValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveWaterValueFinal> listAll(){
+        return receiveWaterValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatch(List<ReceiveWaterValueFinal> waterValueFinals){
+        int i = 0;
+        for (ReceiveWaterValueFinal receiveWaterValueFinal : waterValueFinals){
+            QueryWrapper<ReceiveWaterValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveWaterValueFinal.getId());
+            if(!receiveWaterValueFinalMapper.exists(queryWrapper)){
+                receiveWaterValueFinalMapper.insert(receiveWaterValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveWaterValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveWaterValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveWaterValueFinal::getDeviceName, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveWaterValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveWaterValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveWaterValueFinal::getCreateTime);
+        return receiveWaterValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveWaterValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveWaterValueFinal receiveWaterValueFinal){
+        return receiveWaterValueFinalMapper.updateById(receiveWaterValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveWaterValueFinalMapper.selectCount(null);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueServiceImpl.java
new file mode 100644
index 0000000..9cc4ec8
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWaterValueServiceImpl.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.domain.ReceiveWaterValue;
+import com.ruoyi.fuzhou.mapper.ReceiveWaterValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveWaterValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 姘村疄鏃舵暟鎹� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-13
+ */
+@Service
+public class ReceiveWaterValueServiceImpl extends ServiceImpl<ReceiveWaterValueMapper, ReceiveWaterValue> implements ReceiveWaterValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherAnalyseServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherAnalyseServiceImpl.java
new file mode 100644
index 0000000..191fadb
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherAnalyseServiceImpl.java
@@ -0,0 +1,21 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherAnalyse;
+import com.ruoyi.fuzhou.mapper.ReceiveWeatherAnalyseMapper;
+import com.ruoyi.fuzhou.service.ReceiveWeatherAnalyseService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 姘旇薄璁惧鍒嗘瀽鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Service
+public class ReceiveWeatherAnalyseServiceImpl extends ServiceImpl<ReceiveWeatherAnalyseMapper, ReceiveWeatherAnalyse> implements ReceiveWeatherAnalyseService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherInfoServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherInfoServiceImpl.java
new file mode 100644
index 0000000..0a5e3e8
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherInfoServiceImpl.java
@@ -0,0 +1,82 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.mapper.ReceiveWeatherInfoMapper;
+import com.ruoyi.fuzhou.service.ReceiveWeatherInfoService;
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueService;
+import com.ruoyi.fuzhou.utils.ModbusWeatherServerUtils;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusOilServerUtils;
+import jakarta.annotation.Resource;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * <p>
+ * 姘旇薄鏁版嵁鎺ユ敹绠$悊 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Service
+public class ReceiveWeatherInfoServiceImpl extends ServiceImpl<ReceiveWeatherInfoMapper, ReceiveWeatherInfo> implements ReceiveWeatherInfoService {
+    @Resource
+    private RedisTemplate redisTemplate;
+
+    @Resource
+    private ReceiveWeatherValueService receiveWeatherValueService;
+
+    @Override
+    public void saveData(List<ReceiveWeatherInfo> list, DpEquipment info) {
+         JSONObject jsonObject = ModbusWeatherServerUtils.getValue(list.get(0).getIp(), list.get(0).getPort(), list);
+//        JSONObject jsonObject = ModbusWeatherServerUtils.getValueTest(list.get(0).getIp(), list.get(0).getPort(), list);
+        if (jsonObject != null && jsonObject.size() > 0) {
+            ReceiveWeatherValue receiveWeatherValue = JSON.toJavaObject(jsonObject, ReceiveWeatherValue.class);
+            receiveWeatherValue.setCreateTime(new Date());
+            receiveWeatherValue.setDeviceName(list.get(0).getDeviceName());
+//            if (Math.abs(Double.valueOf(receiveWeatherValue.getOilTimeFlow())) > 0) {
+//                redisTemplate.opsForValue().set("VALUE@" + receiveWeatherValue.getDeviceName(), receiveWeatherValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                receiveWeatherValueService.save(receiveWeatherValue);
+//            } else {
+//                Object obj = redisTemplate.opsForValue().get("VALUE@" + receiveOilValue.getDeviceName());
+//                if (obj == null) {
+//                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                    receiveWeatherValueService.save(receiveOilValue);
+//                } else if (!obj.toString().equals(receiveOilValue.getOilTimeFlow())) {
+//                    redisTemplate.opsForValue().set("VALUE@" + receiveOilValue.getDeviceName(), receiveOilValue.getOilTimeFlow(), 30, TimeUnit.MINUTES);
+//                    receiveWeatherValueService.save(receiveOilValue);
+//                }
+//            }
+            receiveWeatherValueService.save(receiveWeatherValue);
+        }
+        //鍒堕�爏ocket鏁版嵁
+//        JSONArray header = new JSONArray();
+//        list.forEach(item -> {
+//            JSONObject head = new JSONObject();
+//            head.put("param", item.getParam());
+//            head.put("paramCode", item.getParamCode());
+//            head.put("unit", item.getUnit());
+//            header.add(head);
+//        });
+//        ReceiveOilValue receiveOilValue = receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+//            or().eq(ReceiveOilValue::getDeviceName, list.get(0).getDeviceName()).orderByDesc(ReceiveOilValue::getCreateTime).last("limit 1");
+//        }});
+//        if (receiveOilValue != null) {
+//            JSONObject object = new JSONObject();
+//            object.put("header", header);
+//            object.put("body", JSONObject.parseObject(JSON.toJSONString(receiveOilValue)));
+//            object.put("info", JSONObject.parseObject(JSON.toJSONString(info)));
+//            object.put("status", "1");
+////            WebSocketOilServer.sendAllMessage(object.toJSONString());
+//        }
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueFinalServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueFinalServiceImpl.java
new file mode 100644
index 0000000..83eb158
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueFinalServiceImpl.java
@@ -0,0 +1,83 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.common.annotation.DataSource;
+import com.ruoyi.common.enums.DataSourceType;
+import com.ruoyi.fuzhou.domain.ReceiveCarValueFinal;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal;
+import com.ruoyi.fuzhou.domain.vo.ReceiveValueListVo;
+import com.ruoyi.fuzhou.mapper.ReceiveWeatherValueFinalMapper;
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueFinalService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Service
+@DataSource(value = DataSourceType.SLAVE)
+public class ReceiveWeatherValueFinalServiceImpl extends ServiceImpl<ReceiveWeatherValueFinalMapper, ReceiveWeatherValueFinal> implements ReceiveWeatherValueFinalService {
+
+    @Autowired
+    private ReceiveWeatherValueFinalMapper receiveWeatherValueFinalMapper;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<ReceiveWeatherValueFinal> listAll(){
+        return receiveWeatherValueFinalMapper.selectList(null);
+    }
+
+    //鎵归噺鎻掑叆
+    @Override
+    public Integer saveBatchNew(List<ReceiveWeatherValueFinal> carValueFinals){
+        int i = 0;
+        for (ReceiveWeatherValueFinal receiveCarValueFinal : carValueFinals){
+            QueryWrapper<ReceiveWeatherValueFinal> queryWrapper = new QueryWrapper<>();
+            queryWrapper.eq("ID",receiveCarValueFinal.getId());
+            if(!receiveWeatherValueFinalMapper.exists(queryWrapper)){
+                receiveWeatherValueFinalMapper.insert(receiveCarValueFinal);
+                i++;
+            }
+        }
+        return i;
+    }
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<ReceiveWeatherValueFinal> queryData(ReceiveValueListVo vo){
+        LambdaQueryWrapper<ReceiveWeatherValueFinal> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        lambdaQueryWrapper.eq(ReceiveWeatherValueFinal::getDeviceName, String.valueOf(vo.getId()))
+                .ge(vo.getStartTime() != null, ReceiveWeatherValueFinal::getCreateTime, vo.getStartTime())
+                .lt(vo.getEndTime() != null, ReceiveWeatherValueFinal::getCreateTime, vo.getEndTime())
+                .orderByDesc(ReceiveWeatherValueFinal::getCreateTime);
+        return receiveWeatherValueFinalMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public Integer deleteBatch(List<Long> ids){
+        return receiveWeatherValueFinalMapper.deleteBatchIds(ids);
+    }
+
+    //淇敼鏇存柊
+    @Override
+    public Integer updateDate(ReceiveWeatherValueFinal receiveWeatherValueFinal){
+        return receiveWeatherValueFinalMapper.updateById(receiveWeatherValueFinal);
+    }
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return receiveWeatherValueFinalMapper.selectCount(null);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueServiceImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueServiceImpl.java
new file mode 100644
index 0000000..17a0dfc
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/service/impl/ReceiveWeatherValueServiceImpl.java
@@ -0,0 +1,21 @@
+package com.ruoyi.fuzhou.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+
+import com.ruoyi.fuzhou.domain.ReceiveWeatherValue;
+import com.ruoyi.fuzhou.mapper.ReceiveWeatherValueMapper;
+import com.ruoyi.fuzhou.service.ReceiveWeatherValueService;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 姘旇薄璁惧瀹炴椂鏁版嵁 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-20
+ */
+@Service
+public class ReceiveWeatherValueServiceImpl extends ServiceImpl<ReceiveWeatherValueMapper, ReceiveWeatherValue> implements ReceiveWeatherValueService {
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/AnalyseUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/AnalyseUtils.java
new file mode 100644
index 0000000..bcb830e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/AnalyseUtils.java
@@ -0,0 +1,74 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.common.utils.StringUtils;
+
+import java.util.List;
+
+/**
+ * 鏁版嵁娓呮礂宸ュ叿
+ */
+public class AnalyseUtils {
+    //[{"param":"test","rule":"<","value":0.3}]
+    public static <T> JSONArray listToJSONArray(List<T> list, String rule) {
+        JSONArray ruleArray = JSONArray.parseArray(rule);
+        JSONArray result = new JSONArray();
+        JSONArray array = JSONArray.parseArray(JSONArray.toJSONString(list));
+        if (ruleArray.size() == 0) {
+            return array;
+        }
+        for (int i = 0; i < array.size(); i++) {
+            JSONObject object = array.getJSONObject(i);
+            boolean success = true;
+            for (int m = 0; m < ruleArray.size(); m++) {
+                JSONObject jsonObject = ruleArray.getJSONObject(m);
+                String key = jsonObject.getString("param");
+                String sign = jsonObject.getString("rule");
+                Double value = jsonObject.getDouble("value");
+                if (key == null) {
+                    throw new RuntimeException("鍙傛暟涓嶈兘涓虹┖锛�");
+                }
+                if (sign == null) {
+                    throw new RuntimeException("绗﹀彿涓嶈兘涓虹┖锛�");
+                }
+                if (value == null) {
+                    throw new RuntimeException("鍙傛暟涓嶈兘涓虹┖锛�");
+                }
+                //瑙勫垯鍒ゆ柇
+                String objectValue = object.getString(key);
+                if (StringUtils.isNotEmpty(objectValue)) {
+                    try {
+                        if ("<".equals(sign)) {
+                            success = Double.valueOf(objectValue) < value;
+                        } else if ("<=".equals(sign)) {
+                            success = Double.valueOf(objectValue) <= value;
+                        } else if (">=".equals(sign)) {
+                            success = Double.valueOf(objectValue) >= value;
+                        } else if (">".equals(sign)) {
+                            success = Double.valueOf(objectValue) > value;
+                        } else if ("!=".equals(sign)) {
+                            success = !Double.valueOf(objectValue).equals(value);
+                        } else if ("=".equals(sign)) {
+                            success = Double.valueOf(objectValue).equals(value);
+                        } else {
+                            success = false;
+                        }
+                    }catch (Exception e){
+                        success = false;
+                        e.printStackTrace();
+                    }
+                } else {
+                    success = false;
+                }
+                if (!success) {
+                    break;
+                }
+            }
+            if (success) {
+                result.add(object);
+            }
+        }
+        return result;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jUtils.java
new file mode 100644
index 0000000..76ebd4a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jUtils.java
@@ -0,0 +1,154 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+import com.serotonin.modbus4j.*;
+import com.serotonin.modbus4j.code.DataType;
+import com.serotonin.modbus4j.exception.*;
+import com.serotonin.modbus4j.ip.IpParameters;
+import com.serotonin.modbus4j.locator.BaseLocator;
+import com.serotonin.modbus4j.msg.*;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class Modbus4jUtils {
+    static ModbusFactory modbusFactory;
+
+    static {
+        modbusFactory = new ModbusFactory();
+    }
+
+    public static ModbusMaster getMaster(String ip, Integer port) throws ModbusInitException {
+        IpParameters paras = new IpParameters();
+        paras.setHost(ip);
+        paras.setPort(port);
+
+        ModbusMaster master = modbusFactory.createTcpMaster(paras, false);
+        master.init();
+
+        return master;
+    }
+
+    /**
+     * 璇诲彇[01 coil status 0x]绫诲瀷 寮�鍏虫暟鎹�
+     */
+    public static Boolean readCoilStatus(ModbusMaster master, int slaveId, int offset) throws ModbusTransportException, ErrorResponseException {
+        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
+
+        return master.getValue(loc);
+    }
+
+    /**
+     * 璇诲彇[02 input status 1x]绫诲瀷 寮�鍏虫暟鎹�
+     */
+    public static Boolean reaInputStatus(ModbusMaster master, int slaveId, int offset) throws ModbusTransportException, ErrorResponseException {
+        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
+
+        return master.getValue(loc);
+    }
+
+    /**
+     * 璇诲彇[03 holding register 2x]妯℃嫙閲忔暟鎹�
+     */
+    public static Number readHoldingRegister(ModbusMaster master, int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException {
+        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
+
+        return master.getValue(loc);
+    }
+
+    /**
+     * 璇诲彇[04 input register 3x]妯℃嫙閲忔暟鎹�
+     */
+    public static Number readInputRegister(ModbusMaster master, int slaveId, int offset, int dataType) throws ModbusTransportException, ErrorResponseException {
+        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
+
+        return master.getValue(loc);
+    }
+
+    /**
+     * 鎵归噺璇诲彇
+     */
+    public static List<Integer> batchRead(ModbusMaster master, int count, int slaveId, int dataType) throws ModbusTransportException, ErrorResponseException {
+        BatchRead<Integer> batch = new BatchRead<>();
+
+        for (int i = 0; i < count; i++) {
+            batch.addLocator(i, BaseLocator.holdingRegister(slaveId, i, dataType));
+        }
+        batch.setContiguousRequests(false);
+
+        BatchResults<Integer> results = master.send(batch);
+        List<Integer> list = new ArrayList();
+        for (int i = 0; i < count; i++) {
+            list.add(results.getIntValue(i));
+        }
+
+        return list;
+    }
+
+    /**
+     * 鍐橻01 coil status 0x]涓�涓�
+     */
+    public static Boolean writeCoil(ModbusMaster master, int slaveId, int offset, boolean value) throws ModbusTransportException, ErrorResponseException {
+        WriteCoilRequest request = new WriteCoilRequest(slaveId, offset, value);
+        WriteCoilResponse response = (WriteCoilResponse) master.send(request);
+
+        return !response.isException();
+    }
+
+    /**
+     * 鍐橻01 coil status 0x]澶氫釜
+     */
+    public static Boolean writeCoils(ModbusMaster master, int slaveId, int startOffset, boolean[] values) throws ModbusTransportException, ErrorResponseException {
+        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, values);
+        WriteCoilsResponse response = (WriteCoilsResponse) master.send(request);
+
+        return !response.isException();
+    }
+
+    /**
+     * 鍐橻03 holding register 4x]涓�涓�
+     */
+    public static Boolean writeRegister(ModbusMaster master, int slaveId, int offset, short value) throws ModbusTransportException, ErrorResponseException {
+        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
+        WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
+
+        return !response.isException();
+    }
+
+    /**
+     * 鍐橻03 holding register 4x]澶氫釜
+     */
+    public static Boolean writeRegisters(ModbusMaster master, int slaveId, int startOffset, short[] values) throws ModbusTransportException, ErrorResponseException {
+        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, values);
+        WriteRegistersResponse response = (WriteRegistersResponse) master.send(request);
+
+        return !response.isException();
+    }
+
+    /**
+     * 鍐欏叆鏁板瓧绫诲瀷鐨勬ā鎷熼噺
+     */
+    public static Boolean writeHoldingRegister(ModbusMaster master, int slaveId, int offset, Number value, int dataType) throws ModbusTransportException, ErrorResponseException {
+        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
+        master.setValue(locator, value);
+
+        return true;
+    }
+
+    public static boolean getYdkfmStatus(ReceiveModuleInfo rmi) throws Exception {
+        String ip = null == rmi.getIp() ? "localhost" : rmi.getIp();
+        ModbusMaster master = getMaster(ip, rmi.getPort());
+
+        Number val = readHoldingRegister(master, 1, 7, DataType.TWO_BYTE_INT_SIGNED);
+
+        return val.intValue() > 1;
+    }
+
+    public static boolean ctrlYdkfm(ReceiveModuleInfo rmi, Boolean flag) throws Exception {
+        String ip = null == rmi.getIp() ? "localhost" : rmi.getIp();
+        ModbusMaster master = getMaster(ip, rmi.getPort());
+
+        short val = (short) (flag ? 2 : 1);
+        return writeRegister(master, 1, 7, val);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jWriteUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jWriteUtils.java
new file mode 100644
index 0000000..1fff1f5
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/Modbus4jWriteUtils.java
@@ -0,0 +1,173 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.exception.ErrorResponseException;
+import com.serotonin.modbus4j.exception.ModbusInitException;
+import com.serotonin.modbus4j.exception.ModbusTransportException;
+import com.serotonin.modbus4j.ip.IpParameters;
+import com.serotonin.modbus4j.locator.BaseLocator;
+import com.serotonin.modbus4j.msg.*;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+/**
+ * modbus4j鍐欏叆鏁版嵁
+ *
+ * @author zhangyy
+ */
+public class Modbus4jWriteUtils {
+
+    static Log log = LogFactory.getLog(Modbus4jWriteUtils.class);
+    /**
+     * 宸ュ巶銆�
+     */
+    static ModbusFactory modbusFactory;
+
+    static {
+        if (modbusFactory == null) {
+            modbusFactory = new ModbusFactory();
+        }
+    }
+
+    /**
+     * 鑾峰彇tcpMaster
+     *
+     * @return
+     * @throws ModbusInitException
+     */
+    public static ModbusMaster getMaster(String ip) throws ModbusInitException {
+        IpParameters params = new IpParameters();
+        params.setHost(ip);
+        params.setPort(20108);
+//        params.setHost("10.2.73.22");
+//        params.setPort(502);
+        ModbusMaster tcpMaster = modbusFactory.createTcpMaster(params, false);
+        tcpMaster.init();
+        return tcpMaster;
+    }
+
+    /**
+     * 鍐� [01 Coil Status(0x)]鍐欎竴涓� function ID = 5
+     *
+     * @param slaveId     slave鐨処D
+     * @param writeOffset 浣嶇疆
+     * @param writeValue  鍊�
+     * @return 鏄惁鍐欏叆鎴愬姛
+     * @throws ModbusTransportException
+     * @throws ModbusInitException
+     */
+    public static boolean writeCoil(String ip, int slaveId, int writeOffset, boolean writeValue)
+            throws ModbusTransportException, ModbusInitException {
+        // 鑾峰彇master
+        ModbusMaster tcpMaster = getMaster(ip);
+        // 鍒涘缓璇锋眰
+        WriteCoilRequest request = new WriteCoilRequest(slaveId, writeOffset, writeValue);
+        // 鍙戦�佽姹傚苟鑾峰彇鍝嶅簲瀵硅薄
+        WriteCoilResponse response = (WriteCoilResponse) tcpMaster.send(request);
+        if (response.isException()) {
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * 鍐橻01 Coil Status(0x)] 鍐欏涓� function ID = 15
+     *
+     * @param slaveId     slaveId
+     * @param startOffset 寮�濮嬩綅缃�
+     * @param bdata       鍐欏叆鐨勬暟鎹�
+     * @return 鏄惁鍐欏叆鎴愬姛
+     * @throws ModbusTransportException
+     * @throws ModbusInitException
+     */
+    public static boolean writeCoils(String ip, int slaveId, int startOffset, boolean[] bdata)
+            throws ModbusTransportException, ModbusInitException {
+        // 鑾峰彇master
+        ModbusMaster tcpMaster = getMaster(ip);
+        // 鍒涘缓璇锋眰
+        WriteCoilsRequest request = new WriteCoilsRequest(slaveId, startOffset, bdata);
+        // 鍙戦�佽姹傚苟鑾峰彇鍝嶅簲瀵硅薄
+        WriteCoilsResponse response = (WriteCoilsResponse) tcpMaster.send(request);
+        if (response.isException()) {
+            return false;
+        } else {
+            return true;
+        }
+
+    }
+
+    /***
+     * 鍐橻03 Holding Register(4x)] 鍐欎竴涓� function ID = 6
+     *
+     * @param slaveId
+     * @param writeOffset
+     * @param writeValue
+     * @return
+     * @throws ModbusTransportException
+     * @throws ModbusInitException
+     */
+    public static boolean writeRegister(String ip, int slaveId, int writeOffset, short writeValue)
+            throws ModbusTransportException, ModbusInitException {
+        // 鑾峰彇master
+        ModbusMaster tcpMaster = getMaster(ip);
+        // 鍒涘缓璇锋眰瀵硅薄
+        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, writeOffset, writeValue);
+        WriteRegisterResponse response = (WriteRegisterResponse) tcpMaster.send(request);
+        if (response.isException()) {
+            log.error(response.getExceptionMessage());
+            return false;
+        } else {
+            return true;
+        }
+
+    }
+
+    /**
+     * 鍐欏叆[03 Holding Register(4x)]鍐欏涓� function ID=16
+     *
+     * @param slaveId     modbus鐨剆laveID
+     * @param startOffset 璧峰浣嶇疆鍋忕Щ閲忓��
+     * @param sdata       鍐欏叆鐨勬暟鎹�
+     * @return 杩斿洖鏄惁鍐欏叆鎴愬姛
+     * @throws ModbusTransportException
+     * @throws ModbusInitException
+     */
+    public static boolean writeRegisters(String ip, int slaveId, int startOffset, short[] sdata)
+            throws ModbusTransportException, ModbusInitException {
+        // 鑾峰彇master
+        ModbusMaster tcpMaster = getMaster(ip);
+        // 鍒涘缓璇锋眰瀵硅薄
+        WriteRegistersRequest request = new WriteRegistersRequest(slaveId, startOffset, sdata);
+        // 鍙戦�佽姹傚苟鑾峰彇鍝嶅簲瀵硅薄
+        ModbusResponse response = tcpMaster.send(request);
+        if (response.isException()) {
+            log.error(response.getExceptionMessage());
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * 鍐欏叆鏁板瓧绫诲瀷鐨勬ā鎷熼噺锛堝:鍐欏叆Float绫诲瀷鐨勬ā鎷熼噺銆丏ouble绫诲瀷妯℃嫙閲忋�佹暣鏁扮被鍨婼hort銆両nteger銆丩ong锛�
+     *
+     * @param slaveId
+     * @param offset
+     * @param value         鍐欏叆鍊�,Number鐨勫瓙绫�,渚嬪鍐欏叆Float娴偣绫诲瀷,Double鍙岀簿搴︾被鍨�,浠ュ強鏁村瀷short,int,long
+     * @param registerCount ,com.serotonin.modbus4j.code.DataType
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static void writeHoldingRegister(String ip, int slaveId, int offset, Number value, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        // 鑾峰彇master
+        ModbusMaster tcpMaster = getMaster(ip);
+        // 绫诲瀷
+        BaseLocator<Number> locator = BaseLocator.holdingRegister(slaveId, offset, dataType);
+        tcpMaster.setValue(locator, value);
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadRtuUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadRtuUtils.java
new file mode 100644
index 0000000..a8a3c41
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadRtuUtils.java
@@ -0,0 +1,163 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.ruoyi.fuzhou.utils.rtu.SerialPortWrapperImpl;
+import com.serotonin.modbus4j.BatchRead;
+import com.serotonin.modbus4j.BatchResults;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.code.DataType;
+import com.serotonin.modbus4j.exception.ErrorResponseException;
+import com.serotonin.modbus4j.exception.ModbusInitException;
+import com.serotonin.modbus4j.exception.ModbusTransportException;
+import com.serotonin.modbus4j.ip.IpParameters;
+import com.serotonin.modbus4j.locator.BaseLocator;
+import gnu.io.SerialPort;
+
+/**
+ * modbus閫氳宸ュ叿绫�,閲囩敤modbus4j瀹炵幇
+ *
+ * @author zhangyy
+ */
+public class ModbusReadRtuUtils {
+    /**
+     * 宸ュ巶銆�
+     */
+    static ModbusFactory modbusFactory;
+
+    static {
+        if (modbusFactory == null) {
+            modbusFactory = new ModbusFactory();
+        }
+    }
+
+    /**
+     * 鑾峰彇master
+     *
+     * @return
+     * @throws ModbusInitException
+     */
+    public static ModbusMaster getRtuMaster(String ip) throws ModbusInitException {
+        //RTU 鍗忚
+        // 璁剧疆涓插彛鍙傛暟锛屼覆鍙f槸COM1锛屾尝鐗圭巼鏄�9600
+        SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM1", 9600,
+                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
+        ModbusMaster master = modbusFactory.createRtuMaster(wrapper);
+        master.setTimeout(2000);
+        master.init();
+        return master;
+    }
+
+    /**
+     * 璇诲彇[01 Coil Status 0x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId slaveId
+     * @param offset  浣嶇疆
+     * @return 璇诲彇鍊�
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Boolean readCoilStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
+        Boolean value = getRtuMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[02 Input Status 1x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId
+     * @param offset
+     * @return
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static Boolean readInputStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
+        Boolean value = getRtuMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[03 Holding Register绫诲瀷 2x]妯℃嫙閲忔暟鎹�
+     *
+     * @param ip       ip
+     * @param slaveId  slave Id
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readHoldingRegister(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
+        Number value = getRtuMaster(ip).getValue(loc);
+        return value;
+    }
+
+    public static Number readHoldingRegisterTest(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<?> locator = BaseLocator.createLocator(slaveId, 1, 4001, dataType, 8, 22);
+        Object value1 = getRtuMaster(ip).getValue(locator);
+        //Number value = (Number) getMaster().getValue(locator);
+        return 1;
+    }
+
+    /**
+     * 璇诲彇[04 Input Registers 3x]绫诲瀷 妯℃嫙閲忔暟鎹�
+     *
+     * @param slaveId  slaveId
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return 杩斿洖缁撴灉
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readInputRegisters(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        // 04 Input Registers绫诲瀷鏁版嵁璇诲彇
+        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
+        Number value = getRtuMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 鎵归噺璇诲彇浣跨敤鏂规硶
+     *
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static void batchRead(String ip) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BatchRead<Integer> batch = new BatchRead<Integer>();
+        batch.addLocator(0, BaseLocator.holdingRegister(1, 1535, DataType.FOUR_BYTE_FLOAT));
+        //杩炴帴
+        ModbusMaster master = getRtuMaster(ip);
+        batch.setContiguousRequests(false);
+        BatchResults<Integer> results = master.send(batch);
+        System.out.println("楂樺帇杩涚嚎Uab鐢靛帇閲囬泦锛�" + results.getValue(0));
+    }
+
+    /**
+     * 娴嬭瘯
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        try {
+            //todo 鍗曚釜璇诲彇
+            getRtuMaster("192.168.0.7");
+            //楂樺帇杩涚嚎Ubc鐢靛帇閲囬泦-鍥涜垗浜斿叆淇濈暀涓や綅
+            Number number = readHoldingRegister("192.168.0.7", 1, 1587, DataType.FOUR_BYTE_FLOAT);
+            System.out.println("楂樺帇杩涚嚎Ubc鐢靛帇閲囬泦=" + number.doubleValue());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadTcpUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadTcpUtils.java
new file mode 100644
index 0000000..a6a619b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadTcpUtils.java
@@ -0,0 +1,176 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.serotonin.modbus4j.BatchRead;
+import com.serotonin.modbus4j.BatchResults;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.code.DataType;
+import com.serotonin.modbus4j.exception.ErrorResponseException;
+import com.serotonin.modbus4j.exception.ModbusInitException;
+import com.serotonin.modbus4j.exception.ModbusTransportException;
+import com.serotonin.modbus4j.ip.IpParameters;
+import com.serotonin.modbus4j.locator.BaseLocator;
+import com.serotonin.modbus4j.msg.ModbusResponse;
+import com.serotonin.modbus4j.msg.ReadCoilsRequest;
+import com.serotonin.modbus4j.msg.ReadCoilsResponse;
+import com.serotonin.modbus4j.msg.WriteRegistersRequest;
+
+/**
+ * modbus閫氳宸ュ叿绫�,閲囩敤modbus4j瀹炵幇
+ *
+ * @author zhangyy
+ */
+public class ModbusReadTcpUtils {
+    /**
+     * 宸ュ巶銆�
+     */
+    static ModbusFactory modbusFactory;
+
+    static {
+        if (modbusFactory == null) {
+            modbusFactory = new ModbusFactory();
+        }
+    }
+
+    /**
+     * 鑾峰彇master
+     *
+     * @return
+     * @throws ModbusInitException
+     */
+    public static ModbusMaster getTcpMaster(String ip, int port) throws ModbusInitException {
+        IpParameters params = new IpParameters();
+        /**
+         * 璁剧疆ip绔彛
+         */
+        params.setHost(ip);
+        params.setPort(port);
+        params.setEncapsulated(true);
+        System.out.println(params.getHost() + ":" + params.getPort());
+        // TCP 鍗忚
+        ModbusMaster master = modbusFactory.createTcpMaster(params, false);
+        master.setTimeout(5000);
+        master.setRetries(3);
+        master.init();
+        return master;
+    }
+
+    /**
+     * 璇诲彇[01 Coil Status 0x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId slaveId
+     * @param offset  浣嶇疆
+     * @return 璇诲彇鍊�
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Boolean readCoilStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
+        Boolean value = getTcpMaster(ip, 502).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[02 Input Status 1x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId
+     * @param offset
+     * @return
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static Boolean readInputStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
+        Boolean value = getTcpMaster(ip, 502).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[03 Holding Register绫诲瀷 2x]妯℃嫙閲忔暟鎹�
+     *
+     * @param ip       ip
+     * @param slaveId  slave Id
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readHoldingRegister(String ip, int slaveId, int offset, int dataType, int port)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
+        Number value = getTcpMaster(ip, port).getValue(loc);
+        return value;
+    }
+
+    public static Number readHoldingRegisterTest(String ip, int slaveId, int offset, int dataType, int port)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<?> locator = BaseLocator.createLocator(slaveId, 1, 4001, dataType, 8, 22);
+        Object value1 = getTcpMaster(ip, port).getValue(locator);
+        //Number value = (Number) getMaster().getValue(locator);
+        return 1;
+    }
+
+    /**
+     * 璇诲彇[04 Input Registers 3x]绫诲瀷 妯℃嫙閲忔暟鎹�
+     *
+     * @param slaveId  slaveId
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return 杩斿洖缁撴灉
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readInputRegisters(String ip, int slaveId, int offset, int dataType, int port)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        // 04 Input Registers绫诲瀷鏁版嵁璇诲彇
+        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
+        Number value = getTcpMaster(ip, port).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 鎵归噺璇诲彇浣跨敤鏂规硶
+     *
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static void batchRead(String ip, int port) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BatchRead<Integer> batch = new BatchRead<Integer>();
+        batch.addLocator(0, BaseLocator.holdingRegister(1, 1535, DataType.FOUR_BYTE_FLOAT));
+        //杩炴帴
+        ModbusMaster master = getTcpMaster(ip, port);
+        batch.setContiguousRequests(false);
+        BatchResults<Integer> results = master.send(batch);
+        System.out.println("楂樺帇杩涚嚎Uab鐢靛帇閲囬泦锛�" + results.getValue(0));
+    }
+
+    /**
+     * 娴嬭瘯
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        try {
+            //todo 鍗曚釜璇诲彇
+            ModbusMaster master = getTcpMaster("192.168.0.7", 23);
+            // 浠庢満鍦板潃1锛岃捣濮嬪湴鍧�0锛岃鍙�10涓嚎鍦�
+            ReadCoilsRequest request = new ReadCoilsRequest(1, 1, 10);
+            ReadCoilsResponse response = (ReadCoilsResponse) master.send(request);
+            String s = response.toString();
+            System.out.println(s);
+            master.destroy();
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+
+}
\ No newline at end of file
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadUdpUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadUdpUtils.java
new file mode 100644
index 0000000..36b4816
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusReadUdpUtils.java
@@ -0,0 +1,167 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.serotonin.modbus4j.BatchRead;
+import com.serotonin.modbus4j.BatchResults;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.code.DataType;
+import com.serotonin.modbus4j.exception.ErrorResponseException;
+import com.serotonin.modbus4j.exception.ModbusInitException;
+import com.serotonin.modbus4j.exception.ModbusTransportException;
+import com.serotonin.modbus4j.ip.IpParameters;
+import com.serotonin.modbus4j.locator.BaseLocator;
+
+/**
+ * modbus閫氳宸ュ叿绫�,閲囩敤modbus4j瀹炵幇
+ *
+ * @author zhangyy
+ */
+public class ModbusReadUdpUtils {
+    /**
+     * 宸ュ巶銆�
+     */
+    static ModbusFactory modbusFactory;
+
+    static {
+        if (modbusFactory == null) {
+            modbusFactory = new ModbusFactory();
+        }
+    }
+
+    /**
+     * 鑾峰彇master
+     *
+     * @return
+     * @throws ModbusInitException
+     */
+    public static ModbusMaster getUdpMaster(String ip) throws ModbusInitException {
+        IpParameters params = new IpParameters();
+        /**
+         * 璁剧疆ip绔彛
+         */
+        params.setHost(ip);
+        params.setPort(502);
+        /**
+         * 璁剧疆鍗忚
+         */
+        //UDP 鍗忚
+        ModbusMaster master = modbusFactory.createUdpMaster(params);
+        master.setTimeout(2000);
+        master.init();
+        return master;
+    }
+
+    /**
+     * 璇诲彇[01 Coil Status 0x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId slaveId
+     * @param offset  浣嶇疆
+     * @return 璇诲彇鍊�
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Boolean readCoilStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.coilStatus(slaveId, offset);
+        Boolean value = getUdpMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[02 Input Status 1x]绫诲瀷 寮�鍏虫暟鎹�
+     *
+     * @param slaveId
+     * @param offset
+     * @return
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static Boolean readInputStatus(String ip, int slaveId, int offset)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Boolean> loc = BaseLocator.inputStatus(slaveId, offset);
+        Boolean value = getUdpMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 璇诲彇[03 Holding Register绫诲瀷 2x]妯℃嫙閲忔暟鎹�
+     *
+     * @param ip       ip
+     * @param slaveId  slave Id
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readHoldingRegister(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<Number> loc = BaseLocator.holdingRegister(slaveId, offset, dataType);
+        Number value = getUdpMaster(ip).getValue(loc);
+        return value;
+    }
+
+    public static Number readHoldingRegisterTest(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BaseLocator<?> locator = BaseLocator.createLocator(slaveId, 1, 4001, dataType, 8, 22);
+        Object value1 = getUdpMaster(ip).getValue(locator);
+        //Number value = (Number) getMaster().getValue(locator);
+        return 1;
+    }
+
+    /**
+     * 璇诲彇[04 Input Registers 3x]绫诲瀷 妯℃嫙閲忔暟鎹�
+     *
+     * @param slaveId  slaveId
+     * @param offset   浣嶇疆
+     * @param dataType 鏁版嵁绫诲瀷,鏉ヨ嚜com.serotonin.modbus4j.code.DataType
+     * @return 杩斿洖缁撴灉
+     * @throws ModbusTransportException 寮傚父
+     * @throws ErrorResponseException   寮傚父
+     * @throws ModbusInitException      寮傚父
+     */
+    public static Number readInputRegisters(String ip, int slaveId, int offset, int dataType)
+            throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        // 04 Input Registers绫诲瀷鏁版嵁璇诲彇
+        BaseLocator<Number> loc = BaseLocator.inputRegister(slaveId, offset, dataType);
+        Number value = getUdpMaster(ip).getValue(loc);
+        return value;
+    }
+
+    /**
+     * 鎵归噺璇诲彇浣跨敤鏂规硶
+     *
+     * @throws ModbusTransportException
+     * @throws ErrorResponseException
+     * @throws ModbusInitException
+     */
+    public static void batchRead(String ip) throws ModbusTransportException, ErrorResponseException, ModbusInitException {
+        BatchRead<Integer> batch = new BatchRead<Integer>();
+        batch.addLocator(0, BaseLocator.holdingRegister(1, 1535, DataType.FOUR_BYTE_FLOAT));
+        //杩炴帴
+        ModbusMaster master = getUdpMaster(ip);
+        batch.setContiguousRequests(false);
+        BatchResults<Integer> results = master.send(batch);
+        System.out.println("楂樺帇杩涚嚎Uab鐢靛帇閲囬泦锛�" + results.getValue(0));
+    }
+
+    /**
+     * 娴嬭瘯
+     *
+     * @param args
+     */
+    public static void main(String[] args) {
+        try {
+            //todo 鍗曚釜璇诲彇
+            getUdpMaster("192.168.0.210");
+            //楂樺帇杩涚嚎Ubc鐢靛帇閲囬泦-鍥涜垗浜斿叆淇濈暀涓や綅
+            Number number = readHoldingRegister("192.168.0.210", 1, 1587, DataType.FOUR_BYTE_FLOAT);
+            System.out.println("楂樺帇杩涚嚎Ubc鐢靛帇閲囬泦=" + number.doubleValue());
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusSlmServerUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusSlmServerUtils.java
new file mode 100644
index 0000000..0d083b6
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusSlmServerUtils.java
@@ -0,0 +1,550 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.domain.ReceiveSlmInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserLittleUtil;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+public class ModbusSlmServerUtils {
+    public static void main(String[] args) {
+//
+//        //璐ㄩ噺娴侀噺
+//String value = getValue("0.0.0.0", 8140, (byte) 0x05, (byte) 0x04, 167, 0x0002,  1);
+////        //鍒╁拰娌硅澶�
+////        String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 3, 13, 2, 12);
+//        System.out.println(value);
+
+        String dataStr="{\n" +
+                " \"LA\" : \n" +
+                " {\n" +
+                "  \"x\" : \"122.145105\",\n" +
+                "  \"y\" : \"29.947085\"\n" +
+                " },\n" +
+                " \"LB\" :\n" +
+                " {\n" +
+                "  \"x\" : \"122.144408\",\n" +
+                "  \"y\" : \"29.947062\"\n" +
+                " },\n" +
+                " \"POS\" : \n" +
+                " {\n" +
+                "  \"x\" : \"0.000000\",\n" +
+                "  \"y\" : \"0.000000\"\n" +
+                " },\n" +
+                " \"aiddata\" : \n" +
+                " {\n" +
+                "  \"ROT\" : \"0\",\n" +
+                "  \"SOG\" : \"0\",\n" +
+                "  \"aalarm\" : \"Er\",\n" +
+                "  \"adis\" : \"Er\",\n" +
+                "  \"angle\" : \"Er\",\n" +
+                "  \"anglealarm\" : \"Er\",\t\n" +
+                "  \"aspeed\" : \"Er\",\n" +
+                "  \"balarm\" : \"Er\",\n" +
+                "  \"bdis\" : \"Er\",\n" +
+                "  \"bspeed\" : \"Er\",\n" +
+                "  \"direction\" : \"1\",\n" +
+                "  \"flowdirection\" : \"Na\",\n" +
+                "  \"flowspeed\" : \"Na\",\t\n" +
+                "  \"humidity\" : \"98.00\",\n" +
+                "  \"airpressure\":\"1009\",\n" +
+                "  \"status\" : \"0\", \n" +
+                "  \"temperature\" : \"23.10\",\n" +
+                "  \"tidelevel\" : \"Na\",\n" +
+                "  \"visibility\" : \"20000.00\",\n" +
+                "  \"waveheight\" : \"Na\",\n" +
+                "  \"windirection\" : \"888.00\",\n" +
+                "  \"windpower\" : \"16.00\",\n" +
+                "  \"windspeed\" : \"888.00\"\n" +
+                " },\n" +
+                "\"berthname\":\"娉婁綅鍚嶇О\",\n" +
+                "\"boatname\":\"鑸硅埗鍚嶇О\",\n" +
+                " \"mmsi\" : \"\",\n" +
+                " \"timestamp\" : \"1621924763\"\n" +
+                "}";
+
+
+
+
+        System.out.println("1111");
+
+    }
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getValue(String ip, int port, List<ReceiveSlmInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 婵�鍏夐浄杈炬湇鍔$宸插惎鍔紝姝e湪鐩戝惉 " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 婵�鍏夐浄杈惧鎴风宸茶繛鎺�: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                ReceiveSlmInfo info=list.get(0);
+
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    int bytesRead = inputStream.read(response);
+
+                    if (bytesRead == -1) {
+                        System.out.println("鉂� 鏈敹鍒版縺鍏夐浄杈捐澶囧搷搴�");
+                        serverSocket.close();
+                        return jsonObject;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = new String(responseData);
+                    System.out.println("馃摜 鏀跺埌婵�鍏夐浄杈捐澶囧搷搴�: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (resultData.length()< 30) {
+                        System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + resultData.length() + " 瀛楄妭");
+
+                    }
+
+                    String dataStr=resultData;
+
+
+                    JSONObject obj=JSONObject.parseObject(dataStr);
+                    if(obj.getString("berthname")!=null){
+                        jsonObject.put("berthname", obj.getString("berthname"));
+                        System.out.println("鈿狅笍 婵�鍏夐浄杈綽erthname瀛楁鍊�: " + obj.getString("berthname"));
+                    }
+                    if(obj.getString("boatname")!=null){
+                        jsonObject.put("boatname", obj.getString("boatname"));
+                        System.out.println("鈿狅笍 婵�鍏夐浄杈綽oatname瀛楁鍊�: " + obj.getString("boatname"));
+                    }
+
+                    JSONObject aiddataObj=obj.getJSONObject("aiddata");
+                    if(aiddataObj!=null){
+                        if(aiddataObj.getString("status")!=null){
+                            jsonObject.put("status", aiddataObj.getString("status"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈緎tatus瀛楁鍊�: " + aiddataObj.getString("status"));
+                        }
+                        if(aiddataObj.getString("adis")!=null){
+                            jsonObject.put("adis", aiddataObj.getString("adis"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綼dis瀛楁鍊�: " + aiddataObj.getString("adis"));
+                        }
+                        if(aiddataObj.getString("bdis")!=null){
+                            jsonObject.put("bdis", aiddataObj.getString("bdis"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綽dis瀛楁鍊�: " + aiddataObj.getString("bdis"));
+                        }
+                        if(aiddataObj.getString("aspeed")!=null){
+                            jsonObject.put("aspeed", aiddataObj.getString("aspeed"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綼speed瀛楁鍊�: " + aiddataObj.getString("aspeed"));
+                        }
+                        if(aiddataObj.getString("bspeed")!=null){
+                            jsonObject.put("bspeed", aiddataObj.getString("bspeed"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綽speed瀛楁鍊�: " + aiddataObj.getString("bspeed"));
+                        }
+                        if(aiddataObj.getString("aalarm")!=null){
+                            jsonObject.put("aalarm", aiddataObj.getString("aalarm"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綼alarm瀛楁鍊�: " + aiddataObj.getString("aalarm"));
+                        }
+                        if(aiddataObj.getString("balarm")!=null){
+                            jsonObject.put("balarm", aiddataObj.getString("balarm"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈綽alarm瀛楁鍊�: " + aiddataObj.getString("balarm"));
+                        }
+                        if(aiddataObj.getString("status")!=null){
+                            jsonObject.put("status", aiddataObj.getString("status"));
+                            System.out.println("鈿狅笍 婵�鍏夐浄杈緎tatus瀛楁鍊�: " + aiddataObj.getString("status"));
+                        }
+
+                    }
+
+                serverSocket.close();
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鈿狅笍 婵�鍏夐浄杈惧鎴风寮傚父鏂紑: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("婵�鍏夐浄杈捐澶囦笉鍦ㄧ嚎" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 婵�鍏夐浄杈炬湇鍔$鍏抽棴澶辫触: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 婵�鍏夐浄杈炬湇鍔$鍚姩澶辫触: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+
+    public static JSONObject getValueTest(String ip, int port, List<ReceiveWeatherInfo> list) {
+        JSONObject jsonObject = new JSONObject();
+        ReceiveWeatherInfo info=list.get(0);
+        // 鏋勯�犺姹傚抚
+        ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+        if (info.getDeviceAddress() != 0) {
+            requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+        }
+        if (info.getFunctionCode() != 0) {
+            requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+        }
+
+            requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+
+
+            requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+
+        // 璁$畻CRC鏍¢獙鐮�
+        byte[] requestData = requestBuffer.array();
+        String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+        int decimal = Integer.parseInt(hex, 16);
+        requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+        // 鍙戦�佽姹傚抚
+
+        System.out.println("馃摛 宸插彂閫佹縺鍏夐浄杈� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+        // 鎺ユ敹璁惧鍝嶅簲
+        byte[] response = new byte[1024];
+
+
+//        int bytesRead = inputStream.read(response);
+
+
+//        int bytesRead = Integer.parseInt(res, 16);
+//        if (bytesRead == -1) {
+//            System.out.println("鉂� 鏈敹鍒版縺鍏夐浄杈捐澶囧搷搴�");
+//
+//        }
+////         鎵撳嵃鍝嶅簲鏁版嵁
+//        byte[] responseData = new byte[bytesRead];
+//        System.arraycopy(response, 0, responseData, 0, bytesRead);
+//        String resultData = bytesToHex(responseData);
+        String resultData="01030A014A00B60112033103F68534";
+        System.out.println("馃摜 鏀跺埌婵�鍏夐浄杈捐澶囧搷搴�: " + resultData);
+        // 妫�鏌ュ搷搴旈暱搴�
+        if (resultData.length()< 30) {
+            System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + resultData.length() + " 瀛楄妭");
+
+        }
+
+        String data=resultData.substring(6,resultData.length()-1);
+
+
+        //椋庨��
+        int fengsu=Integer.parseInt(data.substring(0,4),16)/100;
+        System.out.println("婵�鍏夐浄杈捐澶�  椋庨�熻В鏋愪负: " + fengsu);
+
+        //椋庡悜
+        int fengxiang=Integer.parseInt(data.substring(4,8),16)/100;
+        System.out.println("婵�鍏夐浄杈捐澶�  椋庨�熻В鏋愪负: " + fengsu);
+        //娓╁害
+        int wendu=Integer.parseInt(data.substring(8,12),16)/100;
+        System.out.println("婵�鍏夐浄杈捐澶�  椋庨�熻В鏋愪负: " + fengsu);
+        //婀垮害
+        int shidu=Integer.parseInt(data.substring(12,16),16)/100;
+        System.out.println("婵�鍏夐浄杈捐澶�  椋庨�熻В鏋愪负: " + fengsu);
+        //澶ф皵鍘�
+        int daqiya=Integer.parseInt(data.substring(16,20),16)/100;
+        System.out.println("婵�鍏夐浄杈捐澶�  椋庨�熻В鏋愪负: " + fengsu);
+        //crc
+
+
+        return jsonObject;
+
+    }
+
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getLijiuValue(String ip, int port, List<ReceiveOilInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("鍘﹂棬鍒╂棫鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveOilInfo info : list
+                ) {
+                    // 鏋勯�犺姹傚抚
+                    ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                    if (info.getDeviceAddress() != 0) {
+                        requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                    }
+                    if (info.getFunctionCode() != 0) {
+                        requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                    }
+                    if (info.getRegisterAdress() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                    }
+                    if (info.getRegisterCount() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                    }
+                    // 璁$畻CRC鏍¢獙鐮�
+                    byte[] requestData = requestBuffer.array();
+                    String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                    int decimal = Integer.parseInt(hex, 16);
+                    requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                    // 鍙戦�佽姹傚抚
+                    outputStream.write(requestBuffer.array());
+                    System.out.println("鍘﹂棬鍒╂棫宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    try {
+                        Thread.sleep(5000);
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鍘﹂棬鍒╂棫鏈敹鍒拌澶囧搷搴�");
+                        continue;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("鍘﹂棬鍒╂棫鏀跺埌璁惧鍝嶅簲: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (responseData.length <= 5) {
+                        System.out.println("鍘﹂棬鍒╂棫鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                        continue;
+                    }
+                    //鍔熻兘鐮�
+                    byte responseFunctionCode = responseData[1];
+                    //鏁版嵁瀛楄妭鏁�
+                    byte byteCount = responseData[2];
+                    byte[] data = new byte[byteCount];
+                    System.arraycopy(responseData, 3, data, 0, byteCount);
+                    byte[] crcReceived = new byte[2];
+                    System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                    // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                    if ((responseFunctionCode & 0x80) != 0) {
+                        byte errorCode = responseData[2];  // 閿欒鐮�
+                        System.out.println("鍘﹂棬鍒╂棫璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                        continue;
+                    }
+                    if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                        serverSocket.close();
+                    }
+                }
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("鍘﹂棬鍒╂棫娌硅澶囦笉鍦ㄧ嚎" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍏抽棴澶辫触: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍚姩澶辫触: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip              ip
+     * @param port            绔彛
+     * @param address         鍦板潃鐮�
+     * @param functionCode    鍔熻兘鐮�
+     * @param registerAddress 瀵勫瓨鍣ㄥ湴鍧�
+     * @param registerCount   瀵勫瓨鍣ㄦ暟閲�
+     * @param dataType        缁撴灉鏁版嵁绫诲瀷
+     */
+    public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (address != 0) {
+                    requestBuffer.put(address);  // 璁惧鍦板潃
+                }
+                if (functionCode != 0) {
+                    requestBuffer.put(functionCode);  // 鍔熻兘鐮�
+                }
+                if (registerAddress != 0) {
+                    requestBuffer.putShort((short) registerAddress);  // 瀵勫瓨鍣ㄥ湴鍧�
+                }
+                if (registerCount != 0) {
+                    requestBuffer.putShort((short) registerCount);  // 瀵勫瓨鍣ㄦ暟閲�
+                }
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                try {
+                    Thread.sleep(3000);
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    return null;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (responseData.length <= 5) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                    return null;
+                }
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    return null;
+                }
+                if (DataTypeEnum.OIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUOIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUJUN.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                    //todo 鏈仛澶勭悊
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                }
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+
+    // CRC16 璁$畻
+    public static int crc16(byte[] data) {
+        int crc = 0xFFFF;
+        for (byte b : data) {
+            crc ^= (b & 0xFF);
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x0001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0xA001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusWeatherServerUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusWeatherServerUtils.java
new file mode 100644
index 0000000..4f43e4f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusWeatherServerUtils.java
@@ -0,0 +1,506 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.domain.ReceiveWeatherInfo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserLittleUtil;
+import com.ruoyi.fuzhou.utils.oilmodbus.ModbusFloatParserUtil;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+public class ModbusWeatherServerUtils {
+    public static void main(String[] args) {
+//
+//        //璐ㄩ噺娴侀噺
+String value = getValue("0.0.0.0", 8140, (byte) 0x05, (byte) 0x04, 167, 0x0002,  1);
+//        //鍒╁拰娌硅澶�
+//        String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 3, 13, 2, 12);
+        System.out.println(value);
+    }
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getValue(String ip, int port, List<ReceiveWeatherInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 姘旇薄鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 姘旇薄瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                ReceiveWeatherInfo info=list.get(0);
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (info.getDeviceAddress() != 0) {
+                    requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                }
+                if (info.getFunctionCode() != 0) {
+                    requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                }
+
+                requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫佹皵璞� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒版皵璞¤澶囧搷搴�");
+                    serverSocket.close();
+                    return jsonObject;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌姘旇薄璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (resultData.length()< 30) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + resultData.length() + " 瀛楄妭");
+
+                }
+
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 姘旇薄璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    serverSocket.close();
+                    return jsonObject;
+                }
+                //鏁版嵁瑙f瀽
+                String dataStr=resultData.substring(6,resultData.length()-1);
+                //椋庨��
+                float fengsu=Integer.parseInt(dataStr.substring(0,4),16);
+                String fengsuStr= String.valueOf(String.format("%.2f",fengsu/100));
+                System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsuStr);
+                jsonObject.put("windSpeed", fengsuStr);
+                //椋庡悜
+                int fengxiang=Integer.parseInt(dataStr.substring(4,8),16);
+                String fengxiangStr=String.valueOf(fengxiang);
+                System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengxiangStr);
+                jsonObject.put("windDirection", fengxiangStr);
+                //娓╁害
+                float wendu=Integer.parseInt(dataStr.substring(8,12),16);
+                String wenduStr=String.valueOf(String.format("%.1f",wendu/10));
+                System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + wenduStr);
+                jsonObject.put("temp", wenduStr);
+                //婀垮害
+                float shidu=Integer.parseInt(dataStr.substring(12,16),16);
+                String shiduStr=String.valueOf(String.format("%.1f",shidu/10));
+                System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " +shiduStr );
+                jsonObject.put("humidity", shiduStr);
+                //澶ф皵鍘�
+                float daqiya=Integer.parseInt(dataStr.substring(16,20),16);
+                String daqiyaStr=String.valueOf(String.format("%.1f",daqiya/10));
+                System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + daqiyaStr);
+                jsonObject.put("atmosphericPressure", daqiyaStr);
+
+                serverSocket.close();
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鈿狅笍 姘旇薄瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("姘旇薄璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 姘旇薄鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 姘旇薄鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+
+    public static JSONObject getValueTest(String ip, int port, List<ReceiveWeatherInfo> list) {
+        JSONObject jsonObject = new JSONObject();
+        ReceiveWeatherInfo info=list.get(0);
+        // 鏋勯�犺姹傚抚
+        ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+        if (info.getDeviceAddress() != 0) {
+            requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+        }
+        if (info.getFunctionCode() != 0) {
+            requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+        }
+
+            requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+
+
+            requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+
+        // 璁$畻CRC鏍¢獙鐮�
+        byte[] requestData = requestBuffer.array();
+        String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+        int decimal = Integer.parseInt(hex, 16);
+        requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+        // 鍙戦�佽姹傚抚
+
+        System.out.println("馃摛 宸插彂閫佹皵璞� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+        // 鎺ユ敹璁惧鍝嶅簲
+        byte[] response = new byte[1024];
+
+
+//        int bytesRead = inputStream.read(response);
+
+
+//        int bytesRead = Integer.parseInt(res, 16);
+//        if (bytesRead == -1) {
+//            System.out.println("鉂� 鏈敹鍒版皵璞¤澶囧搷搴�");
+//
+//        }
+////         鎵撳嵃鍝嶅簲鏁版嵁
+//        byte[] responseData = new byte[bytesRead];
+//        System.arraycopy(response, 0, responseData, 0, bytesRead);
+//        String resultData = bytesToHex(responseData);
+        String resultData="01030A014A00B60112033103F68534";
+        System.out.println("馃摜 鏀跺埌姘旇薄璁惧鍝嶅簲: " + resultData);
+        // 妫�鏌ュ搷搴旈暱搴�
+        if (resultData.length()< 30) {
+            System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + resultData.length() + " 瀛楄妭");
+
+        }
+
+        String data=resultData.substring(6,resultData.length()-1);
+
+
+        //椋庨��
+        int fengsu=Integer.parseInt(data.substring(0,4),16)/100;
+        System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsu);
+
+        //椋庡悜
+        int fengxiang=Integer.parseInt(data.substring(4,8),16)/100;
+        System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsu);
+        //娓╁害
+        int wendu=Integer.parseInt(data.substring(8,12),16)/100;
+        System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsu);
+        //婀垮害
+        int shidu=Integer.parseInt(data.substring(12,16),16)/100;
+        System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsu);
+        //澶ф皵鍘�
+        int daqiya=Integer.parseInt(data.substring(16,20),16)/100;
+        System.out.println("姘旇薄璁惧  椋庨�熻В鏋愪负: " + fengsu);
+        //crc
+
+
+        return jsonObject;
+
+    }
+
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getLijiuValue(String ip, int port, List<ReceiveOilInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("鍘﹂棬鍒╂棫鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveOilInfo info : list
+                ) {
+                    // 鏋勯�犺姹傚抚
+                    ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                    if (info.getDeviceAddress() != 0) {
+                        requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                    }
+                    if (info.getFunctionCode() != 0) {
+                        requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                    }
+                    if (info.getRegisterAdress() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                    }
+                    if (info.getRegisterCount() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                    }
+                    // 璁$畻CRC鏍¢獙鐮�
+                    byte[] requestData = requestBuffer.array();
+                    String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                    int decimal = Integer.parseInt(hex, 16);
+                    requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                    // 鍙戦�佽姹傚抚
+                    outputStream.write(requestBuffer.array());
+                    System.out.println("鍘﹂棬鍒╂棫宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    try {
+                        Thread.sleep(5000);
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鍘﹂棬鍒╂棫鏈敹鍒拌澶囧搷搴�");
+                        continue;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("鍘﹂棬鍒╂棫鏀跺埌璁惧鍝嶅簲: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (responseData.length <= 5) {
+                        System.out.println("鍘﹂棬鍒╂棫鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                        continue;
+                    }
+                    //鍔熻兘鐮�
+                    byte responseFunctionCode = responseData[1];
+                    //鏁版嵁瀛楄妭鏁�
+                    byte byteCount = responseData[2];
+                    byte[] data = new byte[byteCount];
+                    System.arraycopy(responseData, 3, data, 0, byteCount);
+                    byte[] crcReceived = new byte[2];
+                    System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                    // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                    if ((responseFunctionCode & 0x80) != 0) {
+                        byte errorCode = responseData[2];  // 閿欒鐮�
+                        System.out.println("鍘﹂棬鍒╂棫璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                        continue;
+                    }
+                    if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                        serverSocket.close();
+                    }
+                }
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("鍘﹂棬鍒╂棫娌硅澶囦笉鍦ㄧ嚎" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍏抽棴澶辫触: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍚姩澶辫触: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip              ip
+     * @param port            绔彛
+     * @param address         鍦板潃鐮�
+     * @param functionCode    鍔熻兘鐮�
+     * @param registerAddress 瀵勫瓨鍣ㄥ湴鍧�
+     * @param registerCount   瀵勫瓨鍣ㄦ暟閲�
+     * @param dataType        缁撴灉鏁版嵁绫诲瀷
+     */
+    public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (address != 0) {
+                    requestBuffer.put(address);  // 璁惧鍦板潃
+                }
+                if (functionCode != 0) {
+                    requestBuffer.put(functionCode);  // 鍔熻兘鐮�
+                }
+                if (registerAddress != 0) {
+                    requestBuffer.putShort((short) registerAddress);  // 瀵勫瓨鍣ㄥ湴鍧�
+                }
+                if (registerCount != 0) {
+                    requestBuffer.putShort((short) registerCount);  // 瀵勫瓨鍣ㄦ暟閲�
+                }
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                try {
+                    Thread.sleep(3000);
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    return null;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (responseData.length <= 5) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                    return null;
+                }
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    return null;
+                }
+                if (DataTypeEnum.OIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUOIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUJUN.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                    //todo 鏈仛澶勭悊
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                }
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+
+    // CRC16 璁$畻
+    public static int crc16(byte[] data) {
+        int crc = 0xFFFF;
+        for (byte b : data) {
+            crc ^= (b & 0xFF);
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x0001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0xA001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusYdkfmjUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusYdkfmjUtils.java
new file mode 100644
index 0000000..7c7b33c
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/ModbusYdkfmjUtils.java
@@ -0,0 +1,157 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+import com.ruoyi.fuzhou.utils.electricitymodbus.HexStringToInt;
+import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
+import com.ruoyi.fuzhou.utils.watermodbus.FloatInverseWaterParser;
+
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class ModbusYdkfmjUtils {
+    public static JSONObject getValue(ReceiveModuleInfo rmi) throws Exception {
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(rmi.getPort());
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + rmi.getIp() + ":" + rmi.getPort() + "...");
+            serverSocket.setSoTimeout(1500);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+
+            try (clientSocket; InputStream inputStream = clientSocket.getInputStream(); OutputStream outputStream = clientSocket.getOutputStream()) {
+                ByteBuffer buffer = getRequestBuffer(rmi);
+                outputStream.write(buffer.array()); // 鍙戦�佽姹傚抚
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + Crc16Utils.bytesToHex(buffer.array()));
+
+                byte[] response = new byte[1024];
+                int bytesRead = inputStream.read(response); // 鎺ユ敹璁惧鍝嶅簲
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    throw new Exception("鏈敹鍒拌澶囧搷搴�");
+                }
+
+                byte[] data = new byte[bytesRead];
+                System.arraycopy(response, 0, data, 0, bytesRead);
+
+                return getValue(data, rmi);
+            } catch (Exception ex) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + ex.getMessage());
+                throw ex;
+            }
+        } catch (Exception e) {
+            System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            throw e;
+        } finally {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�");
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            }
+        }
+    }
+
+    private static ByteBuffer getRequestBuffer(ReceiveModuleInfo rmi) {
+        ByteBuffer buffer = ByteBuffer.allocate(8); // 鏋勯�犺姹傚抚
+        if (rmi.getDeviceAddress() != 0) buffer.put(rmi.getDeviceAddress());  // 璁惧鍦板潃
+        if (rmi.getFunctionCode() != 0) buffer.put(rmi.getFunctionCode());  // 鍔熻兘鐮�
+        if (rmi.getRegisterAdress() != 0) buffer.putShort((short) rmi.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+        if (rmi.getRegisterCount() != 0) buffer.putShort((short) rmi.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+
+        byte[] bytes = buffer.array(); // 璁$畻CRC鏍¢獙鐮�
+        String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(bytes).substring(0, Crc16Utils.bytesToHex(bytes).length() - 4), true);
+        int decimal = Integer.parseInt(hex, 16);
+        buffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+
+        return buffer;
+    }
+
+    private static JSONObject getValue(byte[] data, ReceiveModuleInfo rmi) throws Exception {
+        String result = Crc16Utils.bytesToHex(data);
+        System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + result);  // 鎵撳嵃鍝嶅簲鏁版嵁
+
+        if (data.length < 6) {
+            System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + data.length + " 瀛楄妭");
+            throw new Exception("鏃犳晥鐨勫搷搴旈暱搴�: " + data.length + " 瀛楄妭");
+        }
+
+        byte byteCount = data[2]; // 鏁版嵁瀛楄妭鏁�
+        byte[] bytes = new byte[byteCount];
+        System.arraycopy(data, 3, bytes, 0, byteCount);
+        byte[] crcReceived = new byte[2];
+        System.arraycopy(data, data.length - 2, crcReceived, 0, 2);
+
+        byte functionCode = data[1]; // 鍔熻兘鐮�
+        if ((functionCode & 0x80) != 0) { // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+            byte errorCode = data[2]; // 閿欒鐮�
+            System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+            throw new Exception("璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+        }
+
+        JSONObject jsonObject = new JSONObject();
+        String src = result.substring(6, 6 + byteCount * 2);
+        if (src.length() == 8) {
+            byte[] arr = FloatInverseWaterParser.hexStringToByteArray(src);
+            byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(arr); // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+            float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+            jsonObject.put(rmi.getParamCode(), floatValue);
+            System.out.println(rmi.getParam() + "鐨勫�间负" + floatValue + rmi.getUnit());
+        } else {
+            long value = HexStringToInt.hexStringToInt(src);
+            jsonObject.put(rmi.getParamCode(), value);
+            System.out.println(rmi.getParam() + "鐨勫�间负" + value + rmi.getUnit());
+        }
+
+        return jsonObject;
+    }
+
+
+    public static void main(String[] args) throws Exception {
+        // 妯℃嫙鍙戦�佹暟鎹�
+        ReceiveModuleInfo rmi = new ReceiveModuleInfo();
+        rmi.setIp("0.0.0.0");
+        rmi.setPort(8379);
+        rmi.setParam("鑾峰彇寮�鍏崇姸鎬�");
+        rmi.setParamCode("getStatus");
+        rmi.setUnit("");
+        rmi.setDeviceAddress((byte) (1 & 0XFF));
+        rmi.setFunctionCode((byte) (3 & 0XFF));
+        rmi.setRegisterAdress(50);
+        rmi.setRegisterCount(1);
+        ByteBuffer requestBuffer = getRequestBuffer(rmi);
+        System.out.println("requestBuffer = " + Crc16Utils.bytesToHex(requestBuffer.array()));
+
+        // 妯℃嫙鎺ユ敹鏁版嵁
+        ByteBuffer responseBuffer = ByteBuffer.allocate(7);
+        responseBuffer.put((byte) (0x1));
+        responseBuffer.put((byte) (0x3));
+        responseBuffer.put((byte) (0x2));
+        responseBuffer.put((byte) (0x0));
+        responseBuffer.put((byte) (0x1));
+        responseBuffer.put((byte) (0x79));
+        responseBuffer.put((byte) (0x84));
+        String resp = Crc16Utils.bytesToHex(responseBuffer.array());
+        System.out.println("responseBuffer = " + resp);
+
+        JSONObject jsonObject = getValue(responseBuffer.array(), rmi);
+        System.out.println("json = " + jsonObject.toJSONString());
+    }
+
+
+    public static boolean getYdkfmStatus(ReceiveModuleInfo rmi) throws Exception {
+
+        return true;
+    }
+
+    public static boolean ctrlYdkfm(ReceiveModuleInfo rmi, Boolean flag) throws Exception {
+
+        return true;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RS485TCPServer.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RS485TCPServer.java
new file mode 100644
index 0000000..16109e6
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RS485TCPServer.java
@@ -0,0 +1,44 @@
+package com.ruoyi.fuzhou.utils;
+
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.PrintWriter;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+public class RS485TCPServer {
+    private static final int PORT = 20108;
+
+    public static void main(String[] args) throws Exception {
+        try (ServerSocket serverSocket = new ServerSocket(PORT)) {
+            System.out.println("RS485 TCP Server is listening on port " + PORT);
+            while (true) {
+                // 绛夊緟瀹㈡埛绔繛鎺�
+                try (Socket socket = serverSocket.accept()) {
+
+                    System.out.println("New client connected: " + socket.getInetAddress());
+                    // 鑾峰彇杈撳叆娴佸拰杈撳嚭娴�
+                    BufferedReader in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
+                    PrintWriter out = new PrintWriter(socket.getOutputStream(), true);
+                    // 璇诲彇瀹㈡埛绔彂閫佺殑鏁版嵁
+                    int  r = in.read();
+                    while(r > -1){
+                        System.out.print(r);
+                    }
+                    /*String inputLine = in.readLine();
+                    while (inputLine != null) {
+                        System.out.println("Received from client: " + inputLine);
+                        // 澶勭悊鏁版嵁锛堣繖閲岀畝鍗曞湴灏嗘暟鎹師鏍疯繑鍥烇級
+                        out.println("Server received: " + inputLine);
+                        Thread.sleep(1000);
+                    }*/
+                } catch (IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuMasterUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuMasterUtils.java
new file mode 100644
index 0000000..7d50cda
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuMasterUtils.java
@@ -0,0 +1,116 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.ruoyi.fuzhou.domain.ReceiveModuleInfo;
+import com.ruoyi.fuzhou.utils.rtu.SerialPortWrapperImpl;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusMaster;
+import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
+import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
+import com.serotonin.modbus4j.msg.WriteRegisterRequest;
+import com.serotonin.modbus4j.msg.WriteRegisterResponse;
+import gnu.io.SerialPort;
+
+import java.util.Arrays;
+
+/**
+ * 妯℃嫙涓荤珯璁惧
+ *
+ * @author zhangyy
+ * @date 2025/3/8
+ */
+public class RtuMasterUtils {
+
+    public static void main(String[] args) throws Exception {
+        createRtuMaster();
+    }
+
+    public static boolean getYdkfmStatus(ReceiveModuleInfo rmi) throws Exception {
+        SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM4", 19200,
+                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
+        ModbusFactory modbusFactory = new ModbusFactory();
+        ModbusMaster master = modbusFactory.createRtuMaster(wrapper);
+        master.init();
+
+        int slaveId = rmi.getRegisterAdress(); // 浠庣珯璁惧ID
+        readValue(master, slaveId, 7, 1);
+
+        return true;
+    }
+
+    public static boolean ctrlYdkfm(ReceiveModuleInfo rmi, Boolean flag) throws Exception {
+        SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM4", 19200,
+                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
+        ModbusFactory modbusFactory = new ModbusFactory();
+        ModbusMaster master = modbusFactory.createRtuMaster(wrapper);
+        master.init();
+
+        int slaveId = rmi.getRegisterAdress();
+        writeValue(master, slaveId, 7, flag ? 2 : 1);
+
+        return true;
+    }
+
+    private static boolean readValue(ModbusMaster master, int slaveId, int start, int len) throws Exception {
+        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
+        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
+
+        if (response.isException()) {
+            System.out.println("璇诲彇淇濇寔瀵勫瓨鍣ㄩ敊璇紝閿欒淇℃伅鏄�" + response.getExceptionMessage());
+        } else {
+            System.out.println("璇诲彇淇濇寔瀵勫瓨鍣�=" + Arrays.toString(response.getShortData()));
+        }
+
+        return !response.isException();
+    }
+
+    private static boolean writeValue(ModbusMaster master, int slaveId, int offset, int value) throws Exception {
+        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
+        WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
+
+        if (response.isException()) {
+            System.out.println("鍐欎繚鎸佸瘎瀛樺櫒閿欒锛岄敊璇俊鎭槸" + response.getExceptionMessage());
+        } else {
+            System.out.println("鍐欎繚鎸佸瘎瀛樺櫒鎴愬姛");
+        }
+
+        return !response.isException();
+    }
+
+
+    private static void createRtuMaster() throws Exception {
+        // 璁剧疆涓插彛鍙傛暟锛屼覆鍙f槸COM1锛屾尝鐗圭巼鏄�9600
+        SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM2", 9600,
+                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
+        ModbusFactory modbusFactory = new ModbusFactory();
+        ModbusMaster master = modbusFactory.createRtuMaster(wrapper);
+        master.init();
+        // 浠庣珯璁惧ID鏄�1
+        int slaveId = 1;
+        // 璇诲彇淇濇寔瀵勫瓨鍣�
+        readHoldingRegisters(master, slaveId, 0, 3);
+        // 灏嗗湴鍧�涓�0鐨勪繚鎸佸瘎瀛樺櫒鏁版嵁淇敼涓�0
+        writeRegister(master, slaveId, 0, 0);
+        // 鍐嶈鍙栦繚鎸佸瘎瀛樺櫒
+        readHoldingRegisters(master, slaveId, 0, 3);
+    }
+
+    private static void readHoldingRegisters(ModbusMaster master, int slaveId, int start, int len) throws Exception {
+        ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(slaveId, start, len);
+        ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) master.send(request);
+        if (response.isException()) {
+            System.out.println("璇诲彇淇濇寔瀵勫瓨鍣ㄩ敊璇紝閿欒淇℃伅鏄�" + response.getExceptionMessage());
+        } else {
+            System.out.println("璇诲彇淇濇寔瀵勫瓨鍣�=" + Arrays.toString(response.getShortData()));
+        }
+    }
+
+    private static void writeRegister(ModbusMaster master, int slaveId, int offset, int value) throws Exception {
+        WriteRegisterRequest request = new WriteRegisterRequest(slaveId, offset, value);
+        WriteRegisterResponse response = (WriteRegisterResponse) master.send(request);
+        if (response.isException()) {
+            System.out.println("鍐欎繚鎸佸瘎瀛樺櫒閿欒锛岄敊璇俊鎭槸" + response.getExceptionMessage());
+        } else {
+            System.out.println("鍐欎繚鎸佸瘎瀛樺櫒鎴愬姛");
+        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuSlaveUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuSlaveUtils.java
new file mode 100644
index 0000000..17fb94d
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/RtuSlaveUtils.java
@@ -0,0 +1,86 @@
+package com.ruoyi.fuzhou.utils;
+
+import com.ruoyi.fuzhou.utils.rtu.MyProcessImageListener;
+import com.ruoyi.fuzhou.utils.rtu.SerialPortWrapperImpl;
+import com.serotonin.modbus4j.BasicProcessImage;
+import com.serotonin.modbus4j.ModbusFactory;
+import com.serotonin.modbus4j.ModbusSlaveSet;
+import com.serotonin.modbus4j.ProcessImage;
+import com.serotonin.modbus4j.exception.ModbusInitException;
+import gnu.io.SerialPort;
+
+/**
+ * 妯℃嫙浠庣珯璁惧
+ * @author zhangyy
+ * @date 2025/3/8
+ */
+public class RtuSlaveUtils {
+
+    public static void main(String[] args) {
+        createRtuSlave();
+    }
+
+    public static void createRtuSlave(){
+        // 璁剧疆涓插彛鍙傛暟锛屼覆鍙f槸COM2锛屾尝鐗圭巼鏄�9600
+        SerialPortWrapperImpl wrapper = new SerialPortWrapperImpl("COM2", 9600,
+                SerialPort.DATABITS_8, SerialPort.STOPBITS_1, SerialPort.PARITY_NONE, 0, 0);
+
+        // Modbus宸ュ巶锛屽彲浠ュ垱寤篟TU銆乀CP绛変笉鍚岀被鍨嬬殑Master鍜孲lave
+        ModbusFactory modbusFactory = new ModbusFactory();
+
+        final ModbusSlaveSet slave = modbusFactory.createRtuSlave(wrapper);
+
+        // 杩欑帺鎰忕綉涓婃湁浜哄彨鍋氳繃绋嬪奖鍍忓尯锛屽叾瀹炲氨鏄瘎瀛樺櫒
+        // 瀵勫瓨鍣ㄩ噷鍙互璁剧疆绾垮湀鐘舵�併�佺鏁h緭鍏ョ姸鎬併�佷繚鎸佸瘎瀛樺櫒鍜岃緭鍏ュ瘎瀛樺櫒
+        // 杩欓噷璁剧疆浜嗕粠绔欒澶嘔D鏄�1
+        BasicProcessImage processImage = new BasicProcessImage(1);
+        processImage.setInvalidAddressValue(Short.MIN_VALUE);
+        slave.addProcessImage(processImage);
+
+        // 娣诲姞鐩戝惉鍣紝鐩戝惉slave绾垮湀鐘舵�佸拰淇濇寔瀵勫瓨鍣ㄧ殑鍐欏叆
+        processImage.addListener(new MyProcessImageListener());
+
+        setCoil(processImage);
+        setInput(processImage);
+        setHoldingRegister(processImage);
+        setInputRegister(processImage);
+
+        // 寮�鍚嚎绋嬪惎鍔ㄤ粠绔欒澶�
+        new Thread(() -> {
+            try {
+                slave.start();
+            }
+            catch (ModbusInitException e) {
+                e.printStackTrace();
+            }
+        }).start();
+    }
+
+    private static void setCoil(ProcessImage processImage){
+        // 妯℃嫙绾垮湀鐘舵��
+        processImage.setCoil(0, true);
+        processImage.setCoil(1, false);
+        processImage.setCoil(2, true);
+    }
+
+    private static void setInput(ProcessImage processImage){
+        // 妯℃嫙绂绘暎杈撳叆鐘舵��
+        processImage.setInput(0, false);
+        processImage.setInput(1, true);
+        processImage.setInput(2, false);
+    }
+
+    private static void setHoldingRegister(ProcessImage processImage){
+        // 妯℃嫙淇濇寔瀵勫瓨鍣ㄧ殑鍊�
+        processImage.setHoldingRegister(0,(short) 11);
+        processImage.setHoldingRegister(1,(short) 22);
+        processImage.setHoldingRegister(2,(short) 33);
+    }
+
+    private static void setInputRegister(ProcessImage processImage){
+        // 妯℃嫙杈撳叆瀵勫瓨鍣ㄧ殑鍊�
+        processImage.setInputRegister(0,(short) 44);
+        processImage.setInputRegister(1,(short) 55);
+        processImage.setInputRegister(2,(short) 66);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/HexStringToInt.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/HexStringToInt.java
new file mode 100644
index 0000000..984987a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/HexStringToInt.java
@@ -0,0 +1,70 @@
+package com.ruoyi.fuzhou.utils.electricitymodbus;
+
+public class HexStringToInt {
+
+    public static void main(String[] args) {
+        String hexString = "FFFFFF02"; // 绀轰緥鍗佸叚杩涘埗瀛楃涓�
+        long intValue = hexStringToIntelc(hexString);
+        System.out.println("Hex String: " + hexString);
+        System.out.println("Int Value: " + intValue);
+    }
+
+    /**
+     * 灏�2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆杞崲涓烘暣鍨�
+     *
+     * @param hexString 2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆锛堜緥濡� "FF9C"锛�
+     * @return 杞崲鍚庣殑鏁村瀷鍊�
+     */
+    public static long hexStringToInt(String hexString) {
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆瑙f瀽涓烘暣鏁�
+        long value = Long.parseLong(hexString, 16);
+
+        // 濡傛灉鍊煎ぇ浜庣瓑浜� 0x8000锛堝嵆鏈�楂樹綅涓�1锛夛紝鍒欒〃绀鸿繖鏄竴涓湁绗﹀彿鐨勮礋鏁�
+        if (value >= 0x8000) {
+            value = value - 0x10000; // 杞崲涓烘湁绗﹀彿鏁存暟
+        }
+
+        return value;
+    }
+
+    /**
+     * 灏�2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆杞崲涓烘暣鍨�
+     *
+     * @param hexString 2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆锛堜緥濡� "FF9C"锛�
+     * @return 杞崲鍚庣殑鏁村瀷鍊�
+     */
+    public static long hexStringToIntelc(String hexString) {
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆瑙f瀽涓烘暣鏁�
+        long value = Long.parseLong(hexString, 16);
+
+        // 濡傛灉鍊煎ぇ浜庣瓑浜� 0x8000锛堝嵆鏈�楂樹綅涓�1锛夛紝鍒欒〃绀鸿繖鏄竴涓湁绗﹀彿鐨勮礋鏁�
+        if (value >= 0x8000) {
+            value = value - 0x10000; // 杞崲涓烘湁绗﹀彿鏁存暟
+        }
+
+        return value;
+    }
+
+    /**
+     * 灏�2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆杞崲涓烘暣鍨�
+     *
+     * @param hexString 2瀛楄妭鐨勫崄鍏繘鍒跺瓧绗︿覆锛堜緥濡� "FF9C"锛�
+     * @return 杞崲鍚庣殑鏁村瀷鍊�
+     */
+    public static long hexStringToInt2(String hexString) {
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆瑙f瀽涓烘暣鏁�
+        long value = Long.parseLong(hexString, 16);
+        return value;
+    }
+
+    public static String hexStringToString(String hexString) {
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆瑙f瀽涓烘暣鏁�
+        int value = Integer.parseInt(hexString, 16);
+        if (value > 9) {
+            return String.valueOf(value);
+        } else {
+            return "0" + String.valueOf(value);
+        }
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/ModbusElectricityUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/ModbusElectricityUtils.java
new file mode 100644
index 0000000..7d7acb7
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/electricitymodbus/ModbusElectricityUtils.java
@@ -0,0 +1,281 @@
+package com.ruoyi.fuzhou.utils.electricitymodbus;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveElectricityInfo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
+import com.ruoyi.fuzhou.utils.watermodbus.FloatInverseWaterParser;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+
+/**
+ * 鐢佃〃璁惧鏁版嵁鎺ュ叆
+ */
+public class ModbusElectricityUtils {
+    public static void main(String[] args) {
+
+        //鍒╁拰娌硅澶�
+        String value = getValue("0.0.0.0", 8334, (byte) 35, (byte) 0x03, 20, 1, 3);
+//        String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 0x03, 13, 2, 3);
+        System.out.println(value);
+    }
+
+    /**
+     * 鏌ヨ澶氫釜璁惧椤�
+     *
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getValue(String ip, int port, List<ReceiveElectricityInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveElectricityInfo info : list
+                ) {
+                    // 鏋勯�犺姹傚抚
+                    ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                    if (info.getDeviceAddress() != 0) {
+                        requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                    }
+                    if (info.getFunctionCode() != 0) {
+                        requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                    }
+                    if (info.getRegisterAdress() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                    }
+                    if (info.getRegisterCount() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                    }
+                    // 璁$畻CRC鏍¢獙鐮�
+                    byte[] requestData = requestBuffer.array();
+                    String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                    int decimal = Integer.parseInt(hex, 16);
+                    requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                    // 鍙戦�佽姹傚抚
+                    outputStream.write(requestBuffer.array());
+                    System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                        continue;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (responseData.length <= 5) {
+                        System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                        continue;
+                    }
+                    //鍔熻兘鐮�
+                    byte responseFunctionCode = responseData[1];
+                    //鏁版嵁瀛楄妭鏁�
+                    byte byteCount = responseData[2];
+                    byte[] data = new byte[byteCount];
+                    System.arraycopy(responseData, 3, data, 0, byteCount);
+                    byte[] crcReceived = new byte[2];
+                    System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                    // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                    if ((responseFunctionCode & 0x80) != 0) {
+                        byte errorCode = responseData[2];  // 閿欒鐮�
+                        System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                        continue;
+                    }
+                    if (DataTypeEnum.ELECTRICITY.getCode().equals(info.getDataType())) {
+                        if (byteCount == 2) {
+                            //瑙f瀽鏁村舰
+                            long value = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
+                            jsonObject.put(info.getParamCode(), String.valueOf(value/10.0));
+                            System.out.println(info.getParam() + "鐨勫�间负" + (value/10.0) + info.getUnit());
+                        } else if (byteCount == 4) {
+                            //瑙f瀽娴偣鍨�
+                            long floatValue = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
+                            jsonObject.put(info.getParamCode(), String.valueOf(floatValue/100.0));
+                            System.out.println(info.getParam() + "鐨勫�间负" + floatValue/100.0 + info.getUnit());
+                        } else {
+                            continue;
+                        }
+                    }
+                }
+                serverSocket.close();
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+
+        } catch (Exception e) {
+            System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+        } finally {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�");
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip              ip
+     * @param port            绔彛
+     * @param address         鍦板潃鐮�
+     * @param functionCode    鍔熻兘鐮�
+     * @param registerAddress 瀵勫瓨鍣ㄥ湴鍧�
+     * @param registerCount   瀵勫瓨鍣ㄦ暟閲�
+     */
+    public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (address != 0) {
+                    requestBuffer.put(address);  // 璁惧鍦板潃
+                }
+                if (functionCode != 0) {
+                    requestBuffer.put(functionCode);  // 鍔熻兘鐮�
+                }
+                if (registerAddress != 0) {
+                    requestBuffer.putShort((short) registerAddress);  // 瀵勫瓨鍣ㄥ湴鍧�
+                }
+                if (registerCount != 0) {
+                    requestBuffer.putShort((short) registerCount);  // 瀵勫瓨鍣ㄦ暟閲�
+                }
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    return null;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (responseData.length <= 5) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                    return null;
+                }
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    return null;
+                }
+                if (DataTypeEnum.ELECTRICITY.getCode().equals(dataType)) {
+                    if (byteCount == 2) {
+                        //瑙f瀽鏁村舰
+                        long value = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
+
+                        System.out.println("鐨勫�间负" + (value/10.0) );
+                    } else if (byteCount == 4) {
+                        //瑙f瀽娴偣鍨�
+                        long floatValue = HexStringToInt.hexStringToIntelc(resultData.substring(6, 6 + byteCount * 2));
+                        System.out.println( "鐨勫�间负" + floatValue/100.0);
+                    } else {
+
+                    }
+                }
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        } finally {
+            try {
+                serverSocket.close();
+            } catch (IOException ex) {
+                System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+            }
+        }
+        return null;
+    }
+
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+
+    // CRC16 璁$畻
+    public static int crc16(byte[] data) {
+        int crc = 0xFFFF;
+        for (byte b : data) {
+            crc ^= (b & 0xFF);
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x0001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0xA001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+}
+
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataReceiver.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataReceiver.java
new file mode 100644
index 0000000..d157f4b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataReceiver.java
@@ -0,0 +1,38 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.Socket;
+
+/**
+ * 鏁版嵁鎺ユ敹瑙f瀽
+ */
+public class DataReceiver {
+    public static String receiveData(String serverIp, int serverPort) throws IOException {
+        try (Socket socket = new Socket(serverIp, serverPort);
+             InputStream inputStream = socket.getInputStream()) {
+            byte[] buffer = new byte[1024];
+            int bytesRead = inputStream.read(buffer);
+            byte[] receivedData = new byte[bytesRead];
+            System.arraycopy(buffer, 0, receivedData, 0, bytesRead);
+            return parseData(receivedData);
+        }
+    }
+
+    private static String parseData(byte[] data) {
+        // 妫�鏌ヨ捣濮嬬鍜岀粨鏉熺
+        if (data[0] != ProtocolDataEncoder.START_FLAG || data[data.length - 1] != ProtocolDataEncoder.END_FLAG) {
+            throw new IllegalArgumentException("Invalid data frame");
+        }
+        // 鎻愬彇鏁版嵁娈�
+        byte[] dataSegment = new byte[data.length - 2];
+        System.arraycopy(data, 1, dataSegment, 0, dataSegment.length);
+        // 鏍¢獙鏍¢獙鐮�
+        byte receivedChecksum = data[data.length - 2];
+        byte calculatedChecksum = ProtocolDataEncoder.calculateChecksum(dataSegment);
+        if (receivedChecksum != calculatedChecksum) {
+            throw new IllegalArgumentException("Checksum error");
+        }
+        return new String(dataSegment);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataSender.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataSender.java
new file mode 100644
index 0000000..29757be
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/DataSender.java
@@ -0,0 +1,18 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.net.Socket;
+
+/**
+ * 鏁版嵁鍙戦��
+ */
+public class DataSender {
+    public static void sendData(byte[] data, String serverIp, int serverPort) throws IOException {
+        try (Socket socket = new Socket(serverIp, serverPort);
+             OutputStream outputStream = socket.getOutputStream()) {
+            outputStream.write(data);
+            outputStream.flush();
+        }
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/FileReadUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/FileReadUtils.java
new file mode 100644
index 0000000..52cbf9a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/FileReadUtils.java
@@ -0,0 +1,67 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+import java.io.*;
+import java.util.ArrayList;
+
+/**
+ * 鏂囦欢璇诲彇宸ュ叿绫�
+ */
+public class FileReadUtils {
+    public static void main(String[] args) throws Exception {
+        byte[] bytes = readFromByteFile("D:\\绂忓窞椤圭洰\\ftp\\VEXJJYEY937103845_25032121");
+        String content = bytesToHex(bytes);
+        content = content.replace("aaaabbbbccccaaaa", "aaaabbbb,ccccaaaa");
+        String[] src = content.split(",");
+        for (int i = 0; i < src.length; i++) {
+            String items = src[i];
+        }
+        System.out.println(src);
+    }
+
+    public static byte[] readFromByteFile(String pathname) throws IOException {
+        File filename = new File(pathname);
+        BufferedInputStream in = new BufferedInputStream(new FileInputStream(filename));
+        ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
+        byte[] temp = new byte[1024];
+        int size = 0;
+        while ((size = in.read(temp)) != -1) {
+            out.write(temp, 0, size);
+        }
+        in.close();
+        byte[] content = out.toByteArray();
+        return content;
+    }
+
+    /**
+     * 瀛楄妭鏁扮粍杞�16杩涘埗
+     *
+     * @param bytes 闇�瑕佽浆鎹㈢殑byte鏁扮粍
+     * @return 杞崲鍚庣殑Hex瀛楃涓�
+     */
+    public static String bytesToHex(byte[] bytes) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(bytes[i] & 0xFF);
+            if (hex.length() < 2) {
+                sb.append(0);
+            }
+            sb.append(hex);
+        }
+        return sb.toString();
+    }
+
+    public ArrayList<String> readFromTextFile(String pathname) throws IOException {
+        ArrayList<String> strArray = new ArrayList<String>();
+        File filename = new File(pathname);
+        InputStreamReader reader = new InputStreamReader(new FileInputStream(filename));
+        BufferedReader br = new BufferedReader(reader);
+        String line = "";
+        line = br.readLine();
+        while (line != null) {
+            strArray.add(line);
+            line = br.readLine();
+        }
+        return strArray;
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/Main.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/Main.java
new file mode 100644
index 0000000..090a29b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/Main.java
@@ -0,0 +1,22 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+import java.io.IOException;
+
+public class Main {
+    public static void main(String[] args) {
+        String dataToSend = "01 06 00 09 00 00 59 C8";
+        String serverIp = "192.168.0.7";
+        int serverPort = 20108;
+        try {
+            // 灏佽鏁版嵁
+            byte[] encodedData = ProtocolDataEncoder.encodeData(dataToSend);
+            // 鍙戦�佹暟鎹�
+            DataSender.sendData(encodedData, serverIp, serverPort);
+            // 鎺ユ敹骞惰В鏋愭暟鎹�
+            String receivedData = DataReceiver.receiveData(serverIp, serverPort);
+            System.out.println("Received data: " + receivedData);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/ProtocolDataEncoder.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/ProtocolDataEncoder.java
new file mode 100644
index 0000000..9f6548f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/ProtocolDataEncoder.java
@@ -0,0 +1,30 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+import java.nio.charset.StandardCharsets;
+
+/**
+ * 鏁版嵁灏佽
+ */
+public class ProtocolDataEncoder {
+    public static final byte START_FLAG = 0x01;
+    public static final byte END_FLAG = 0x02;
+
+    public static byte[] encodeData(String data) {
+        byte[] dataBytes = data.getBytes(StandardCharsets.UTF_8);
+        byte checksum = calculateChecksum(dataBytes);
+        byte[] frame = new byte[2 + dataBytes.length + 1];
+        frame[0] = START_FLAG;
+        System.arraycopy(dataBytes, 0, frame, 1, dataBytes.length);
+        frame[frame.length - 2] = checksum;
+        frame[frame.length - 1] = END_FLAG;
+        return frame;
+    }
+
+    public static byte calculateChecksum(byte[] data) {
+        byte sum = 0;
+        for (byte b : data) {
+            sum += b;
+        }
+        return sum;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/StringToHexUtil.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/StringToHexUtil.java
new file mode 100644
index 0000000..ff374b3
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/hj1239/StringToHexUtil.java
@@ -0,0 +1,50 @@
+package com.ruoyi.fuzhou.utils.hj1239;
+
+public class StringToHexUtil {
+
+    public static String convertStringToHex(String str) {
+
+        char[] chars = str.toCharArray();
+
+        StringBuffer hex = new StringBuffer();
+        for (int i = 0; i < chars.length; i++) {
+            hex.append(Integer.toHexString((int) chars[i]));
+        }
+
+        return hex.toString();
+    }
+
+    public static String convertHexToString(String hex) {
+
+        StringBuilder sb = new StringBuilder();
+        StringBuilder temp = new StringBuilder();
+
+        //49204c6f7665204a617661 split into two characters 49, 20, 4c...
+        for (int i = 0; i < hex.length() - 1; i += 2) {
+
+            //grab the hex in pairs
+            String output = hex.substring(i, (i + 2));
+            //convert hex to decimal
+            int decimal = Integer.parseInt(output, 16);
+            //convert the decimal to character
+            sb.append((char) decimal);
+
+            temp.append(decimal);
+        }
+
+        return sb.toString();
+    }
+
+    //504F533838383834  POS88884
+    public static void main(String[] args) {
+//        System.out.println("\n-----ASCII鐮佽浆鎹负16杩涘埗 -----");
+//        String str = "POS88884";
+//        System.out.println("瀛楃涓�: " + str);
+//        String hex = strToHex.convertStringToHex(str);
+//        System.out.println("杞崲涓�16杩涘埗 : " + hex);
+        String hex = "5645574e4256524e323437383439393339";
+        System.out.println("\n***** 16杩涘埗杞崲涓篈SCII *****");
+        System.out.println("Hex : " + hex);
+        System.out.println("ASCII : " + StringToHexUtil.convertHexToString(hex));
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/Crc16Utils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/Crc16Utils.java
new file mode 100644
index 0000000..e453561
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/Crc16Utils.java
@@ -0,0 +1,70 @@
+package com.ruoyi.fuzhou.utils.oilmodbus;
+
+/**
+ * crc鏍¢獙
+ */
+public class Crc16Utils {
+    /**
+     * 鍗佸叚杩涘埗鐨勫瓧绗︿覆杞崲涓篵yte鏁扮粍
+     *
+     * @param hex16Str 鍗佸叚杩涘埗瀛楃涓�
+     * @return byte鏁扮粍
+     */
+    public static byte[] conver16HexToByte(String hex16Str) {
+        char[] c = hex16Str.toCharArray();
+        byte[] b = new byte[c.length / 2];
+        for (int i = 0; i < b.length; i++) {
+            int pos = i * 2;
+            b[i] = (byte) ("0123456789ABCDEF".indexOf(c[pos]) << 4 | "0123456789ABCDEF"
+                    .indexOf(c[pos + 1]));
+        }
+        return b;
+    }
+
+    /**
+     * 瀛楄妭鏁扮粍杞�16杩涘埗
+     *
+     * @param bytes 闇�瑕佽浆鎹㈢殑byte鏁扮粍
+     * @return 杞崲鍚庣殑Hex瀛楃涓�
+     */
+    public static String bytesToHex(byte[] bytes) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < bytes.length; i++) {
+            String hex = Integer.toHexString(bytes[i] & 0xFF);
+            if (hex.length() < 2) {
+                sb.append(0);
+            }
+            sb.append(hex);
+        }
+        return sb.toString().toUpperCase();
+    }
+
+
+    /**
+     * CRC鏍¢獙鐮�
+     *
+     * @param hex16Str 鍗佸叚杩涘埗瀛楃涓�
+     * @param format   鏄惁闇�瑕侀珮浣庝綅浜掓崲锛屼匠宀氱殑闇�瑕侀珮浣庝綅浜掓崲
+     * @return CRC鏍¢獙鐮�
+     */
+    public static String makeCRC(String hex16Str, boolean format) {
+        byte[] bytes = conver16HexToByte(hex16Str);
+        int crc = 0x0000ffff;
+        for (int i = 0; i < bytes.length; i++) {
+            crc ^= ((int) bytes[i] & 0x000000ff);
+            for (int j = 0; j < 8; j++) {
+                if ((crc & 0x00000001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0x0000a001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        // 楂樹綆浣嶄簰鎹紝杈撳嚭绗﹀悎鐩稿叧宸ュ叿瀵筂odbus CRC16鐨勮繍绠�
+        if (format) {
+            crc = ((crc & 0xff00) >> 8) | ((crc & 0x00ff) << 8);
+        }
+        return String.format("%04X", crc);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserLittleUtil.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserLittleUtil.java
new file mode 100644
index 0000000..6cf41f0
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserLittleUtil.java
@@ -0,0 +1,69 @@
+package com.ruoyi.fuzhou.utils.oilmodbus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * 娴偣鍨嬭В鏋� 鏈�涓嶉噸瑕佺殑瀵勫瓨鍣ㄤ紭鍏�
+ */
+public class ModbusFloatParserLittleUtil {
+
+    public static void main(String[] args) {
+        // 绀轰緥杈撳叆锛氫袱涓瘎瀛樺櫒鐨勫崄鍏繘鍒跺瓧绗︿覆锛堟渶涓嶉噸瑕佺殑瀵勫瓨鍣ㄤ紭鍏堬級
+        String hexString = "C41C6000"; // 浣庡瓧鑺傚湪鍓嶏紝琛ㄧず娴偣鏁� 3.14
+
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆杞崲涓哄瓧鑺傛暟缁�
+        byte[] bytes = hexStringToByteArray(hexString);
+
+        // 璋冩暣瀛楄妭椤哄簭锛堟渶涓嶉噸瑕佺殑瀵勫瓨鍣ㄤ紭鍏堬級
+        byte[] reorderedBytes = reorderBytesForFloat(bytes);
+
+        // 瑙f瀽涓烘诞鐐规暟
+        float floatValue = parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+
+        // 杈撳嚭缁撴灉
+        System.out.println("瑙f瀽鐨勬诞鐐规暟鍊�: " + floatValue);
+    }
+
+    /**
+     * 灏嗗崄鍏繘鍒跺瓧绗︿覆杞崲涓哄瓧鑺傛暟缁�
+     */
+    public static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        if (len % 2 != 0) {
+            throw new IllegalArgumentException("鍗佸叚杩涘埗瀛楃涓查暱搴﹀繀椤讳负鍋舵暟銆�");
+        }
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            int high = Character.digit(s.charAt(i), 16) << 4;
+            int low = Character.digit(s.charAt(i + 1), 16);
+            if (high == -1 || low == -1) {
+                throw new IllegalArgumentException("鍖呭惈鏃犳晥鐨勫崄鍏繘鍒跺瓧绗�: " + s);
+            }
+            data[i / 2] = (byte) (high + low);
+        }
+        return data;
+    }
+
+    /**
+     * 璋冩暣瀛楄妭椤哄簭锛堟渶涓嶉噸瑕佺殑瀵勫瓨鍣ㄤ紭鍏堬級
+     * 灏嗗瓧鑺傛暟缁勯噸鏂版帓鍒椾负娴偣鏁扮殑姝g‘椤哄簭
+     */
+    public static byte[] reorderBytesForFloat(byte[] bytes) {
+        if (bytes.length != 4) {
+            throw new IllegalArgumentException("瀛楄妭鏁扮粍闀垮害蹇呴』涓�4瀛楄妭銆�");
+        }
+        // 灏嗗瓧鑺傞『搴忚皟鏁翠负灏忕椤哄簭
+        return new byte[] { bytes[2], bytes[3], bytes[0], bytes[1] };
+    }
+
+    /**
+     * 灏嗗瓧鑺傛暟缁勮В鏋愪负娴偣鏁�
+     * @param bytes 瀛楄妭鏁扮粍锛堝繀椤讳负4瀛楄妭锛�
+     * @param order 瀛楄妭椤哄簭锛堝ぇ绔垨灏忕锛�
+     */
+    public static float parseAsFloat(byte[] bytes, ByteOrder order) {
+        ByteBuffer buffer = ByteBuffer.wrap(bytes).order(order);
+        return buffer.getFloat();
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserUtil.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserUtil.java
new file mode 100644
index 0000000..b0f92bc
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusFloatParserUtil.java
@@ -0,0 +1,55 @@
+package com.ruoyi.fuzhou.utils.oilmodbus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+/**
+ * 16浣嶆诞鐐瑰瀷鏁版嵁杞寲鎼暟浼樺厛
+ */
+public class ModbusFloatParserUtil {
+
+    public static void main(String[] args) {
+        //String hexString = "BFC00000"; // 绀轰緥杈撳叆锛�-1.5
+        String hexString = "464CE7E2"; // 绀轰緥杈撳叆锛�0.1234567
+       // String hexString = "FF00"; // 绀轰緥杈撳叆锛�-1.5
+        // 灏嗗崄鍏繘鍒跺瓧绗︿覆杞崲涓哄瓧鑺傛暟缁�
+        byte[] bytes = hexStringToByteArray(hexString);
+        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+        float floatValue = parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+        // 杈撳嚭缁撴灉
+        System.out.println("瑙f瀽鐨勬诞鐐规暟鍊�: " + floatValue);
+    }
+
+    /**
+     * 灏嗗崄鍏繘鍒跺瓧绗︿覆杞崲涓哄瓧鑺傛暟缁�
+     */
+    public static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        if (len % 2 != 0) {
+            throw new IllegalArgumentException("鍗佸叚杩涘埗瀛楃涓查暱搴﹀繀椤讳负鍋舵暟銆�");
+        }
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            int high = Character.digit(s.charAt(i), 16) << 4;
+            int low = Character.digit(s.charAt(i + 1), 16);
+            if (high == -1 || low == -1) {
+                throw new IllegalArgumentException("鍖呭惈鏃犳晥鐨勫崄鍏繘鍒跺瓧绗�: " + s);
+            }
+            data[i / 2] = (byte) (high + low);
+        }
+        return data;
+    }
+
+    /**
+     * 灏嗗瓧鑺傛暟缁勮В鏋愪负娴偣鏁�
+     * @param bytes 瀛楄妭鏁扮粍锛堝繀椤讳负4瀛楄妭锛�
+     * @param order 瀛楄妭椤哄簭锛堝ぇ绔垨灏忕锛�
+     */
+    public static float parseAsFloat(byte[] bytes, ByteOrder order) {
+        if (bytes.length != 4) {
+            throw new IllegalArgumentException("瀛楄妭鏁扮粍闀垮害蹇呴』涓�4瀛楄妭銆�");
+        }
+        ByteBuffer buffer = ByteBuffer.wrap(bytes).order(order);
+        return buffer.getFloat();
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusHexToFloat.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusHexToFloat.java
new file mode 100644
index 0000000..c165c6d
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusHexToFloat.java
@@ -0,0 +1,35 @@
+package com.ruoyi.fuzhou.utils.oilmodbus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class ModbusHexToFloat {
+
+    public static float hexToFloat(String hexSrc, String byteOrder) {
+        hexSrc = hexSrc.replaceAll("\\s|0x", "").toLowerCase();
+        if (hexSrc.length() != 8) {
+            throw new IllegalArgumentException("闀垮害涓嶅");
+        }
+        byte[] bytes = new byte[4];
+        for (int i = 1; i < 4; i++) {
+            int index = i * 2;
+            int val = Integer.parseInt(hexSrc.substring(index, index + 2), 16);
+            bytes[i] = (byte) val;
+        }
+        ByteBuffer buffer = ByteBuffer.wrap(bytes);
+        if (byteOrder.equalsIgnoreCase("big")) {
+            buffer.order(ByteOrder.BIG_ENDIAN);
+        } else if (byteOrder.equalsIgnoreCase("little")) {
+            buffer.order(ByteOrder.LITTLE_ENDIAN);
+        } else {
+            throw new IllegalArgumentException("鏃犳晥鐨勫瓧鑺傚簭鍒�");
+        }
+        return buffer.getFloat();
+    }
+
+    public static void main(String[] args) {
+        String hexSrc = "464CE7E2";
+        float value = hexToFloat(hexSrc, "big");
+        System.out.println(value);
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusOilServerUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusOilServerUtils.java
new file mode 100644
index 0000000..92197db
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/oilmodbus/ModbusOilServerUtils.java
@@ -0,0 +1,423 @@
+package com.ruoyi.fuzhou.utils.oilmodbus;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveOilInfo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+public class ModbusOilServerUtils {
+    public static void main(String[] args) {
+//
+//        //璐ㄩ噺娴侀噺
+String value = getValue("0.0.0.0", 8140, (byte) 0x05, (byte) 0x04, 167, 0x0002,  1);
+//        //鍒╁拰娌硅澶�
+//        String value = getValue("0.0.0.0", 8247, (byte) 1, (byte) 3, 13, 2, 12);
+        System.out.println(value);
+    }
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getValue(String ip, int port, List<ReceiveOilInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveOilInfo info : list
+                ) {
+                    // 鏋勯�犺姹傚抚
+                    ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                    if (info.getDeviceAddress() != 0) {
+                        requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                    }
+                    if (info.getFunctionCode() != 0) {
+                        requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                    }
+                    if (info.getRegisterAdress() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                    }
+                    if (info.getRegisterCount() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                    }
+                    // 璁$畻CRC鏍¢獙鐮�
+                    byte[] requestData = requestBuffer.array();
+                    String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                    int decimal = Integer.parseInt(hex, 16);
+                    requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                    // 鍙戦�佽姹傚抚
+                    outputStream.write(requestBuffer.array());
+                    System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                        continue;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (responseData.length <= 5) {
+                        System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                        continue;
+                    }
+                    //鍔熻兘鐮�
+                    byte responseFunctionCode = responseData[1];
+                    //鏁版嵁瀛楄妭鏁�
+                    byte byteCount = responseData[2];
+                    byte[] data = new byte[byteCount];
+                    System.arraycopy(responseData, 3, data, 0, byteCount);
+                    byte[] crcReceived = new byte[2];
+                    System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                    // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                    if ((responseFunctionCode & 0x80) != 0) {
+                        byte errorCode = responseData[2];  // 閿欒鐮�
+                        System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                        continue;
+                    }
+                    if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    }
+                }
+                serverSocket.close();
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("娌硅澶囦笉鍦ㄧ嚎" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 娌规湇鍔$鍏抽棴澶辫触: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 娌规湇鍔$鍚姩澶辫触: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getLijiuValue(String ip, int port, List<ReceiveOilInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("鍘﹂棬鍒╂棫鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveOilInfo info : list
+                ) {
+                    // 鏋勯�犺姹傚抚
+                    ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                    if (info.getDeviceAddress() != 0) {
+                        requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                    }
+                    if (info.getFunctionCode() != 0) {
+                        requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                    }
+                    if (info.getRegisterAdress() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                    }
+                    if (info.getRegisterCount() != 0) {
+                        requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                    }
+                    // 璁$畻CRC鏍¢獙鐮�
+                    byte[] requestData = requestBuffer.array();
+                    String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                    int decimal = Integer.parseInt(hex, 16);
+                    requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                    // 鍙戦�佽姹傚抚
+                    outputStream.write(requestBuffer.array());
+                    System.out.println("鍘﹂棬鍒╂棫宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                    // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    try {
+                        Thread.sleep(5000);
+                    } catch (Exception ex) {
+                        ex.printStackTrace();
+                    }
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鍘﹂棬鍒╂棫鏈敹鍒拌澶囧搷搴�");
+                        continue;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("鍘﹂棬鍒╂棫鏀跺埌璁惧鍝嶅簲: " + resultData);
+                    // 妫�鏌ュ搷搴旈暱搴�
+                    if (responseData.length <= 5) {
+                        System.out.println("鍘﹂棬鍒╂棫鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                        continue;
+                    }
+                    //鍔熻兘鐮�
+                    byte responseFunctionCode = responseData[1];
+                    //鏁版嵁瀛楄妭鏁�
+                    byte byteCount = responseData[2];
+                    byte[] data = new byte[byteCount];
+                    System.arraycopy(responseData, 3, data, 0, byteCount);
+                    byte[] crcReceived = new byte[2];
+                    System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                    // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                    if ((responseFunctionCode & 0x80) != 0) {
+                        byte errorCode = responseData[2];  // 閿欒鐮�
+                        System.out.println("鍘﹂棬鍒╂棫璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                        continue;
+                    }
+                    if (DataTypeEnum.OIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUOIL.getCode().equals(info.getDataType())) {
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.LIJIUJUN.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                    } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(info.getDataType())) {
+                        //todo 鏈仛澶勭悊
+                        byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                        byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                        jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                        serverSocket.close();
+                    }
+                }
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鍘﹂棬鍒╂棫瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("鍘﹂棬鍒╂棫娌硅澶囦笉鍦ㄧ嚎" + e.getMessage());
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍏抽棴澶辫触: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鍘﹂棬鍒╂棫娌规湇鍔$鍚姩澶辫触: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip              ip
+     * @param port            绔彛
+     * @param address         鍦板潃鐮�
+     * @param functionCode    鍔熻兘鐮�
+     * @param registerAddress 瀵勫瓨鍣ㄥ湴鍧�
+     * @param registerCount   瀵勫瓨鍣ㄦ暟閲�
+     * @param dataType        缁撴灉鏁版嵁绫诲瀷
+     */
+    public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;  // 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;        // 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (address != 0) {
+                    requestBuffer.put(address);  // 璁惧鍦板潃
+                }
+                if (functionCode != 0) {
+                    requestBuffer.put(functionCode);  // 鍔熻兘鐮�
+                }
+                if (registerAddress != 0) {
+                    requestBuffer.putShort((short) registerAddress);  // 瀵勫瓨鍣ㄥ湴鍧�
+                }
+                if (registerCount != 0) {
+                    requestBuffer.putShort((short) registerCount);  // 瀵勫瓨鍣ㄦ暟閲�
+                }
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                try {
+                    Thread.sleep(3000);
+                } catch (Exception ex) {
+                    ex.printStackTrace();
+                }
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    return null;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (responseData.length <= 5) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                    return null;
+                }
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    return null;
+                }
+                if (DataTypeEnum.OIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUOIL.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.LIJIUJUN.getCode().equals(dataType)) {
+                    byte[] bytes = ModbusFloatParserUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserUtil.parseAsFloat(bytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                } else if (DataTypeEnum.NIGDETUIYOU.getCode().equals(dataType)) {
+                    //todo 鏈仛澶勭悊
+                    byte[] bytes = ModbusFloatParserLittleUtil.hexStringToByteArray(resultData.substring(6, 6 + byteCount * 2));
+                    byte[] reorderedBytes = ModbusFloatParserLittleUtil.reorderBytesForFloat(bytes);
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    float floatValue = ModbusFloatParserLittleUtil.parseAsFloat(reorderedBytes, ByteOrder.BIG_ENDIAN);
+                    return String.valueOf(floatValue);
+                }
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+
+    // CRC16 璁$畻
+    public static int crc16(byte[] data) {
+        int crc = 0xFFFF;
+        for (byte b : data) {
+            crc ^= (b & 0xFF);
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x0001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0xA001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/MyProcessImageListener.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/MyProcessImageListener.java
new file mode 100644
index 0000000..4217718
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/MyProcessImageListener.java
@@ -0,0 +1,20 @@
+package com.ruoyi.fuzhou.utils.rtu;
+
+import com.serotonin.modbus4j.ProcessImageListener;
+
+/**
+ * @author zhangyy
+ * @date 2025/3/8
+ */
+public class MyProcessImageListener implements ProcessImageListener {
+
+    @Override
+    public void coilWrite(int offset, boolean oldValue, boolean newValue) {
+        System.out.println("绾垮湀鐘舵�佸湴鍧�=" + offset + "锛屾棫鍊�=" + oldValue + "锛屾柊鍊�=" + newValue);
+    }
+
+    @Override
+    public void holdingRegisterWrite(int offset, short oldValue, short newValue) {
+        System.out.println("淇濇寔瀵勫瓨鍣ㄥ湴鍧�=" + offset + "锛屾棫鍊�=" + oldValue + "锛屾柊鍊�=" + newValue);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortUtils.java
new file mode 100644
index 0000000..4793dc3
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortUtils.java
@@ -0,0 +1,61 @@
+package com.ruoyi.fuzhou.utils.rtu;
+
+import gnu.io.CommPort;
+import gnu.io.CommPortIdentifier;
+import gnu.io.SerialPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * 涓插彛宸ュ叿绫�
+ * @author zhangyy
+ * @date 2025/3/8
+ */
+public class SerialPortUtils {
+
+    private static Logger log = LoggerFactory.getLogger(SerialPortUtils.class);
+
+    /**
+     * 鎵撳崱涓插彛
+     * @param portName 涓插彛鍚�
+     * @param baudRate 娉㈢壒鐜�
+     * @param dataBits 鏁版嵁浣�
+     * @param stopBits 鍋滄浣�
+     * @param parity 鏍¢獙浣�
+     * @return 涓插彛瀵硅薄
+     */
+    public static SerialPort open(String portName, Integer baudRate, Integer dataBits,
+                                  Integer stopBits, Integer parity) {
+        SerialPort result = null;
+        try {
+            // 閫氳繃绔彛鍚嶈瘑鍒鍙�
+            CommPortIdentifier identifier = CommPortIdentifier.getPortIdentifier(portName);
+            // 鎵撳紑绔彛锛屽苟缁欑鍙e悕瀛楀拰涓�涓猼imeout锛堟墦寮�鎿嶄綔鐨勮秴鏃舵椂闂达級
+            CommPort commPort = identifier.open(portName, 2000);
+            // 鍒ゆ柇鏄笉鏄覆鍙�
+            if (commPort instanceof SerialPort) {
+                result = (SerialPort) commPort;
+                // 璁剧疆涓�涓嬩覆鍙g殑娉㈢壒鐜囩瓑鍙傛暟
+                result.setSerialPortParams(baudRate, dataBits, stopBits, parity);
+                log.info("鎵撳紑涓插彛{}鎴愬姛", portName);
+            }else{
+                log.info("{}涓嶆槸涓插彛", portName);
+            }
+        } catch (Exception e) {
+            log.error("鎵撳紑涓插彛{}閿欒", portName, e);
+        }
+        return result;
+    }
+
+    /**
+     * 鍏抽棴涓插彛
+     * @param serialPort
+     */
+    public static void close(SerialPort serialPort) {
+        if (serialPort != null) {
+            serialPort.close();
+            log.warn("涓插彛{}鍏抽棴", serialPort.getName());
+        }
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortWrapperImpl.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortWrapperImpl.java
new file mode 100644
index 0000000..9b1eb6b
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/rtu/SerialPortWrapperImpl.java
@@ -0,0 +1,189 @@
+package com.ruoyi.fuzhou.utils.rtu;
+
+import com.serotonin.modbus4j.serial.SerialPortWrapper;
+import gnu.io.SerialPort;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * 鑷畾涔変覆鍙e皝瑁�
+ * @author zhangyy
+ * @date 2025/3/8
+ */
+public class SerialPortWrapperImpl implements SerialPortWrapper {
+
+    private final Logger log = LoggerFactory.getLogger(this.getClass());
+
+    /**
+     * 涓插彛瀵硅薄
+     */
+    private SerialPort serialPort;
+
+    /**
+     * 涓插彛
+     */
+    private String port;
+
+    /**
+     * 娉㈢壒鐜�
+     */
+    private Integer baudRate;
+
+    /**
+     * 鏁版嵁浣嶇殑浣嶆暟锛孯TU鏄�8浣嶏紝ASCII鏄�7浣�
+     */
+    private Integer dataBits;
+
+    /**
+     * 鍋滄浣嶇殑浣嶆暟锛屽鏋滄棤濂囧伓鏍¢獙涓�2锛屾湁濂囧伓鏍¢獙涓�1
+     */
+    private Integer stopBits;
+
+    /**
+     * 濂囧伓鏍¢獙浣嶏紝鏃犳牎楠屾槸0锛屽鏍¢獙鏄�1锛屽伓鏍¢獙鏄�2
+     */
+    private Integer parity;
+
+    /**
+     * 纭欢涔嬮棿杈撳叆娴佸簲绛旀帶鍒�
+     */
+    private Integer flowControlIn;
+
+    /**
+     * 纭欢涔嬮棿杈撳嚭娴佸簲绛旀帶鍒�
+     */
+    private Integer flowControlOut;
+
+    public SerialPortWrapperImpl() {
+        super();
+    }
+
+    /**
+     *
+     * @param port 绔彛
+     * @param baudRate 娉㈢壒鐜�
+     * @param dataBits 鏁版嵁浣�
+     * @param stopBits 鍋滄浣�
+     * @param parity 鏍¢獙浣�
+     * @param flowControlIn
+     * @param flowControlOut
+     */
+    public SerialPortWrapperImpl(String port, int baudRate, int dataBits, int stopBits, int parity,
+                                 int flowControlIn, int flowControlOut) {
+        this.port = port;
+        this.baudRate = baudRate;
+        this.dataBits = dataBits;
+        this.stopBits = stopBits;
+        this.parity = parity;
+        this.flowControlIn = flowControlIn;
+        this.flowControlOut = flowControlOut;
+    }
+
+    @Override
+    public void close() throws Exception {
+        SerialPortUtils.close(serialPort);
+    }
+
+    @Override
+    public void open() throws Exception {
+        serialPort = SerialPortUtils.open(port, baudRate, dataBits, stopBits, parity);
+    }
+
+    @Override
+    public InputStream getInputStream() {
+        InputStream in = null;
+        try {
+            in = serialPort.getInputStream();
+        } catch (IOException e) {
+            log.error("鑾峰彇涓插彛杈撳叆娴侀敊璇�", e);
+        }
+
+        return in;
+    }
+
+    @Override
+    public OutputStream getOutputStream() {
+        OutputStream out = null;
+        try {
+            out = serialPort.getOutputStream();
+        } catch (IOException e) {
+            log.error("鑾峰彇涓插彛杈撳嚭娴侀敊璇�", e);
+        }
+
+        return out;
+    }
+
+    @Override
+    public int getBaudRate() {
+        return this.baudRate;
+    }
+
+    @Override
+    public int getDataBits() {
+        return this.dataBits;
+    }
+
+    @Override
+    public int getStopBits() {
+        return this.stopBits;
+    }
+
+    @Override
+    public int getParity() {
+        return this.parity;
+    }
+
+    @Override
+    public int getFlowControlIn() {
+        return this.flowControlIn;
+    }
+
+    @Override
+    public int getFlowControlOut() {
+        return this.flowControlOut;
+    }
+
+    public SerialPort getSerialPort() {
+        return serialPort;
+    }
+
+    public void setSerialPort(SerialPort serialPort) {
+        this.serialPort = serialPort;
+    }
+
+    public String getPort() {
+        return port;
+    }
+
+    public void setPort(String port) {
+        this.port = port;
+    }
+
+    public void setBaudRate(Integer baudRate) {
+        this.baudRate = baudRate;
+    }
+
+    public void setDataBits(Integer dataBits) {
+        this.dataBits = dataBits;
+    }
+
+    public void setStopBits(Integer stopBits) {
+        this.stopBits = stopBits;
+    }
+
+    public void setParity(Integer parity) {
+        this.parity = parity;
+    }
+
+    public void setFlowControlIn(Integer flowControlIn) {
+        this.flowControlIn = flowControlIn;
+    }
+
+    public void setFlowControlOut(Integer flowControlOut) {
+        this.flowControlOut = flowControlOut;
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/waterdept/ModbusWaterDeptUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/waterdept/ModbusWaterDeptUtils.java
new file mode 100644
index 0000000..29c5ee5
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/waterdept/ModbusWaterDeptUtils.java
@@ -0,0 +1,128 @@
+package com.ruoyi.fuzhou.utils.waterdept;
+
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.fuzhou.utils.hj1239.StringToHexUtil;
+import org.apache.ibatis.executor.ExecutorException;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+
+/**
+ * 姘存繁鏁版嵁鎺ュ叆
+ */
+public class ModbusWaterDeptUtils {
+
+    public static void main(String[] args) {
+        String value = getDept("0.0.0.0", 8320);
+        System.out.println(value);
+    }
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     */
+    public static String getDept(String ip, int port) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;// 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;// 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream()) {
+                // 鎺ユ敹璁惧鍝嶅簲
+                while (true) {
+                    byte[] response = new byte[1024];
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                        return null;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                    System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + StringToHexUtil.convertHexToString(resultData));
+                }
+                //return StringToHex.convertHexToString(resultData);
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     */
+    public static String getWaterDept(String ip, int port) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;// 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;// 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾按娣辨鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream()) {
+                // 鎺ユ敹璁惧鍝嶅簲
+                    byte[] response = new byte[1024];
+                    int bytesRead = inputStream.read(response);
+                    if (bytesRead == -1) {
+                        System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                        return null;
+                    }
+                    // 鎵撳嵃鍝嶅簲鏁版嵁
+                    byte[] responseData = new byte[bytesRead];
+                    System.arraycopy(response, 0, responseData, 0, bytesRead);
+                    String resultData = bytesToHex(responseData);
+                return resultData;
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                    throw new ServiceException("璁惧涓嶅湪绾�");
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/FloatInverseWaterParser.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/FloatInverseWaterParser.java
new file mode 100644
index 0000000..23851e2
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/FloatInverseWaterParser.java
@@ -0,0 +1,61 @@
+package com.ruoyi.fuzhou.utils.watermodbus;
+
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+
+public class FloatInverseWaterParser {
+
+    public static void main(String[] args) {
+        // 绀轰緥杈撳叆锛�8浣嶅崄鍏繘鍒跺瓧绗︿覆锛團loatInverse鏍煎紡锛�
+        String hexString = "0005"; // 鍙嶈浆鍚庣殑瀛楄妭椤哄簭锛岃〃绀烘诞鐐规暟 3.14
+        byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(hexString);
+        byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes);
+        float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+        System.out.println("3鍊间负" + floatValue);
+    }
+
+    /**
+     * 灏嗗崄鍏繘鍒跺瓧绗︿覆杞崲涓哄瓧鑺傛暟缁�
+     */
+    public static byte[] hexStringToByteArray(String s) {
+        int len = s.length();
+        if (len % 2 != 0) {
+            throw new IllegalArgumentException("鍗佸叚杩涘埗瀛楃涓查暱搴﹀繀椤讳负鍋舵暟銆�");
+        }
+        byte[] data = new byte[len / 2];
+        for (int i = 0; i < len; i += 2) {
+            int high = Character.digit(s.charAt(i), 16) << 4;
+            int low = Character.digit(s.charAt(i + 1), 16);
+            if (high == -1 || low == -1) {
+                throw new IllegalArgumentException("鍖呭惈鏃犳晥鐨勫崄鍏繘鍒跺瓧绗�: " + s);
+            }
+            data[i / 2] = (byte) (high + low);
+        }
+        return data;
+    }
+
+    /**
+     * 鍙嶈浆瀛楄妭鏁扮粍
+     */
+    public static byte[] reverseByteArray(byte[] bytes) {
+        byte[] reversed = new byte[bytes.length];
+        for (int i = 0; i < bytes.length; i++) {
+            reversed[i] = bytes[bytes.length - 1 - i];
+        }
+        return reversed;
+    }
+
+    /**
+     * 灏嗗瓧鑺傛暟缁勮В鏋愪负娴偣鏁�
+     *
+     * @param bytes 瀛楄妭鏁扮粍锛堝繀椤讳负4瀛楄妭锛�
+     * @param order 瀛楄妭椤哄簭锛堝ぇ绔垨灏忕锛�
+     */
+    public static float parseAsFloat(byte[] bytes, ByteOrder order) {
+        if (bytes.length != 4) {
+            throw new IllegalArgumentException("瀛楄妭鏁扮粍闀垮害蹇呴』涓�4瀛楄妭銆�");
+        }
+        ByteBuffer buffer = ByteBuffer.wrap(bytes).order(order);
+        return buffer.getFloat();
+    }
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/ModbusWaterUtils.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/ModbusWaterUtils.java
new file mode 100644
index 0000000..d57c5a6
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/utils/watermodbus/ModbusWaterUtils.java
@@ -0,0 +1,296 @@
+package com.ruoyi.fuzhou.utils.watermodbus;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.ruoyi.fuzhou.domain.ReceiveWaterInfo;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.utils.electricitymodbus.HexStringToInt;
+import com.ruoyi.fuzhou.utils.oilmodbus.Crc16Utils;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.ServerSocket;
+import java.net.Socket;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.util.List;
+
+
+/**
+ * 姘磋〃璁惧鏁版嵁鎺ュ叆
+ */
+public class ModbusWaterUtils {
+    public static void main(String[] args) {
+        //鍒╁拰娌硅澶�
+        //String value = getValue("10.3.10.201", 8137, (byte) 2, (byte) 0x03, 22, 2, 10,"");
+        String value = getValue("0.0.0.0", 8136, (byte) 1, (byte) 0x04, 4120, 2, 2, "鏁存暟");
+
+    }
+
+    /**
+     * @param ip   ip
+     * @param port 绔彛
+     * @param list 鏌ヨ椤瑰垪琛�
+     */
+    public static JSONObject getValue(String ip, int port, List<ReceiveWaterInfo> list) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;// 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;// 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(4000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                JSONObject jsonObject = new JSONObject();
+                for (ReceiveWaterInfo info : list
+                ) {
+                    if (!"createTime".equals(info.getParamCode())) {
+                        // 鏋勯�犺姹傚抚
+                        ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                        if (info.getDeviceAddress() != 0) {
+                            requestBuffer.put(info.getDeviceAddress());  // 璁惧鍦板潃
+                        }
+                        if (info.getFunctionCode() != 0) {
+                            requestBuffer.put(info.getFunctionCode());  // 鍔熻兘鐮�
+                        }
+                        if (info.getRegisterAdress() != 0) {
+                            requestBuffer.putShort((short) info.getRegisterAdress().intValue());  // 瀵勫瓨鍣ㄥ湴鍧�
+                        }
+                        if (info.getRegisterCount() != 0) {
+                            requestBuffer.putShort((short) info.getRegisterCount().intValue());  // 瀵勫瓨鍣ㄦ暟閲�
+                        }
+                        // 璁$畻CRC鏍¢獙鐮�
+                        byte[] requestData = requestBuffer.array();
+                        String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                        int decimal = Integer.parseInt(hex, 16);
+                        requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                        // 鍙戦�佽姹傚抚
+                        outputStream.write(requestBuffer.array());
+                        System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                        // 鎺ユ敹璁惧鍝嶅簲
+                        byte[] response = new byte[1024];
+                        int bytesRead = inputStream.read(response);
+                        if (bytesRead == -1) {
+                            System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                            continue;
+                        }
+                        // 鎵撳嵃鍝嶅簲鏁版嵁
+                        byte[] responseData = new byte[bytesRead];
+                        System.arraycopy(response, 0, responseData, 0, bytesRead);
+                        String resultData = bytesToHex(responseData);
+                        System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                        // 妫�鏌ュ搷搴旈暱搴�
+                        if (responseData.length <= 5) {
+                            System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                            continue;
+                        }
+                        //鍔熻兘鐮�
+                        byte responseFunctionCode = responseData[1];
+                        //鏁版嵁瀛楄妭鏁�
+                        byte byteCount = responseData[2];
+                        byte[] data = new byte[byteCount];
+                        System.arraycopy(responseData, 3, data, 0, byteCount);
+                        byte[] crcReceived = new byte[2];
+                        System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                        // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                        if ((responseFunctionCode & 0x80) != 0) {
+                            byte errorCode = responseData[2];  // 閿欒鐮�
+                            System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                            continue;
+                        }
+                        if (DataTypeEnum.WATER_FLOW.getCode().equals(info.getDataType())) {
+                            String src = resultData.substring(6, 6 + byteCount * 2);
+                            if (info.getParam().contains("鏁存暟")) {
+                                long value = HexStringToInt.hexStringToInt(src);
+                                jsonObject.put(info.getParamCode(), String.valueOf(value));
+                                System.out.println(info.getParam() + "鐨勫�间负" + value + info.getUnit());
+                            } else if (src.length() == 8) {
+                                byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(src);
+                                // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                                byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes);
+                                float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+                                jsonObject.put(info.getParamCode(), String.valueOf(floatValue));
+                                System.out.println(info.getParam() + "鐨勫�间负" + floatValue + info.getUnit());
+                            } else {
+                                long value = HexStringToInt.hexStringToInt(src);
+                                jsonObject.put(info.getParamCode(), String.valueOf(value));
+                                System.out.println(info.getParam() + "鐨勫�间负" + value + info.getUnit());
+                            }
+                        } else if (DataTypeEnum.WATER_YA.getCode().equals(info.getDataType())) {
+                            byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(resultData.substring(6, 14));
+                            // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                            byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes);
+                            float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+                            jsonObject.put(info.getParamCode(), String.valueOf(String.format("%.3f",floatValue)));
+                        }
+                    }
+                }
+                return jsonObject;
+            } catch (Exception e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (Exception e) {
+            System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+        } finally {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�");
+                    serverSocket.close();
+                } catch (Exception ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            }
+        }
+        return null;
+    }
+
+
+    /**
+     * @param ip              ip
+     * @param port            绔彛
+     * @param address         鍦板潃鐮�
+     * @param functionCode    鍔熻兘鐮�
+     * @param registerAddress 瀵勫瓨鍣ㄥ湴鍧�
+     * @param registerCount   瀵勫瓨鍣ㄦ暟閲�
+     */
+    public static String getValue(String ip, int port, byte address, byte functionCode, int registerAddress, int registerCount, int dataType, String ss) {
+        // 鏈嶅姟绔厤缃�
+        String SERVER_IP = ip;// 鐩戝惉鎵�鏈夌綉缁滄帴鍙�
+        int SERVER_PORT = port;// 绔彛鍙�
+        ServerSocket serverSocket = null;
+        try {
+            serverSocket = new ServerSocket(SERVER_PORT);
+            System.out.println("馃洝锔� 鏈嶅姟绔凡鍚姩锛屾鍦ㄧ洃鍚� " + SERVER_IP + ":" + SERVER_PORT + "...");
+            serverSocket.setSoTimeout(8000);
+            Socket clientSocket = serverSocket.accept();
+            System.out.println("馃攲 瀹㈡埛绔凡杩炴帴: " + clientSocket.getInetAddress().getHostAddress() + ":" + clientSocket.getPort());
+            try (InputStream inputStream = clientSocket.getInputStream();
+                 OutputStream outputStream = clientSocket.getOutputStream()) {
+                // 鏋勯�犺姹傚抚
+                ByteBuffer requestBuffer = ByteBuffer.allocate(8);
+                if (address != 0) {
+                    requestBuffer.put(address);  // 璁惧鍦板潃
+                }
+                if (functionCode != 0) {
+                    requestBuffer.put(functionCode);  // 鍔熻兘鐮�
+                }
+                if (registerAddress != 0) {
+                    requestBuffer.putShort((short) registerAddress);  // 瀵勫瓨鍣ㄥ湴鍧�
+                }
+                if (registerCount != 0) {
+                    requestBuffer.putShort((short) registerCount);  // 瀵勫瓨鍣ㄦ暟閲�
+                }
+                // 璁$畻CRC鏍¢獙鐮�
+                byte[] requestData = requestBuffer.array();
+                String hex = Crc16Utils.makeCRC(Crc16Utils.bytesToHex(requestData).substring(0, Crc16Utils.bytesToHex(requestData).length() - 4), true);
+                int decimal = Integer.parseInt(hex, 16);
+                requestBuffer.putShort((short) decimal);  // CRC鏍¢獙鐮�
+                // 鍙戦�佽姹傚抚
+                outputStream.write(requestBuffer.array());
+                System.out.println("馃摛 宸插彂閫� MODBUS 璇锋眰: " + bytesToHex(requestBuffer.array()));
+                // 鎺ユ敹璁惧鍝嶅簲
+                byte[] response = new byte[1024];
+                int bytesRead = inputStream.read(response);
+                if (bytesRead == -1) {
+                    System.out.println("鉂� 鏈敹鍒拌澶囧搷搴�");
+                    return null;
+                }
+                // 鎵撳嵃鍝嶅簲鏁版嵁
+                byte[] responseData = new byte[bytesRead];
+                System.arraycopy(response, 0, responseData, 0, bytesRead);
+                String resultData = bytesToHex(responseData);
+                System.out.println("馃摜 鏀跺埌璁惧鍝嶅簲: " + resultData);
+                // 妫�鏌ュ搷搴旈暱搴�
+                if (responseData.length <= 5) {
+                    System.out.println("鉂� 鏃犳晥鐨勫搷搴旈暱搴�: " + responseData.length + " 瀛楄妭");
+                    return null;
+                }
+                //鍔熻兘鐮�
+                byte responseFunctionCode = responseData[1];
+                //鏁版嵁瀛楄妭鏁�
+                byte byteCount = responseData[2];
+                byte[] data = new byte[byteCount];
+                System.arraycopy(responseData, 3, data, 0, byteCount);
+                byte[] crcReceived = new byte[2];
+                System.arraycopy(responseData, responseData.length - 2, crcReceived, 0, 2);
+                // 妫�鏌ユ槸鍚︿负閿欒鍝嶅簲锛堝姛鑳界爜 + 0x80锛�
+                if ((responseFunctionCode & 0x80) != 0) {
+                    byte errorCode = responseData[2];  // 閿欒鐮�
+                    System.out.println("鉂� 璁惧杩斿洖閿欒鍝嶅簲锛岄敊璇爜: " + errorCode);
+                    return null;
+                }
+                if (DataTypeEnum.WATER_FLOW.getCode().equals(dataType)) {
+                    String src = resultData.substring(6, 6 + byteCount * 2);
+                    if (ss.contains("鏁存暟")) {
+                        long value = HexStringToInt.hexStringToInt(src);
+                        System.out.println("2鍊间负" + value);
+                    } else if (src.length() == 8) {
+                        byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(src);
+                        // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                        byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes);
+                        float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+                        System.out.println("1鍊间负" + floatValue);
+                    } else {
+                        long value = HexStringToInt.hexStringToInt(src);
+                        System.out.println("3鍊间负" + value);
+                    }
+                } else if (DataTypeEnum.WATER_YA.getCode().equals(dataType)) {
+                    byte[] bytes = FloatInverseWaterParser.hexStringToByteArray(resultData.substring(6, 14));
+                    // 瑙f瀽涓烘诞鐐规暟锛堝ぇ绔瓧鑺傞『搴忥級
+                    byte[] reversedBytes = FloatInverseWaterParser.reverseByteArray(bytes);
+                    float floatValue = FloatInverseWaterParser.parseAsFloat(reversedBytes, ByteOrder.LITTLE_ENDIAN);
+                    System.out.println(floatValue);
+                }
+            } catch (IOException e) {
+                System.out.println("鈿狅笍 瀹㈡埛绔紓甯告柇寮�: " + e.getMessage());
+            } finally {
+                clientSocket.close();
+            }
+        } catch (IOException e) {
+            if (serverSocket != null) {
+                try {
+                    System.out.println("璁惧涓嶅湪绾�" + e.getMessage());
+                    serverSocket.close();
+                } catch (IOException ex) {
+                    System.out.println("鉂� 鏈嶅姟绔叧闂け璐�: " + ex.getMessage());
+                }
+            } else {
+                System.out.println("鉂� 鏈嶅姟绔惎鍔ㄥけ璐�: " + e.getMessage());
+            }
+        }
+        return null;
+    }
+
+    // 灏嗗瓧鑺傛暟缁勮浆鎹负鍗佸叚杩涘埗瀛楃涓�
+    public static String bytesToHex(byte[] bytes) {
+        StringBuilder sb = new StringBuilder();
+        for (byte b : bytes) {
+            sb.append(String.format("%02X", b));
+        }
+        return sb.toString();
+    }
+
+    // CRC16 璁$畻
+    public static int crc16(byte[] data) {
+        int crc = 0xFFFF;
+        for (byte b : data) {
+            crc ^= (b & 0xFF);
+            for (int i = 0; i < 8; i++) {
+                if ((crc & 0x0001) != 0) {
+                    crc >>= 1;
+                    crc ^= 0xA001;
+                } else {
+                    crc >>= 1;
+                }
+            }
+        }
+        return crc;
+    }
+}
+
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketOilServer.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketOilServer.java
new file mode 100644
index 0000000..136e8e4
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketOilServer.java
@@ -0,0 +1,304 @@
+package com.ruoyi.fuzhou.websocket;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import jakarta.websocket.*;
+import jakarta.websocket.server.PathParam;
+import jakarta.websocket.server.ServerEndpoint;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.context.ApplicationContext;
+import org.springframework.context.ApplicationContextAware;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.Iterator;
+import java.util.List;
+import java.util.concurrent.*;
+
+//@ServerEndpoint("/dp/sendOil/{userId}")
+//@Component
+public class WebSocketOilServer implements ApplicationContextAware {
+    private final static Logger log = LoggerFactory.getLogger(WebSocketOilServer.class);
+    /**
+     * 鍦ㄧ嚎浜烘暟
+     */
+    private static int onlineCount = 0;
+    /**
+     * 鍦ㄧ嚎浜哄憳session
+     */
+    private static ConcurrentHashMap<String, WebSocketOilServer> webSocketMap = new ConcurrentHashMap<>();
+    /**
+     * 涓庢煇涓鎴风鐨勮繛鎺ヤ細璇濓紝闇�瑕侀�氳繃瀹冩潵缁欏鎴风鍙戦�佹暟鎹�
+     */
+    private Session session;
+    /**
+     * 鎺ユ敹userId
+     */
+    private String userId = "";
+
+    //瀹氭椂浠诲姟
+    private ScheduledExecutorService scheduler;
+    //娉婁綅ID
+    private Integer beId = 0;
+    private static final Object lock = new Object();
+
+    private static ApplicationContext context;
+
+    @Override
+    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
+        context = applicationContext;
+    }
+    public static <T> T getBean(Class<T> beanClass){
+        return context.getBean(beanClass);
+    }
+
+
+//    private EquipmentService equipmentService;
+//    private ReceiveOilValueService receiveOilValueService;
+//    private ReceiveWaterValueService receiveWaterValueService;
+//    private ReceiveElectricityValueService receiveElectricityValueService;
+//    private DpRfidTaskService dpRfidTaskService;
+//    private DpRfidVehicleService dpRfidVehicleService;
+
+
+    /**
+     * 杩炴帴寤虹珛鎴愬姛璋冪敤鐨勬柟娉�
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("userId") String userId) {
+        this.session = session;
+        this.userId = userId;
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+            webSocketMap.put(userId, this);
+            //鍔犲叆set涓�
+        } else {
+            webSocketMap.put(userId, this);
+        }
+        try {
+            sendMessage("杩炴帴鎴愬姛");
+        } catch (IOException e) {
+            log.error("鐢ㄦ埛:" + userId + ",缃戠粶寮傚父!!!!!!");
+        }
+
+    }
+
+    /**
+     * 杩炴帴鍏抽棴璋冪敤鐨勬柟娉�
+     */
+    @OnClose
+    public void onClose() {
+        if(scheduler != null){
+            scheduler.shutdown();
+        }
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+        }
+    }
+
+
+    /**
+     * 鏀跺埌瀹㈡埛绔秷鎭悗璋冪敤鐨勬柟娉�
+     *
+     * @param message 瀹㈡埛绔彂閫佽繃鏉ョ殑娑堟伅
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        JSONObject beObject = JSONObject.parseObject(message);
+        String type = beObject.getString("type");
+        try {
+            if(!type.isEmpty()){
+                sendMessage(type);
+//            beId = Integer.parseInt(beObject.getString("beId"));
+//            if(!type.isEmpty() && type.equals("startSupply") && beId != null && beId != 0){
+//                //鍒涘缓瀹氭椂浠诲姟
+//                scheduler = Executors.newSingleThreadScheduledExecutor();
+//                //姣�10绉掓墽琛屼竴娆�
+//                scheduler.scheduleAtFixedRate(()->{
+//                            try {
+//                                synchronized (lock){
+//                                    if(session !=null && session.isOpen()){
+//                                        JSONObject jsonObject = new JSONObject();
+//                                        jsonObject.put("type","Supply");
+//                                        EquipmentService equipmentService = getBean(EquipmentService.class);
+//                                        LambdaQueryWrapper<DpEquipment> oilWrapper = new LambdaQueryWrapper<>();
+//                                        oilWrapper.eq(DpEquipment::getBeId,beId)
+//                                                .in(DpEquipment::getEquipmentTypeId,DataTypeEnum.LIJIUOIL.getCode(),DataTypeEnum.OIL.getCode(),DataTypeEnum.LIJIUJUN.getCode())
+//                                                .orderByAsc(DpEquipment::getId);
+//                                        List<DpEquipment> oilList = equipmentService.list(oilWrapper);
+//                                        JSONArray oilArray = new JSONArray();
+//                                        for (DpEquipment dpEquipment:oilList){
+//                                            ReceiveOilValue oilValue = (ReceiveOilValue) equDataList(dpEquipment.getId());
+//                                            if(oilValue != null){
+//                                                oilValue.setId(dpEquipment.getId().longValue());
+//                                            }
+//                                            oilArray.add(oilValue);
+//                                        }
+//                                        jsonObject.put("oil",oilArray);
+//
+//                                        LambdaQueryWrapper<DpEquipment> waterWrapper = new LambdaQueryWrapper<>();
+//                                        waterWrapper.eq(DpEquipment::getBeId,beId)
+//                                                .eq(DpEquipment::getEquipmentTypeId,2)
+//                                                .orderByAsc(DpEquipment::getId);
+//                                        List<DpEquipment> waterList = equipmentService.list(waterWrapper);
+//                                        JSONArray waterArray = new JSONArray();
+//                                        for (DpEquipment dpEquipment:waterList){
+//                                            ReceiveWaterValue waterValue = (ReceiveWaterValue) equDataList(dpEquipment.getId());
+//                                            if(waterValue != null){
+//                                                waterValue.setId(dpEquipment.getId().longValue());
+//                                            }
+//                                            waterArray.add(waterValue);
+//                                        }
+//                                        jsonObject.put("water",waterArray);
+//
+//                                        LambdaQueryWrapper<DpEquipment> elecWrapper = new LambdaQueryWrapper<>();
+//                                        elecWrapper.eq(DpEquipment::getBeId,beId)
+//                                                .eq(DpEquipment::getEquipmentTypeId,3)
+//                                                .orderByAsc(DpEquipment::getId);
+//                                        List<DpEquipment> elecList = equipmentService.list(elecWrapper);
+//                                        JSONArray elecArray = new JSONArray();
+//                                        for (DpEquipment dpEquipment:elecList){
+//                                            ReceiveElectricityValue electricityValue = (ReceiveElectricityValue)equDataList(dpEquipment.getId());
+//                                            if(electricityValue != null){
+//                                                electricityValue.setId(dpEquipment.getId().longValue());
+//                                            }
+//                                            elecArray.add(electricityValue);
+//                                        }
+//                                        jsonObject.put("elec",elecArray);
+//
+//                                        DpRfidTaskService dpRfidTaskService = getBean(DpRfidTaskService.class);
+//                                        LambdaQueryWrapper<DpRfidTask> rfidTaskWrapper = new LambdaQueryWrapper<>();
+//                                        rfidTaskWrapper.orderByDesc(DpRfidTask::getCreateTime).last("LIMIT 1");
+//                                        List<DpRfidTask> rfidTaskList = dpRfidTaskService.list(rfidTaskWrapper);
+//                                        DpRfidTask dpRfidTask = rfidTaskList.get(0);
+//                                        JSONArray jsonArray = JSON.parseArray(dpRfidTask.getGoodsList().toString());
+//                                        JSONObject goods = jsonArray.getJSONObject(0);
+//                                        String rfidNum = goods.getString("rfid");
+//                                        jsonObject.put("RFID_Task",rfidTaskList);
+//
+//                                        DpRfidVehicleService dpRfidVehicleService = getBean(DpRfidVehicleService.class);
+//                                        LambdaQueryWrapper<DpRfidVehicle> rfidVehicleWrapper = new LambdaQueryWrapper<>();
+//                                        rfidVehicleWrapper.eq(DpRfidVehicle::getRfidNum,rfidNum)
+//                                                .orderByDesc(DpRfidVehicle::getPassTime).last("LIMIT 1");
+//                                        List<DpRfidVehicle> rfidVehicleList = dpRfidVehicleService.list(rfidVehicleWrapper);
+//                                        jsonObject.put("RFID_Vehicle",rfidVehicleList);
+//
+//                                        sendMessage(jsonObject.toString());
+//
+//                                    }
+//                                }
+//                            }catch (Exception e){
+//                                e.printStackTrace();
+//                            }
+//                        },0,10, TimeUnit.SECONDS
+//
+//                );
+            }else if(type.equals("endSupply")){
+                onClose();
+            }
+            else {
+                sendMessage("浼犲弬澶辫触");
+            }
+
+        } catch (Exception e) {
+            log.error("蹇冭烦澶辫触锛屽鎴风宸叉柇绾�", e);
+        }
+    }
+
+    /**
+     * @param session
+     * @param error
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("鐢ㄦ埛閿欒:" + this.userId + ",鍘熷洜:" + error.getMessage());
+        error.printStackTrace();
+    }
+
+    /**
+     * 瀹炵幇鏈嶅姟鍣ㄤ富鍔ㄦ帹閫�
+     */
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+
+    /**
+     * 鍙戦�佽嚜瀹氫箟娑堟伅
+     */
+    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
+        log.info("鍙戦�佹秷鎭埌:" + userId + "锛屾姤鏂�:" + message);
+        if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
+            webSocketMap.get(userId).sendMessage(message);
+        } else {
+            log.error("鐢ㄦ埛" + userId + ",涓嶅湪绾匡紒");
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketOilServer.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketOilServer.onlineCount--;
+    }
+
+    /**
+     * 瀹炵幇鏈嶅姟鍣ㄤ富鍔ㄦ帹閫�
+     */
+    public static void sendAllMessage(String message) {
+        Iterator<String> key = webSocketMap.keys().asIterator();
+        while (key.hasNext()) {
+            String strList = (String) key.next();
+            try {
+                log.info(strList);
+                webSocketMap.get(strList).sendMessage(message);
+            } catch (Exception e) {
+                e.printStackTrace();
+                log.error("鎺ㄩ�佸け璐ワ紒", e);
+            }
+        }
+    }
+
+//    public Object equDataList(Integer id){
+//        EquipmentService equipmentService = getBean(EquipmentService.class);
+//        ReceiveOilValueService receiveOilValueService = getBean(ReceiveOilValueService.class);
+//        ReceiveWaterValueService receiveWaterValueService = getBean(ReceiveWaterValueService.class);
+//        ReceiveElectricityValueService receiveElectricityValueService = getBean(ReceiveElectricityValueService.class);
+//        DpEquipment receiveInfo = equipmentService.getById(id);
+//        if (receiveInfo == null) {
+//            return new Object();
+//        }
+//        if (DataTypeEnum.LIJIUOIL.getCode().equals(receiveInfo.getEquSeType()) || DataTypeEnum.OIL.getCode().equals(receiveInfo.getEquSeType())) {
+//            return receiveOilValueService.getOne(new LambdaQueryWrapper<ReceiveOilValue>() {{
+//                or().eq(ReceiveOilValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+//                        .orderByDesc(ReceiveOilValue::getCreateTime).last("LIMIT 1");
+//            }});
+//        } else if (DataTypeEnum.WATER_FLOW.getCode().equals(receiveInfo.getEquSeType()) || DataTypeEnum.WATER_YA.getCode().equals(receiveInfo.getEquSeType())
+//                || DataTypeEnum.WATER_DEPT.getCode().equals(receiveInfo.getEquSeType())) {
+//            return receiveWaterValueService.getOne(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+//                or().eq(ReceiveWaterValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+//                        .orderByDesc(ReceiveWaterValue::getCreateTime).last("LIMIT 1");
+//            }});
+//        } else if (DataTypeEnum.ELECTRICITY.getCode().equals(receiveInfo.getEquSeType())) {
+//            return receiveElectricityValueService.getOne(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+//                or().eq(ReceiveElectricityValue::getDeviceName, String.valueOf(receiveInfo.getId()))
+//                        .orderByDesc(ReceiveElectricityValue::getCreateTime).last("LIMIT 1");
+//            }});
+//        }
+//        return new Object();
+//    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketServer.java b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketServer.java
new file mode 100644
index 0000000..aa0be24
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/java/com/ruoyi/fuzhou/websocket/WebSocketServer.java
@@ -0,0 +1,132 @@
+package com.ruoyi.fuzhou.websocket;
+
+import jakarta.websocket.*;
+import jakarta.websocket.server.PathParam;
+import jakarta.websocket.server.ServerEndpoint;
+import org.apache.commons.lang3.StringUtils;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Component;
+
+import java.io.IOException;
+import java.util.concurrent.ConcurrentHashMap;
+
+@ServerEndpoint("/sendInfo/{userId}")
+@Component
+public class WebSocketServer {
+    private final static Logger log = LoggerFactory.getLogger(WebSocketServer.class);
+    /**
+     * 鍦ㄧ嚎浜烘暟
+     */
+    private static int onlineCount = 0;
+    /**
+     * 鍦ㄧ嚎浜哄憳session
+     */
+    private static ConcurrentHashMap<String, WebSocketServer> webSocketMap = new ConcurrentHashMap<>();
+    /**
+     * 涓庢煇涓鎴风鐨勮繛鎺ヤ細璇濓紝闇�瑕侀�氳繃瀹冩潵缁欏鎴风鍙戦�佹暟鎹�
+     */
+    private Session session;
+    /**
+     * 鎺ユ敹userId
+     */
+    private String userId = "";
+
+    /**
+     * 杩炴帴寤虹珛鎴愬姛璋冪敤鐨勬柟娉�
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("userId") String userId) {
+        this.session = session;
+        this.userId = userId;
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+            webSocketMap.put(userId, this);
+            //鍔犲叆set涓�
+        } else {
+            webSocketMap.put(userId, this);
+            //鍔犲叆set涓�
+            addOnlineCount();
+            //鍦ㄧ嚎鏁板姞1
+        }
+
+        log.info("鐢ㄦ埛杩炴帴:" + userId + ",褰撳墠鍦ㄧ嚎浜烘暟涓�:" + getOnlineCount());
+
+        try {
+            sendMessage("杩炴帴鎴愬姛");
+        } catch (IOException e) {
+            log.error("鐢ㄦ埛:" + userId + ",缃戠粶寮傚父!!!!!!");
+        }
+    }
+
+    /**
+     * 杩炴帴鍏抽棴璋冪敤鐨勬柟娉�
+     */
+    @OnClose
+    public void onClose() {
+        if (webSocketMap.containsKey(userId)) {
+            webSocketMap.remove(userId);
+            //浠巗et涓垹闄�
+            subOnlineCount();
+        }
+        log.info("鐢ㄦ埛閫�鍑�:" + userId + ",褰撳墠鍦ㄧ嚎浜烘暟涓�:" + getOnlineCount());
+    }
+
+    /**
+     * 鏀跺埌瀹㈡埛绔秷鎭悗璋冪敤鐨勬柟娉�
+     *
+     * @param message 瀹㈡埛绔彂閫佽繃鏉ョ殑娑堟伅
+     */
+    @OnMessage
+    public void onMessage(String message, Session session) {
+        log.info("鐢ㄦ埛娑堟伅:" + userId + ",鎶ユ枃:" + message);
+        try {
+            sendInfo(message, userId);
+        } catch (Exception e) {
+            log.error("蹇冭烦澶辫触锛屽鎴风宸叉柇绾�", e);
+        }
+    }
+
+    /**
+     * @param session
+     * @param error
+     */
+    @OnError
+    public void onError(Session session, Throwable error) {
+        log.error("鐢ㄦ埛閿欒:" + this.userId + ",鍘熷洜:" + error.getMessage());
+        error.printStackTrace();
+    }
+
+    /**
+     * 瀹炵幇鏈嶅姟鍣ㄤ富鍔ㄦ帹閫�
+     */
+    public void sendMessage(String message) throws IOException {
+        this.session.getBasicRemote().sendText(message);
+    }
+
+
+    /**
+     * 鍙戦�佽嚜瀹氫箟娑堟伅
+     */
+    public static void sendInfo(String message, @PathParam("userId") String userId) throws IOException {
+        log.info("鍙戦�佹秷鎭埌:" + userId + "锛屾姤鏂�:" + message);
+        if (StringUtils.isNotBlank(userId) && webSocketMap.containsKey(userId)) {
+            webSocketMap.get(userId).sendMessage(message);
+        } else {
+            log.error("鐢ㄦ埛" + userId + ",涓嶅湪绾匡紒");
+        }
+    }
+
+    public static synchronized int getOnlineCount() {
+        return onlineCount;
+    }
+
+    public static synchronized void addOnlineCount() {
+        WebSocketServer.onlineCount++;
+    }
+
+    public static synchronized void subOnlineCount() {
+        WebSocketServer.onlineCount--;
+    }
+
+}
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/DpRfidTaskMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/DpRfidTaskMapper.xml
new file mode 100644
index 0000000..e3639ef
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/DpRfidTaskMapper.xml
@@ -0,0 +1,14 @@
+<?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.fuzhou.mapper.DpRfidTaskMapper">
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_RFID_TASK
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.fuzhou.domain.DpRfidTask">
+        select * from DP_RFID_TASK
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/DpRfidVehicleMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/DpRfidVehicleMapper.xml
new file mode 100644
index 0000000..5e265dc
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/DpRfidVehicleMapper.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.DpRfidVehicleMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.DpRfidVehicle">
+        <id column="ID" property="id" />
+        <result column="NODE_NAME" property="nodeName" />
+        <result column="NODE_NUM" property="nodeNum" />
+        <result column="PASS_TIME" property="passTime" />
+        <result column="RFID_NUM" property="rfidNum" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, NODE_NAME, NODE_NUM, PASS_TIME, RFID_NUM
+    </sql>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_RFID_VEHICLE
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.fuzhou.domain.DpRfidVehicle">
+        select * from DP_RFID_VEHICLE
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+    <select id="selectRfidVehicle" parameterType="com.ruoyi.fuzhou.domain.vo.RfidVehicleVO" resultType="com.ruoyi.fuzhou.domain.DpRfidVehicle">
+        select * from DP_RFID_VEHICLE
+        <where>
+            <if test="startTime!=null and startTime!='' ">
+                and PASS_TIME <![CDATA[>=]]> #{startTime}
+            </if>
+            <if test="endTime!=null and endTime!='' ">
+                and PASS_TIME <![CDATA[<=]]> #{endTime}
+            </if>
+            <if test="terminalId!=null and terminalId!='' ">
+                and NODE_NUM = #{nodeNum}
+            </if>
+        </where>
+        order by PASS_TIME DESC
+    </select>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/EquipmentMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/EquipmentMapper.xml
new file mode 100644
index 0000000..b2d203f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/EquipmentMapper.xml
@@ -0,0 +1,128 @@
+<?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.fuzhou.mapper.EquipmentMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.DpEquipment">
+        <id column="ID" property="id" />
+        <result column="BE_ID" property="beId" />
+        <result column="EQU_NAME" property="equName" />
+        <result column="PROTOCOL" property="protocol" />
+        <result column="EQU_SE_TYPE" property="equSeType" />
+        <result column="PERIOD_TIME" property="periodTime" />
+        <result column="INTERVAL_TIME" property="intervalTime" />
+        <result column="WH_ID" property="whId" />
+        <result column="X" property="x" />
+        <result column="Y" property="y" />
+        <result column="Z" property="z" />
+        <result column="FIELD_NAME" property="fieldName" />
+        <result column="EQUIPMENT_TYPE_ID" property="equipmentTypeId" />
+    </resultMap>
+
+
+    <delete id="deleteBy">
+        delete from DP_EQUIPMENT where wh_id in (select wh_id from DP_BERTH where be_id = #{beId})
+    </delete>
+    <select id="getTotal" resultType="java.lang.Long">
+        select count(1) from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        <where>
+            <if test="beId != null and beId != ''">
+                and a.BE_ID = #{beId}
+            </if>
+            <if test="whId != null and whId != ''">
+                and b.pkId = #{whId}
+            </if>
+            <if test="equName != null and equName != ''">
+                and a.EQU_NAME like concat('%',#{equName},'%')
+            </if>
+        </where>
+    </select>
+
+    <select id="getListByBeId" resultType="com.ruoyi.fuzhou.domain.vo.DpEquipmentVO">
+        select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as equtype,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        <where>
+            <if test="beId != null and beId != ''">
+                and a.BE_ID = #{beId}
+            </if>
+        </where>
+    </select>
+
+    <select id="getListByWhId" resultType="com.ruoyi.fuzhou.domain.vo.DpEquipmentVO">
+        select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as equtype,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        <where>
+            <if test="whId != null and whId != ''">
+                and b.pkId = #{whId}
+            </if>
+        </where>
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.fuzhou.domain.vo.DpEquipmentVO">
+        select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as typeName,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        <where>
+            <if test="beId != null and beId != ''">
+                and a.BE_ID = #{beId}
+            </if>
+            <if test="whId != null and whId != ''">
+                and b.pkId = #{whId}
+            </if>
+            <if test="equipmentTypeId != null and equipmentTypeId != ''">
+                and d.ID = #{equipmentTypeId}
+            </if>
+            <if test="equName != null and equName != ''">
+                and a.EQU_NAME like concat('%',#{equName},'%')
+            </if>
+        </where>
+        order by a.ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+    <select id="queryById" resultType="com.ruoyi.fuzhou.domain.vo.DpEquipmentVO">
+        select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as equtype,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        where a.ID = #{id}
+    </select>
+
+    <select id="getListByBeIdTypeId" resultType="com.ruoyi.fuzhou.domain.vo.DpEquipmentVO">
+        select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as equtype,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        <where>
+            <if test="beId != null and beId != ''">
+                and a.BE_ID = #{beId}
+            </if>
+<!--            <if test="typeId != null and typeId != ''">-->
+<!--                and a.EQUIPMENT_TYPE_ID = #{typeId}-->
+<!--            </if>-->
+            <if test="typeIds !=null and typeIds.size() > 0">
+                and a.EQUIPMENT_TYPE_ID in
+                <foreach item="typeId" collection="typeIds" open="(" separator="," close=")">
+                    #{typeId}
+                </foreach>
+            </if>
+        </where>
+    </select>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/HikEventMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/HikEventMapper.xml
new file mode 100644
index 0000000..14806ec
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/HikEventMapper.xml
@@ -0,0 +1,36 @@
+<?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.fuzhou.mapper.HikEventMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.HikEvent">
+        <result column="ID" property="id" />
+        <result column="SEND_TIME" property="sendTime" />
+        <result column="HAPPEN_TIME" property="happenTime" />
+        <result column="EVENT_TYPE" property="eventType" />
+        <result column="SRC_INDEX" property="srcIndex" />
+        <result column="SRC_NAME" property="srcName" />
+        <result column="SRC_TYPE" property="srcType" />
+        <result column="IP_ADDRESS" property="ipAddress" />
+        <result column="PORT_NO" property="portNo" />
+        <result column="CAMERA_INDEX_CODE" property="cameraIndexCode" />
+        <result column="CAMERA_ADDRESS" property="cameraAddress" />
+        <result column="IMAGE_URL" property="imageUrl" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, SEND_TIME, HAPPEN_TIME, EVENT_TYPE, SRC_INDEX, SRC_NAME, SRC_TYPE, IP_ADDRESS, PORT_NO, CAMERA_INDEX_CODE, CAMERA_ADDRESS, IMAGE_URL
+    </sql>
+
+    <select id="getPageList" resultMap="BaseResultMap">
+        select * from HIK_EVENT
+        order by SEND_TIME DESC
+        limit #{pageSize} offset #{offset}
+    </select>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from  HIK_EVENT
+    </select>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarRuleMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarRuleMapper.xml
new file mode 100644
index 0000000..a4e409d
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarRuleMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveCarRuleMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueFinalMapper.xml
new file mode 100644
index 0000000..41c1644
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueFinalMapper.xml
@@ -0,0 +1,37 @@
+<?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.fuzhou.mapper.ReceiveCarValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveCarValueFinal">
+        <id column="ID" property="id" />
+        <result column="VIN" property="vin" />
+        <result column="LENGTH" property="length" />
+        <result column="DATA_TIME" property="dataTime" />
+        <result column="SPEED" property="speed" />
+        <result column="PRESSURE" property="pressure" />
+        <result column="TORQUE" property="torque" />
+        <result column="FRICTION_TORQUE" property="frictionTorque" />
+        <result column="ENGINE_SPEED" property="engineSpeed" />
+        <result column="FLOW" property="flow" />
+        <result column="SCR_UP_NO" property="scrUpNo" />
+        <result column="SCR_DOWN_NO" property="scrDownNo" />
+        <result column="LAST" property="last" />
+        <result column="ENGINE_IN" property="engineIn" />
+        <result column="SCR_IN_TEMP" property="scrInTemp" />
+        <result column="SCR_OUT_TEMP" property="scrOutTemp" />
+        <result column="DPF_PRESSURE" property="dpfPressure" />
+        <result column="TEMP" property="temp" />
+        <result column="LEVEL" property="level" />
+        <result column="STATUS" property="status" />
+        <result column="LON" property="lon" />
+        <result column="LAT" property="lat" />
+        <result column="CREATE_TIME" property="createTime" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, VIN, LENGTH, DATA_TIME, SPEED, PRESSURE, TORQUE, FRICTION_TORQUE, ENGINE_SPEED, FLOW, SCR_UP_NO, SCR_DOWN_NO, LAST, ENGINE_IN, SCR_IN_TEMP, SCR_OUT_TEMP, DPF_PRESSURE, TEMP, LEVEL, STATUS, LON, LAT, CREATE_TIME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueMapper.xml
new file mode 100644
index 0000000..d91fd60
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveCarValueMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveCarValueMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityAnalyseMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityAnalyseMapper.xml
new file mode 100644
index 0000000..c6f2cc1
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityAnalyseMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveElectricityAnalyseMapper">
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityInfoMapper.xml
new file mode 100644
index 0000000..45d12a6
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityInfoMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveElectricityInfoMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueFinalMapper.xml
new file mode 100644
index 0000000..d483a95
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueFinalMapper.xml
@@ -0,0 +1,36 @@
+<?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.fuzhou.mapper.ReceiveElectricityValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveElectricityValueFinal">
+        <id column="ID" property="id" />
+        <result column="TEMP" property="temp" />
+        <result column="VOLTAGE_A" property="voltageA" />
+        <result column="VOLTAGE_B" property="voltageB" />
+        <result column="VOLTAGE_C" property="voltageC" />
+        <result column="VOLTAGE_AB" property="voltageAb" />
+        <result column="VOLTAGE_BC" property="voltageBc" />
+        <result column="VOLTAGE_CA" property="voltageCa" />
+        <result column="CURRENT_A" property="currentA" />
+        <result column="CURRENT_B" property="currentB" />
+        <result column="CURRENT_C" property="currentC" />
+        <result column="POWER_A" property="powerA" />
+        <result column="POWER_B" property="powerB" />
+        <result column="POWER_C" property="powerC" />
+        <result column="POWER" property="power" />
+        <result column="TEMP_A" property="tempA" />
+        <result column="TEMP_B" property="tempB" />
+        <result column="TEMP_C" property="tempC" />
+        <result column="WARN_STATUS" property="warnStatus" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="ZHENG_POWER" property="zhengPower" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, TEMP, VOLTAGE_A, VOLTAGE_B, VOLTAGE_C, VOLTAGE_AB, VOLTAGE_BC, VOLTAGE_CA, CURRENT_A, CURRENT_B, CURRENT_C, POWER_A, POWER_B, POWER_C, POWER, TEMP_A, TEMP_B, TEMP_C, WARN_STATUS, CREATE_TIME, DEVICE_NAME, ZHENG_POWER
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueMapper.xml
new file mode 100644
index 0000000..cb9c9af
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveElectricityValueMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveElectricityValueMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveModuleInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveModuleInfoMapper.xml
new file mode 100644
index 0000000..682749f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveModuleInfoMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveModuleInfoMapper">
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilAnalyseMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilAnalyseMapper.xml
new file mode 100644
index 0000000..d3a6f9a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilAnalyseMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveOilAnalyseMapper">
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilInfoMapper.xml
new file mode 100644
index 0000000..4ba0ed3
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilInfoMapper.xml
@@ -0,0 +1,25 @@
+<?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.fuzhou.mapper.ReceiveOilInfoMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveOilInfo">
+        <id column="ID" property="id" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="DEVICE_ADDRESS" property="deviceAddress" />
+        <result column="IP" property="ip" />
+        <result column="PORT" property="port" />
+        <result column="FUNCTION_CODE" property="functionCode" />
+        <result column="REGISTER_ADRESS" property="registerAdress" />
+        <result column="REGISTER_COUNT" property="registerCount" />
+        <result column="CRC" property="crc" />
+        <result column="DATA_TYPE" property="dataType" />
+        <result column="PARAM" property="param" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, DEVICE_NAME, DEVICE_ADDRESS, IP, PORT, FUNCTION_CODE, REGISTER_ADRESS, REGISTER_COUNT, CRC, DATA_TYPE, PARAM
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueFinalMapper.xml
new file mode 100644
index 0000000..bd72eae
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueFinalMapper.xml
@@ -0,0 +1,39 @@
+<?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.fuzhou.mapper.ReceiveOilValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveOilValueFinal">
+        <id column="ID" property="id" />
+        <result column="QUALITY_FLOW" property="qualityFlow" />
+        <result column="DENSITY" property="density" />
+        <result column="TEMP" property="temp" />
+        <result column="VOLUME_FLOW" property="volumeFlow" />
+        <result column="VOLUME_QUALITY" property="volumeQuality" />
+        <result column="VOLUME_TOTAL" property="volumeTotal" />
+        <result column="WATER_RATE" property="waterRate" />
+        <result column="OIL_TOTAL" property="oilTotal" />
+        <result column="WATER_TOTAL" property="waterTotal" />
+        <result column="OIL_TEMP" property="oilTemp" />
+        <result column="WATER_TEMP" property="waterTemp" />
+        <result column="OIL" property="oil" />
+        <result column="WATER" property="water" />
+        <result column="TEMP_OIL_DENSITY" property="tempOilDensity" />
+        <result column="TEMP_WATER_DENSITY" property="tempWaterDensity" />
+        <result column="OIL_TIME_FLOW" property="oilTimeFlow" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="FLOW_TOTAL" property="flowTotal" />
+        <result column="FLOW_TOTAL_L" property="flowTotalL" />
+        <result column="FLOW_TOTAL_H" property="flowTotalH" />
+        <result column="VOLUME_TOTAL_L" property="volumeTotalL" />
+        <result column="VOLUME_TOTAL_H" property="volumeTotalH" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, QUALITY_FLOW, DENSITY, TEMP, VOLUME_FLOW, VOLUME_QUALITY, VOLUME_TOTAL, WATER_RATE, OIL_TOTAL, WATER_TOTAL, OIL_TEMP, WATER_TEMP, OIL, WATER, TEMP_OIL_DENSITY, TEMP_WATER_DENSITY, OIL_TIME_FLOW, CREATE_TIME, DEVICE_NAME, FLOW_TOTAL, FLOW_TOTAL_L, FLOW_TOTAL_H, VOLUME_TOTAL_L, VOLUME_TOTAL_H
+    </sql>
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueMapper.xml
new file mode 100644
index 0000000..9b74dd7
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveOilValueMapper.xml
@@ -0,0 +1,32 @@
+<?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.fuzhou.mapper.ReceiveOilValueMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveOilValue">
+        <id column="ID" property="id" />
+        <result column="QUALITY_FLOW" property="qualityFlow" />
+        <result column="DENSITY" property="density" />
+        <result column="TEMP" property="temp" />
+        <result column="VOLUME_FLOW" property="volumeFlow" />
+        <result column="VOLUME_QUALITY" property="volumeQuality" />
+        <result column="VOLUME_TOTAL" property="volumeTotal" />
+        <result column="WATER_RATE" property="waterRate" />
+        <result column="OIL_TOTAL" property="oilTotal" />
+        <result column="WATER_TOTAL" property="waterTotal" />
+        <result column="OIL_TEMP" property="oilTemp" />
+        <result column="WATER_TEMP" property="waterTemp" />
+        <result column="OIL" property="oil" />
+        <result column="WATER" property="water" />
+        <result column="TEMP_OIL_DENSITY" property="tempOilDensity" />
+        <result column="TEMP_WATER_DENSITY" property="tempWaterDensity" />
+        <result column="OIL_TIME_FLOW" property="oilTimeFlow" />
+        <result column="CREATE_TIME" property="createTime" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, QUALITY_FLOW, DENSITY, TEMP, VOLUME_FLOW, VOLUME_QUALITY, VOLUME_TOTAL, WATER_RATE, OIL_TOTAL, WATER_TOTAL, OIL_TEMP, WATER_TEMP, OIL, WATER, TEMP_OIL_DENSITY, TEMP_WATER_DENSITY, OIL_TIME_FLOW, CREATE_TIME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSelectRuleMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSelectRuleMapper.xml
new file mode 100644
index 0000000..2cb9686
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSelectRuleMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveSelectRuleMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmAnalyseMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmAnalyseMapper.xml
new file mode 100644
index 0000000..caa915f
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmAnalyseMapper.xml
@@ -0,0 +1,25 @@
+<?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.fuzhou.mapper.ReceiveSlmAnalyseMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveSlmAnalyse">
+        <id column="ID" property="id" />
+        <result column="ADIS" property="adis" />
+        <result column="BDIS" property="bdis" />
+        <result column="ASPEED" property="aspeed" />
+        <result column="BSPEED" property="bspeed" />
+        <result column="AALARM" property="aalarm" />
+        <result column="BALARM" property="balarm" />
+        <result column="STATUS" property="status" />
+        <result column="BERTHNAME" property="berthname" />
+        <result column="BOATNAME" property="boatname" />
+        <result column="CREATE_TIME" property="createTime" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, ADIS, BDIS, ASPEED, BSPEED, AALARM, BALARM, STATUS, BERTHNAME, BOATNAME, CREATE_TIME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmInfoMapper.xml
new file mode 100644
index 0000000..b89713e
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmInfoMapper.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveSlmInfoMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveSlmInfo">
+        <id column="ID" property="id" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="DEVICE_ADDRESS" property="deviceAddress" />
+        <result column="IP" property="ip" />
+        <result column="PORT" property="port" />
+        <result column="FUNCTION_CODE" property="functionCode" />
+        <result column="REGISTER_ADRESS" property="registerAdress" />
+        <result column="REGISTER_COUNT" property="registerCount" />
+        <result column="CRC" property="crc" />
+        <result column="DATA_TYPE" property="dataType" />
+        <result column="PARAM" property="param" />
+        <result column="PARAM_CODE" property="paramCode" />
+        <result column="UNIT" property="unit" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, DEVICE_NAME, DEVICE_ADDRESS, IP, PORT, FUNCTION_CODE, REGISTER_ADRESS, REGISTER_COUNT, CRC, DATA_TYPE, PARAM, PARAM_CODE, UNIT
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueFinalMapper.xml
new file mode 100644
index 0000000..2681b04
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueFinalMapper.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveSlmValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveSlmValueFinal">
+        <id column="ID" property="id" />
+        <result column="ADIS" property="adis" />
+        <result column="BDIS" property="bdis" />
+        <result column="ASPEED" property="aspeed" />
+        <result column="BSPEED" property="bspeed" />
+        <result column="AALARM" property="aalarm" />
+        <result column="BALARM" property="balarm" />
+        <result column="STATUS" property="status" />
+        <result column="BERTHNAME" property="berthname" />
+        <result column="BOATNAME" property="boatname" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="DEVICE_NAME" property="deviceName" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, ADIS, BDIS, ASPEED, BSPEED, AALARM, BALARM, STATUS, BERTHNAME, BOATNAME, CREATE_TIME, DEVICE_NAME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueMapper.xml
new file mode 100644
index 0000000..770eba3
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveSlmValueMapper.xml
@@ -0,0 +1,25 @@
+<?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.fuzhou.mapper.ReceiveSlmValueMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveSlmValue">
+        <id column="ID" property="id" />
+        <result column="ADIS" property="adis" />
+        <result column="BDIS" property="bdis" />
+        <result column="ASPEED" property="aspeed" />
+        <result column="BSPEED" property="bspeed" />
+        <result column="AALARM" property="aalarm" />
+        <result column="BALARM" property="balarm" />
+        <result column="STATUS" property="status" />
+        <result column="BERTHNAME" property="berthname" />
+        <result column="BOATNAME" property="boatname" />
+        <result column="CREATE_TIME" property="createTime" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, ADIS, BDIS, ASPEED, BSPEED, AALARM, BALARM, STATUS, BERTHNAME, BOATNAME, CREATE_TIME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterAnalyseMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterAnalyseMapper.xml
new file mode 100644
index 0000000..f2a95b3
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterAnalyseMapper.xml
@@ -0,0 +1,6 @@
+<?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.fuzhou.mapper.ReceiveWaterAnalyseMapper">
+
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterInfoMapper.xml
new file mode 100644
index 0000000..0addbde
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterInfoMapper.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveWaterInfoMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWaterInfo">
+        <id column="ID" property="id" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="DEVICE_ADDRESS" property="deviceAddress" />
+        <result column="IP" property="ip" />
+        <result column="PORT" property="port" />
+        <result column="FUNCTION_CODE" property="functionCode" />
+        <result column="REGISTER_ADRESS" property="registerAdress" />
+        <result column="REGISTER_COUNT" property="registerCount" />
+        <result column="CRC" property="crc" />
+        <result column="DATA_TYPE" property="dataType" />
+        <result column="PARAM" property="param" />
+        <result column="PARAM_CODE" property="paramCode" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, DEVICE_NAME, DEVICE_ADDRESS, IP, PORT, FUNCTION_CODE, REGISTER_ADRESS, REGISTER_COUNT, CRC, DATA_TYPE, PARAM, PARAM_CODE
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueFinalMapper.xml
new file mode 100644
index 0000000..4f03ab8
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueFinalMapper.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveWaterValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWaterValueFinal">
+        <id column="ID" property="id" />
+        <result column="TIME_FLOW" property="timeFlow" />
+        <result column="FLOW_RATE" property="flowRate" />
+        <result column="RATE" property="rate" />
+        <result column="FLOW_ELECTRICITY" property="flowElectricity" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="WATER_DEEP" property="waterDeep" />
+        <result column="WATER_YA" property="waterYa" />
+        <result column="ZHENG_TOTAL" property="zhengTotal" />
+        <result column="ZHENG_LITLE_TOTAL" property="zhengLitleTotal" />
+        <result column="FAN_TOTAL" property="fanTotal" />
+        <result column="FAN_LITLE_TOTAL" property="fanLitleTotal" />
+        <result column="FLOW_UNIT" property="flowUnit" />
+        <result column="TOTAL_UNIT" property="totalUnit" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, TIME_FLOW, FLOW_RATE, RATE, FLOW_ELECTRICITY, CREATE_TIME, DEVICE_NAME, WATER_DEEP, WATER_YA, ZHENG_TOTAL, ZHENG_LITLE_TOTAL, FAN_TOTAL, FAN_LITLE_TOTAL, FLOW_UNIT, TOTAL_UNIT
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueMapper.xml
new file mode 100644
index 0000000..2cb317a
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWaterValueMapper.xml
@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveWaterValueMapper">
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherAnalyseMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherAnalyseMapper.xml
new file mode 100644
index 0000000..9a7cb02
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherAnalyseMapper.xml
@@ -0,0 +1,20 @@
+<?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.web.base1.mapper.ReceiveWeatherAnalyseMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWeatherAnalyse">
+        <id column="ID" property="id" />
+        <result column="WIND_SPEED" property="windSpeed" />
+        <result column="WIND_DIRECTION" property="windDirection" />
+        <result column="TEMP" property="temp" />
+        <result column="HUMIDITY" property="humidity" />
+        <result column="ATMOSPHERIC_PRESSURE" property="atmosphericPressure" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, WIND_SPEED, WIND_DIRECTION, TEMP, HUMIDITY, ATMOSPHERIC_PRESSURE
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherInfoMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherInfoMapper.xml
new file mode 100644
index 0000000..47456c1
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherInfoMapper.xml
@@ -0,0 +1,27 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.fuzhou.mapper.ReceiveWeatherInfoMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWeatherInfo">
+        <id column="ID" property="id" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="DEVICE_ADDRESS" property="deviceAddress" />
+        <result column="IP" property="ip" />
+        <result column="PORT" property="port" />
+        <result column="FUNCTION_CODE" property="functionCode" />
+        <result column="REGISTER_ADRESS" property="registerAdress" />
+        <result column="REGISTER_COUNT" property="registerCount" />
+        <result column="CRC" property="crc" />
+        <result column="DATA_TYPE" property="dataType" />
+        <result column="PARAM" property="param" />
+        <result column="PARAM_CODE" property="paramCode" />
+        <result column="UNIT" property="unit" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, DEVICE_NAME, DEVICE_ADDRESS, IP, PORT, FUNCTION_CODE, REGISTER_ADRESS, REGISTER_COUNT, CRC, DATA_TYPE, PARAM, PARAM_CODE, UNIT
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueFinalMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueFinalMapper.xml
new file mode 100644
index 0000000..be95535
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueFinalMapper.xml
@@ -0,0 +1,22 @@
+<?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.fuzhou.mapper.ReceiveWeatherValueFinalMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWeatherValueFinal">
+        <id column="ID" property="id" />
+        <result column="WIND_SPEED" property="windSpeed" />
+        <result column="WIND_DIRECTION" property="windDirection" />
+        <result column="TEMP" property="temp" />
+        <result column="HUMIDITY" property="humidity" />
+        <result column="ATMOSPHERIC_PRESSURE" property="atmosphericPressure" />
+        <result column="DEVICE_NAME" property="deviceName" />
+        <result column="CREATE_TIME" property="createTime" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, WIND_SPEED, WIND_DIRECTION, TEMP, HUMIDITY, ATMOSPHERIC_PRESSURE, DEVICE_NAME, CREATE_TIME
+    </sql>
+
+</mapper>
diff --git a/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueMapper.xml b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueMapper.xml
new file mode 100644
index 0000000..c101408
--- /dev/null
+++ b/ruoyi-fuzhou/src/main/resources/mapper/ReceiveWeatherValueMapper.xml
@@ -0,0 +1,20 @@
+<?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.fuzhou.mapper.ReceiveWeatherValueMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.fuzhou.domain.ReceiveWeatherValue">
+        <id column="ID" property="id" />
+        <result column="WIND_SPEED" property="windSpeed" />
+        <result column="WIND_DIRECTION" property="windDirection" />
+        <result column="TEMP" property="temp" />
+        <result column="HUMIDITY" property="humidity" />
+        <result column="ATMOSPHERIC_PRESSURE" property="atmosphericPressure" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, WIND_SPEED, WIND_DIRECTION, TEMP, HUMIDITY, ATMOSPHERIC_PRESSURE
+    </sql>
+
+</mapper>
diff --git a/ruoyi-generator/pom.xml b/ruoyi-generator/pom.xml
new file mode 100644
index 0000000..5638eb5
--- /dev/null
+++ b/ruoyi-generator/pom.xml
@@ -0,0 +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浠g爜鐢熸垚
+    </description>
+
+    <dependencies>
+
+        <!-- velocity浠g爜鐢熸垚浣跨敤妯℃澘 -->
+        <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-3-starter</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi-generator/ruoyi-generator.iml b/ruoyi-generator/ruoyi-generator.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-generator/ruoyi-generator.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java
new file mode 100644
index 0000000..c01857c
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/config/GenConfig.java
@@ -0,0 +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;
+
+/**
+ * 璇诲彇浠g爜鐢熸垚鐩稿叧閰嶇疆
+ * 
+ * @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;
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
new file mode 100644
index 0000000..070a4a9
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/controller/GenController.java
@@ -0,0 +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 jakarta.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;
+
+/**
+ * 浠g爜鐢熸垚 鎿嶄綔澶勭悊
+ * 
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/tool/gen")
+public class GenController extends BaseController
+{
+    @Autowired
+    private IGenTableService genTableService;
+
+    @Autowired
+    private IGenTableColumnService genTableColumnService;
+
+    /**
+     * 鏌ヨ浠g爜鐢熸垚鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:list')")
+    @GetMapping("/list")
+    public TableDataInfo genList(GenTable genTable)
+    {
+        startPage();
+        List<GenTable> list = genTableService.selectGenTableList(genTable);
+        return getDataTable(list);
+    }
+
+    /**
+     * 淇敼浠g爜鐢熸垚涓氬姟
+     */
+    @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 = "浠g爜鐢熸垚", 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("鍒涘缓琛ㄧ粨鏋勫紓甯�");
+        }
+    }
+
+    /**
+     * 淇敼淇濆瓨浠g爜鐢熸垚涓氬姟
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:edit')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult editSave(@Validated @RequestBody GenTable genTable)
+    {
+        genTableService.validateEdit(genTable);
+        genTableService.updateGenTable(genTable);
+        return success();
+    }
+
+    /**
+     * 鍒犻櫎浠g爜鐢熸垚
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:remove')")
+    @Log(title = "浠g爜鐢熸垚", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{tableIds}")
+    public AjaxResult remove(@PathVariable Long[] tableIds)
+    {
+        genTableService.deleteGenTableByIds(tableIds);
+        return success();
+    }
+
+    /**
+     * 棰勮浠g爜
+     */
+    @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);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", 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);
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", 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 = "浠g爜鐢熸垚", businessType = BusinessType.UPDATE)
+    @GetMapping("/synchDb/{tableName}")
+    public AjaxResult synchDb(@PathVariable("tableName") String tableName)
+    {
+        genTableService.synchDb(tableName);
+        return success();
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜
+     */
+    @PreAuthorize("@ss.hasPermi('tool:gen:code')")
+    @Log(title = "浠g爜鐢熸垚", 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());
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
new file mode 100644
index 0000000..9ef6cfd
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTable.java
@@ -0,0 +1,385 @@
+package com.ruoyi.generator.domain;
+
+import java.util.List;
+import jakarta.validation.Valid;
+import jakarta.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;
+
+    /** 鍓嶇绫诲瀷锛坋lement-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;
+
+    /** 鐢熸垚浠g爜鏂瑰紡锛�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/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
new file mode 100644
index 0000000..3dc6d62
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/domain/GenTableColumn.java
@@ -0,0 +1,373 @@
+package com.ruoyi.generator.domain;
+
+import jakarta.validation.constraints.NotBlank;
+import com.ruoyi.common.core.domain.BaseEntity;
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 浠g爜鐢熸垚涓氬姟瀛楁琛� 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;
+
+    /** 鏌ヨ鏂瑰紡锛圗Q绛変簬銆丯E涓嶇瓑浜庛�丟T澶т簬銆丩T灏忎簬銆丩IKE妯$硦銆丅ETWEEN鑼冨洿锛� */
+    private String queryType;
+
+    /** 鏄剧ず绫诲瀷锛坕nput鏂囨湰妗嗐�乼extarea鏂囨湰鍩熴�乻elect涓嬫媺妗嗐�乧heckbox澶嶉�夋銆乺adio鍗曢�夋銆乨atetime鏃ユ湡鎺т欢銆乮mage鍥剧墖涓婁紶鎺т欢銆乽pload鏂囦欢涓婁紶鎺т欢銆乪ditor瀵屾枃鏈帶浠讹級 */
+    private String htmlType;
+
+    /** 瀛楀吀绫诲瀷 */
+    private String dictType;
+
+    /** 鎺掑簭 */
+    private Integer sort;
+
+    public 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/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java
new file mode 100644
index 0000000..951e166
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableColumnMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
new file mode 100644
index 0000000..937656d
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/mapper/GenTableMapper.java
@@ -0,0 +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();
+
+    /**
+     * 鏌ヨ琛↖D涓氬姟淇℃伅
+     * 
+     * @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/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java
new file mode 100644
index 0000000..0679689
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableColumnServiceImpl.java
@@ -0,0 +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));
+	}
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
new file mode 100644
index 0000000..fc19233
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/GenTableServiceImpl.java
@@ -0,0 +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());
+        }
+    }
+
+    /**
+     * 棰勮浠g爜
+     * 
+     * @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;
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @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();
+    }
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     * 
+     * @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);
+        }
+    }
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @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();
+    }
+
+    /**
+     * 鏌ヨ琛ㄤ俊鎭苟鐢熸垚浠g爜
+     */
+    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
+            {
+                // 娣诲姞鍒皕ip
+                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));
+        }
+    }
+
+    /**
+     * 璁剧疆浠g爜鐢熸垚鍏朵粬閫夐」鍊�
+     * 
+     * @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);
+        }
+    }
+
+    /**
+     * 鑾峰彇浠g爜鐢熸垚鍦板潃
+     * 
+     * @param table 涓氬姟琛ㄤ俊鎭�
+     * @param template 妯℃澘鏂囦欢璺緞
+     * @return 鐢熸垚鍦板潃
+     */
+    public static String getGenPath(GenTable table, String template)
+    {
+        String genPath = table.getGenPath();
+        if (StringUtils.equals(genPath, "/"))
+        {
+            return System.getProperty("user.dir") + File.separator + "src" + File.separator + VelocityUtils.getFileName(template, table);
+        }
+        return genPath + File.separator + VelocityUtils.getFileName(template, table);
+    }
+}
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java
new file mode 100644
index 0000000..3037f70
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableColumnService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
new file mode 100644
index 0000000..695426e
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/service/IGenTableService.java
@@ -0,0 +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 闇�瑕佸垹闄ょ殑琛ㄦ暟鎹甀D
+     * @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);
+
+    /**
+     * 棰勮浠g爜
+     * 
+     * @param tableId 琛ㄧ紪鍙�
+     * @return 棰勮鏁版嵁鍒楄〃
+     */
+    public Map<String, String> previewCode(Long tableId);
+
+    /**
+     * 鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    public byte[] downloadCode(String tableName);
+
+    /**
+     * 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 鏁版嵁
+     */
+    public void generatorCode(String tableName);
+
+    /**
+     * 鍚屾鏁版嵁搴�
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     */
+    public void synchDb(String tableName);
+
+    /**
+     * 鎵归噺鐢熸垚浠g爜锛堜笅杞芥柟寮忥級
+     * 
+     * @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/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
new file mode 100644
index 0000000..e7ebc20
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/GenUtils.java
@@ -0,0 +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;
+
+/**
+ * 浠g爜鐢熸垚鍣� 宸ュ叿绫�
+ * 
+ * @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);
+
+            // 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal
+            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);
+    }
+
+    /**
+     * 琛ㄥ悕杞崲鎴怞ava绫诲悕
+     * 
+     * @param tableName 琛ㄥ悕绉�
+     * @return 绫诲悕
+     */
+    public static String convertClassName(String tableName)
+    {
+        boolean autoRemovePre = GenConfig.getAutoRemovePre();
+        String tablePrefix = GenConfig.getTablePrefix();
+        if (autoRemovePre && StringUtils.isNotEmpty(tablePrefix))
+        {
+            String[] searchList = StringUtils.split(tablePrefix, ",");
+            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/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
new file mode 100644
index 0000000..9f69403
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityInitializer.java
@@ -0,0 +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
+{
+    /**
+     * 鍒濆鍖杤m鏂规硶
+     */
+    public static void initVelocity()
+    {
+        Properties p = new Properties();
+        try
+        {
+            // 鍔犺浇classpath鐩綍涓嬬殑vm鏂囦欢
+            p.setProperty("resource.loader.file.class", "org.apache.velocity.runtime.resource.loader.ClasspathResourceLoader");
+            // 瀹氫箟瀛楃闆�
+            p.setProperty(Velocity.INPUT_ENCODING, Constants.UTF8);
+            // 鍒濆鍖朧elocity寮曟搸锛屾寚瀹氶厤缃甈roperties
+            Velocity.init(p);
+        }
+        catch (Exception e)
+        {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
new file mode 100644
index 0000000..1a14681
--- /dev/null
+++ b/ruoyi-generator/src/main/java/com/ruoyi/generator/util/VelocityUtils.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/generator.yml b/ruoyi-generator/src/main/resources/generator.yml
new file mode 100644
index 0000000..d1cbf48
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/generator.yml
@@ -0,0 +1,12 @@
+# 浠g爜鐢熸垚
+gen:
+  # 浣滆��
+  author: ruoyi
+  # 榛樿鐢熸垚鍖呰矾寰� system 闇�鏀规垚鑷繁鐨勬ā鍧楀悕绉� 濡� system monitor tool
+  packageName: com.ruoyi.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/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
new file mode 100644
index 0000000..52857e8
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableColumnMapper.xml
@@ -0,0 +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>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml b/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
new file mode 100644
index 0000000..d1110f7
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/mapper/generator/GenTableMapper.xml
@@ -0,0 +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>
+
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-generator/src/main/resources/vm/java/controller.java.vm b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
new file mode 100644
index 0000000..b8457a3
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/controller.java.vm
@@ -0,0 +1,115 @@
+package ${packageName}.controller;
+
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.security.access.prepost.PreAuthorize;
+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.DeleteMapping;
+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 ${packageName}.domain.${ClassName};
+import ${packageName}.service.I${ClassName}Service;
+import com.ruoyi.common.utils.poi.ExcelUtil;
+#if($table.crud || $table.sub)
+import com.ruoyi.common.core.page.TableDataInfo;
+#elseif($table.tree)
+#end
+
+/**
+ * ${functionName}Controller
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+@RestController
+@RequestMapping("/${moduleName}/${businessName}")
+public class ${ClassName}Controller extends BaseController
+{
+    @Autowired
+    private I${ClassName}Service ${className}Service;
+
+    /**
+     * 鏌ヨ${functionName}鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:list')")
+    @GetMapping("/list")
+#if($table.crud || $table.sub)
+    public TableDataInfo list(${ClassName} ${className})
+    {
+        startPage();
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        return getDataTable(list);
+    }
+#elseif($table.tree)
+    public AjaxResult list(${ClassName} ${className})
+    {
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        return success(list);
+    }
+#end
+
+    /**
+     * 瀵煎嚭${functionName}鍒楄〃
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:export')")
+    @Log(title = "${functionName}", businessType = BusinessType.EXPORT)
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, ${ClassName} ${className})
+    {
+        List<${ClassName}> list = ${className}Service.select${ClassName}List(${className});
+        ExcelUtil<${ClassName}> util = new ExcelUtil<${ClassName}>(${ClassName}.class);
+        util.exportExcel(response, list, "${functionName}鏁版嵁");
+    }
+
+    /**
+     * 鑾峰彇${functionName}璇︾粏淇℃伅
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:query')")
+    @GetMapping(value = "/{${pkColumn.javaField}}")
+    public AjaxResult getInfo(@PathVariable("${pkColumn.javaField}") ${pkColumn.javaType} ${pkColumn.javaField})
+    {
+        return success(${className}Service.select${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaField}));
+    }
+
+    /**
+     * 鏂板${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:add')")
+    @Log(title = "${functionName}", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@RequestBody ${ClassName} ${className})
+    {
+        return toAjax(${className}Service.insert${ClassName}(${className}));
+    }
+
+    /**
+     * 淇敼${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:edit')")
+    @Log(title = "${functionName}", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@RequestBody ${ClassName} ${className})
+    {
+        return toAjax(${className}Service.update${ClassName}(${className}));
+    }
+
+    /**
+     * 鍒犻櫎${functionName}
+     */
+    @PreAuthorize("@ss.hasPermi('${permissionPrefix}:remove')")
+    @Log(title = "${functionName}", businessType = BusinessType.DELETE)
+	@DeleteMapping("/{${pkColumn.javaField}s}")
+    public AjaxResult remove(@PathVariable ${pkColumn.javaType}[] ${pkColumn.javaField}s)
+    {
+        return toAjax(${className}Service.delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaField}s));
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/domain.java.vm b/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
new file mode 100644
index 0000000..bd51c17
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/domain.java.vm
@@ -0,0 +1,105 @@
+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();
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
new file mode 100644
index 0000000..7e7d7c2
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/mapper.java.vm
@@ -0,0 +1,91 @@
+package ${packageName}.mapper;
+
+import java.util.List;
+import ${packageName}.domain.${ClassName};
+#if($table.sub)
+import ${packageName}.domain.${subClassName};
+#end
+
+/**
+ * ${functionName}Mapper鎺ュ彛
+ * 
+ * @author ${author}
+ * @date ${datetime}
+ */
+public interface ${ClassName}Mapper 
+{
+    /**
+     * 鏌ヨ${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} ${functionName}涓婚敭
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}(${pkColumn.javaType} ${pkColumn.javaField});
+
+    /**
+     * 鎵归噺鍒犻櫎${functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int delete${ClassName}By${pkColumn.capJavaField}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+#if($table.sub)
+
+    /**
+     * 鎵归噺鍒犻櫎${subTable.functionName}
+     * 
+     * @param ${pkColumn.javaField}s 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int delete${subClassName}By${subTableFkClassName}s(${pkColumn.javaType}[] ${pkColumn.javaField}s);
+    
+    /**
+     * 鎵归噺鏂板${subTable.functionName}
+     * 
+     * @param ${subclassName}List ${subTable.functionName}鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batch${subClassName}(List<${subClassName}> ${subclassName}List);
+    
+
+    /**
+     * 閫氳繃${functionName}涓婚敭鍒犻櫎${subTable.functionName}淇℃伅
+     * 
+     * @param ${pkColumn.javaField} ${functionName}ID
+     * @return 缁撴灉
+     */
+    public int delete${subClassName}By${subTableFkClassName}(${pkColumn.javaType} ${pkColumn.javaField});
+#end
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/service.java.vm b/ruoyi-generator/src/main/resources/vm/java/service.java.vm
new file mode 100644
index 0000000..264882b
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/service.java.vm
@@ -0,0 +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});
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
new file mode 100644
index 0000000..14746e1
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/serviceImpl.java.vm
@@ -0,0 +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
+}
diff --git a/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm b/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm
new file mode 100644
index 0000000..a3f53eb
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/java/sub-domain.java.vm
@@ -0,0 +1,76 @@
+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();
+    }
+}
diff --git a/ruoyi-generator/src/main/resources/vm/js/api.js.vm b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
new file mode 100644
index 0000000..9295524
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/js/api.js.vm
@@ -0,0 +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'
+  })
+}
diff --git a/ruoyi-generator/src/main/resources/vm/sql/sql.vm b/ruoyi-generator/src/main/resources/vm/sql/sql.vm
new file mode 100644
index 0000000..0575583
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/sql/sql.vm
@@ -0,0 +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}鑿滃崟');
+
+-- 鎸夐挳鐖惰彍鍗旾D
+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/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
new file mode 100644
index 0000000..4819c2a
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/index-tree.vue.vm
@@ -0,0 +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>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
new file mode 100644
index 0000000..6296014
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/index.vue.vm
@@ -0,0 +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>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
new file mode 100644
index 0000000..c54d62b
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/v3/index-tree.vue.vm
@@ -0,0 +1,474 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :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="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="閫夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}" style="width: 308px">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          value-format="YYYY-MM-DD"
+          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="Search" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="Refresh" @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="Plus"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="Sort"
+          @click="toggleExpandAll"
+        >灞曞紑/鎶樺彔</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="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 #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template #default="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+#if(${foreach.index} == 1)
+      <el-table-column label="${comment}" prop="${javaField}" />
+#else
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+          <el-button link type="primary" icon="Plus" @click="handleAdd(scope.row)" v-hasPermi="['${moduleName}:${businessName}:add']">鏂板</el-button>
+          <el-button link type="primary" icon="Delete" @click="handleDelete(scope.row)" v-hasPermi="['${moduleName}:${businessName}:remove']">鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :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}">
+          <el-tree-select
+            v-model="form.${treeParentCode}"
+            :data="${businessName}Options"
+            :props="{ value: '${treeCode}', label: '${treeName}', children: 'children' }"
+            value-key="${treeCode}"
+            placeholder="璇烽�夋嫨${comment}"
+            check-strictly
+          />
+        </el-form-item>
+#elseif($column.htmlType == "input")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-input v-model="form.${field}" placeholder="璇疯緭鍏�${comment}" />
+        </el-form-item>
+#elseif($column.htmlType == "imageUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <image-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "fileUpload")
+        <el-form-item label="${comment}" prop="${field}">
+          <file-upload v-model="form.${field}"/>
+        </el-form-item>
+#elseif($column.htmlType == "editor")
+        <el-form-item label="${comment}">
+          <editor v-model="form.${field}" :min-height="192"/>
+        </el-form-item>
+#elseif($column.htmlType == "select" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="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>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+const ${businessName}Options = ref([]);
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const title = ref("");
+const isExpandAll = ref(true);
+const refreshTable = ref(true);
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  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
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    loading.value = false;
+  });
+}
+
+/** 鏌ヨ${functionName}涓嬫媺鏍戠粨鏋� */
+function getTreeselect() {
+  list${BusinessName}().then(response => {
+    ${businessName}Options.value = [];
+    const data = { ${treeCode}: 0, ${treeName}: '椤剁骇鑺傜偣', children: [] };
+    data.children = proxy.handleTree(response.data, "${treeCode}", "${treeParentCode}");
+    ${businessName}Options.value.push(data);
+  });
+}
+	
+// 鍙栨秷鎸夐挳
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+  form.value = {
+#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
+  };
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+function handleAdd(row) {
+  reset();
+  getTreeselect();
+  if (row != null && row.${treeCode}) {
+    form.value.${treeParentCode} = row.${treeCode};
+  } else {
+    form.value.${treeParentCode} = 0;
+  }
+  open.value = true;
+  title.value = "娣诲姞${functionName}";
+}
+
+/** 灞曞紑/鎶樺彔鎿嶄綔 */
+function toggleExpandAll() {
+  refreshTable.value = false;
+  isExpandAll.value = !isExpandAll.value;
+  nextTick(() => {
+    refreshTable.value = true;
+  });
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+async function handleUpdate(row) {
+  reset();
+  await getTreeselect();
+  if (row != null) {
+    form.value.${treeParentCode} = row.${treeParentCode};
+  }
+  get${BusinessName}(row.${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+    open.value = true;
+    title.value = "淇敼${functionName}";
+  });
+}
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+  proxy.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + row.${pkColumn.javaField} + '"鐨勬暟鎹」锛�').then(function() {
+    return del${BusinessName}(row.${pkColumn.javaField});
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+getList();
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm b/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
new file mode 100644
index 0000000..8b25665
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/vue/v3/index.vue.vm
@@ -0,0 +1,590 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryRef" :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="handleQuery"
+        />
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && "" != $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option
+            v-for="dict in ${dictType}"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+#elseif(($column.htmlType == "select" || $column.htmlType == "radio") && $dictType)
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-select v-model="queryParams.${column.javaField}" placeholder="璇烽�夋嫨${comment}" clearable>
+          <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+        </el-select>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType != "BETWEEN")
+      <el-form-item label="${comment}" prop="${column.javaField}">
+        <el-date-picker clearable
+          v-model="queryParams.${column.javaField}"
+          type="date"
+          value-format="YYYY-MM-DD"
+          placeholder="璇烽�夋嫨${comment}">
+        </el-date-picker>
+      </el-form-item>
+#elseif($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+      <el-form-item label="${comment}" style="width: 308px">
+        <el-date-picker
+          v-model="daterange${AttrName}"
+          value-format="YYYY-MM-DD"
+          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="Search" @click="handleQuery">鎼滅储</el-button>
+        <el-button icon="Refresh" @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="Plus"
+          @click="handleAdd"
+          v-hasPermi="['${moduleName}:${businessName}:add']"
+        >鏂板</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="Edit"
+          :disabled="single"
+          @click="handleUpdate"
+          v-hasPermi="['${moduleName}:${businessName}:edit']"
+        >淇敼</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="Delete"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['${moduleName}:${businessName}:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="Download"
+          @click="handleExport"
+          v-hasPermi="['${moduleName}:${businessName}:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar v-model:showSearch="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <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 #default="scope">
+          <span>{{ parseTime(scope.row.${javaField}, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+#elseif($column.list && $column.htmlType == "imageUpload")
+      <el-table-column label="${comment}" align="center" prop="${javaField}" width="100">
+        <template #default="scope">
+          <image-preview :src="scope.row.${javaField}" :width="50" :height="50"/>
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $column.dictType)
+      <el-table-column label="${comment}" align="center" prop="${javaField}">
+        <template #default="scope">
+#if($column.htmlType == "checkbox")
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField} ? scope.row.${javaField}.split(',') : []"/>
+#else
+          <dict-tag :options="${column.dictType}" :value="scope.row.${javaField}"/>
+#end
+        </template>
+      </el-table-column>
+#elseif($column.list && "" != $javaField)
+      <el-table-column label="${comment}" align="center" prop="${javaField}" />
+#end
+#end
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template #default="scope">
+          <el-button link type="primary" icon="Edit" @click="handleUpdate(scope.row)" v-hasPermi="['${moduleName}:${businessName}:edit']">淇敼</el-button>
+          <el-button link type="primary" 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"
+      v-model:page="queryParams.pageNum"
+      v-model:limit="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀�${functionName}瀵硅瘽妗� -->
+    <el-dialog :title="title" v-model="open" width="500px" append-to-body>
+      <el-form ref="${businessName}Ref" :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 ${dictType}"
+              :key="dict.value"
+              :label="dict.label"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :value="parseInt(dict.value)"
+#else
+              :value="dict.value"
+#end
+            ></el-option>
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "select" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-select v-model="form.${field}" placeholder="璇烽�夋嫨${comment}">
+            <el-option label="璇烽�夋嫨瀛楀吀鐢熸垚" value="" />
+          </el-select>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+              :label="dict.value">
+              {{dict.label}}
+            </el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "checkbox" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-checkbox-group v-model="form.${field}">
+            <el-checkbox>璇烽�夋嫨瀛楀吀鐢熸垚</el-checkbox>
+          </el-checkbox-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && "" != $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio
+              v-for="dict in ${dictType}"
+              :key="dict.value"
+#if($column.javaType == "Integer" || $column.javaType == "Long")
+              :label="parseInt(dict.value)"
+#else
+              :label="dict.value"
+#end
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "radio" && $dictType)
+        <el-form-item label="${comment}" prop="${field}">
+          <el-radio-group v-model="form.${field}">
+            <el-radio label="1">璇烽�夋嫨瀛楀吀鐢熸垚</el-radio>
+          </el-radio-group>
+        </el-form-item>
+#elseif($column.htmlType == "datetime")
+        <el-form-item label="${comment}" prop="${field}">
+          <el-date-picker clearable
+            v-model="form.${field}"
+            type="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="Plus" @click="handleAdd${subClassName}">娣诲姞</el-button>
+          </el-col>
+          <el-col :span="1.5">
+            <el-button type="danger" icon="Delete" @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 #default="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 #default="scope">
+              <el-date-picker clearable
+                v-model="scope.row.$javaField"
+                type="date"
+                value-format="YYYY-MM-DD"
+                placeholder="璇烽�夋嫨$comment">
+              </el-date-picker>
+            </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 #default="scope">
+              <el-select v-model="scope.row.$javaField" placeholder="璇烽�夋嫨$comment">
+                <el-option
+                  v-for="dict in $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 #default="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>
+      <template #footer>
+        <div class="dialog-footer">
+          <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+          <el-button @click="cancel">鍙� 娑�</el-button>
+        </div>
+      </template>
+    </el-dialog>
+  </div>
+</template>
+
+<script setup name="${BusinessName}">
+import { list${BusinessName}, get${BusinessName}, del${BusinessName}, add${BusinessName}, update${BusinessName} } from "@/api/${moduleName}/${businessName}";
+
+const { proxy } = getCurrentInstance();
+#if(${dicts} != '')
+#set($dictsNoSymbol=$dicts.replace("'", ""))
+const { ${dictsNoSymbol} } = proxy.useDict(${dicts});
+#end
+
+const ${businessName}List = ref([]);
+#if($table.sub)
+const ${subclassName}List = ref([]);
+#end
+const open = ref(false);
+const loading = ref(true);
+const showSearch = ref(true);
+const ids = ref([]);
+#if($table.sub)
+const checked${subClassName} = ref([]);
+#end
+const single = ref(true);
+const multiple = ref(true);
+const total = ref(0);
+const title = ref("");
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+const daterange${AttrName} = ref([]);
+#end
+#end
+
+const data = reactive({
+  form: {},
+  queryParams: {
+    pageNum: 1,
+    pageSize: 10,
+    #foreach ($column in $columns)
+#if($column.query)
+    $column.javaField: null#if($foreach.count != $columns.size()),#end
+#end
+#end
+  },
+  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
+  }
+});
+
+const { queryParams, form, rules } = toRefs(data);
+
+/** 鏌ヨ${functionName}鍒楄〃 */
+function getList() {
+  loading.value = true;
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+  queryParams.value.params = {};
+#break
+#end
+#end
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  if (null != daterange${AttrName} && '' != daterange${AttrName}) {
+    queryParams.value.params["begin${AttrName}"] = daterange${AttrName}.value[0];
+    queryParams.value.params["end${AttrName}"] = daterange${AttrName}.value[1];
+  }
+#end
+#end
+  list${BusinessName}(queryParams.value).then(response => {
+    ${businessName}List.value = response.rows;
+    total.value = response.total;
+    loading.value = false;
+  });
+}
+
+// 鍙栨秷鎸夐挳
+function cancel() {
+  open.value = false;
+  reset();
+}
+
+// 琛ㄥ崟閲嶇疆
+function reset() {
+  form.value = {
+#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)
+  ${subclassName}List.value = [];
+#end
+  proxy.resetForm("${businessName}Ref");
+}
+
+/** 鎼滅储鎸夐挳鎿嶄綔 */
+function handleQuery() {
+  queryParams.value.pageNum = 1;
+  getList();
+}
+
+/** 閲嶇疆鎸夐挳鎿嶄綔 */
+function resetQuery() {
+#foreach ($column in $columns)
+#if($column.htmlType == "datetime" && $column.queryType == "BETWEEN")
+#set($AttrName=$column.javaField.substring(0,1).toUpperCase() + ${column.javaField.substring(1)})
+  daterange${AttrName}.value = [];
+#end
+#end
+  proxy.resetForm("queryRef");
+  handleQuery();
+}
+
+// 澶氶�夋閫変腑鏁版嵁
+function handleSelectionChange(selection) {
+  ids.value = selection.map(item => item.${pkColumn.javaField});
+  single.value = selection.length != 1;
+  multiple.value = !selection.length;
+}
+
+/** 鏂板鎸夐挳鎿嶄綔 */
+function handleAdd() {
+  reset();
+  open.value = true;
+  title.value = "娣诲姞${functionName}";
+}
+
+/** 淇敼鎸夐挳鎿嶄綔 */
+function handleUpdate(row) {
+  reset();
+  const _${pkColumn.javaField} = row.${pkColumn.javaField} || ids.value
+  get${BusinessName}(_${pkColumn.javaField}).then(response => {
+    form.value = response.data;
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+    form.value.$column.javaField = form.value.${column.javaField}.split(",");
+#end
+#end
+#if($table.sub)
+    ${subclassName}List.value = response.data.${subclassName}List;
+#end
+    open.value = true;
+    title.value = "淇敼${functionName}";
+  });
+}
+
+/** 鎻愪氦鎸夐挳 */
+function submitForm() {
+  proxy.#[[$]]#refs["${businessName}Ref"].validate(valid => {
+    if (valid) {
+#foreach ($column in $columns)
+#if($column.htmlType == "checkbox")
+      form.value.$column.javaField = form.value.${column.javaField}.join(",");
+#end
+#end
+#if($table.sub)
+      form.value.${subclassName}List = ${subclassName}List.value;
+#end
+      if (form.value.${pkColumn.javaField} != null) {
+        update${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("淇敼鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      } else {
+        add${BusinessName}(form.value).then(response => {
+          proxy.#[[$modal]]#.msgSuccess("鏂板鎴愬姛");
+          open.value = false;
+          getList();
+        });
+      }
+    }
+  });
+}
+
+/** 鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete(row) {
+  const _${pkColumn.javaField}s = row.${pkColumn.javaField} || ids.value;
+  proxy.#[[$modal]]#.confirm('鏄惁纭鍒犻櫎${functionName}缂栧彿涓�"' + _${pkColumn.javaField}s + '"鐨勬暟鎹」锛�').then(function() {
+    return del${BusinessName}(_${pkColumn.javaField}s);
+  }).then(() => {
+    getList();
+    proxy.#[[$modal]]#.msgSuccess("鍒犻櫎鎴愬姛");
+  }).catch(() => {});
+}
+
+#if($table.sub)
+/** ${subTable.functionName}搴忓彿 */
+function row${subClassName}Index({ row, rowIndex }) {
+  row.index = rowIndex + 1;
+}
+
+/** ${subTable.functionName}娣诲姞鎸夐挳鎿嶄綔 */
+function handleAdd${subClassName}() {
+  let obj = {};
+#foreach($column in $subTable.columns)
+#if($column.pk || $column.javaField == ${subTableFkclassName})
+#elseif($column.list && "" != $javaField)
+  obj.$column.javaField = "";
+#end
+#end
+  ${subclassName}List.value.push(obj);
+}
+
+/** ${subTable.functionName}鍒犻櫎鎸夐挳鎿嶄綔 */
+function handleDelete${subClassName}() {
+  if (checked${subClassName}.value.length == 0) {
+    proxy.#[[$modal]]#.msgError("璇峰厛閫夋嫨瑕佸垹闄ょ殑${subTable.functionName}鏁版嵁");
+  } else {
+    const ${subclassName}s = ${subclassName}List.value;
+    const checked${subClassName}s = checked${subClassName}.value;
+    ${subclassName}List.value = ${subclassName}s.filter(function(item) {
+      return checked${subClassName}s.indexOf(item.index) == -1
+    });
+  }
+}
+
+/** 澶嶉�夋閫変腑鏁版嵁 */
+function handle${subClassName}SelectionChange(selection) {
+  checked${subClassName}.value = selection.map(item => item.index)
+}
+
+#end
+/** 瀵煎嚭鎸夐挳鎿嶄綔 */
+function handleExport() {
+  proxy.download('${moduleName}/${businessName}/export', {
+    ...queryParams.value
+  }, `${businessName}_#[[${new Date().getTime()}]]#.xlsx`)
+}
+
+getList();
+</script>
diff --git a/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
new file mode 100644
index 0000000..456755b
--- /dev/null
+++ b/ruoyi-generator/src/main/resources/vm/xml/mapper.xml.vm
@@ -0,0 +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
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-manage/pom.xml b/ruoyi-manage/pom.xml
new file mode 100644
index 0000000..1aedee4
--- /dev/null
+++ b/ruoyi-manage/pom.xml
@@ -0,0 +1,59 @@
+<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-manage</artifactId>
+    <description>
+        fuzhou绯荤粺妯″潡
+    </description>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+        <!-- 閫氱敤宸ュ叿-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-fuzhou</artifactId>
+        </dependency>
+    </dependencies>
+    <repositories>
+        <repository>
+            <releases>
+                <enabled>false</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+            <id>ias-snapshots</id>
+            <name>Infinite Automation Snapshot Repository</name>
+            <url>https://maven.mangoautomation.net/repository/ias-snapshot/</url>
+        </repository>
+        <repository>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>false</enabled>
+            </snapshots>
+            <id>ias-releases</id>
+            <name>Infinite Automation Release Repository</name>
+            <url>https://maven.mangoautomation.net/repository/ias-release/</url>
+        </repository>
+    </repositories>
+</project>
diff --git a/ruoyi-manage/ruoyi-manage.iml b/ruoyi-manage/ruoyi-manage.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-manage/ruoyi-manage.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmBerth.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmBerth.java
new file mode 100644
index 0000000..9c0fcc6
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmBerth.java
@@ -0,0 +1,266 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅淇℃伅
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-17
+ */
+@Getter
+@Setter
+@TableName("DM_BERTH")
+@Schema(description = "娉婁綅淇℃伅")
+public class DmBerth {
+
+    @Schema(title = "缂栧彿")
+    @TableId(value = "PKID", type = IdType.AUTO)
+    private BigInteger pkid;
+
+    @Schema(title = "娉婁綅鍚嶇О")
+    @TableField(value = "NAME")
+    private String name;
+
+    @Schema(title = "娓彛缂栧彿")
+    @TableField(value = "HARBOR_ID")
+    private BigInteger harborId;
+
+//    @Schema(title = "娓彛鍚嶇О")
+//    @TableField(value = "HARBOR_NAME")
+    @TableField(exist = false)
+    private String harborName;
+
+    @Schema(title = "娉婁綅闀垮害")
+    @TableField(value = "BERTH_LEN")
+    private BigDecimal berthLen;
+
+    @Schema(title = "鏈�灏忔按娣�")
+    @TableField(value = "DEPTH")
+    private BigDecimal depth;
+
+    @Schema(title = "鍙敤鐘舵��")
+    @TableField(value = "STATUS")
+    private Integer status;
+
+    @Schema(title = "鎺掑簭")
+    @TableField(value = "ORDER_NUM")
+    private Integer orderNum;
+
+    @Schema(title = "鍒犻櫎鏍囪")
+    @TableField(value = "DEL_FLAG")
+    private Integer delFlag;
+
+    @Schema(title = "鏂板缓鐢ㄦ埛")
+    @TableField(value = "CREATE_BY")
+    private String createBy;
+
+    @Schema(title = "鏂板缓鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title = "鏇存柊鐢ㄦ埛")
+    @TableField(value = "CREATE_BY")
+    private String updateBy;
+
+    @Schema(title = "鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title = "澶囨敞")
+    @TableField(value = "REMARK")
+    private String remark;
+
+    @Schema(title = "鍋滄硦鑸拌墖鏁伴噺")
+    @TableField(value = "SHIPS_NUM")
+    private Integer shipsNum;
+
+    @Schema(title = "閬撹矾瑙勫垝")
+    @TableField(value = "PATH")
+    private String path;
+
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private List<DpShips> shipsParking;
+
+    public BigInteger getPkid() {
+        return pkid;
+    }
+
+    public void setPkid(BigInteger pkid) {
+        this.pkid = pkid;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public BigInteger getHarborId() {
+        return harborId;
+    }
+
+    public void setHarborId(BigInteger harborId) {
+        this.harborId = harborId;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public BigDecimal getBerthLen() {
+        return berthLen;
+    }
+
+    public void setBerthLen(BigDecimal berthLen) {
+        this.berthLen = berthLen;
+    }
+
+    public BigDecimal getDepth() {
+        return depth;
+    }
+
+    public void setDepth(BigDecimal depth) {
+        this.depth = depth;
+    }
+
+    public Integer getStatus() {
+        return status;
+    }
+
+    public void setStatus(Integer status) {
+        this.status = status;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public Integer getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(Integer delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    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 Integer getShipsNum() {
+        return shipsNum;
+    }
+
+    public void setShipsNum(Integer shipsNum) {
+        this.shipsNum = shipsNum;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public List<DpShips> getShipsParking() {
+        return shipsParking;
+    }
+
+    public void setShipsParking(List<DpShips> shipsParking) {
+        this.shipsParking = shipsParking;
+    }
+
+    public String getPath() {
+        return path;
+    }
+
+    public void setPath(String path) {
+        this.path = path;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmHarbor.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmHarbor.java
new file mode 100644
index 0000000..2ed982b
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DmHarbor.java
@@ -0,0 +1,456 @@
+package com.ruoyi.manage.domain;
+
+
+import com.ruoyi.common.core.domain.BaseEntity;
+import lombok.Data;
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 娓彛淇℃伅瀵硅薄 dm_harbor
+ *
+ * @author ruoyi
+ * @date 2025-03-17
+ */
+@Data
+@TableName("dm_harbor")
+public class DmHarbor{
+
+    /** id */
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "PKID", type = IdType.AUTO)
+    private Long pkId;
+
+    /** 娓彛鍚嶇О */
+    @Schema(title = "娓彛鍚嶇О")
+    @TableField("HARBOR_NAME")
+    private String harborName;
+
+    /** 鎵�灞炴敮闃焛d */
+    @Schema(title = "鎵�灞炴敮闃焛d")
+    @TableField("DEPT_ID")
+    private Long deptId;
+
+    /** 鏀槦鍚嶇О */
+    @Schema(title = "鏀槦鍚嶇О")
+    @TableField(exist = false)
+    private String deptName;
+
+    /** 娉婁綅鏁伴噺 */
+    @Schema(title = "娉婁綅鏁伴噺")
+    @TableField("BERTH_NO")
+    private Long berthNo;
+
+    /** 鑸扮敤鏌存补瀛橀噺 */
+    @Schema(title = "鑸扮敤鏌存补瀛橀噺")
+    @TableField("OIL_B")
+    private Double oilB;
+
+    /** 鑸扮敤鐓ゆ补瀛橀噺 */
+    @Schema(title = "鑸扮敤鐓ゆ补瀛橀噺")
+    @TableField("OIL_G")
+    private Double oilG;
+
+    /** 鑸扮敤鐓ゆ补瀛橀噺 */
+    @Schema(title = "鑸┖鐓ゆ补瀛橀噺")
+    @TableField("OIL_A")
+    private Double oilA;
+
+    /** 瀵煎脊鏁伴噺 */
+    @Schema(title = "瀵煎脊鏁伴噺")
+    @TableField("AMMO_D")
+    private Long ammoD;
+
+    /** 鐐脊鏁伴噺 */
+    @Schema(title = "鐐脊鏁伴噺")
+    @TableField("AMMO_P")
+    private Long ammoP;
+
+    /** 姘撮浄鏁伴噺 */
+    @Schema(title = "姘撮浄鏁伴噺")
+    @TableField("AMMO_S")
+    private Long ammoS;
+
+    /** $column.columnComment */
+    @Schema(title = "鍒犻櫎鏍囪")
+    @TableField("DEL_FLAG")
+    private String delFlag;
+
+    /** 鐮佸ご鍚嶇О */
+    @Schema(title = "鐮佸ご鍚嶇О")
+    @TableField("DOCKNAME")
+    private String dockName;
+
+    /** 娣℃按鏁伴噺 */
+    @Schema(title = "娣℃按鏁伴噺")
+    @TableField("WATER")
+    private Double water;
+
+    /** 鐗╄祫鏁伴噺 */
+    @Schema(title = "鐗╄祫鏁伴噺")
+    @TableField("MATERIAL")
+    private Double material;
+
+    /** 鍏朵粬寮硅嵂鏁伴噺 */
+    @Schema(title = "鍏朵粬寮硅嵂鏁伴噺")
+    @TableField("AMMO_O")
+    private Long ammoO;
+
+    @Schema(title = "鏂板缓鐢ㄦ埛")
+    @TableField("CREATE_BY")
+    private String createBy;
+
+    @Schema(title = "鏂板缓鏃堕棿")
+    @TableField(value = "CREATE_TIME",fill = FieldFill.INSERT_UPDATE)
+    private Date createTime;
+
+    @Schema(title = "鏇存柊鐢ㄦ埛")
+    @TableField("UPDATE_BY")
+    private String updateBy;
+
+    @Schema(title = "鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME",fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title = "澶囨敞")
+    @TableField("REMARK")
+    private String remark;
+
+    @TableField("HEIGHT")
+    private Double height;
+
+    @TableField("HEADING")
+    private Double heading;
+
+    @TableField("PITCH")
+    private Double pitch;
+
+    @TableField("ROLL")
+    private Double roll;
+
+    @TableField("LATITUDE")
+    private Double latitude;
+
+    @TableField("LONGITUDE")
+    private Double longitude;
+
+    @TableField("POINT_X")
+    private Double pointX;
+
+    @TableField("POINT_Y")
+    private Double pointY;
+
+    @TableField("VEHICLE_COUNT")
+    private Integer vehicleCount;
+
+    @TableField("ROAD_CONDITIONS")
+    private String roadConditions;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private String bumenName;
+
+    @TableField(exist = false)
+    private List<DmBerth> dmBerthList;
+
+    public List<DmBerth> getDmBerthList() {
+        return dmBerthList;
+    }
+
+    public void setDmBerthList(List<DmBerth> dmBerthList) {
+        this.dmBerthList = dmBerthList;
+    }
+
+    public Long getPkId() {
+        return pkId;
+    }
+
+    public void setPkId(Long pkId) {
+        this.pkId = pkId;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public Long getBerthNo() {
+        return berthNo;
+    }
+
+    public void setBerthNo(Long berthNo) {
+        this.berthNo = berthNo;
+    }
+
+    public Double getOilB() {
+        return oilB;
+    }
+
+    public void setOilB(Double oilB) {
+        this.oilB = oilB;
+    }
+
+    public Double getOilG() {
+        return oilG;
+    }
+
+    public void setOilG(Double oilG) {
+        this.oilG = oilG;
+    }
+
+    public Double getOilA() {
+        return oilA;
+    }
+
+    public void setOilA(Double oilA) {
+        this.oilA = oilA;
+    }
+
+    public Long getAmmoD() {
+        return ammoD;
+    }
+
+    public void setAmmoD(Long ammoD) {
+        this.ammoD = ammoD;
+    }
+
+    public Long getAmmoP() {
+        return ammoP;
+    }
+
+    public void setAmmoP(Long ammoP) {
+        this.ammoP = ammoP;
+    }
+
+    public Long getAmmoS() {
+        return ammoS;
+    }
+
+    public void setAmmoS(Long ammoS) {
+        this.ammoS = ammoS;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    public String getDockName() {
+        return dockName;
+    }
+
+    public void setDockName(String dockName) {
+        this.dockName = dockName;
+    }
+
+    public Double getWater() {
+        return water;
+    }
+
+    public void setWater(Double water) {
+        this.water = water;
+    }
+
+    public Double getMaterial() {
+        return material;
+    }
+
+    public void setMaterial(Double material) {
+        this.material = material;
+    }
+
+    public Long getAmmoO() {
+        return ammoO;
+    }
+
+    public void setAmmoO(Long ammoO) {
+        this.ammoO = ammoO;
+    }
+
+    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 Double getHeight() {
+        return height;
+    }
+
+    public void setHeight(Double height) {
+        this.height = height;
+    }
+
+    public Double getHeading() {
+        return heading;
+    }
+
+    public void setHeading(Double heading) {
+        this.heading = heading;
+    }
+
+    public Double getPitch() {
+        return pitch;
+    }
+
+    public void setPitch(Double pitch) {
+        this.pitch = pitch;
+    }
+
+    public Double getRoll() {
+        return roll;
+    }
+
+    public void setRoll(Double roll) {
+        this.roll = roll;
+    }
+
+    public Double getLatitude() {
+        return latitude;
+    }
+
+    public void setLatitude(Double latitude) {
+        this.latitude = latitude;
+    }
+
+    public Double getLongitude() {
+        return longitude;
+    }
+
+    public void setLongitude(Double longitude) {
+        this.longitude = longitude;
+    }
+
+    public Double getPointX() {
+        return pointX;
+    }
+
+    public void setPointX(Double pointX) {
+        this.pointX = pointX;
+    }
+
+    public Double getPointY() {
+        return pointY;
+    }
+
+    public void setPointY(Double pointY) {
+        this.pointY = pointY;
+    }
+
+    public Integer getVehicleCount() {
+        return vehicleCount;
+    }
+
+    public void setVehicleCount(Integer vehicleCount) {
+        this.vehicleCount = vehicleCount;
+    }
+
+    public String getRoadConditions() {
+        return roadConditions;
+    }
+
+    public void setRoadConditions(String roadConditions) {
+        this.roadConditions = roadConditions;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+
+    public String getBumenName() {
+        return bumenName;
+    }
+
+    public void setBumenName(String bumenName) {
+        this.bumenName = bumenName;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpBerth.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpBerth.java
new file mode 100644
index 0000000..f3f699b
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpBerth.java
@@ -0,0 +1,70 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+//import io.swagger.annotations.ApiModel;
+//import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 娉婁綅
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Getter
+@Setter
+@TableName("DP_BERTH")
+//@ApiModel(value = "DpBerth瀵硅薄", description = "娉婁綅")
+public class DpBerth {
+
+    @TableId(value = "BE_ID", type = IdType.AUTO)
+    private Integer beId;
+
+    @TableField("WH_ID")
+    private Integer whId;
+
+    @TableField("BE_NAME")
+    private String beName;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private String whName;
+
+    public Integer getBeId() {
+        return beId;
+    }
+
+    public void setBeId(Integer beId) {
+        this.beId = beId;
+    }
+
+    public Integer getWhId() {
+        return whId;
+    }
+
+    public void setWhId(Integer whId) {
+        this.whId = whId;
+    }
+
+    public String getBeName() {
+        return beName;
+    }
+
+    public void setBeName(String beName) {
+        this.beName = beName;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEffectAssessList.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEffectAssessList.java
new file mode 100644
index 0000000..72ff5cb
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEffectAssessList.java
@@ -0,0 +1,89 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.Date;
+
+/**
+ * <p>
+ * 
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Getter
+@Setter
+@TableName("DS_EFFECT_ASSESS_LIST")
+public class DpEffectAssessList {
+
+    @TableId(value = "PKID", type = IdType.AUTO)
+    private BigInteger pkid;
+
+    @TableField("ASSESS_ID")
+    private BigInteger assessId;
+
+    @TableField("TYPE")
+    private String type;
+
+    @TableField("DEL_FLAG")
+    private String delFlag;
+
+    @TableField("CREATE_BY")
+    private String createBy;
+
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @TableField("UPDATE_BY")
+    private String updateBy;
+
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @TableField("REMARK")
+    private String remark;
+
+    @TableField("PLAN")
+    private String plan;
+
+    @TableField("ITEM")
+    private String item;
+
+    @TableField("ITEM_DETAIL")
+    private String itemDetail;
+
+    @TableField("UNIT")
+    private String unit;
+
+    @TableField("CODE")
+    private String code;
+
+    @TableField("NORMAL")
+    private String normal;
+
+    @TableField("WEIGHT")
+    private BigDecimal weight;
+
+    @TableField("CLASSIFY_INDEX")
+    private String classifyIndex;
+
+    @TableField("CLASSIFY_WEIGHT")
+    private BigDecimal classifyWeight;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEquipmentType.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEquipmentType.java
new file mode 100644
index 0000000..ad5ef3e
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpEquipmentType.java
@@ -0,0 +1,58 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 璁惧绫诲瀷琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Getter
+@Setter
+@TableName("DP_EQUIPMENT_TYPE")
+@Schema(description = "璁惧绫诲瀷琛�")
+public class DpEquipmentType {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "绫诲瀷鍚嶇О")
+    @TableField("TYPE_NAME")
+    private String typeName;
+
+    @Schema(title = "鎻忚堪")
+    @TableField("DESCRIPTION")
+    private String description;
+
+    @Schema(title = "鍥剧墖妯″瀷鍦板潃")
+    @TableField("FILE_PATH")
+    private String filePath;
+
+    @Schema(title = "鍥炬爣鍚嶇О")
+    @TableField("ICON")
+    private String icon;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+
+
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipDevice.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipDevice.java
new file mode 100644
index 0000000..cd67305
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipDevice.java
@@ -0,0 +1,104 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 鑸拌墖璁惧琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-12
+ */
+@Getter
+@Setter
+@TableName("DP_SHIP_DEVICE")
+@Schema(description = "鑸拌墖璁惧琛�")
+public class DpShipDevice {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private String id;
+
+    @Schema(title = "璁惧缂栧彿")
+    @TableField("DEVICE_ID")
+    private String deviceId;
+
+    @Schema(title = "璁惧鍚嶇О")
+    @TableField("DEVICE_NAME")
+    private String deviceName;
+
+    @Schema(title = "璁惧鎵�灞炶埌鑸圭紪鍙�")
+    @TableField("DEVICE_SHIP_ID")
+    private String deviceShipId;
+
+    @TableField(exist = false)
+    private String deviceShipName;
+
+    @Schema(title = "璁惧姒傝堪")
+    @TableField("DEVICE_OVERVIEW")
+    private String deviceOverview;
+
+    @Schema(title = "璁惧妯″瀷鏂囦欢")
+    @TableField(exist = false)
+    private String deviceModel;
+
+    @Schema(title = "璁惧鍙傛暟")
+    @TableField("DEVICE_PARAMETERS")
+    private String deviceParameters;
+
+    @Schema(title = "鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    @Schema(title = "鏇存柊鐢ㄦ埛")
+    @TableField("UPDATE_USER")
+    private String updateUser;
+
+    @Schema(title = "position")
+    @TableField("POSITION")
+    private String position;
+
+    @Schema(title = "target")
+    @TableField("TARGET")
+    private String target;
+
+    @Schema(title = "fieldName")
+    @TableField("FIELD_NAME")
+    private String fieldName;
+
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @Schema(title = "鑸拌埞绫诲瀷ID")
+    @TableField("SHIP_TYPE_ID")
+    private Integer shipTypeId;
+
+    @TableField(exist = false)
+    private String shipTypeName;
+
+    @TableField(exist = false)
+    private String shipDesign;
+
+    public String getShipTypeName() {
+        return shipTypeName+" - "+shipDesign;
+    }
+
+    public void setShipTypeName(String shipTypeName) {
+        this.shipTypeName = shipTypeName;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipParking.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipParking.java
new file mode 100644
index 0000000..ce63eca
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipParking.java
@@ -0,0 +1,72 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 娉婁綅鍋滆埞淇℃伅琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-22
+ */
+@Getter
+@Setter
+@TableName("DP_SHIP_PARKING")
+@Schema(description = "娉婁綅鍋滆埞淇℃伅琛�")
+public class DpShipParking {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "鐮佸ごID")
+    @TableField("WH_ID")
+    private Integer whId;
+
+    @Schema(title = "娉婁綅ID")
+    @TableField("BE_ID")
+    private Integer beId;
+
+    @Schema(title = "鑸拌埞涓婚敭ID")
+    @TableField("SHIP_PKID")
+    private String shipPkid;
+
+    @Schema(title = "缁忓害")
+    @TableField("LON")
+    private Double lon;
+
+    @Schema(title = "绾害")
+    @TableField("LAT")
+    private Double lat;
+
+    @Schema(title = "娴锋嫈")
+    @TableField("ALT")
+    private Double alt;
+
+    @Schema(title = "杞")
+    @TableField("HEADING")
+    private Double heading;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private String shipModel;
+
+    @TableField(exist = false)
+    private String shipId;
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipType.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipType.java
new file mode 100644
index 0000000..4ef5571
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShipType.java
@@ -0,0 +1,83 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 鑸拌埞绫诲瀷琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Getter
+@Setter
+@TableName("DP_SHIP_TYPE")
+@Schema(description = "鑸拌埞绫诲瀷琛�")
+public class DpShipType {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "绫诲瀷鍚嶇О")
+    @TableField("TYPE_NAME")
+    private String typeName;
+
+    @Schema(title = "鎻忚堪")
+    @TableField("SHIP_OVERVIEW")
+    private String shipOverview;
+
+    @Schema(title = "鍙傛暟")
+    @TableField("SHIP_PARAMETERS")
+    private String shipParameters;
+
+    @Schema(title = "鍥剧墖妯″瀷鍦板潃")
+    @TableField("SHIP_MODEL")
+    private String shipModel;
+
+    @Schema(title = "鑸拌埞鍨嬪彿")
+    @TableField("SHIP_DESIGN")
+    private String shipDesign;
+
+    @Schema(title = "鑸拌埞鍚ㄤ綅")
+    @TableField("TONNAGE")
+    private Double tonnage;
+
+    @Schema(title = "鑸拌埞鍚冩按")
+    @TableField("DRAFT")
+    private Double draft;
+
+    @Schema(title = "鑸伴暱")
+    @TableField("LENGTH")
+    private Double length;
+
+    @Schema(title = "鑸拌埞瀹氬憳")
+    @TableField("CREW")
+    private Integer crew;
+
+    @Schema(title = "position")
+    @TableField("POSITION")
+    private String position;
+
+    @Schema(title = "target")
+    @TableField("TARGET")
+    private String target;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShips.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShips.java
new file mode 100644
index 0000000..ba3c2c3
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpShips.java
@@ -0,0 +1,131 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌埞琛�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Getter
+@Setter
+@TableName("DP_SHIPS")
+@Schema(description = "鑸拌埞琛�")
+public class DpShips {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private String id;
+
+    @Schema(title = "鎵�灞炵爜澶碔D")
+    @TableField(value = "WH_ID")
+    private Integer whId;
+
+    @Schema(title = "鎵�灞炴硦浣岻D")
+    @TableField(value = "BE_ID")
+    private Integer beId;
+
+    @Schema(title = "鑸拌埞缂栧彿")
+    @TableField(value = "SHIP_ID")
+    private String shipId;
+
+    @Schema(title = "鑸拌埞鍚嶇О")
+    @TableField("SHIP_NAME")
+    private String shipName;
+
+    @Schema(title = "鑸拌埞绫诲瀷")
+    @TableField(exist = false)
+    private String shipType;
+
+    @Schema(title = "鑸拌埞妯″瀷鏂囦欢")
+    @TableField(exist = false)
+    private String shipModel;
+
+    @Schema(title = "鑸拌埞姒傝堪")
+    @TableField(exist = false)
+    private String shipOverview;
+
+    @Schema(title = "鑸拌埞鍙傛暟")
+    @TableField(exist = false)
+    private String shipParameters;
+
+    @Schema(title = "鏇存柊鏃堕棿")
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    @Schema(title = "鏇存柊鐢ㄦ埛")
+    @TableField("UPDATE_USER")
+    private String updateUser;
+
+    @TableField(exist = false)
+    private String position;
+
+    @TableField(exist = false)
+    private String target;
+
+    @Schema(title = "鑸拌埞鍨嬪彿")
+    @TableField(exist = false)
+    private String shipDesign;
+
+    @TableField(exist = false)
+    private Double tonnage;
+
+    @TableField(exist = false)
+    private Double draft;
+
+    @TableField(exist = false)
+    private Double length;
+
+    @TableField(exist = false)
+    private Integer crew;
+
+    @Schema(title = "鑸拌埞绫诲瀷ID")
+    @TableField("SHIP_TYPE_ID")
+    private Integer shipTypeId;
+
+    @Schema(title = "缁忓害")
+    @TableField("LON")
+    private Double lon;
+
+    @Schema(title = "绾害")
+    @TableField("LAT")
+    private Double lat;
+
+    @Schema(title = "娴锋嫈")
+    @TableField("ALT")
+    private Double alt;
+
+    @Schema(title = "杞")
+    @TableField("HEADING")
+    private Double heading;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    @TableField(exist = false)
+    private String whName;
+
+    @TableField(exist = false)
+    private String beName;
+
+    @TableField(exist = false)
+    private List<DpShipDevice> devices;
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpUnitSupplyTime.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpUnitSupplyTime.java
new file mode 100644
index 0000000..27ca203
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpUnitSupplyTime.java
@@ -0,0 +1,57 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.math.BigDecimal;
+
+/**
+ * <p>
+ * 鍗曚綅琛ョ粰鏃堕棿琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-20
+ */
+@Getter
+@Setter
+@TableName("DP_UNIT_SUPPLY_TIME")
+@Schema(description = "鍗曚綅琛ョ粰鏃堕棿琛�")
+public class DpUnitSupplyTime {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.AUTO)
+    private Integer id;
+
+    @Schema(title = "鍗曚綅")
+    @TableField("UNIT")
+    private String unit;
+
+    @Schema(title = "琛ョ粰绉嶇被")
+    @TableField("CATEGORY")
+    private String category;
+
+    @Schema(title = "琛ョ粰鏃堕棿")
+    @TableField("SUPPLY_TIME")
+    private Double supplyTime;
+
+    @Schema(title = "鑸拌墖鍨嬪彿")
+    @TableField("SHIP_DESIGN")
+    private String shipDesign;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpWharf.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpWharf.java
new file mode 100644
index 0000000..4e9a11d
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DpWharf.java
@@ -0,0 +1,63 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+
+import lombok.Getter;
+import lombok.Setter;
+
+/**
+ * <p>
+ * 鐮佸ご
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Getter
+@Setter
+@TableName("DP_WHARF")
+//@ApiModel(value = "DpWharf瀵硅薄", description = "鐮佸ご")
+public class DpWharf {
+
+    @TableId(value = "WH_ID", type = IdType.AUTO)
+    private Integer whId;
+
+    @TableField("NAME")
+    private String name;
+
+    @TableField("HEIGHT")
+    private Double height;
+
+    @TableField("HEADING")
+    private Double heading;
+
+    @TableField("PITCH")
+    private Double pitch;
+
+    @TableField("ROLL")
+    private Double roll;
+
+    @TableField("LATITUDE")
+    private Double latitude;
+
+    @TableField("LONGITUDE")
+    private Double longitude;
+
+    @TableField("POINT_X")
+    private Double pointX;
+
+    @TableField("POINT_Y")
+    private Double pointY;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DsTaskList.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DsTaskList.java
new file mode 100644
index 0000000..6d9d610
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/DsTaskList.java
@@ -0,0 +1,605 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.time.LocalDateTime;
+import java.util.Date;
+
+/**
+ * <p>
+ * 浠诲姟鍒嗛厤璇︽儏琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-24
+ */
+@TableName("DS_TASK_LIST")
+@Schema(description = "浠诲姟鍒嗛厤璇︽儏琛�")
+public class DsTaskList {
+
+    @Schema(title = "浠诲姟缂栧彿")
+    @TableField("TASK_ID")
+    private BigInteger taskId;
+
+    @Schema(title = "鑸峰彿")
+    @TableField("SHIP_NO")
+    private String shipNo;
+
+    @Schema(title = "鑸板瀷")
+    @TableField("SHIP_TYPE")
+    private String shipType;
+
+    @Schema(title = "鍚ㄤ綅")
+    @TableField("TONNAGE")
+    private BigDecimal tonnage;
+
+    @Schema(title = "鍚冩按")
+    @TableField("DRAFT")
+    private BigDecimal draft;
+
+    @Schema(title = "鑸伴暱")
+    @TableField("LEADER")
+    private String leader;
+
+    @Schema(title = "瀹氬憳")
+    @TableField("STAFF")
+    private Integer staff;
+
+    @Schema(title = "鎴樻湳缂栫粍")
+    @TableField("GRP_NAME")
+    private String grpName;
+
+    @Schema(title = "浼樺厛绾�")
+    @TableField("LEVEL")
+    private Integer level;
+
+    @Schema(title = "绾害")
+    @TableField("LAT")
+    private BigDecimal lat;
+
+    @Schema(title = "缁忓害")
+    @TableField("LON")
+    private BigDecimal lon;
+
+    @TableField("DEL_FLAG")
+    private String delFlag;
+
+    @TableField("CREATE_BY")
+    private String createBy;
+
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @TableField("UPDATE_BY")
+    private String updateBy;
+
+    @TableField(value = "UPDATE_TIME", fill = FieldFill.INSERT_UPDATE)
+    private Date updateTime;
+
+    @Schema(title = "鑸扮敤鏌存补")
+    @TableField("OIL_B")
+    private BigDecimal oilB;
+
+    @Schema(title = "閫氱敤鏌存补")
+    @TableField("OIL_G")
+    private BigDecimal oilG;
+
+    @Schema(title = "鑸┖鐓ゆ补")
+    @TableField("OIL_A")
+    private BigDecimal oilA;
+
+    @Schema(title = "瀵煎脊")
+    @TableField("AMMO_D")
+    private Integer ammoD;
+
+    @Schema(title = "鐐脊")
+    @TableField("AMMO_P")
+    private Integer ammoP;
+
+    @Schema(title = "姘撮浄")
+    @TableField("AMMO_S")
+    private Integer ammoS;
+
+    @Schema(title = "鍏朵粬寮硅嵂")
+    @TableField("AMMO_O")
+    private Integer ammoO;
+
+    @Schema(title = "娣℃按")
+    @TableField("WATER")
+    private BigDecimal water;
+
+    @Schema(title = "绾按")
+    @TableField("WATER_P")
+    private BigDecimal waterP;
+
+    @Schema(title = "涓诲壇椋�")
+    @TableField("FOOD")
+    private Integer food;
+
+    @Schema(title = "妗惰姘�")
+    @TableField("FOOD_W")
+    private Integer foodW;
+
+    @Schema(title = "鍏朵粬鐗╄祫")
+    @TableField("FOOD_O")
+    private Integer foodO;
+
+    @Schema(title = "璁″垝鎶垫腐鏃堕棿")
+    @TableField("P_S_TIME")
+    private Date psTime;
+
+    @Schema(title = "璁″垝绂绘腐鏃堕棿")
+    @TableField("P_E_TIME")
+    private Date peTime;
+
+    @Schema(title = "鐘舵��")
+    @TableField("STATUS")
+    private String status;
+
+    @Schema(title = "鍒嗛厤鐮佸ご缂栧彿")
+    @TableField("HARBOR_ID")
+    private BigInteger harborId;
+
+    @Schema(title = "鍒嗛厤鐮佸ご鍚嶇О")
+    @TableField("HARBOR_NAME")
+    private String harborName;
+
+    @Schema(title = "娉婁綅缂栧彿")
+    @TableField("BERTH_ID")
+    private BigInteger berthId;
+
+    @Schema(title = "娉婁綅鍚嶇О")
+    @TableField("BERTH_NAME")
+    private String berthName;
+
+    @Schema(title = "骞堕潬绛栫暐")
+    @TableField("PARKING_TYPE")
+    private String parkingType;
+
+    @Schema(title = "缂栧彿")
+    @TableId(value = "PKID", type = IdType.AUTO)
+    private BigInteger pkid;
+
+    @TableField("REMARK")
+    private String remark;
+
+    @Schema(title = "鐮佸ご鎵�灞為儴闂ㄧ紪鐮�")
+    @TableField("DEPT_ID")
+    private BigInteger deptId;
+
+    @Schema(title = "鐮佸ご鎵�灞為儴闂ㄥ悕绉�")
+    @TableField("DEPT_NAME")
+    private String deptName;
+
+    @Schema(title = "浣嶇疆鍖洪棿")
+    @TableField("POS_AREA")
+    private String posArea;
+
+    @Schema(title = "鑸伴暱")
+    @TableField("SHIP_LEN")
+    private BigDecimal shipLen;
+
+    @Schema(title = "琛ョ粰椤哄簭")
+    @TableField("SUPPLY_SEQ")
+    private String supplySeq;
+
+    @Schema(title = "璁″垝鍋滈潬鏃堕棿")
+    @TableField("DOCK_TIME")
+    private BigDecimal dockTime;
+
+    @Schema(title = "鍋滄硦闋嗗簭")
+    @TableField("DOCK_INDEX")
+    private Integer dockIndex;
+
+    @Schema(title = "缁戝畾RFID缂栫爜")
+    @TableField("RFID_NUM")
+    private String rfidNum;
+
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+
+    public String getRfidNum() {
+        return rfidNum;
+    }
+
+    public void setRfidNum(String rfidNum) {
+        this.rfidNum = rfidNum;
+    }
+
+    public BigInteger getTaskId() {
+        return taskId;
+    }
+
+    public void setTaskId(BigInteger taskId) {
+        this.taskId = taskId;
+    }
+
+    public String getShipNo() {
+        return shipNo;
+    }
+
+    public void setShipNo(String shipNo) {
+        this.shipNo = shipNo;
+    }
+
+    public String getShipType() {
+        return shipType;
+    }
+
+    public void setShipType(String shipType) {
+        this.shipType = shipType;
+    }
+
+    public BigDecimal getTonnage() {
+        return tonnage;
+    }
+
+    public void setTonnage(BigDecimal tonnage) {
+        this.tonnage = tonnage;
+    }
+
+    public BigDecimal getDraft() {
+        return draft;
+    }
+
+    public void setDraft(BigDecimal draft) {
+        this.draft = draft;
+    }
+
+    public String getLeader() {
+        return leader;
+    }
+
+    public void setLeader(String leader) {
+        this.leader = leader;
+    }
+
+    public Integer getStaff() {
+        return staff;
+    }
+
+    public void setStaff(Integer staff) {
+        this.staff = staff;
+    }
+
+    public String getGrpName() {
+        return grpName;
+    }
+
+    public void setGrpName(String grpName) {
+        this.grpName = grpName;
+    }
+
+    public Integer getLevel() {
+        return level;
+    }
+
+    public void setLevel(Integer level) {
+        this.level = level;
+    }
+
+    public BigDecimal getLat() {
+        return lat;
+    }
+
+    public void setLat(BigDecimal lat) {
+        this.lat = lat;
+    }
+
+    public BigDecimal getLon() {
+        return lon;
+    }
+
+    public void setLon(BigDecimal lon) {
+        this.lon = lon;
+    }
+
+    public String getDelFlag() {
+        return delFlag;
+    }
+
+    public void setDelFlag(String delFlag) {
+        this.delFlag = delFlag;
+    }
+
+    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 BigDecimal getOilB() {
+        return oilB;
+    }
+
+    public void setOilB(BigDecimal oilB) {
+        this.oilB = oilB;
+    }
+
+    public BigDecimal getOilG() {
+        return oilG;
+    }
+
+    public void setOilG(BigDecimal oilG) {
+        this.oilG = oilG;
+    }
+
+    public BigDecimal getOilA() {
+        return oilA;
+    }
+
+    public void setOilA(BigDecimal oilA) {
+        this.oilA = oilA;
+    }
+
+    public Integer getAmmoD() {
+        return ammoD;
+    }
+
+    public void setAmmoD(Integer ammoD) {
+        this.ammoD = ammoD;
+    }
+
+    public Integer getAmmoP() {
+        return ammoP;
+    }
+
+    public void setAmmoP(Integer ammoP) {
+        this.ammoP = ammoP;
+    }
+
+    public Integer getAmmoS() {
+        return ammoS;
+    }
+
+    public void setAmmoS(Integer ammoS) {
+        this.ammoS = ammoS;
+    }
+
+    public Integer getAmmoO() {
+        return ammoO;
+    }
+
+    public void setAmmoO(Integer ammoO) {
+        this.ammoO = ammoO;
+    }
+
+    public BigDecimal getWater() {
+        return water;
+    }
+
+    public void setWater(BigDecimal water) {
+        this.water = water;
+    }
+
+    public BigDecimal getWaterP() {
+        return waterP;
+    }
+
+    public void setWaterP(BigDecimal waterP) {
+        this.waterP = waterP;
+    }
+
+    public Integer getFood() {
+        return food;
+    }
+
+    public void setFood(Integer food) {
+        this.food = food;
+    }
+
+    public Integer getFoodW() {
+        return foodW;
+    }
+
+    public void setFoodW(Integer foodW) {
+        this.foodW = foodW;
+    }
+
+    public Integer getFoodO() {
+        return foodO;
+    }
+
+    public void setFoodO(Integer foodO) {
+        this.foodO = foodO;
+    }
+
+    public Date getPsTime() {
+        return psTime;
+    }
+
+    public void setPsTime(Date psTime) {
+        this.psTime = psTime;
+    }
+
+    public Date getPeTime() {
+        return peTime;
+    }
+
+    public void setPeTime(Date peTime) {
+        this.peTime = peTime;
+    }
+
+    public String getStatus() {
+        return status;
+    }
+
+    public void setStatus(String status) {
+        this.status = status;
+    }
+
+    public BigInteger getHarborId() {
+        return harborId;
+    }
+
+    public void setHarborId(BigInteger harborId) {
+        this.harborId = harborId;
+    }
+
+    public String getHarborName() {
+        return harborName;
+    }
+
+    public void setHarborName(String harborName) {
+        this.harborName = harborName;
+    }
+
+    public BigInteger getBerthId() {
+        return berthId;
+    }
+
+    public void setBerthId(BigInteger berthId) {
+        this.berthId = berthId;
+    }
+
+    public String getBerthName() {
+        return berthName;
+    }
+
+    public void setBerthName(String berthName) {
+        this.berthName = berthName;
+    }
+
+    public String getParkingType() {
+        return parkingType;
+    }
+
+    public void setParkingType(String parkingType) {
+        this.parkingType = parkingType;
+    }
+
+    public BigInteger getPkid() {
+        return pkid;
+    }
+
+    public void setPkid(BigInteger pkid) {
+        this.pkid = pkid;
+    }
+
+    public String getRemark() {
+        return remark;
+    }
+
+    public void setRemark(String remark) {
+        this.remark = remark;
+    }
+
+    public BigInteger getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(BigInteger deptId) {
+        this.deptId = deptId;
+    }
+
+    public String getDeptName() {
+        return deptName;
+    }
+
+    public void setDeptName(String deptName) {
+        this.deptName = deptName;
+    }
+
+    public String getPosArea() {
+        return posArea;
+    }
+
+    public void setPosArea(String posArea) {
+        this.posArea = posArea;
+    }
+
+    public BigDecimal getShipLen() {
+        return shipLen;
+    }
+
+    public void setShipLen(BigDecimal shipLen) {
+        this.shipLen = shipLen;
+    }
+
+    public String getSupplySeq() {
+        return supplySeq;
+    }
+
+    public void setSupplySeq(String supplySeq) {
+        this.supplySeq = supplySeq;
+    }
+
+    public BigDecimal getDockTime() {
+        return dockTime;
+    }
+
+    public void setDockTime(BigDecimal dockTime) {
+        this.dockTime = dockTime;
+    }
+
+    public Integer getDockIndex() {
+        return dockIndex;
+    }
+
+    public void setDockIndex(Integer dockIndex) {
+        this.dockIndex = dockIndex;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/MyMetaObjectHandler.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/MyMetaObjectHandler.java
new file mode 100644
index 0000000..add9d6f
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/MyMetaObjectHandler.java
@@ -0,0 +1,22 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
+import org.apache.ibatis.reflection.MetaObject;
+import org.springframework.stereotype.Component;
+
+import java.time.LocalDateTime;
+import java.util.Date;
+
+@Component
+public class MyMetaObjectHandler implements MetaObjectHandler {
+    @Override
+    public void insertFill(MetaObject metaObject){
+        this.strictInsertFill(metaObject,"createTime",Date.class,new Date());
+        this.strictInsertFill(metaObject,"updateTime",Date.class,new Date());
+        this.strictInsertFill(metaObject,"passTime",Date.class,new Date());
+    }
+
+    public void updateFill(MetaObject metaObject){
+        this.strictUpdateFill(metaObject,"updateTime",Date.class,new Date());
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/SysFileManage.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/SysFileManage.java
new file mode 100644
index 0000000..5c40622
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/SysFileManage.java
@@ -0,0 +1,57 @@
+package com.ruoyi.manage.domain;
+
+import com.baomidou.mybatisplus.annotation.*;
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.Date;
+
+/**
+ * <p>
+ * 鏂囦欢绠$悊琛�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Getter
+@Setter
+@TableName("SYS_FILE_MANAGE")
+@Schema(description = "鏂囦欢绠$悊琛�")
+public class SysFileManage {
+
+    @Schema(title = "涓婚敭ID")
+    @TableId(value = "ID", type = IdType.ASSIGN_ID)
+    private String id;
+
+    @Schema(title = "鏂囦欢鍚嶇О")
+    @TableField("NAME")
+    private String name;
+
+    @Schema(title = "鏂囦欢绫诲瀷")
+    @TableField("TYPE")
+    private String type;
+
+    @Schema(title = "鏂囦欢澶у皬")
+    @TableField("SIZE")
+    private String size;
+
+    @Schema(title = "璇存槑")
+    @TableField("REMARK")
+    private String remark;
+
+    @Schema(title = "涓婁紶鏃堕棿")
+    @TableField(value = "CREATE_TIME", fill = FieldFill.INSERT)
+    private Date createTime;
+
+    @Schema(title = "棰勭暀瀛楁")
+    @TableField("EXT")
+    private String ext;
+
+    @Schema(title = "鏂囦欢璺緞")
+    @TableField("FILE_PATH")
+    private String filePath;
+
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/ShipTypeVO.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/ShipTypeVO.java
new file mode 100644
index 0000000..1ee74ed
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/ShipTypeVO.java
@@ -0,0 +1,33 @@
+package com.ruoyi.manage.domain.vo;
+
+import java.util.List;
+
+public class ShipTypeVO {
+    private String id;
+    private String name;
+    private List<Integer> ids;
+
+    public List<Integer> getIds() {
+        return ids;
+    }
+
+    public void setIds(List<Integer> ids) {
+        this.ids = ids;
+    }
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/SysFileManageVO.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/SysFileManageVO.java
new file mode 100644
index 0000000..2bcf028
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/SysFileManageVO.java
@@ -0,0 +1,33 @@
+package com.ruoyi.manage.domain.vo;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.constraints.NotNull;
+import lombok.Data;
+
+import java.util.Date;
+
+@Data
+public class SysFileManageVO {
+
+    @Schema(title = "鏂囦欢鍚嶇О")
+    private String name;
+
+    @Schema(title = "鏂囦欢绫诲瀷")
+    private String type;
+
+//    @Schema(title = "寮�濮嬫椂闂�")
+//    private Date startTime;
+//
+//    @Schema(title = "缁撴潫鏃堕棿")
+//    private Date endTime;
+
+    @TableField(exist = false)
+    private Integer pageSize;
+
+    @TableField(exist = false)
+    private Integer pageNum;
+
+    @TableField(exist = false)
+    private Integer offset;
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/Tree.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/Tree.java
new file mode 100644
index 0000000..65b6dc7
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/Tree.java
@@ -0,0 +1,74 @@
+package com.ruoyi.manage.domain.vo;
+
+import lombok.Data;
+import org.w3c.dom.stylesheets.LinkStyle;
+
+import java.util.List;
+
+@Data
+public class Tree {
+
+    private Integer id;
+    private String label;
+    private Boolean disabled;
+    private Integer intervalTime;//鏇存柊闂撮殧锛堝垎閽燂級
+    private Integer periodTime;//鏌ヨ鏃堕棿娈靛ぇ灏忥紙鍒嗛挓锛�
+    private List<Tree> children;
+    private String icon;
+
+    public String getIcon() {
+        return icon;
+    }
+
+    public void setIcon(String icon) {
+        this.icon = icon;
+    }
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public Integer getIntervalTime() {
+        return intervalTime;
+    }
+
+    public void setIntervalTime(Integer intervalTime) {
+        this.intervalTime = intervalTime;
+    }
+
+    public Integer getPeriodTime() {
+        return periodTime;
+    }
+
+    public void setPeriodTime(Integer periodTime) {
+        this.periodTime = periodTime;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Boolean getDisabled() {
+        return disabled;
+    }
+
+    public void setDisabled(Boolean disabled) {
+        this.disabled = disabled;
+    }
+
+    public List<Tree> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<Tree> children) {
+        this.children = children;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/TreeVO.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/TreeVO.java
new file mode 100644
index 0000000..4f47020
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/domain/vo/TreeVO.java
@@ -0,0 +1,45 @@
+package com.ruoyi.manage.domain.vo;
+
+import lombok.Data;
+
+import java.util.List;
+
+@Data
+public class TreeVO {
+    private String id;
+    private String label;
+    private Boolean disabled;
+    private List<TreeVO> children;
+
+    public String getId() {
+        return id;
+    }
+
+    public void setId(String id) {
+        this.id = id;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public Boolean getDisabled() {
+        return disabled;
+    }
+
+    public void setDisabled(Boolean disabled) {
+        this.disabled = disabled;
+    }
+
+    public List<TreeVO> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<TreeVO> children) {
+        this.children = children;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DmHarborMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DmHarborMapper.java
new file mode 100644
index 0000000..9d65780
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DmHarborMapper.java
@@ -0,0 +1,66 @@
+package com.ruoyi.manage.mapper;
+
+import java.util.List;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DmHarbor;
+
+/**
+ * 娓彛淇℃伅Mapper鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-03-17
+ */
+public interface DmHarborMapper extends BaseMapper<DmHarbor>
+{
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    public DmHarbor selectDmHarborByPkId(Long pkId);
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor> selectDmHarborList(DmHarbor dmHarbor);
+
+    /**
+     * 鏂板娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmHarbor(DmHarbor dmHarbor);
+
+    /**
+     * 淇敼娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmHarbor(DmHarbor dmHarbor);
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPkId(Long pkId);
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     *
+     * @param pkIds 闇�瑕佸垹闄ょ殑鏁版嵁涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPkIds(Long[] pkIds);
+
+    List<DmHarbor> getPageList(DmHarbor dmHarbor);
+
+    Integer getTotal(DmHarbor dmHarbor);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpBerthMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpBerthMapper.java
new file mode 100644
index 0000000..c981964
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpBerthMapper.java
@@ -0,0 +1,26 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DmBerth;
+import com.ruoyi.manage.domain.DpBerth;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅 Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Mapper
+public interface DpBerthMapper extends BaseMapper<DmBerth> {
+
+    List<DmBerth> getPageList(DmBerth dpBerth);
+
+    long getTotal(DmBerth dpBerth);
+
+    void deleteByWhId(Integer whId);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEffectAssessListMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEffectAssessListMapper.java
new file mode 100644
index 0000000..b3b368e
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEffectAssessListMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpEffectAssessList;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Mapper
+public interface DpEffectAssessListMapper extends BaseMapper<DpEffectAssessList> {
+
+    List<DpEffectAssessList> getPageList(DpEffectAssessList dpEffectAssessList);
+
+    Integer getTotal(DpEffectAssessList dpEffectAssessList);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEquipmentTypeMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEquipmentTypeMapper.java
new file mode 100644
index 0000000..b70caa7
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpEquipmentTypeMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpEquipmentType;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璁惧绫诲瀷琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Mapper
+public interface DpEquipmentTypeMapper extends BaseMapper<DpEquipmentType> {
+
+    List<DpEquipmentType> getPageList(DpEquipmentType dpEquipmentType);
+
+    Integer getTotal(DpEquipmentType dpEquipmentType);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipDeviceMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipDeviceMapper.java
new file mode 100644
index 0000000..e771895
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipDeviceMapper.java
@@ -0,0 +1,39 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpShipDevice;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌墖璁惧琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-12
+ */
+@Mapper
+public interface DpShipDeviceMapper extends BaseMapper<DpShipDevice> {
+    //鏂板鑸拌埞璁惧鏁版嵁
+    int insertDpShipDevice(DpShipDevice dpShipDevice);
+    //鏇存柊鑸拌埞璁惧鏁版嵁
+    int updateDpShipDevice(DpShipDevice dpShipDevice);
+    //鍒犻櫎鑸拌埞璁惧鏁版嵁
+    int deleteDpShipDevice(String id);
+    //鑾峰彇鑸拌埞璁惧鏁版嵁鍒楄〃
+    List<DpShipDevice> getDpShipDevices();
+    //鏍规嵁鑸拌埞缂栧彿鏌ヨ璁惧鍒楄〃
+    List<DpShipDevice> selectDpShipDeviceByShipId(String deviceShipId);
+
+    //鏍规嵁ID鑾峰彇鑸拌埞璁惧鏁版嵁
+    DpShipDevice selectDpShipDevice(String id);
+
+    //鏍规嵁name鑾峰彇鑸拌埞璁惧鏁版嵁
+    DpShipDevice selectDpShipDeviceByName(String name);
+
+    List<DpShipDevice> getPageList(DpShipDevice shipDevice);
+
+    long getTotal(DpShipDevice shipDevice);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipParkingMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipParkingMapper.java
new file mode 100644
index 0000000..1f04612
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipParkingMapper.java
@@ -0,0 +1,22 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpShipParking;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅鍋滆埞淇℃伅琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-22
+ */
+@Mapper
+public interface DpShipParkingMapper extends BaseMapper<DpShipParking> {
+    List<DpShipParking> getPageList(DpShipParking dpShipParking);
+
+    Integer getTotal(DpShipParking dpShipType);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipTypeMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipTypeMapper.java
new file mode 100644
index 0000000..f4c1844
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipTypeMapper.java
@@ -0,0 +1,26 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpShipType;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌埞绫诲瀷琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Mapper
+public interface DpShipTypeMapper extends BaseMapper<DpShipType> {
+
+    List<DpShipType> getPageList(DpShipType dpShipType);
+
+    Integer getTotal(DpShipType dpShipType);
+
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipsMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipsMapper.java
new file mode 100644
index 0000000..5100291
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpShipsMapper.java
@@ -0,0 +1,32 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpShips;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.apache.ibatis.annotations.Select;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 鑸拌埞琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Mapper
+public interface DpShipsMapper extends BaseMapper<DpShips> {
+
+    DpShips getDpShipsById(String id);
+
+    List<DpShips> getPageList(DpShips ships);
+
+    long getTotal(DpShips ships);
+
+    //鏍规嵁鐮佸ごID鍜屾硦浣岻D鏌ヨ鑸拌埞鍒楄〃
+    List<DpShips> getByWhIdBeId(DpShips dpShips);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpUnitSupplyTimeMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpUnitSupplyTimeMapper.java
new file mode 100644
index 0000000..6fb3b3d
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpUnitSupplyTimeMapper.java
@@ -0,0 +1,24 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpUnitSupplyTime;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鍗曚綅琛ョ粰鏃堕棿琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-20
+ */
+@Mapper
+public interface DpUnitSupplyTimeMapper extends BaseMapper<DpUnitSupplyTime> {
+
+    List<DpUnitSupplyTime> getPageList(DpUnitSupplyTime dpUnitSupplyTime);
+
+    Integer getTotal(DpUnitSupplyTime dpUnitSupplyTime);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpWharfMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpWharfMapper.java
new file mode 100644
index 0000000..3a2e868
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DpWharfMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DpWharf;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鐮佸ご Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Mapper
+public interface DpWharfMapper extends BaseMapper<DpWharf> {
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DsTaskListMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DsTaskListMapper.java
new file mode 100644
index 0000000..5e1b571
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/DsTaskListMapper.java
@@ -0,0 +1,27 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.DsTaskList;
+import org.apache.ibatis.annotations.Mapper;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 浠诲姟鍒嗛厤璇︽儏琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-24
+ */
+@Mapper
+public interface DsTaskListMapper extends BaseMapper<DsTaskList> {
+    List<DsTaskList> getPageList(DsTaskList dsTaskList);
+
+    Integer getTotal(DsTaskList dsTaskList);
+
+    List<DsTaskList> getPageListDaily(DsTaskList dsTaskList);
+
+    Integer getTotalDaily(DsTaskList dsTaskList);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/SysFileMapper.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/SysFileMapper.java
new file mode 100644
index 0000000..2312069
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/mapper/SysFileMapper.java
@@ -0,0 +1,18 @@
+package com.ruoyi.manage.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.manage.domain.SysFileManage;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * <p>
+ * 鏂囦欢绠$悊琛� Mapper 鎺ュ彛
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Mapper
+public interface SysFileMapper extends BaseMapper<SysFileManage> {
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpBerthService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpBerthService.java
new file mode 100644
index 0000000..f72111f
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpBerthService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.manage.service;
+
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DmBerth;
+import com.ruoyi.manage.domain.DpBerth;
+import com.baomidou.mybatisplus.extension.service.IService;
+
+/**
+ * <p>
+ * 娉婁綅 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+public interface DpBerthService extends IService<DmBerth> {
+    TableDataInfo getPageList(DmBerth dpBerth);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEffectAssessListService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEffectAssessListService.java
new file mode 100644
index 0000000..4b6fd0a
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEffectAssessListService.java
@@ -0,0 +1,18 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpEffectAssessList;
+
+/**
+ * <p>
+ *  鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+public interface DpEffectAssessListService extends IService<DpEffectAssessList> {
+    TableDataInfo getList(DpEffectAssessList dpEffectAssessList);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEquipmentTypeService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEquipmentTypeService.java
new file mode 100644
index 0000000..f6e2b2b
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpEquipmentTypeService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpEquipmentType;
+
+/**
+ * <p>
+ * 璁惧绫诲瀷琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+public interface DpEquipmentTypeService extends IService<DpEquipmentType> {
+    TableDataInfo getPageList(DpEquipmentType dpEquipmentType);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipDeviceService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipDeviceService.java
new file mode 100644
index 0000000..46f22fd
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipDeviceService.java
@@ -0,0 +1,37 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipDevice;
+import com.ruoyi.manage.domain.DpShips;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌墖璁惧琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-12
+ */
+public interface DpShipDeviceService extends IService<DpShipDevice> {
+    //鏂板鑸拌埞璁惧鏁版嵁
+    int insertDpShipDevice(DpShipDevice dpShipDevice);
+    //鏇存柊鑸拌埞璁惧鏁版嵁
+    int updateDpShipDevice(DpShipDevice dpShipDevice);
+    //鍒犻櫎鑸拌埞璁惧鏁版嵁
+    int deleteDpShipDevice(String id);
+    //鑾峰彇鑸拌埞璁惧鏁版嵁鍒楄〃
+    List<DpShipDevice> getDpShipDevices();
+    //鏍规嵁ID鑾峰彇鑸拌埞璁惧鏁版嵁
+    DpShipDevice selectDpShipDevice(String id);
+    //鏍规嵁name鑾峰彇鑸拌埞璁惧鏁版嵁
+    DpShipDevice selectDpShipDeviceByName(String name);
+
+    //鏍规嵁鑸拌埞缂栧彿鏌ヨ璁惧鍒楄〃
+    List<DpShipDevice> selectDpShipDeviceByShipId(String deviceShipId);
+
+    TableDataInfo getDpShipDevicesPage(DpShipDevice shipDevice);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipParkingService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipParkingService.java
new file mode 100644
index 0000000..c760f8d
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipParkingService.java
@@ -0,0 +1,23 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipParking;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅鍋滆埞淇℃伅琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-22
+ */
+public interface DpShipParkingService extends IService<DpShipParking> {
+
+    TableDataInfo getPageList(DpShipParking dpShipParking);
+
+    List<DpShipParking> getByWhBeId(Integer whId,Integer beId,Integer id);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipTypeService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipTypeService.java
new file mode 100644
index 0000000..c98a270
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipTypeService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipType;
+
+/**
+ * <p>
+ * 鑸拌埞绫诲瀷琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+public interface DpShipTypeService extends IService<DpShipType> {
+    TableDataInfo getPageList(DpShipType dpShipType);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipsService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipsService.java
new file mode 100644
index 0000000..028f295
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpShipsService.java
@@ -0,0 +1,35 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.domain.vo.ShipTypeVO;
+import com.ruoyi.manage.domain.vo.Tree;
+import com.ruoyi.manage.domain.vo.TreeVO;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * <p>
+ * 鑸拌埞琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+public interface DpShipsService extends IService<DpShips> {
+
+    //鏍规嵁ID鏌ヨ鑸拌埞淇℃伅
+    DpShips getDpShipsById(String id);
+    //鏍规嵁鐮佸ごID鏌ヨ鑸硅埌绫诲瀷
+    List<ShipTypeVO> getDpShipTypeByWhId(Integer whId);
+    List<ShipTypeVO> getDpShipTypeByWhIdNEW(Integer whId);
+    //鏍规嵁鐮佸ごID鍜岃埌鑸圭被鍨嬫煡璇㈣埌鑸瑰垪琛�
+    List<TreeVO> getDpShipsByWhIdType(Integer whId, String shipType);
+    List<TreeVO> getDpShipsByWhIdTypeNEW(Integer whId, List<Integer> shipType);
+    //鏍规嵁鐮佸ごID鍜屾硦浣岻D鏌ヨ鑸拌埞鍒楄〃
+    List<DpShips> getByWhIdBeId(Integer whId,Integer beId);
+
+    TableDataInfo getPageList(DpShips ships);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpUnitSupplyTimeService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpUnitSupplyTimeService.java
new file mode 100644
index 0000000..2ae4a23
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpUnitSupplyTimeService.java
@@ -0,0 +1,19 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpUnitSupplyTime;
+
+/**
+ * <p>
+ * 鍗曚綅琛ョ粰鏃堕棿琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-20
+ */
+public interface DpUnitSupplyTimeService extends IService<DpUnitSupplyTime> {
+
+    TableDataInfo getPageList(DpUnitSupplyTime dpUnitSupplyTime);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpWharfService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpWharfService.java
new file mode 100644
index 0000000..1f715fc
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DpWharfService.java
@@ -0,0 +1,17 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.manage.domain.DpWharf;
+
+/**
+ * <p>
+ * 鐮佸ご 鏈嶅姟绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+public interface DpWharfService extends IService<DpWharf> {
+
+    void deleteWhraf(Integer whId);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DsTaskListService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DsTaskListService.java
new file mode 100644
index 0000000..b24c259
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/DsTaskListService.java
@@ -0,0 +1,20 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DsTaskList;
+
+/**
+ * <p>
+ * 浠诲姟鍒嗛厤璇︽儏琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-24
+ */
+public interface DsTaskListService extends IService<DsTaskList> {
+    TableDataInfo getPageList(DsTaskList dsTaskList);
+
+    TableDataInfo getPageListDaily(DsTaskList dsTaskList);
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/IDmHarborService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/IDmHarborService.java
new file mode 100644
index 0000000..d89fca6
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/IDmHarborService.java
@@ -0,0 +1,65 @@
+package com.ruoyi.manage.service;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DmHarbor;
+
+/**
+ * 娓彛淇℃伅Service鎺ュ彛
+ *
+ * @author ruoyi
+ * @date 2025-03-17
+ */
+public interface IDmHarborService extends IService<DmHarbor>
+{
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    public DmHarbor selectDmHarborByPkId(Long pkId);
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 娓彛淇℃伅闆嗗悎
+     */
+    public List<DmHarbor> selectDmHarborList(DmHarbor dmHarbor);
+
+    /**
+     * 鏂板娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDmHarbor(DmHarbor dmHarbor);
+
+    /**
+     * 淇敼娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDmHarbor(DmHarbor dmHarbor);
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     *
+     * @param pkIds 闇�瑕佸垹闄ょ殑娓彛淇℃伅涓婚敭闆嗗悎
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPkIds(Long[] pkIds);
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    public int deleteDmHarborByPkId(Long pkId);
+
+    TableDataInfo getList(DmHarbor dmHarbor);
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/SysFileService.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/SysFileService.java
new file mode 100644
index 0000000..9d16013
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/SysFileService.java
@@ -0,0 +1,43 @@
+package com.ruoyi.manage.service;
+
+import com.baomidou.mybatisplus.extension.service.IService;
+import com.ruoyi.manage.domain.SysFileManage;
+import com.ruoyi.manage.domain.vo.SysFileManageVO;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鏂囦欢绠$悊琛� 鏈嶅姟绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+public interface SysFileService extends IService<SysFileManage> {
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    List<SysFileManage> listAll();
+
+    //鍗曟枃浠朵笂浼�
+    Integer saveFile(MultipartFile file,SysFileManage sysFileManage) throws Exception;
+
+    //鍗曠嫭鏁版嵁鎻掑叆
+    Integer saveData(SysFileManage sysFileManage) throws Exception;
+
+    //鎵归噺鎻掑叆
+//    Integer saveBatch(List<MultipartFile> files);
+
+    //鏉′欢鏌ヨ
+    List<SysFileManage> queryData(SysFileManageVO vo);
+
+    //鎵归噺鍒犻櫎
+    List<String> deleteBatch(List<String> ids);
+
+    //涓嬭浇鏂囦欢
+
+
+
+    //鏌ヨ鎬绘暟
+    Long queryCount();
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DmHarborServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DmHarborServiceImpl.java
new file mode 100644
index 0000000..72bc822
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DmHarborServiceImpl.java
@@ -0,0 +1,108 @@
+package com.ruoyi.manage.service.impl;
+
+import java.util.List;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.common.utils.DateUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.manage.mapper.DmHarborMapper;
+import com.ruoyi.manage.domain.DmHarbor;
+import com.ruoyi.manage.service.IDmHarborService;
+
+/**
+ * 娓彛淇℃伅Service涓氬姟灞傚鐞�
+ *
+ * @author ruoyi
+ * @date 2025-03-17
+ */
+@Service
+public class DmHarborServiceImpl extends ServiceImpl<DmHarborMapper, DmHarbor> implements IDmHarborService
+{
+    @Autowired
+    private DmHarborMapper dmHarborMapper;
+
+    /**
+     * 鏌ヨ娓彛淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 娓彛淇℃伅
+     */
+    @Override
+    public DmHarbor selectDmHarborByPkId(Long pkId)
+    {
+        return dmHarborMapper.selectDmHarborByPkId(pkId);
+    }
+
+    /**
+     * 鏌ヨ娓彛淇℃伅鍒楄〃
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 娓彛淇℃伅
+     */
+    @Override
+    public List<DmHarbor> selectDmHarborList(DmHarbor dmHarbor)
+    {
+        return dmHarborMapper.selectDmHarborList(dmHarbor);
+    }
+
+    /**
+     * 鏂板娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertDmHarbor(DmHarbor dmHarbor)
+    {
+            return dmHarborMapper.insertDmHarbor(dmHarbor);
+    }
+
+    /**
+     * 淇敼娓彛淇℃伅
+     *
+     * @param dmHarbor 娓彛淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateDmHarbor(DmHarbor dmHarbor)
+    {
+        return dmHarborMapper.updateDmHarbor(dmHarbor);
+    }
+
+    /**
+     * 鎵归噺鍒犻櫎娓彛淇℃伅
+     *
+     * @param pkIds 闇�瑕佸垹闄ょ殑娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmHarborByPkIds(Long[] pkIds)
+    {
+        return dmHarborMapper.deleteDmHarborByPkIds(pkIds);
+    }
+
+    /**
+     * 鍒犻櫎娓彛淇℃伅淇℃伅
+     *
+     * @param pkId 娓彛淇℃伅涓婚敭
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteDmHarborByPkId(Long pkId)
+    {
+        return dmHarborMapper.deleteDmHarborByPkId(pkId);
+    }
+
+    @Override
+    public TableDataInfo getList(DmHarbor dmHarbor) {
+        Integer offset = (dmHarbor.getPageNum()-1)*dmHarbor.getPageSize();
+        dmHarbor.setOffset(offset);
+        List<DmHarbor> dmHarborList = dmHarborMapper.getPageList(dmHarbor);
+        Integer total = dmHarborMapper.getTotal(dmHarbor);
+        TableDataInfo tableDataInfo = new TableDataInfo();
+        tableDataInfo.setRows(dmHarborList);
+        tableDataInfo.setTotal(total);
+        return tableDataInfo;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpBerthServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpBerthServiceImpl.java
new file mode 100644
index 0000000..f6e8cdc
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpBerthServiceImpl.java
@@ -0,0 +1,36 @@
+package com.ruoyi.manage.service.impl;
+
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DmBerth;
+import com.ruoyi.manage.domain.DpBerth;
+import com.ruoyi.manage.mapper.DpBerthMapper;
+import com.ruoyi.manage.service.DpBerthService;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Service
+public class DpBerthServiceImpl extends ServiceImpl<DpBerthMapper, DmBerth> implements DpBerthService {
+    @Resource
+    private DpBerthMapper dpBerthMapper;
+    @Override
+    public TableDataInfo getPageList(DmBerth dpBerth) {
+        Integer offset = (dpBerth.getPageNum()-1)*dpBerth.getPageSize();
+        dpBerth.setOffset(offset);
+        List<DmBerth> records = dpBerthMapper.getPageList(dpBerth);
+        long total = dpBerthMapper.getTotal(dpBerth);
+        return new TableDataInfo(records,Integer.parseInt(String.valueOf(total)));
+    }
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEffectAssessListServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEffectAssessListServiceImpl.java
new file mode 100644
index 0000000..91a6ff3
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEffectAssessListServiceImpl.java
@@ -0,0 +1,39 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DpEffectAssessListMapper;
+import com.ruoyi.manage.domain.DpEffectAssessList;
+import com.ruoyi.manage.service.DpEffectAssessListService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ *  鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-23
+ */
+@Service
+public class DpEffectAssessListServiceImpl extends ServiceImpl<DpEffectAssessListMapper, DpEffectAssessList>
+        implements DpEffectAssessListService {
+
+    @Autowired
+    DpEffectAssessListMapper dpEffectAssessListMapper;
+
+    @Override
+    public TableDataInfo getList(DpEffectAssessList dpEffectAssessList) {
+        Integer offset = (dpEffectAssessList.getPageNum()-1)*dpEffectAssessList.getPageSize();
+        dpEffectAssessList.setOffset(offset);
+        List<DpEffectAssessList> dmHarborList = dpEffectAssessListMapper.getPageList(dpEffectAssessList);
+        Integer total = dpEffectAssessListMapper.getTotal(dpEffectAssessList);
+        TableDataInfo tableDataInfo = new TableDataInfo();
+        tableDataInfo.setRows(dmHarborList);
+        tableDataInfo.setTotal(total);
+        return tableDataInfo;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEquipmentTypeServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEquipmentTypeServiceImpl.java
new file mode 100644
index 0000000..2453384
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpEquipmentTypeServiceImpl.java
@@ -0,0 +1,35 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DpEquipmentTypeMapper;
+import com.ruoyi.manage.domain.DpEquipmentType;
+import com.ruoyi.manage.service.DpEquipmentTypeService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 璁惧绫诲瀷琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Service
+public class DpEquipmentTypeServiceImpl extends ServiceImpl<DpEquipmentTypeMapper, DpEquipmentType> implements DpEquipmentTypeService {
+    @Resource
+    private DpEquipmentTypeMapper dpEquipmentTypeMapper;
+
+    @Override
+    public TableDataInfo getPageList(DpEquipmentType dpEquipmentType) {
+        Integer offset = (dpEquipmentType.getPageNum()-1)*dpEquipmentType.getPageSize();
+        dpEquipmentType.setOffset(offset);
+        List<DpEquipmentType> records = dpEquipmentTypeMapper.getPageList(dpEquipmentType);
+        Integer total = dpEquipmentTypeMapper.getTotal(dpEquipmentType);
+        return new TableDataInfo(records,total);
+    }
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipDeviceServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipDeviceServiceImpl.java
new file mode 100644
index 0000000..588e058
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipDeviceServiceImpl.java
@@ -0,0 +1,80 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DpShipDeviceMapper;
+import com.ruoyi.manage.domain.DpShipDevice;
+import com.ruoyi.manage.service.DpShipDeviceService;
+import jakarta.annotation.Resource;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌墖璁惧琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-12
+ */
+@Service
+@Component
+public class DpShipDeviceServiceImpl extends ServiceImpl<DpShipDeviceMapper, DpShipDevice> implements DpShipDeviceService {
+
+    @Resource
+    private DpShipDeviceMapper dpShipDeviceMapper;
+
+    //鏂板鑸拌埞璁惧鏁版嵁
+    @Override
+    public int insertDpShipDevice(DpShipDevice dpShipDevice){
+        return dpShipDeviceMapper.insertDpShipDevice(dpShipDevice);
+    }
+    //鏇存柊鑸拌埞璁惧鏁版嵁
+    @Override
+    public int updateDpShipDevice(DpShipDevice dpShipDevice){
+        return dpShipDeviceMapper.updateDpShipDevice(dpShipDevice);
+    }
+    //鍒犻櫎鑸拌埞璁惧鏁版嵁
+    @Override
+    public int deleteDpShipDevice(String id){
+        return dpShipDeviceMapper.deleteDpShipDevice(id);
+    }
+    //鑾峰彇鑸拌埞璁惧鏁版嵁鍒楄〃
+    @Override
+    public List<DpShipDevice> getDpShipDevices(){
+        return dpShipDeviceMapper.getDpShipDevices();
+    }
+    //鏍规嵁鑸拌埞缂栧彿鏌ヨ璁惧鍒楄〃
+    @Override
+    public List<DpShipDevice> selectDpShipDeviceByShipId(String deviceShipId){
+        return dpShipDeviceMapper.selectDpShipDeviceByShipId(deviceShipId);
+    }
+
+    //鏍规嵁ID鑾峰彇鑸拌埞璁惧鏁版嵁
+    @Override
+    public DpShipDevice selectDpShipDevice(String id){
+        return dpShipDeviceMapper.selectDpShipDevice(id);
+    }
+
+    //鏍规嵁name鑾峰彇鑸拌埞璁惧鏁版嵁
+    @Override
+    public DpShipDevice selectDpShipDeviceByName(String name){
+        return dpShipDeviceMapper.selectDpShipDeviceByName(name);
+    }
+
+    @Override
+    public TableDataInfo getDpShipDevicesPage(DpShipDevice shipDevice) {
+        if(shipDevice.getPageNum()!=null && shipDevice.getPageSize()!=null){
+            Integer offset = (shipDevice.getPageNum()-1)*shipDevice.getPageSize();
+            shipDevice.setOffset(offset);
+            List<DpShipDevice> records = dpShipDeviceMapper.getPageList(shipDevice);
+            long total = dpShipDeviceMapper.getTotal(shipDevice);
+            return new TableDataInfo(records,Integer.parseInt(String.valueOf(total)));
+        }else {
+            return null;
+        }
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipParkingServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipParkingServiceImpl.java
new file mode 100644
index 0000000..233e271
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipParkingServiceImpl.java
@@ -0,0 +1,57 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.mapper.DpShipParkingMapper;
+import com.ruoyi.manage.domain.DpShipParking;
+import com.ruoyi.manage.service.DpShipParkingService;
+import com.ruoyi.manage.service.DpShipsService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 娉婁綅鍋滆埞淇℃伅琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-22
+ */
+@Service
+public class DpShipParkingServiceImpl extends ServiceImpl<DpShipParkingMapper, DpShipParking> implements DpShipParkingService {
+    @Resource
+    private DpShipParkingMapper dpShipParkingMapper;
+    @Resource
+    private DpShipsService dpShipsService;
+
+    @Override
+    public TableDataInfo getPageList(DpShipParking dpShipParking) {
+        Integer offset = (dpShipParking.getPageNum()-1)*dpShipParking.getPageSize();
+        dpShipParking.setOffset(offset);
+        List<DpShipParking> records = dpShipParkingMapper.getPageList(dpShipParking);
+        Integer total = dpShipParkingMapper.getTotal(dpShipParking);
+        return new TableDataInfo(records,total);
+    }
+
+    @Override
+    public List<DpShipParking> getByWhBeId(Integer whId,Integer beId,Integer id){
+        QueryWrapper<DpShipParking> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("WH_ID",whId)
+                .eq("BE_ID",beId)
+                .le("ID",id);
+        List<DpShipParking> list = dpShipParkingMapper.selectList(queryWrapper);
+        List<DpShipParking> parkingList = new ArrayList<>();
+        for (DpShipParking dpShipParking : list){
+            DpShips dpShips = dpShipsService.getDpShipsById(dpShipParking.getShipPkid());
+            dpShipParking.setShipModel(dpShips.getShipModel());
+            dpShipParking.setShipId(dpShips.getShipId());
+            parkingList.add(dpShipParking);
+        }
+        return parkingList;
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipTypeServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipTypeServiceImpl.java
new file mode 100644
index 0000000..9329819
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipTypeServiceImpl.java
@@ -0,0 +1,35 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DpShipTypeMapper;
+import com.ruoyi.manage.domain.DpShipType;
+import com.ruoyi.manage.service.DpShipTypeService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鑸拌埞绫诲瀷琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-18
+ */
+@Service
+public class DpShipTypeServiceImpl extends ServiceImpl<DpShipTypeMapper, DpShipType> implements DpShipTypeService {
+    @Resource
+    private DpShipTypeMapper dpShipTypeMapper;
+
+    @Override
+    public TableDataInfo getPageList(DpShipType dpShipType) {
+        Integer offset = (dpShipType.getPageNum()-1)*dpShipType.getPageSize();
+        dpShipType.setOffset(offset);
+        List<DpShipType> records = dpShipTypeMapper.getPageList(dpShipType);
+        Integer total = dpShipTypeMapper.getTotal(dpShipType);
+        return new TableDataInfo(records,total);
+    }
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipsServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipsServiceImpl.java
new file mode 100644
index 0000000..46ad4be
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpShipsServiceImpl.java
@@ -0,0 +1,193 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.domain.DpShipDevice;
+import com.ruoyi.manage.domain.vo.ShipTypeVO;
+import com.ruoyi.manage.domain.vo.TreeVO;
+import com.ruoyi.manage.mapper.DpShipDeviceMapper;
+import com.ruoyi.manage.mapper.DpShipsMapper;
+import com.ruoyi.manage.domain.DpShips;
+import com.ruoyi.manage.service.DpShipsService;
+import com.ruoyi.system.service.ISysDictDataService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+import org.springframework.stereotype.Service;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * <p>
+ * 鑸拌埞琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Service
+@Component
+public class DpShipsServiceImpl extends ServiceImpl<DpShipsMapper, DpShips> implements DpShipsService {
+    @Resource
+    private DpShipsMapper dpShipsMapper;
+    @Resource
+    private DpShipDeviceMapper dpShipDeviceMapper;
+    @Resource
+    private ISysDictDataService iSysDictDataService;
+
+    //鏍规嵁ID鏌ヨ鑸拌埞淇℃伅
+    @Override
+    public DpShips getDpShipsById(String id){
+        return dpShipsMapper.getDpShipsById(id);
+    }
+
+
+    //鏍规嵁鐮佸ごID鏌ヨ鑸硅埌绫诲瀷
+    @Override
+    public List<ShipTypeVO> getDpShipTypeByWhId(Integer whId){
+        QueryWrapper<DpShips> queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("SHIP_TYPE_ID").eq("WH_ID", whId);
+        List<Map<String, Object>> shipTypeMaps = dpShipsMapper.selectMaps(queryWrapper);
+        List<String> list= shipTypeMaps.stream()
+                .map(map -> String.valueOf(map.get("SHIP_TYPE_ID")))
+                .collect(Collectors.toList());
+        List<ShipTypeVO> shipTypeVOS = new ArrayList<>();
+        Map<String,String> shipTypeMap = shipTypeByDict();
+        for (String typeKey:list){
+            ShipTypeVO shipTypeVO =new ShipTypeVO();
+            shipTypeVO.setId(typeKey);
+            shipTypeVO.setName(shipTypeMap.get(typeKey));
+            shipTypeVOS.add(shipTypeVO);
+        }
+        return shipTypeVOS;
+    }
+
+    //鏍规嵁鐮佸ごID鏌ヨ鑸硅埌绫诲瀷锛堟柊锛�
+    @Override
+    public List<ShipTypeVO> getDpShipTypeByWhIdNEW(Integer whId){
+        DpShips ship = new DpShips();
+        ship.setWhId(whId);
+        List<DpShips> shipsList = dpShipsMapper.getByWhIdBeId(ship);
+        Map<String,List<Integer>> mapShipType = new HashMap<>();
+        for (DpShips dpShips : shipsList){
+            String shipType = dpShips.getShipType();
+            Integer shipTypeId = dpShips.getShipTypeId();
+            mapShipType.putIfAbsent(shipType,new ArrayList<>());
+            mapShipType.get(shipType).add(shipTypeId);
+        }
+        List<ShipTypeVO> shipTypeVOS = new ArrayList<>();
+        for(Map.Entry<String,List<Integer>> entry : mapShipType.entrySet()){
+            ShipTypeVO shipTypeVO =new ShipTypeVO();
+            shipTypeVO.setId(String.valueOf(generateId()));
+            shipTypeVO.setName(entry.getKey());
+            shipTypeVO.setIds(entry.getValue());
+            shipTypeVOS.add(shipTypeVO);
+        }
+        return shipTypeVOS;
+    }
+
+    //鏍规嵁瀛楀吀鑾峰彇鑸拌墖绫诲瀷
+    private Map<String,String> shipTypeByDict(){
+        SysDictData sysDictData = new SysDictData();
+        sysDictData.setDictType("dp_ship_type");
+        List<SysDictData> dictDataList = iSysDictDataService.selectDictDataList(sysDictData);
+        Map<String,String> shipTypeMap = new HashMap<>();
+        for (SysDictData dictData : dictDataList){
+            shipTypeMap.put(dictData.getDictValue(),dictData.getDictLabel());
+        }
+        return shipTypeMap;
+    }
+
+    //鏍规嵁鐮佸ごID鍜屾硦浣岻D鏌ヨ鑸拌埞鍒楄〃
+    @Override
+    public List<DpShips> getByWhIdBeId(Integer whId,Integer beId){
+        DpShips dpShips = new DpShips();
+        dpShips.setWhId(whId);
+        dpShips.setBeId(beId);
+        return dpShipsMapper.getByWhIdBeId(dpShips);
+    }
+
+    //鏍规嵁鐮佸ごID鍜岃埌鑸圭被鍨嬫煡璇㈣埌鑸瑰垪琛�
+    @Override
+    public List<TreeVO> getDpShipsByWhIdType(Integer whId, String shipType){
+        QueryWrapper<DpShips> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("WH_ID",whId).eq("SHIP_TYPE_ID",shipType);
+        List<DpShips> list = dpShipsMapper.selectList(queryWrapper);
+        List<TreeVO> treeList = new ArrayList<>();
+        for (DpShips dpShip : list) {
+            TreeVO treeVO = new TreeVO();
+            treeVO.setId(dpShip.getId());
+            treeVO.setLabel(dpShip.getShipName());
+            //闈炲瓙鑺傜偣disable涓簍rue
+            treeVO.setDisabled(true);
+            // 鍒濆鍖栧瓙璁惧鍒楄〃
+            List<TreeVO> treeListChil = new ArrayList<>();
+            QueryWrapper<DpShipDevice> deviceWrapper = new QueryWrapper<>();
+            deviceWrapper.eq("DEVICE_SHIP_ID", dpShip.getShipId());
+            List<DpShipDevice> devices = dpShipDeviceMapper.selectList(deviceWrapper);
+            for (DpShipDevice dpShipDevice : devices){
+                TreeVO treeChil = new TreeVO();
+                treeChil.setId(dpShipDevice.getId());
+                treeChil.setLabel(dpShipDevice.getDeviceName());
+                treeListChil.add(treeChil);
+            }
+            treeVO.setChildren(treeListChil);
+            treeList.add(treeVO);
+        }
+        return treeList;
+    }
+
+    @Override
+    public List<TreeVO> getDpShipsByWhIdTypeNEW(Integer whId, List<Integer> shipTypes){
+        QueryWrapper<DpShips> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("WH_ID",whId).in("SHIP_TYPE_ID",shipTypes);
+        List<DpShips> list = dpShipsMapper.selectList(queryWrapper);
+        List<TreeVO> treeList = new ArrayList<>();
+        for (DpShips dpShip : list) {
+            TreeVO treeVO = new TreeVO();
+            treeVO.setId(dpShip.getId());
+            treeVO.setLabel(dpShip.getShipName());
+            //闈炲瓙鑺傜偣disable涓簍rue
+            treeVO.setDisabled(true);
+            // 鍒濆鍖栧瓙璁惧鍒楄〃
+            List<TreeVO> treeListChil = new ArrayList<>();
+            QueryWrapper<DpShipDevice> deviceWrapper = new QueryWrapper<>();
+            deviceWrapper.eq("SHIP_TYPE_ID", dpShip.getShipTypeId());
+            List<DpShipDevice> devices = dpShipDeviceMapper.selectList(deviceWrapper);
+            for (DpShipDevice dpShipDevice : devices){
+                TreeVO treeChil = new TreeVO();
+//                treeChil.setId(dpShipDevice.getId());
+                treeChil.setId(String.valueOf(generateId()));
+                treeChil.setLabel(dpShipDevice.getDeviceName());
+                treeChil.setDisabled(false);
+                treeChil.setChildren(new ArrayList<>());
+                treeListChil.add(treeChil);
+            }
+            treeVO.setChildren(treeListChil);
+            treeList.add(treeVO);
+        }
+        return treeList;
+    }
+
+    @Override
+    public TableDataInfo getPageList(DpShips ships) {
+        if(ships.getPageNum()!=null && ships.getPageSize()!=null){
+            Integer offset = (ships.getPageNum()-1)*ships.getPageSize();
+            ships.setOffset(offset);
+            List<DpShips> records = dpShipsMapper.getPageList(ships);
+            long total = dpShipsMapper.getTotal(ships);
+            return new TableDataInfo(records,Integer.parseInt(String.valueOf(total)));
+        }
+        return null;
+    }
+
+    //鐢熸垚涓嶉噸澶岻D
+    private int generateId(){
+        UUID uuid = UUID.randomUUID();
+        long hash = uuid.hashCode();
+        return (int)(hash&Integer.MAX_VALUE);
+    }
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpUnitSupplyTimeServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpUnitSupplyTimeServiceImpl.java
new file mode 100644
index 0000000..77dfae1
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpUnitSupplyTimeServiceImpl.java
@@ -0,0 +1,35 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DpUnitSupplyTimeMapper;
+import com.ruoyi.manage.domain.DpUnitSupplyTime;
+import com.ruoyi.manage.service.DpUnitSupplyTimeService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 鍗曚綅琛ョ粰鏃堕棿琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-20
+ */
+@Service
+public class DpUnitSupplyTimeServiceImpl extends ServiceImpl<DpUnitSupplyTimeMapper, DpUnitSupplyTime> implements DpUnitSupplyTimeService {
+    @Resource
+    private DpUnitSupplyTimeMapper dpUnitSupplyTimeMapper;
+
+    @Override
+    public TableDataInfo getPageList(DpUnitSupplyTime dpUnitSupplyTime) {
+        Integer offset = (dpUnitSupplyTime.getPageNum()-1)*dpUnitSupplyTime.getPageSize();
+        dpUnitSupplyTime.setOffset(offset);
+        List<DpUnitSupplyTime> records = dpUnitSupplyTimeMapper.getPageList(dpUnitSupplyTime);
+        Integer total = dpUnitSupplyTimeMapper.getTotal(dpUnitSupplyTime);
+        return new TableDataInfo(records,total);
+    }
+
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpWharfServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpWharfServiceImpl.java
new file mode 100644
index 0000000..569edb6
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DpWharfServiceImpl.java
@@ -0,0 +1,35 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.fuzhou.mapper.EquipmentMapper;
+import com.ruoyi.manage.domain.DpWharf;
+import com.ruoyi.manage.mapper.DpBerthMapper;
+import com.ruoyi.manage.mapper.DpWharfMapper;
+import com.ruoyi.manage.service.DpWharfService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 鐮佸ご 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author zhangyy
+ * @since 2025-03-11
+ */
+@Service
+public class DpWharfServiceImpl extends ServiceImpl<DpWharfMapper, DpWharf> implements DpWharfService {
+    @Autowired
+    private EquipmentMapper equipmentMapper;
+    @Autowired
+    private DpBerthMapper berthMapper;
+    @Override
+    public void deleteWhraf(Integer whId) {
+        //鍒犻櫎鐮佸ご涓嬫硦浣�
+        berthMapper.deleteByWhId(whId);
+        //鍒犻櫎娉婁綅涓嬭澶�
+        equipmentMapper.deleteBy(whId);
+        //鍒犻櫎鐮佸ご
+        this.deleteWhraf(whId);
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DsTaskListServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DsTaskListServiceImpl.java
new file mode 100644
index 0000000..f265ce0
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/DsTaskListServiceImpl.java
@@ -0,0 +1,43 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.core.page.TableDataInfo;
+import com.ruoyi.manage.mapper.DsTaskListMapper;
+import com.ruoyi.manage.domain.DsTaskList;
+import com.ruoyi.manage.service.DsTaskListService;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * <p>
+ * 浠诲姟鍒嗛厤璇︽儏琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-03-24
+ */
+@Service
+public class DsTaskListServiceImpl extends ServiceImpl<DsTaskListMapper, DsTaskList> implements DsTaskListService {
+    @Resource
+    private DsTaskListMapper dsTaskListMapper;
+
+    @Override
+    public TableDataInfo getPageList(DsTaskList dsTaskList) {
+        Integer offset = (dsTaskList.getPageNum()-1)*dsTaskList.getPageSize();
+        dsTaskList.setOffset(offset);
+        List<DsTaskList> records = dsTaskListMapper.getPageList(dsTaskList);
+        Integer total = dsTaskListMapper.getTotal(dsTaskList);
+        return new TableDataInfo(records,total);
+    }
+
+    @Override
+    public TableDataInfo getPageListDaily(DsTaskList dsTaskList){
+        Integer offset = (dsTaskList.getPageNum()-1)*dsTaskList.getPageSize();
+        dsTaskList.setOffset(offset);
+        List<DsTaskList> records = dsTaskListMapper.getPageListDaily(dsTaskList);
+        Integer total = dsTaskListMapper.getTotalDaily(dsTaskList);
+        return new TableDataInfo(records,total);
+    }
+}
diff --git a/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/SysFileServiceImpl.java b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/SysFileServiceImpl.java
new file mode 100644
index 0000000..94f12d4
--- /dev/null
+++ b/ruoyi-manage/src/main/java/com/ruoyi/manage/service/impl/SysFileServiceImpl.java
@@ -0,0 +1,118 @@
+package com.ruoyi.manage.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.ruoyi.common.config.RuoYiConfig;
+import com.ruoyi.common.utils.file.FileUploadUtils;
+import com.ruoyi.framework.config.ServerConfig;
+import com.ruoyi.manage.domain.vo.SysFileManageVO;
+import com.ruoyi.manage.mapper.SysFileMapper;
+import com.ruoyi.manage.domain.SysFileManage;
+import com.ruoyi.manage.service.SysFileService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * <p>
+ * 鏂囦欢绠$悊琛� 鏈嶅姟瀹炵幇绫�
+ * </p>
+ *
+ * @author sunjiawei
+ * @since 2025-05-21
+ */
+@Service
+public class SysFileServiceImpl extends ServiceImpl<SysFileMapper, SysFileManage> implements SysFileService {
+    @Autowired
+    private SysFileMapper sysFileMapper;
+    @Autowired
+    private ServerConfig serverConfig;
+
+    //鏌ヨ鎵�鏈夋暟鎹垪琛�
+    @Override
+    public List<SysFileManage> listAll(){
+        return sysFileMapper.selectList(null);
+    }
+
+    //鍗曟枃浠朵笂浼�
+    @Override
+    public Integer saveFile(MultipartFile file,SysFileManage sysFileManage) throws Exception{
+        // 涓婁紶鏂囦欢璺緞
+        String filePath = RuoYiConfig.getUploadPath();
+        // 涓婁紶骞惰繑鍥炴柊鏂囦欢鍚嶇О
+        String fileName = FileUploadUtils.upload(filePath, file);
+        sysFileManage.setFilePath(fileName);
+        sysFileManage.setSize(FileUploadUtils.getFileSize(file));
+        return sysFileMapper.insert(sysFileManage);
+    }
+
+    //鍗曠嫭鏁版嵁鎻掑叆\
+    @Override
+    public Integer saveData(SysFileManage sysFileManage) throws Exception{
+        return sysFileMapper.insert(sysFileManage);
+    }
+
+    //鎵归噺鎻掑叆
+//    Integer saveBatch(List<SysFileManage> sysFileManages);
+
+    //鏉′欢鏌ヨ
+    @Override
+    public List<SysFileManage> queryData(SysFileManageVO vo){
+        LambdaQueryWrapper<SysFileManage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        String name = vo.getName();
+        String type = vo.getType();
+        if(name!=null && !name.trim().isEmpty()){
+            lambdaQueryWrapper.like(SysFileManage::getName,name);
+        }
+        if(type!=null){
+            lambdaQueryWrapper.like(SysFileManage::getType,type);
+        }
+        return sysFileMapper.selectList(lambdaQueryWrapper);
+    }
+
+    //鎵归噺鍒犻櫎
+    @Override
+    public List<String> deleteBatch(List<String> ids){
+        List<String> failedToDelete = new ArrayList<>();
+        LambdaQueryWrapper<SysFileManage> lambdaQueryWrapper = new LambdaQueryWrapper<>();
+        for (String id : ids){
+            SysFileManage sysFileManage = sysFileMapper.selectById(id);
+            String name = sysFileManage.getName();
+            String filePath = sysFileManage.getFilePath();
+            String realFilePath = filePath.replaceFirst("/profile",RuoYiConfig.getProfile());
+            String realFileName = name + realFilePath.substring(realFilePath.indexOf("_") + 1);
+            if(judgmentOS()){
+                realFilePath = realFilePath.replace("/","\\");
+            }
+            boolean success = FileUploadUtils.deleteFile(realFilePath);
+            if(!success){
+                failedToDelete.add(realFileName);
+            }else {
+                lambdaQueryWrapper.eq(SysFileManage::getFilePath,filePath);
+                sysFileMapper.delete(lambdaQueryWrapper);
+            }
+        }
+        return failedToDelete;
+    }
+
+
+    //鏌ヨ鎬绘暟
+    @Override
+    public Long queryCount(){
+        return sysFileMapper.selectCount(null);
+    }
+
+    //鍒ゆ柇褰撳墠绯荤粺鏄惁鏄痺indows
+    public boolean judgmentOS(){
+        boolean flag = false;
+        String osName = System.getProperty("os.name").toLowerCase();
+        if(osName.contains("win")){
+            flag = true;
+        }
+        return flag;
+    }
+
+}
diff --git a/ruoyi-manage/src/main/resources/mapper/DmHarborMapper.xml b/ruoyi-manage/src/main/resources/mapper/DmHarborMapper.xml
new file mode 100644
index 0000000..645dee8
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DmHarborMapper.xml
@@ -0,0 +1,187 @@
+<?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.manage.mapper.DmHarborMapper">
+    
+    <resultMap type="com.ruoyi.manage.domain.DmHarbor" id="DmHarborResult">
+        <result property="pkId"    column="pkId"    />
+        <result property="harborName"    column="HARBOR_NAME"    />
+        <result property="deptId"    column="dept_id"    />
+        <result property="deptName"    column="dept_name"    />
+        <result property="berthNo"    column="berth_no"    />
+        <result property="oilB"    column="oil_b"    />
+        <result property="oilG"    column="oil_g"    />
+        <result property="ammoD"    column="ammo_d"    />
+        <result property="ammoP"    column="ammo_p"    />
+        <result property="ammoS"    column="ammo_s"    />
+        <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="dockName"    column="dockName"    />
+        <result property="water"    column="water"    />
+        <result property="material"    column="material"    />
+        <result property="ammoO"    column="ammo_o"    />
+        <result property="remark"    column="remark"    />
+        <result property="height"    column="HEIGHT"    />
+        <result property="heading"    column="HEADING"    />
+        <result property="pitch"    column="PITCH"    />
+        <result property="roll"    column="ROLL"    />
+        <result property="latitude"    column="LATITUDE"    />
+        <result property="longitude"    column="LONGITUDE"    />
+        <result property="pointX"    column="POINT_X"    />
+        <result property="pointY"    column="POINT_Y"    />
+    </resultMap>
+
+    <sql id="selectDmHarborVo">
+        select pkId, HARBOR_NAME, dept_id, dept_name, berth_no, oil_b, oil_g, ammo_d, ammo_p, ammo_s, del_flag,
+         create_by, create_time, update_by, update_time, dockName, water, material, ammo_o, remark,
+          HEIGHT, HEADING, PITCH, ROLL, LATITUDE, LONGITUDE, POINT_X, POINT_Y from dm_harbor
+    </sql>
+
+    <select id="selectDmHarborList" parameterType="DmHarbor" resultMap="DmHarborResult">
+        <include refid="selectDmHarborVo"/>
+        <where>  
+            <if test="name != null  and name != ''"> and name like concat('%', #{name}, '%')</if>
+            <if test="deptId != null "> and dept_id = #{deptId}</if>
+            <if test="deptName != null  and deptName != ''"> and dept_name like concat('%', #{deptName}, '%')</if>
+            <if test="berthNo != null "> and berth_no = #{berthNo}</if>
+            <if test="oilB != null "> and oil_b = #{oilB}</if>
+            <if test="oilG != null "> and oil_g = #{oilG}</if>
+            <if test="ammoD != null "> and ammo_d = #{ammoD}</if>
+            <if test="ammoP != null "> and ammo_p = #{ammoP}</if>
+            <if test="ammoS != null "> and ammo_s = #{ammoS}</if>
+            <if test="dockName != null  and dockName != ''"> and dockName like concat('%', #{dockName}, '%')</if>
+            <if test="water != null "> and water = #{water}</if>
+            <if test="material != null "> and material = #{material}</if>
+            <if test="ammoO != null "> and ammo_o = #{ammoO}</if>
+        </where>
+    </select>
+    
+    <select id="selectDmHarborByPkId" parameterType="Long" resultMap="DmHarborResult">
+        <include refid="selectDmHarborVo"/>
+        where pkId = #{pkId}
+    </select>
+        
+    <insert id="insertDmHarbor" parameterType="DmHarbor" useGeneratedKeys="true" keyProperty="pkId">
+        insert into dm_harbor
+        <trim prefix="(" suffix=")" suffixOverrides=",">
+            <if test="name != null and name != ''">name,</if>
+            <if test="deptId != null">dept_id,</if>
+            <if test="deptName != null and deptName != ''">dept_name,</if>
+            <if test="berthNo != null">berth_no,</if>
+            <if test="oilB != null">oil_b,</if>
+            <if test="oilG != null">oil_g,</if>
+            <if test="ammoD != null">ammo_d,</if>
+            <if test="ammoP != null">ammo_p,</if>
+            <if test="ammoS != null">ammo_s,</if>
+            <if test="delFlag != null">del_flag,</if>
+            <if test="createBy != null">create_by,</if>
+            <if test="createTime != null">create_time,</if>
+            <if test="updateBy != null">update_by,</if>
+            <if test="updateTime != null">update_time,</if>
+            <if test="dockName != null">dockName,</if>
+            <if test="water != null">water,</if>
+            <if test="material != null">material,</if>
+            <if test="ammoO != null">ammo_o,</if>
+            <if test="remark != null">remark,</if>
+            <if test="height != null">HEIGHT,</if>
+            <if test="heading != null">HEADING,</if>
+            <if test="pitch != null">PITCH,</if>
+            <if test="roll != null">ROLL,</if>
+            <if test="latitude != null">LATITUDE,</if>
+            <if test="longitude != null">LONGITUDE,</if>
+            <if test="pointX != null">POINT_X,</if>
+            <if test="pointY != null">POINT_Y,</if>
+         </trim>
+        <trim prefix="values (" suffix=")" suffixOverrides=",">
+            <if test="name != null and name != ''">#{name},</if>
+            <if test="deptId != null">#{deptId},</if>
+            <if test="deptName != null and deptName != ''">#{deptName},</if>
+            <if test="berthNo != null">#{berthNo},</if>
+            <if test="oilB != null">#{oilB},</if>
+            <if test="oilG != null">#{oilG},</if>
+            <if test="ammoD != null">#{ammoD},</if>
+            <if test="ammoP != null">#{ammoP},</if>
+            <if test="ammoS != null">#{ammoS},</if>
+            <if test="delFlag != null">#{delFlag},</if>
+            <if test="createBy != null">#{createBy},</if>
+            <if test="createTime != null">#{createTime},</if>
+            <if test="updateBy != null">#{updateBy},</if>
+            <if test="updateTime != null">#{updateTime},</if>
+            <if test="dockName != null">#{dockName},</if>
+            <if test="water != null">#{water},</if>
+            <if test="material != null">#{material},</if>
+            <if test="ammoO != null">#{ammoO},</if>
+            <if test="remark != null">#{remark},</if>
+            <if test="height != null">#{height},</if>
+            <if test="heading != null">#{heading},</if>
+            <if test="pitch != null">#{pitch},</if>
+            <if test="roll != null">#{roll},</if>
+            <if test="latitude != null">#{latitude},</if>
+            <if test="longitude != null">#{longitude},</if>
+            <if test="pointX != null">#{pointX},</if>
+            <if test="pointY != null">#{pointY},</if>
+         </trim>
+    </insert>
+
+    <update id="updateDmHarbor" parameterType="DmHarbor">
+        update dm_harbor
+        <trim prefix="SET" suffixOverrides=",">
+            <if test="name != null and name != ''">name = #{name},</if>
+            <if test="deptId != null">dept_id = #{deptId},</if>
+            <if test="deptName != null and deptName != ''">dept_name = #{deptName},</if>
+            <if test="berthNo != null">berth_no = #{berthNo},</if>
+            <if test="oilB != null">oil_b = #{oilB},</if>
+            <if test="oilG != null">oil_g = #{oilG},</if>
+            <if test="ammoD != null">ammo_d = #{ammoD},</if>
+            <if test="ammoP != null">ammo_p = #{ammoP},</if>
+            <if test="ammoS != null">ammo_s = #{ammoS},</if>
+            <if test="delFlag != null">del_flag = #{delFlag},</if>
+            <if test="createBy != null">create_by = #{createBy},</if>
+            <if test="createTime != null">create_time = #{createTime},</if>
+            <if test="updateBy != null">update_by = #{updateBy},</if>
+            <if test="updateTime != null">update_time = #{updateTime},</if>
+            <if test="dockName != null">dockName = #{dockName},</if>
+            <if test="water != null">water = #{water},</if>
+            <if test="material != null">material = #{material},</if>
+            <if test="ammoO != null">ammo_o = #{ammoO},</if>
+            <if test="remark != null">remark = #{remark},</if>
+        </trim>
+        where pkId = #{pkId}
+    </update>
+
+    <delete id="deleteDmHarborByPkId" parameterType="Long">
+        delete from dm_harbor where pkId = #{pkId}
+    </delete>
+
+    <delete id="deleteDmHarborByPkIds" parameterType="String">
+        delete from dm_harbor where pkId in 
+        <foreach item="pkId" collection="array" open="(" separator="," close=")">
+            #{pkId}
+        </foreach>
+    </delete>
+
+    <select id="getPageList" resultMap="DmHarborResult">
+        select a.*,b.DEPT_NAME as bumenName from dm_harbor a left join sys_dept b on a.DEPT_ID = b.DEPT_ID
+        <where>
+            <if test="dockName!=null and dockName!=''">
+                dockname like concat('%',#{dockName},'%')
+            </if>
+        </where>
+        order by PKID DESC
+        limit #{pageSize} offset #{offset}
+
+    </select>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from  dm_harbor a left join sys_dept b on a.DEPT_ID = b.DEPT_ID
+        <where>
+            <if test="dockName!=null and dockName!=''">
+                dockname like concat('%',#{dockName},'%')
+            </if>
+        </where>
+    </select>
+</mapper>
\ No newline at end of file
diff --git a/ruoyi-manage/src/main/resources/mapper/DpBerthMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpBerthMapper.xml
new file mode 100644
index 0000000..3016b33
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpBerthMapper.xml
@@ -0,0 +1,55 @@
+<?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.manage.mapper.DpBerthMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DmBerth">
+        <result column="PKID" property="pkid" />
+        <result column="NAME" property="name" />
+        <result column="HARBOR_ID" property="harborId" />
+        <result column="HARBOR_NAME" property="harborName" />
+        <result column="BERTH_LEN" property="berthLen" />
+        <result column="DEPTH" property="depth" />
+        <result column="STATUS" property="status" />
+        <result column="ORDER_NUM" property="orderNum" />
+        <result column="DEL_FLAG" property="delFlag" />
+        <result column="CREATE_BY" property="createBy" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="UPDATE_BY" property="updateBy" />
+        <result column="UPDATE_TIME" property="updateTime" />
+        <result column="REMARK" property="remark" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        PKID, NAME, HARBOR_ID, HARBOR_NAME, BERTH_LEN, DEPTH, STATUS, ORDER_NUM, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK
+    </sql>
+
+    <delete id="deleteByWhId">
+        delete from DM_BERTH where HARBOR_ID = #{whId}
+    </delete>
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DmBerth">
+        select a.*,b.HARBOR_NAME as harborName from DM_BERTH a left join DM_HARBOR b on a.HARBOR_ID = b.PKID
+        <where>
+            <if test="name!=null and name!=''">
+                a.NAME like concat('%',#{name},'%')
+            </if>
+            <if test="harborId!=null and harborId!=0">
+                a.harbor_id = #{harborId}
+            </if>
+        </where>
+             order by a.ORDER_NUM DESC limit #{pageSize} offset #{offset}
+    </select>
+    <select id="getTotal" resultType="java.lang.Long">
+        select count(1) from DM_BERTH a left join DM_HARBOR b on a.HARBOR_ID = b.PKID
+        <where>
+            <if test="name!=null and name!=''">
+                a.NAME like concat('%',#{name},'%')
+            </if>
+            <if test="harborId!=null and harborId!=0">
+                a.harbor_id = #{harborId}
+            </if>
+        </where>
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpEffectAssessListMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpEffectAssessListMapper.xml
new file mode 100644
index 0000000..7ce5116
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpEffectAssessListMapper.xml
@@ -0,0 +1,43 @@
+<?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.manage.mapper.DpEffectAssessListMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpEffectAssessList">
+        <id column="PKID" property="pkid" />
+        <result column="ASSESS_ID" property="assessId" />
+        <result column="TYPE" property="type" />
+        <result column="DEL_FLAG" property="delFlag" />
+        <result column="CREATE_BY" property="createBy" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="UPDATE_BY" property="updateBy" />
+        <result column="UPDATE_TIME" property="updateTime" />
+        <result column="REMARK" property="remark" />
+        <result column="PLAN" property="plan" />
+        <result column="ITEM" property="item" />
+        <result column="ITEM_DETAIL" property="itemDetail" />
+        <result column="UNIT" property="unit" />
+        <result column="CODE" property="code" />
+        <result column="NORMAL" property="normal" />
+        <result column="WEIGHT" property="weight" />
+        <result column="CLASSIFY_INDEX" property="classifyIndex" />
+        <result column="CLASSIFY_WEIGHT" property="classifyWeight" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        PKID, ASSESS_ID, TYPE, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, REMARK, PLAN, ITEM, ITEM_DETAIL, UNIT, CODE, NORMAL, WEIGHT, CLASSIFY_INDEX, CLASSIFY_WEIGHT
+    </sql>
+
+    <select id="getPageList" resultMap="BaseResultMap">
+        select * from DS_EFFECT_ASSESS_LIST
+        order by PKID DESC
+        limit #{pageSize} offset #{offset}
+    </select>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from  DS_EFFECT_ASSESS_LIST
+    </select>
+
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpEquipmentTypeMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpEquipmentTypeMapper.xml
new file mode 100644
index 0000000..b01e889
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpEquipmentTypeMapper.xml
@@ -0,0 +1,32 @@
+<?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.manage.mapper.DpEquipmentTypeMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpEquipmentType">
+        <id column="ID" property="id" />
+        <result column="TYPE_NAME" property="typeName" />
+        <result column="DESCRIPTION" property="description" />
+        <result column="FILE_PATH" property="filePath" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, TYPE_NAME, DESCRIPTION, FILE_PATH
+    </sql>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_EQUIPMENT_TYPE
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpEquipmentType">
+        select * from DP_EQUIPMENT_TYPE
+        <where>
+            <if test="typeName != null and typeName != ''">
+                and TYPE_NAME like concat('%',#{typeName},'%')
+            </if>
+        </where>
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpShipDeviceMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpShipDeviceMapper.xml
new file mode 100644
index 0000000..e2efd70
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpShipDeviceMapper.xml
@@ -0,0 +1,97 @@
+<?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.manage.mapper.DpShipDeviceMapper">
+
+    <insert id="insertDpShipDevice" parameterType="com.ruoyi.manage.domain.DpShipDevice">
+        insert into DP_SHIP_DEVICE(DEVICE_ID, DEVICE_NAME, DEVICE_SHIP_ID, DEVICE_OVERVIEW,
+                                   DEVICE_MODEL, DEVICE_PARAMETERS, UPDATE_TIME, UPDATE_USER)
+        values(#{entity.deviceId}, #{entity.deviceName}, #{entity.deviceShipId},  #{entity.deviceOverview},
+               #{entity.deviceModel}, #{entity.deviceParameters}, #{entity.updateTime}, #{entity.updateUser})
+    </insert>
+
+    <update id="updateDpShipDevice" parameterType="com.ruoyi.manage.domain.DpShipDevice">
+        UPDATE DP_SHIP_DEVICE
+        SET
+            DEVICE_ID = #{entity.deviceId},
+            DEVICE_NAME = #{entity.deviceName},
+            DEVICE_SHIP_ID = #{entity.deviceShipId},
+            DEVICE_OVERVIEW = #{entity.deviceOverview},
+            DEVICE_MODEL = #{entity.deviceModel},
+            DEVICE_PARAMETERS = #{entity.deviceParameters},
+            UPDATE_TIME = #{entity.updateTime},
+            UPDATE_USER = #{entity.updateUser}
+        WHERE ID = #{entity.id}
+    </update>
+
+    <delete id="deleteDpShipDevice" parameterType="string">
+        delete from DP_SHIP_DEVICE where ID = #{id}
+    </delete>
+
+    <select id="selectDpShipDevice" parameterType="string" resultType="com.ruoyi.manage.domain.DpShipDevice">
+        select a.*,b.SHIP_NAME as deviceShipName,c.SHIP_MODEL as deviceModel,c.TYPE_NAME as shipTypeName from DP_SHIP_DEVICE a
+        left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="id != null and id != ''">
+                and a.ID = #{id}
+            </if>
+        </where>
+    </select>
+
+    <select id="selectDpShipDeviceByName" parameterType="string" resultType="com.ruoyi.manage.domain.DpShipDevice">
+        select a.*,b.SHIP_NAME as deviceShipName,c.SHIP_MODEL as deviceModel,c.TYPE_NAME as shipTypeName from DP_SHIP_DEVICE a
+        left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="name != null and name != ''">
+                and a.DEVICE_NAME = #{name}
+            </if>
+        </where>
+    </select>
+
+    <select id="getDpShipDevices" resultType="com.ruoyi.manage.domain.DpShipDevice">
+        select a.*,b.SHIP_NAME as deviceShipName,c.SHIP_MODEL as deviceModel,c.TYPE_NAME as shipTypeName from DP_SHIP_DEVICE a
+        left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+    </select>
+
+    <select id="selectDpShipDeviceByShipId" parameterType="string" resultType="com.ruoyi.manage.domain.DpShipDevice">
+        select a.*,b.SHIP_NAME as deviceShipName,c.SHIP_MODEL as deviceModel,c.TYPE_NAME as shipTypeName from DP_SHIP_DEVICE a
+        left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+        <if test="deviceShipId != null and deviceShipId != ''">
+         and a.DEVICE_SHIP_ID = #{deviceShipId}
+        </if>
+        </where>
+    </select>
+
+    <select id="getTotal" resultType="java.lang.Long">
+        select count(1) from DP_SHIP_DEVICE a left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        <where>
+            <if test="deviceName != null and deviceName != ''">
+                and a.DEVICE_NAME like concat('%', #{deviceName}, '%')
+            </if>
+            <if test="deviceId!=null and deviceId!=''">
+                and a.DEVICE_ID like concat('%', #{deviceId}, '%')
+            </if>
+        </where>
+    </select>
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpShipDevice">
+        select a.*,b.SHIP_NAME as deviceShipName,c.SHIP_MODEL as deviceModel,c.TYPE_NAME as shipTypeName,
+        c.SHIP_DESIGN as shipDesign from DP_SHIP_DEVICE a
+        left join DP_Ships b on a.DEVICE_SHIP_ID = b.SHIP_ID
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="deviceName != null and deviceName != ''">
+                and a.DEVICE_NAME like concat('%', #{deviceName}, '%')
+            </if>
+            <if test="deviceId!=null and deviceId!=''">
+                and a.DEVICE_ID like concat('%', #{deviceId}, '%')
+            </if>
+        </where>
+        order by a.ID DESC
+        limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpShipParkingMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpShipParkingMapper.xml
new file mode 100644
index 0000000..c625da2
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpShipParkingMapper.xml
@@ -0,0 +1,31 @@
+<?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.manage.mapper.DpShipParkingMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpShipParking">
+        <id column="ID" property="id" />
+        <result column="WH_ID" property="whId" />
+        <result column="BE_ID" property="beId" />
+        <result column="SHIP_PKID" property="shipPkid" />
+        <result column="LON" property="lon" />
+        <result column="LAT" property="lat" />
+        <result column="ALT" property="alt" />
+        <result column="HEADING" property="heading" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, WH_ID, BE_ID, SHIP_PKID, LON, LAT, ALT, HEADING
+    </sql>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_SHIP_PARKING
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpShipParking">
+        select * from DP_SHIP_PARKING
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpShipTypeMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpShipTypeMapper.xml
new file mode 100644
index 0000000..9724064
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpShipTypeMapper.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.manage.mapper.DpShipTypeMapper">
+
+<!--    &lt;!&ndash; 閫氱敤鏌ヨ鏄犲皠缁撴灉 &ndash;&gt;-->
+<!--    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpShipType">-->
+<!--        <id column="ID" property="id" />-->
+<!--        <result column="TYPE_NAME" property="typeName" />-->
+<!--        <result column="SHIP_OVERVIEW" property="shipOverview" />-->
+<!--        <result column="SHIP_PARAMETERS" property="shipParameters" />-->
+<!--        <result column="SHIP_MODEL" property="shipModel" />-->
+<!--    </resultMap>-->
+
+<!--    &lt;!&ndash; 閫氱敤鏌ヨ缁撴灉鍒� &ndash;&gt;-->
+<!--    <sql id="Base_Column_List">-->
+<!--        ID, TYPE_NAME, SHIP_OVERVIEW, SHIP_PARAMETERS, SHIP_MODEL-->
+<!--    </sql>-->
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_SHIP_TYPE
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpShipType">
+        select * from DP_SHIP_TYPE
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpShipsMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpShipsMapper.xml
new file mode 100644
index 0000000..484236b
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpShipsMapper.xml
@@ -0,0 +1,60 @@
+<?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.manage.mapper.DpShipsMapper">
+
+    <select id="getDpShipsById" parameterType="java.lang.String" resultType="com.ruoyi.manage.domain.DpShips">
+        select a.*, c.TYPE_NAME as shipType, c.SHIP_DESIGN as shipDesign, c.SHIP_OVERVIEW as shipOverview,
+        c.SHIP_PARAMETERS as shipParameters, c.SHIP_MODEL as shipModel,c.POSITION as position,c.TARGET as target,
+        c.TONNAGE as tonnage, c.DRAFT as draft, c.LENGTH as length, c.CREW as crew from DP_SHIPS a
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="id != null and id != ''">
+                and a.ID = #{id}
+            </if>
+
+        </where>
+    </select>
+
+    <select id="getByWhIdBeId" parameterType="com.ruoyi.manage.domain.DpShips" resultType="com.ruoyi.manage.domain.DpShips">
+        select a.*, c.TYPE_NAME as shipType, c.SHIP_DESIGN as shipDesign, c.SHIP_OVERVIEW as shipOverview,
+        c.SHIP_PARAMETERS as shipParameters, c.SHIP_MODEL as shipModel,c.POSITION as position,c.TARGET as target,
+        c.TONNAGE as tonnage, c.DRAFT as draft, c.LENGTH as length, c.CREW as crew from DP_SHIPS a
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="whId != null and whId != ''">
+                and a.WH_ID = #{whId}
+            </if>
+            <if test="beId != null and beId != ''">
+                and a.BE_ID = #{beId}
+            </if>
+        </where>
+    </select>
+
+
+
+    <select id="getTotal" resultType="java.lang.Long">
+        select count(1) from DP_SHIPS a left join DP_WHARF b on a.WH_ID = b.WH_ID
+        <where>
+            <if test="shipName != null and shipName != ''">
+                and a.SHIP_NAME LIKE CONCAT('%', #{shipName}, '%')
+            </if>
+
+        </where>
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpShips">
+        select a.*, c.TYPE_NAME as shipType, c.SHIP_DESIGN as shipDesign, c.SHIP_OVERVIEW as shipOverview,c.POSITION as position,c.TARGET as target,
+        c.SHIP_PARAMETERS as shipParameters, c.SHIP_MODEL as shipModel,b.HARBOR_NAME as whName,d.name as beName,
+        c.TONNAGE as tonnage, c.DRAFT as draft, c.LENGTH as length, c.CREW as crew from DP_SHIPS a
+        left join dm_harbor b on a.WH_ID = b.pkId
+        left join DM_BERTH d on a.BE_ID = d.pkId
+        left join DP_SHIP_TYPE c on a.SHIP_TYPE_ID = c.ID
+        <where>
+            <if test="shipName != null and shipName != ''">
+                and a.SHIP_NAME LIKE CONCAT('%', #{shipName}, '%')
+            </if>
+        </where>
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpUnitSupplyTimeMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpUnitSupplyTimeMapper.xml
new file mode 100644
index 0000000..3d27a47
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpUnitSupplyTimeMapper.xml
@@ -0,0 +1,28 @@
+<?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.manage.mapper.DpUnitSupplyTimeMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpUnitSupplyTime">
+        <id column="ID" property="id" />
+        <result column="UNIT" property="unit" />
+        <result column="CATEGORY" property="category" />
+        <result column="SUPPLY_TIME" property="supplyTime" />
+        <result column="SHIP_DESIGN" property="shipDesign" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, UNIT, CATEGORY, SUPPLY_TIME, SHIP_DESIGN
+    </sql>
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DP_UNIT_SUPPLY_TIME
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DpUnitSupplyTime">
+        select * from DP_UNIT_SUPPLY_TIME
+        order by ID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DpWharfMapper.xml b/ruoyi-manage/src/main/resources/mapper/DpWharfMapper.xml
new file mode 100644
index 0000000..1540fa4
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DpWharfMapper.xml
@@ -0,0 +1,22 @@
+<?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.manage.mapper.DpWharfMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DpWharf">
+        <id column="WH_ID" property="whId" />
+        <result column="NAME" property="whId" />
+        <result column="HEIGHT" property="height" />
+        <result column="HEADING" property="heading" />
+        <result column="PITCH" property="pitch" />
+        <result column="ROLL" property="roll" />
+        <result column="LATITUDE" property="latitude" />
+        <result column="LONGITUDE" property="longitude" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        WH_ID, NAME, HEIGHT, HEADING, PITCH, ROLL, LATITUDE, LONGITUDE
+    </sql>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/DsTaskListMapper.xml b/ruoyi-manage/src/main/resources/mapper/DsTaskListMapper.xml
new file mode 100644
index 0000000..b5f4b3e
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/DsTaskListMapper.xml
@@ -0,0 +1,91 @@
+<?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.manage.mapper.DsTaskListMapper">
+
+<!--    &lt;!&ndash; 閫氱敤鏌ヨ鏄犲皠缁撴灉 &ndash;&gt;-->
+<!--    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.DsTaskList">-->
+<!--        <id column="PKID" property="pkid" />-->
+<!--        <result column="TASK_ID" property="taskId" />-->
+<!--        <result column="SHIP_NO" property="shipNo" />-->
+<!--        <result column="SHIP_TYPE" property="shipType" />-->
+<!--        <result column="TONNAGE" property="tonnage" />-->
+<!--        <result column="DRAFT" property="draft" />-->
+<!--        <result column="LEADER" property="leader" />-->
+<!--        <result column="STAFF" property="staff" />-->
+<!--        <result column="GRP_NAME" property="grpName" />-->
+<!--        <result column="LEVEL" property="level" />-->
+<!--        <result column="LAT" property="lat" />-->
+<!--        <result column="LON" property="lon" />-->
+<!--        <result column="DEL_FLAG" property="delFlag" />-->
+<!--        <result column="CREATE_BY" property="createBy" />-->
+<!--        <result column="CREATE_TIME" property="createTime" />-->
+<!--        <result column="UPDATE_BY" property="updateBy" />-->
+<!--        <result column="UPDATE_TIME" property="updateTime" />-->
+<!--        <result column="OIL_B" property="oilB" />-->
+<!--        <result column="OIL_G" property="oilG" />-->
+<!--        <result column="OIL_A" property="oilA" />-->
+<!--        <result column="AMMO_D" property="ammoD" />-->
+<!--        <result column="AMMO_P" property="ammoP" />-->
+<!--        <result column="AMMO_S" property="ammoS" />-->
+<!--        <result column="AMMO_O" property="ammoO" />-->
+<!--        <result column="WATER" property="water" />-->
+<!--        <result column="WATER_P" property="waterP" />-->
+<!--        <result column="FOOD" property="food" />-->
+<!--        <result column="FOOD_W" property="foodW" />-->
+<!--        <result column="FOOD_O" property="foodO" />-->
+<!--        <result column="P_S_TIME" property="pSTime" />-->
+<!--        <result column="P_E_TIME" property="pETime" />-->
+<!--        <result column="STATUS" property="status" />-->
+<!--        <result column="HARBOR_ID" property="harborId" />-->
+<!--        <result column="HARBOR_NAME" property="harborName" />-->
+<!--        <result column="BERTH_ID" property="berthId" />-->
+<!--        <result column="BERTH_NAME" property="berthName" />-->
+<!--        <result column="PARKING_TYPE" property="parkingType" />-->
+<!--        <result column="REMARK" property="remark" />-->
+<!--        <result column="DEPT_ID" property="deptId" />-->
+<!--        <result column="DEPT_NAME" property="deptName" />-->
+<!--        <result column="POS_AREA" property="posArea" />-->
+<!--        <result column="SHIP_LEN" property="shipLen" />-->
+<!--    </resultMap>-->
+
+<!--    &lt;!&ndash; 閫氱敤鏌ヨ缁撴灉鍒� &ndash;&gt;-->
+<!--    <sql id="Base_Column_List">-->
+<!--        TASK_ID, SHIP_NO, SHIP_TYPE, TONNAGE, DRAFT, LEADER, STAFF, GRP_NAME, LEVEL, LAT, LON, DEL_FLAG, CREATE_BY, CREATE_TIME, UPDATE_BY, UPDATE_TIME, OIL_B, OIL_G, OIL_A, AMMO_D, AMMO_P, AMMO_S, AMMO_O, WATER, WATER_P, FOOD, FOOD_W, FOOD_O, P_S_TIME, P_E_TIME, STATUS, HARBOR_ID, HARBOR_NAME, BERTH_ID, BERTH_NAME, PARKING_TYPE, PKID, REMARK, DEPT_ID, DEPT_NAME, POS_AREA, SHIP_LEN-->
+<!--    </sql>-->
+
+    <select id="getTotal" resultType="java.lang.Integer">
+        select count(1) from DS_TASK_LIST
+    </select>
+
+    <select id="getPageList" resultType="com.ruoyi.manage.domain.DsTaskList">
+        select * from DS_TASK_LIST
+        <where>
+            <if test="shipType != null and shipType != ''">
+                and SHIP_TYPE LIKE CONCAT('%', #{shipType}, '%')
+            </if>
+            <if test="shipNo != null and shipNo != ''">
+                and SHIP_NO LIKE CONCAT('%', #{shipNo}, '%')
+            </if>
+        </where>
+        order by PKID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+    <select id="getTotalDaily" resultType="java.lang.Integer">
+        select count(1) from DS_TASK_LIST where TASK_ID = 999
+    </select>
+
+    <select id="getPageListDaily" resultType="com.ruoyi.manage.domain.DsTaskList">
+        select * from DS_TASK_LIST
+        <where>
+                and TASK_ID = 999
+            <if test="shipType != null and shipType != ''">
+                and SHIP_TYPE LIKE CONCAT('%', #{shipType}, '%')
+            </if>
+            <if test="shipNo != null and shipNo != ''">
+                and SHIP_NO LIKE CONCAT('%', #{shipNo}, '%')
+            </if>
+        </where>
+        order by PKID DESC limit #{pageSize} offset #{offset}
+    </select>
+
+</mapper>
diff --git a/ruoyi-manage/src/main/resources/mapper/SysFileMapper.xml b/ruoyi-manage/src/main/resources/mapper/SysFileMapper.xml
new file mode 100644
index 0000000..1667ad3
--- /dev/null
+++ b/ruoyi-manage/src/main/resources/mapper/SysFileMapper.xml
@@ -0,0 +1,22 @@
+<?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.manage.mapper.SysFileMapper">
+
+    <!-- 閫氱敤鏌ヨ鏄犲皠缁撴灉 -->
+    <resultMap id="BaseResultMap" type="com.ruoyi.manage.domain.SysFileManage">
+        <result column="ID" property="id" />
+        <result column="NAME" property="name" />
+        <result column="TYPE" property="type" />
+        <result column="SIZE" property="size" />
+        <result column="REMARK" property="remark" />
+        <result column="CREATE_TIME" property="createTime" />
+        <result column="EXT" property="ext" />
+        <result column="FILE_PATH" property="filePath" />
+    </resultMap>
+
+    <!-- 閫氱敤鏌ヨ缁撴灉鍒� -->
+    <sql id="Base_Column_List">
+        ID, NAME, TYPE, SIZE, REMARK, CREATE_TIME, EXT, FILE_PATH
+    </sql>
+
+</mapper>
diff --git a/ruoyi-quartz/pom.xml b/ruoyi-quartz/pom.xml
new file mode 100644
index 0000000..dabea87
--- /dev/null
+++ b/ruoyi-quartz/pom.xml
@@ -0,0 +1,44 @@
+<?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>-->
+        <dependency>
+            <groupId>com.ruoyi</groupId>
+            <artifactId>ruoyi-fuzhou</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi-quartz/ruoyi-quartz.iml b/ruoyi-quartz/ruoyi-quartz.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-quartz/ruoyi-quartz.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
new file mode 100644
index 0000000..d4e065a
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/config/ScheduleConfig.java
@@ -0,0 +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
+//        // 鍚姩鏃舵洿鏂板繁瀛樺湪鐨凧ob锛岃繖鏍峰氨涓嶇敤姣忔淇敼targetObject鍚庡垹闄rtz_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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
new file mode 100644
index 0000000..c96a92c
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobController.java
@@ -0,0 +1,157 @@
+package com.ruoyi.quartz.controller;
+
+import java.util.List;
+
+import jakarta.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 {
+        System.out.println(job);
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return error("鏂板浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+        } 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 {
+        System.out.println(job);
+        if (!CronUtils.isValid(job.getCronExpression())) {
+            return error("淇敼浠诲姟'" + job.getJobName() + "'澶辫触锛孋ron琛ㄨ揪寮忎笉姝g‘");
+        } 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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
new file mode 100644
index 0000000..c9ab428
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/controller/SysJobLogController.java
@@ -0,0 +1,106 @@
+package com.ruoyi.quartz.controller;
+
+import java.util.ArrayList;
+import java.util.List;
+import jakarta.servlet.http.HttpServletResponse;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+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,
+                              @RequestParam(value = "pageNum", required = false)Integer pageNum,
+                              @RequestParam(value = "pageSize", required = false)Integer pageSize)
+    {
+        startPage();
+        List<SysJobLog> list = jobLogService.selectJobLogList(sysJobLog);
+//        return getDataTable(list);
+        return paginate(list,pageNum,pageSize);
+    }
+
+    /**
+     * 瀵煎嚭瀹氭椂浠诲姟璋冨害鏃ュ織鍒楄〃
+     */
+    @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();
+    }
+
+    //瀵瑰垪琛ㄨ繘琛屽垎椤�
+    private TableDataInfo paginate(List list, int pageNum, int pageSize) {
+        if (list == null || list.isEmpty()) {
+            return new TableDataInfo(new ArrayList<>(), 0);
+        }
+        int total = list.size();
+        int formIndex = (pageNum - 1) * pageSize;
+        int toIndex = Math.min(formIndex + pageSize, total);
+        if (formIndex >= total) {
+            return new TableDataInfo(new ArrayList<>(), total);
+        }
+        List subList = list.subList(formIndex, toIndex);
+        return new TableDataInfo(subList, total);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
new file mode 100644
index 0000000..5594358
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJob.java
@@ -0,0 +1,171 @@
+package com.ruoyi.quartz.domain;
+
+import java.util.Date;
+import jakarta.validation.constraints.NotBlank;
+import jakarta.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姝e父 1鏆傚仠锛� */
+    @Excel(name = "浠诲姟鐘舵��", readConverterExp = "0=姝e父,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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
new file mode 100644
index 0000000..121c035
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/domain/SysJobLog.java
@@ -0,0 +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姝e父 1澶辫触锛� */
+    @Excel(name = "鎵ц鐘舵��", readConverterExp = "0=姝e父,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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
new file mode 100644
index 0000000..727d916
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobLogMapper.java
@@ -0,0 +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();
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java
new file mode 100644
index 0000000..20f45db
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/mapper/SysJobMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java
new file mode 100644
index 0000000..8546792
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobLogService.java
@@ -0,0 +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();
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java
new file mode 100644
index 0000000..437ade8
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/ISysJobService.java
@@ -0,0 +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;
+
+    /**
+     * 鍒犻櫎浠诲姟鍚庯紝鎵�瀵瑰簲鐨則rigger涔熷皢琚垹闄�
+     * 
+     * @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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
new file mode 100644
index 0000000..812eed7
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobLogServiceImpl.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
new file mode 100644
index 0000000..6572193
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/service/impl/SysJobServiceImpl.java
@@ -0,0 +1,261 @@
+package com.ruoyi.quartz.service.impl;
+
+import java.util.List;
+import jakarta.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;
+    }
+
+    /**
+     * 鍒犻櫎浠诲姟鍚庯紝鎵�瀵瑰簲鐨則rigger涔熷皢琚垹闄�
+     *
+     * @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/ElectricityAnalyseTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/ElectricityAnalyseTask.java
new file mode 100644
index 0000000..ff45c48
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/ElectricityAnalyseTask.java
@@ -0,0 +1,146 @@
+package com.ruoyi.quartz.task;
+
+import com.alibaba.fastjson2.JSONArray;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.common.exception.ServiceException;
+import com.ruoyi.common.utils.StringUtils;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.service.*;
+import com.ruoyi.fuzhou.utils.AnalyseUtils;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 鏁版嵁娓呮礂
+ *
+ * @author ruoyi
+ */
+
+@Component("electricityAnalyseTask")
+public class ElectricityAnalyseTask {
+
+    @Resource
+    private ReceiveElectricityAnalyseService receiveElectricityAnalyseService;
+
+    @Resource
+    private ReceiveElectricityValueService receiveElectricityValueService;
+
+    @Resource
+    private ReceiveWaterValueService receiveWaterValueService;
+
+    @Resource
+    private ReceiveWaterAnalyseService receiveWaterAnalyseService;
+
+    @Resource
+    private ReceiveOilAnalyseService receiveOilAnalyseService;
+
+    @Resource
+    private ReceiveOilValueService receiveOilValueService;
+
+    @Resource
+    private ReceiveSelectRuleService receiveSelectRuleService;
+
+    public void electricity() {
+        electricityAnalyse("", -480, "鐢垫暟鎹竻娲�");
+    }
+
+    public void electricityAnalyse(String deviceName, Integer hour, String rule) {
+        List<ReceiveSelectRule> list = receiveSelectRuleService.list(new LambdaQueryWrapper<ReceiveSelectRule>() {{
+            or().eq(ReceiveSelectRule::getRuleName, rule);
+        }});
+        if (list == null || list.size() == 0) {
+            throw new ServiceException("瑙勫垯涓嶅瓨鍦紒");
+        }
+        JSONArray jsonArray = new JSONArray();
+        for (ReceiveSelectRule r : list
+        ) {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("param", r.getParam());
+            jsonObject.put("rule", r.getRule());
+            jsonObject.put("value", r.getValue().toString());
+            jsonArray.add(jsonObject);
+        }
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.HOUR_OF_DAY, hour);
+        Date date = cal.getTime();
+        List<ReceiveElectricityValue> receiveElectricityValues = receiveElectricityValueService.list(new LambdaQueryWrapper<ReceiveElectricityValue>() {{
+            or().like(!"NONE".equals(deviceName), ReceiveElectricityValue::getDeviceName, deviceName).ge(ReceiveElectricityValue::getCreateTime, date);
+        }});
+        if (receiveElectricityValues.size() > 0) {
+            JSONArray array = AnalyseUtils.listToJSONArray(receiveElectricityValues, jsonArray.toString());
+            if (array.size() > 0) {
+                List<ReceiveElectricityAnalyse> receiveElectricityAnalyses = array.toJavaList(ReceiveElectricityAnalyse.class);
+                receiveElectricityAnalyseService.saveOrUpdateBatch(receiveElectricityAnalyses);
+            }
+        }
+    }
+
+    public void waterAnalyse(String deviceName, int hour, String rule) {
+        List<ReceiveSelectRule> list = receiveSelectRuleService.list(new LambdaQueryWrapper<ReceiveSelectRule>() {{
+            or().eq(ReceiveSelectRule::getRuleName, rule);
+        }});
+        if (list == null || list.size() == 0) {
+            throw new ServiceException("瑙勫垯涓嶅瓨鍦紒");
+        }
+        JSONArray jsonArray = new JSONArray();
+        for (ReceiveSelectRule r : list
+        ) {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("param", r.getParam());
+            jsonObject.put("rule", r.getRule());
+            jsonObject.put("value", r.getValue().toString());
+            jsonArray.add(jsonObject);
+        }
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.HOUR_OF_DAY, hour);
+        Date date = cal.getTime();
+        List<ReceiveWaterValue> receiveWaterValues = receiveWaterValueService.list(new LambdaQueryWrapper<ReceiveWaterValue>() {{
+            or().like(StringUtils.isNotEmpty(deviceName), ReceiveWaterValue::getDeviceName, deviceName).ge(ReceiveWaterValue::getCreateTime, date);
+        }});
+        if (receiveWaterValues.size() > 0) {
+            JSONArray array = AnalyseUtils.listToJSONArray(receiveWaterValues, jsonArray.toString());
+            if (array.size() > 0) {
+                List<ReceiveWaterAnalyse> waterAnalyseList = array.toJavaList(ReceiveWaterAnalyse.class);
+                receiveWaterAnalyseService.saveOrUpdateBatch(waterAnalyseList);
+            }
+        }
+    }
+
+    public void oilAnalyse(String deviceName, int hour, String rule) {
+        List<ReceiveSelectRule> list = receiveSelectRuleService.list(new LambdaQueryWrapper<ReceiveSelectRule>() {{
+            or().eq(ReceiveSelectRule::getRuleName, rule);
+        }});
+        if (list == null || list.size() == 0) {
+            throw new ServiceException("瑙勫垯涓嶅瓨鍦紒");
+        }
+        JSONArray jsonArray = new JSONArray();
+        for (ReceiveSelectRule r : list
+        ) {
+            JSONObject jsonObject = new JSONObject();
+            jsonObject.put("param", r.getParam());
+            jsonObject.put("rule", r.getRule());
+            jsonObject.put("value", r.getValue().toString());
+            jsonArray.add(jsonObject);
+        }
+        Calendar cal = Calendar.getInstance();
+        cal.add(Calendar.HOUR_OF_DAY, hour);
+        Date date = cal.getTime();
+        List<ReceiveOilValue> receiveOilValues = receiveOilValueService.list(new LambdaQueryWrapper<ReceiveOilValue>() {{
+            or().like(StringUtils.isNotEmpty(deviceName), ReceiveOilValue::getDeviceName, deviceName).ge(ReceiveOilValue::getCreateTime, date);
+        }});
+        if (receiveOilValues.size() > 0) {
+            JSONArray array = AnalyseUtils.listToJSONArray(receiveOilValues, jsonArray.toString());
+            if (array.size() > 0) {
+                List<ReceiveOilAnalyse> oilAnalyseList = array.toJavaList(ReceiveOilAnalyse.class);
+                receiveOilAnalyseService.saveOrUpdateBatch(oilAnalyseList);
+            }
+        }
+    }
+
+
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
new file mode 100644
index 0000000..330932d
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/task/RyTask.java
@@ -0,0 +1,514 @@
+package com.ruoyi.quartz.task;
+
+import com.alibaba.fastjson2.JSON;
+import com.alibaba.fastjson2.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.ruoyi.fuzhou.domain.*;
+import com.ruoyi.fuzhou.enums.DataTypeEnum;
+import com.ruoyi.fuzhou.service.*;
+import com.ruoyi.fuzhou.utils.electricitymodbus.HexStringToInt;
+import com.ruoyi.fuzhou.utils.hj1239.FileReadUtils;
+import com.ruoyi.fuzhou.utils.hj1239.StringToHexUtil;
+import jakarta.annotation.Resource;
+import org.springframework.stereotype.Component;
+import com.ruoyi.common.utils.StringUtils;
+
+import java.io.File;
+import java.math.BigDecimal;
+import java.math.RoundingMode;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 瀹氭椂浠诲姟璋冨害娴嬭瘯
+ *
+ * @author ruoyi
+ */
+@Component("ryTask")
+public class RyTask {
+    @Resource
+    private EquipmentService equipmentService;
+
+    @Resource
+    private ReceiveElectricityInfoService receiveElectricityInfoService;
+
+    @Resource
+    private ReceiveOilInfoService receiveOilInfoService;
+
+    @Resource
+    private ReceiveWaterInfoService receiveWaterInfoService;
+
+    @Resource
+    private ReceiveCarRuleService receiveCarRuleService;
+
+    @Resource
+    private ReceiveCarValueService receiveCarValueService;
+
+    @Resource
+    private ReceiveWeatherInfoService receiveWeatherInfoService;
+
+    @Resource
+    private ReceiveSlmInfoService receiveSlmInfoService;
+
+    @Resource
+    private ReceiveWeatherValueService receiveWeatherValueService;
+
+    @Resource
+    private HikService hikService;
+
+    @Resource
+    private ReceiveElectricityValueService receiveElectricityValueService;
+
+    /**
+     * 鐢垫暟鎹帴鍏�
+     */
+    public void ryMultipleParams(String name) {
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).eq(DpEquipment::getEquipmentTypeId, DataTypeEnum.ELECTRICITY.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            List<ReceiveElectricityInfo> list = receiveElectricityInfoService.list(new LambdaQueryWrapper<ReceiveElectricityInfo>() {{
+                or().eq(ReceiveElectricityInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveElectricityInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveElectricityInfoService.saveElectricity(list, info);
+            }
+        }
+    }
+
+    /**
+     * 娌规暟鎹帴鍏�
+     *
+     * @param name
+     */
+    public void ryParams(String name) {
+        System.out.println("鎵ц鏈夊弬鏂规硶锛�" + name);
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.OIL.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            List<ReceiveOilInfo> list = receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                or().eq(ReceiveOilInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveOilInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveOilInfoService.saveOil(list, info);
+            }
+        }
+    }
+
+
+    /**
+     * 姘旇薄鏁版嵁鏁版嵁鎺ュ叆
+     *
+     * @param name
+     */
+    public void wsParams(String name) {
+        System.out.println("鎵ц鏈夊弬鏂规硶锛�" + name);
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.WEATHER.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            List<ReceiveWeatherInfo> list = receiveWeatherInfoService.list(new LambdaQueryWrapper<ReceiveWeatherInfo>() {{
+                or().eq(ReceiveWeatherInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveWeatherInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveWeatherInfoService.saveData(list, info);
+            }
+        }
+    }
+
+    /**
+     * 姘旇薄鏁版嵁鍛婅
+     *
+     * @param windSpeedValue  椋庨�熼槇鍊�
+     * @param windSpeedTime   椋庨�熸娴嬫椂闂�
+     * @param tempSpeedValue  娓╁害闃堝��
+     * @param tempSpeedTime   娓╁害妫�娴嬫椂闂�
+     */
+    public void wsGaoJingParams(Integer windSpeedValue,Integer windSpeedTime,Integer tempSpeedValue,Integer tempSpeedTime,Integer interval) {
+        System.out.println("鎵ц姘旇薄鏁版嵁--鍛婅鏈夊弬鏂规硶锛�" + windSpeedValue+";"+ windSpeedTime+";"+ tempSpeedValue+";"+ tempSpeedTime+";");
+
+        if(interval==null){
+            interval=10;
+        }
+        LocalDateTime now=LocalDateTime.now();
+        Date nowDate=new Date();
+
+        LocalDateTime agoSpeedTime=now.minusMinutes(windSpeedTime);
+        LocalDateTime agoWenduSpeedTime=now.minusMinutes(tempSpeedTime);
+
+
+        List<ReceiveWeatherValue> list = receiveWeatherValueService.list(new LambdaQueryWrapper<ReceiveWeatherValue>() {{
+             ge(ReceiveWeatherValue::getCreateTime,agoSpeedTime).le(ReceiveWeatherValue::getCreateTime,now);
+        }});
+
+        Boolean hasfengsubaojing=fengsubaojingpanduan(list,windSpeedValue,nowDate,interval);
+
+        if(hasfengsubaojing){
+            HikEvent hikEvent=new HikEvent();
+            hikEvent.setHappenTime(list.get(0).getCreateTime());
+            hikEvent.setSendTime(nowDate);
+            hikEvent.setEventType(101);//椋庨��101 娓╁害102
+            hikEvent.setSrcName("椋庨�熷憡璀�");
+            hikEvent.setSrcType("姘旇薄璁惧");
+            hikService.saveInsert(hikEvent);
+        }
+        List<ReceiveWeatherValue> listTemp = receiveWeatherValueService.list(new LambdaQueryWrapper<ReceiveWeatherValue>() {{
+            ge(ReceiveWeatherValue::getCreateTime,agoWenduSpeedTime).le(ReceiveWeatherValue::getCreateTime,now);
+        }});
+
+        Boolean haswendubaojing=wendubaojingpanduan(listTemp,tempSpeedValue,nowDate,interval);
+
+        if(haswendubaojing){
+            HikEvent hikEvent=new HikEvent();
+            hikEvent.setHappenTime(list.get(0).getCreateTime());
+            hikEvent.setSendTime(nowDate);
+            hikEvent.setEventType(102);//椋庨��101 娓╁害102
+            hikEvent.setSrcName("娓╁害鍛婅");
+            hikEvent.setSrcType("姘旇薄璁惧");
+            hikService.saveInsert(hikEvent);
+        }
+    }
+
+    /**
+     * 鏅鸿兘鐢佃〃鎶ヨ
+     * @param lXian 绾跨數鍘�-浣�
+     * @param hXian 绾跨數鍘�-楂�
+     * @param lXiang 鐩哥數鍘�-浣�
+     * @param hXiang 鐩哥數鍘�-楂�
+     */
+    public void dbGaoJing(Integer lXian, Integer hXian, Integer lXiang, Integer hXiang) {
+        List<DpEquipment> list = equipmentService.getListByType(3);
+        if (null == list || list.isEmpty()) return;
+
+        for (DpEquipment dp : list) {
+            QueryWrapper<ReceiveElectricityValue> wrapper = new QueryWrapper<>();
+            //wrapper.eq(ReceiveElectricityValue::getDeviceName, String.valueOf(dp.getId()));
+            wrapper.eq("DEVICE_NAME", String.valueOf(dp.getId()));
+            //wrapper.orderByDesc(ReceiveElectricityValue::getCreateTime);
+            wrapper.orderByDesc("CREATE_TIME");
+            wrapper.last("limit 1");
+
+            ReceiveElectricityValue rs = receiveElectricityValueService.getOne(wrapper);
+            if (null == rs) continue;
+            double voltageA = Double.parseDouble(rs.getVoltageA());
+            double voltageB = Double.parseDouble(rs.getVoltageB());
+            double voltageC = Double.parseDouble(rs.getVoltageC());
+            double voltageCa = Double.parseDouble(rs.getVoltageCa());
+            double voltageAb = Double.parseDouble(rs.getVoltageAb());
+            double voltageBc = Double.parseDouble(rs.getVoltageBc());
+
+            HikEvent hikEvent = new HikEvent();
+            hikEvent.setHappenTime(rs.getCreateTime());
+            hikEvent.setSendTime(new Date());
+            hikEvent.setSrcName(dp.getEquName());
+            hikEvent.setSrcIndex(String.valueOf(dp.getId()));
+
+            // voltageA-A鐩哥數鍘�, B鐩哥數鍘�-voltageB, C鐩哥數鍘�-voltageC
+            List<String> ycList = new ArrayList<>();
+            if (voltageA < 1) ycList.add("A");
+            if (voltageB < 1) ycList.add("B");
+            if (voltageC < 1) ycList.add("C");
+            if (!ycList.isEmpty()) {
+                hikEvent.setEventType(103); // 103-鐢靛帇寮傚父, 104-杩囨瑺鍘�
+                hikEvent.setSrcType(StringUtils.join(ycList, " | "));
+                hikService.saveInsert(hikEvent);
+                continue;
+            }
+
+            List<String> qyList = new ArrayList<>();
+            // voltageCa-CA绾跨數鍘�, AB绾跨數鍘�-voltageAb, BC绾跨數鍘�-voltageBc
+            if (voltageCa < lXian || voltageCa > hXian) qyList.add("CA");
+            if (voltageAb < lXian || voltageAb > hXian) qyList.add("AB");
+            if (voltageBc < lXian || voltageBc > hXian) qyList.add("BC");
+
+            // voltageA-A鐩哥數鍘�, B鐩哥數鍘�-voltageB, C鐩哥數鍘�-voltageC
+            if (voltageA < lXiang || voltageA > hXiang) qyList.add("A");
+            if (voltageB < lXiang || voltageB > hXiang) qyList.add("B");
+            if (voltageC < lXiang || voltageC > hXiang) qyList.add("C");
+            if (!qyList.isEmpty()) {
+                hikEvent.setEventType(104); // 103-鐢靛帇寮傚父, 104-杩囨瑺鍘�
+                hikEvent.setSrcType(StringUtils.join(qyList, " | "));
+                hikService.saveInsert(hikEvent);
+            }
+        }
+    }
+
+    public Boolean fengsubaojingpanduan(List<ReceiveWeatherValue> list,int value,Date now,Integer interval){
+        if(list.size()>=5){
+            for (int i = 0; i < list.size(); i++) {
+                if(list.get(i).getWindSpeed()!=null&&Double.parseDouble(list.get(i).getWindSpeed())<value){
+                    return false;
+                }
+            }
+            //鏈�鍚庝竴娆℃姤璀︽椂闂�   getSendTime 鎻掑叆鏃堕棿  happenTime 鏁版嵁鏃堕棿
+            List<HikEvent> hList=hikService.list(new LambdaQueryWrapper<HikEvent>() {{
+                eq(HikEvent::getEventType,101).orderByDesc(HikEvent::getSendTime).last("LIMIT 1");
+            }});
+            if(hList.size()>0){
+                HikEvent hData=hList.get(0);
+
+                if(now.getTime()-hData.getSendTime().getTime()>=1000*60*interval){
+                    return true;
+                }
+
+
+            }
+            return false;
+        }else {
+            return false;
+        }
+
+    }
+
+    public Boolean wendubaojingpanduan(List<ReceiveWeatherValue> list,int value,Date now,Integer interval){
+        if(list.size()>=5){
+            for (int i = 0; i < list.size(); i++) {
+                if(list.get(i).getTemp()!=null&&Double.parseDouble(list.get(i).getTemp())<value){
+                    return false;
+                }
+            }
+            //鏈�鍚庝竴娆℃姤璀︽椂闂�   getSendTime 鎻掑叆鏃堕棿  happenTime 鏁版嵁鏃堕棿
+            List<HikEvent> hList=hikService.list(new LambdaQueryWrapper<HikEvent>() {{
+                eq(HikEvent::getEventType,102).orderByDesc(HikEvent::getSendTime).last("LIMIT 1");
+            }});
+            if(hList.size()>0){
+                HikEvent hData=hList.get(0);
+
+                if(now.getTime()-hData.getSendTime().getTime()>=1000*60*interval){
+                    return true;
+                }
+
+
+            }
+            return false;
+        }else {
+            return false;
+        }
+
+    }
+
+    /**
+     * 婵�鍏夐浄杈炬暟鎹暟鎹帴鍏�
+     *
+     * @param name
+     */
+    public void slmParams(String name) {
+        System.out.println("鎵ц鏈夊弬鏂规硶锛�" + name);
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.SLM.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            List<ReceiveSlmInfo> list = receiveSlmInfoService.list(new LambdaQueryWrapper<ReceiveSlmInfo>() {{
+                or().eq(ReceiveSlmInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveSlmInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveSlmInfoService.saveData(list, info);
+            }
+        }
+    }
+
+    /**
+     * 鍒╂棫娌规暟鎹帴鍏�
+     *
+     * @param name
+     */
+    public void ryLijiuParams(String name) {
+        System.out.println("鎵ц鏈夊弬鏂规硶锛�" + name);
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.LIJIUOIL.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            List<ReceiveOilInfo> list = receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                or().eq(ReceiveOilInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveOilInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveOilInfoService.saveLijiuOil(list, info);
+            }
+        }
+    }
+
+    /**
+     * 瀹佸痉閫�娌规暟鎹帴鍏�
+     *
+     * @param name
+     */
+    public synchronized void ningdeLijiuParams(String name) {
+        System.out.println("鎵ц鏈夊弬鏂规硶锛�" + name);
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.LIJIUJUN.getCode());
+        }});
+        for (DpEquipment info : equipments) {
+            try {
+                List<ReceiveOilInfo> list = receiveOilInfoService.list(new LambdaQueryWrapper<ReceiveOilInfo>() {{
+                    or().eq(ReceiveOilInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveOilInfo::getParamCode, "createTime");
+                }});
+                Thread.sleep(1000);
+                if (list != null && list.size() > 0) {
+                    receiveOilInfoService.saveOilLijiuNingde(list, info);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+
+        }
+    }
+
+    /**
+     * 姘存暟鎹帴鍏�
+     */
+    public void ryNoParams(String name) {
+        System.out.println("鎵ц鏃犲弬鏂规硶");
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.WATER_FLOW.getCode());
+        }});
+        for (DpEquipment info : equipments
+        ) {
+            List<ReceiveWaterInfo> list = receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                or().eq(ReceiveWaterInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveWaterInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveWaterInfoService.saveWater(list, info);
+            }
+        }
+    }
+
+    /**
+     * 姘存暟鎹帴鍏�
+     */
+    public void saveWaterYa(String name) {
+        System.out.println("鎵ц鏃犲弬鏂规硶");
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.WATER_YA.getCode());
+        }});
+        for (DpEquipment info : equipments
+        ) {
+            List<ReceiveWaterInfo> list = receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                or().eq(ReceiveWaterInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveWaterInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveWaterInfoService.saveWaterYa(list, info);
+            }
+        }
+    }
+
+    /**
+     * 姘存暟鎹帴鍏�
+     */
+    public void saveWaterDept(String name) {
+        System.out.println("鎵ц鏃犲弬鏂规硶");
+        List<DpEquipment> equipments = equipmentService.list(new LambdaQueryWrapper<DpEquipment>() {{
+            or().like(StringUtils.isNotEmpty(name), DpEquipment::getEquName, name).in(DpEquipment::getEquipmentTypeId, DataTypeEnum.WATER_DEPT.getCode());
+        }});
+        for (DpEquipment info : equipments
+        ) {
+            List<ReceiveWaterInfo> list = receiveWaterInfoService.list(new LambdaQueryWrapper<ReceiveWaterInfo>() {{
+                or().eq(ReceiveWaterInfo::getDeviceName, String.valueOf(info.getId())).notIn(ReceiveWaterInfo::getParamCode, "createTime");
+            }});
+            if (list != null && list.size() > 0) {
+                receiveWaterInfoService.saveWaterDept(list, info);
+            }
+        }
+    }
+
+    public void carHj1239Task(String ftpFilePath, String tmpPath) {
+        File file = new File(ftpFilePath);
+        File[] fs = file.listFiles();
+        List<String> filePath = new ArrayList<>();
+        for (File f : fs) {
+            if (!f.isDirectory()) {
+                filePath.add(f.getAbsolutePath());
+            }
+        }
+        List<ReceiveCarRule> receiveCarRules = receiveCarRuleService.list(new LambdaQueryWrapper<ReceiveCarRule>() {{
+            orderByAsc(ReceiveCarRule::getId);
+        }});
+        for (String path : filePath
+        ) {
+            try {
+                byte[] bytes = FileReadUtils.readFromByteFile(path);
+                String content = FileReadUtils.bytesToHex(bytes);
+                content = content.replace("aaaabbbbccccaaaa", "aaaabbbb,ccccaaaa");
+                String[] src = content.split(",");
+                List<ReceiveCarValue> receiveCarValues = new ArrayList<>();
+                for (int i = 0; i < src.length; i++) {
+                    String item = src[i];
+                    JSONObject jsonObject = getvalue(receiveCarRules, item);
+                    ReceiveCarValue receiveCarValue = JSON.parseObject(jsonObject.toJSONString(), ReceiveCarValue.class);
+                    receiveCarValue.setCreateTime(new Date());
+                    receiveCarValues.add(receiveCarValue);
+                    System.out.println(jsonObject);
+                }
+                receiveCarValueService.saveOrUpdateBatch(receiveCarValues);
+                //婧愭枃浠�
+                File a = new File(path);
+                //鐩爣鐩綍
+                File b = new File(tmpPath);
+                if (!b.exists()) {
+                    b.mkdirs();
+                }
+                File bFile = new File(b + a.getName());
+                //璋冪敤File绫荤殑鏍稿績鏂规硶renameTo
+                a.renameTo(bFile);
+            } catch (Exception e) {
+                e.printStackTrace();
+            }
+        }
+    }
+
+    private static JSONObject getvalue(List<ReceiveCarRule> rule, String content) {
+        JSONObject jsonObject = new JSONObject();
+        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
+        for (ReceiveCarRule r : rule
+        ) {
+
+            if (!"createTime".equals(r.getCarCode())) {
+                String xx = content.substring(r.getStart() * 2, r.getStart() * 2 + r.getDataLength() * 2);
+                if ("VARCHAR".equals(r.getDataType()) && "NONE".equals(r.getRule())) {
+                    jsonObject.put(r.getCarCode(), StringToHexUtil.convertHexToString(xx));
+                } else if ("WORD".equals(r.getDataType()) && "NONE".equals(r.getRule())) {
+                    jsonObject.put(r.getCarCode(), String.valueOf(HexStringToInt.hexStringToInt2(xx)));
+                } else if ("BYTE[6]".equals(r.getDataType()) && "NONE".equals(r.getRule())) {
+                    String dateTime = "20";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(0, 2)) + "-";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(2, 4)) + "-";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(4, 6)) + " ";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(6, 8)) + ":";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(8, 10)) + ":";
+                    dateTime = dateTime + HexStringToInt.hexStringToString(xx.substring(10, 12));
+                    jsonObject.put(r.getCarCode(), dateTime);
+                } else if ("WORD".equals(r.getDataType()) && "COMPUTE".equals(r.getRule())) {
+                    if ("ffff".equals(xx)) {
+                        jsonObject.put(r.getCarCode(), "");
+                    } else {
+                        jsonObject.put(r.getCarCode(), String.valueOf(new BigDecimal(HexStringToInt.hexStringToInt2(xx) * Double.valueOf(r.getRuleValue()) + Double.valueOf(r.getOffset())).setScale(3, RoundingMode.UP).doubleValue()));
+                    }
+                } else if ("BYTE".equals(r.getDataType()) && "COMPUTE".equals(r.getRule())) {
+                    if ("ff".equals(xx)) {
+                        jsonObject.put(r.getCarCode(), "");
+                    } else {
+                        jsonObject.put(r.getCarCode(), String.valueOf(HexStringToInt.hexStringToInt2(xx) * Double.valueOf(r.getRuleValue()) + Double.valueOf(r.getOffset())));
+                    }
+                } else if ("DWORD".equals(r.getDataType()) && "COMPUTE".equals(r.getRule())) {
+                    if ("ffffffff".equals(xx)) {
+                        jsonObject.put(r.getCarCode(), "");
+                    } else {
+                        jsonObject.put(r.getCarCode(), String.valueOf(Long.parseLong(xx, 16) * Double.valueOf(r.getRuleValue()) + Double.valueOf(r.getOffset())));
+                    }
+
+                }
+            }
+        }
+        try {
+            jsonObject.put("id", sdf.parse(jsonObject.getString("dataTime")).getTime() + jsonObject.getString("vin"));
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return jsonObject;
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
new file mode 100644
index 0000000..731a5eb
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/AbstractQuartzJob.java
@@ -0,0 +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;
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java
new file mode 100644
index 0000000..dd53839
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/CronUtils.java
@@ -0,0 +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);
+    }
+
+    /**
+     * 杩斿洖涓�涓瓧绗︿覆鍊�,琛ㄧず璇ユ秷鎭棤鏁圕ron琛ㄨ揪寮忕粰鍑烘湁鏁堟��
+     *
+     * @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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
new file mode 100644
index 0000000..e3dc62c
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/JobInvokeUtil.java
@@ -0,0 +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甯冨皵绫诲瀷锛岀瓑浜巘rue鎴栬�協alse
+            else if ("true".equalsIgnoreCase(str) || "false".equalsIgnoreCase(str))
+            {
+                classs.add(new Object[] { Boolean.valueOf(str), Boolean.class });
+            }
+            // long闀挎暣褰紝浠缁撳熬
+            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/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java
new file mode 100644
index 0000000..5e13558
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzDisallowConcurrentExecution.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java
new file mode 100644
index 0000000..e975326
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/QuartzJobExecution.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java
new file mode 100644
index 0000000..21fedae
--- /dev/null
+++ b/ruoyi-quartz/src/main/java/com/ruoyi/quartz/util/ScheduleUtils.java
@@ -0,0 +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);
+
+        // 鎸夋柊鐨刢ronExpression琛ㄨ揪寮忔瀯寤轰竴涓柊鐨則rigger
+        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/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
new file mode 100644
index 0000000..ba1b683
--- /dev/null
+++ b/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobLogMapper.xml
@@ -0,0 +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>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml b/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
new file mode 100644
index 0000000..5605c44
--- /dev/null
+++ b/ruoyi-quartz/src/main/resources/mapper/quartz/SysJobMapper.xml
@@ -0,0 +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>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/pom.xml b/ruoyi-system/pom.xml
new file mode 100644
index 0000000..3ee5011
--- /dev/null
+++ b/ruoyi-system/pom.xml
@@ -0,0 +1,24 @@
+<?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>
+
+</project>
\ No newline at end of file
diff --git a/ruoyi-system/ruoyi-system.iml b/ruoyi-system/ruoyi-system.iml
new file mode 100644
index 0000000..1daccae
--- /dev/null
+++ b/ruoyi-system/ruoyi-system.iml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module version="4">
+  <component name="FacetManager">
+    <facet type="Spring" name="Spring">
+      <configuration />
+    </facet>
+  </component>
+</module>
\ No newline at end of file
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java
new file mode 100644
index 0000000..83f0703
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysCache.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
new file mode 100644
index 0000000..cae07be
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysConfig.java
@@ -0,0 +1,111 @@
+package com.ruoyi.system.domain;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.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;
+
+    /** 绯荤粺鍐呯疆锛圷鏄� 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/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
new file mode 100644
index 0000000..7fdea30
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysLogininfor.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
new file mode 100644
index 0000000..8603ad8
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysNotice.java
@@ -0,0 +1,102 @@
+package com.ruoyi.system.domain;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.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姝e父 1鍏抽棴锛� */
+    private String status;
+
+    public Long getNoticeId()
+    {
+        return noticeId;
+    }
+
+    public void setNoticeId(Long noticeId)
+    {
+        this.noticeId = noticeId;
+    }
+
+    public void setNoticeTitle(String noticeTitle)
+    {
+        this.noticeTitle = noticeTitle;
+    }
+
+    @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/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
new file mode 100644
index 0000000..4c995f3
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysOperLog.java
@@ -0,0 +1,272 @@
+package com.ruoyi.system.domain;
+
+import java.util.Date;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+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=鐢熸垚浠g爜,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姝e父 1寮傚父锛� */
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,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/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
new file mode 100644
index 0000000..62dbd47
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysPost.java
@@ -0,0 +1,124 @@
+package com.ruoyi.system.domain;
+
+import jakarta.validation.constraints.NotBlank;
+import jakarta.validation.constraints.NotNull;
+import jakarta.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姝e父 1鍋滅敤锛� */
+    @Excel(name = "鐘舵��", readConverterExp = "0=姝e父,1=鍋滅敤")
+    private String status;
+
+    /** 鐢ㄦ埛鏄惁瀛樺湪姝ゅ矖浣嶆爣璇� 榛樿涓嶅瓨鍦� */
+    private boolean flag = false;
+
+    public Long getPostId()
+    {
+        return postId;
+    }
+
+    public void setPostId(Long postId)
+    {
+        this.postId = postId;
+    }
+
+    @NotBlank(message = "宀椾綅缂栫爜涓嶈兘涓虹┖")
+    @Size(min = 0, max = 64, message = "宀椾綅缂栫爜闀垮害涓嶈兘瓒呰繃64涓瓧绗�")
+    public String getPostCode()
+    {
+        return postCode;
+    }
+
+    public void setPostCode(String postCode)
+    {
+        this.postCode = postCode;
+    }
+
+    @NotBlank(message = "宀椾綅鍚嶇О涓嶈兘涓虹┖")
+    @Size(min = 0, max = 50, message = "宀椾綅鍚嶇О闀垮害涓嶈兘瓒呰繃50涓瓧绗�")
+    public String getPostName()
+    {
+        return postName;
+    }
+
+    public void setPostName(String postName)
+    {
+        this.postName = postName;
+    }
+
+    @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/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
new file mode 100644
index 0000000..47b21bf
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleDept.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
new file mode 100644
index 0000000..de10a74
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysRoleMenu.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
new file mode 100644
index 0000000..2bbd318
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserOnline.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
new file mode 100644
index 0000000..6e8c416
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserPost.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
new file mode 100644
index 0000000..4d15810
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/SysUserRole.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
new file mode 100644
index 0000000..a5d5fdc
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/MetaVo.java
@@ -0,0 +1,106 @@
+package com.ruoyi.system.domain.vo;
+
+import com.ruoyi.common.utils.StringUtils;
+
+/**
+ * 璺敱鏄剧ず淇℃伅
+ * 
+ * @author ruoyi
+ */
+public class MetaVo
+{
+    /**
+     * 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+     */
+    private String title;
+
+    /**
+     * 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/assets/icons/svg
+     */
+    private String icon;
+
+    /**
+     * 璁剧疆涓簍rue锛屽垯涓嶄細琚� <keep-alive>缂撳瓨
+     */
+    private boolean noCache;
+
+    /**
+     * 鍐呴摼鍦板潃锛坔ttp(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/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
new file mode 100644
index 0000000..afff8c9
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/RouterVo.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVO.java b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVO.java
new file mode 100644
index 0000000..4585c41
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/domain/vo/SysOperLogVO.java
@@ -0,0 +1,60 @@
+package com.ruoyi.system.domain.vo;
+
+public class SysOperLogVO {
+
+    private String title;
+    private String startTime;
+    private String endTime;
+
+    private Integer pageSize;
+    private Integer pageNum;
+    private Integer offset;
+
+    public String getTitle() {
+        return title;
+    }
+
+    public void setTitle(String title) {
+        this.title = title;
+    }
+
+    public String getStartTime() {
+        return startTime;
+    }
+
+    public void setStartTime(String startTime) {
+        this.startTime = startTime;
+    }
+
+    public String getEndTime() {
+        return endTime;
+    }
+
+    public void setEndTime(String endTime) {
+        this.endTime = endTime;
+    }
+
+    public Integer getPageSize() {
+        return pageSize;
+    }
+
+    public void setPageSize(Integer pageSize) {
+        this.pageSize = pageSize;
+    }
+
+    public Integer getPageNum() {
+        return pageNum;
+    }
+
+    public void setPageNum(Integer pageNum) {
+        this.pageNum = pageNum;
+    }
+
+    public Integer getOffset() {
+        return offset;
+    }
+
+    public void setOffset(Integer offset) {
+        this.offset = offset;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
new file mode 100644
index 0000000..829229d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysConfigMapper.java
@@ -0,0 +1,77 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.ruoyi.system.domain.SysConfig;
+
+/**
+ * 鍙傛暟閰嶇疆 鏁版嵁灞�
+ *
+ * @author ruoyi
+ */
+public interface SysConfigMapper extends BaseMapper<SysConfig> {
+    /**
+     * 鏌ヨ鍙傛暟閰嶇疆淇℃伅
+     *
+     * @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/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
new file mode 100644
index 0000000..c4ad697
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDeptMapper.java
@@ -0,0 +1,118 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.common.core.domain.entity.SysDept;
+import io.lettuce.core.dynamic.annotation.Param;
+
+/**
+ * 閮ㄩ棬绠$悊 鏁版嵁灞�
+ * 
+ * @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 鐖堕儴闂↖D
+     * @return 缁撴灉
+     */
+    public SysDept checkDeptNameUnique(@Param("deptName") String deptName, @Param("parentId") Long parentId);
+
+    /**
+     * 鏂板閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int insertDept(SysDept dept);
+
+    /**
+     * 淇敼閮ㄩ棬淇℃伅
+     * 
+     * @param dept 閮ㄩ棬淇℃伅
+     * @return 缁撴灉
+     */
+    public int updateDept(SysDept dept);
+
+    /**
+     * 淇敼鎵�鍦ㄩ儴闂ㄦ甯哥姸鎬�
+     * 
+     * @param 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/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
new file mode 100644
index 0000000..6c3255f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictDataMapper.java
@@ -0,0 +1,95 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.common.core.domain.entity.SysDictData;
+import io.lettuce.core.dynamic.annotation.Param;
+
+/**
+ * 瀛楀吀琛� 鏁版嵁灞�
+ * 
+ * @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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
new file mode 100644
index 0000000..5fb48fb
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysDictTypeMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
new file mode 100644
index 0000000..629866f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysLogininforMapper.java
@@ -0,0 +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();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
new file mode 100644
index 0000000..06e7f52
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysMenuMapper.java
@@ -0,0 +1,126 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+
+import io.lettuce.core.dynamic.annotation.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 鐖惰彍鍗旾D
+     * @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/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
new file mode 100644
index 0000000..c34f0a2
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysNoticeMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
new file mode 100644
index 0000000..8c88730
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysOperLogMapper.java
@@ -0,0 +1,59 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysOperLog;
+import com.ruoyi.system.domain.vo.SysOperLogVO;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏁版嵁灞�
+ * 
+ * @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();
+
+    /**
+     * 鏌ヨ鏃堕棿娈靛唴姣忓ぉ鐨勬搷浣滄棩蹇�
+     */
+    public List<SysOperLog> queryByDate(SysOperLogVO logVO);
+
+    /**
+     * 绛涢�夋煡璇㈡搷浣滄棩蹇�
+     */
+    public List<SysOperLog> queryData(SysOperLogVO logVO);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
new file mode 100644
index 0000000..19be227
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysPostMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
new file mode 100644
index 0000000..f9d3a2f
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleDeptMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
new file mode 100644
index 0000000..cf2bd8c
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
new file mode 100644
index 0000000..6602bee
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysRoleMenuMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
new file mode 100644
index 0000000..078e18e
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserMapper.java
@@ -0,0 +1,127 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.common.core.domain.entity.SysUser;
+import io.lettuce.core.dynamic.annotation.Param;
+
+/**
+ * 鐢ㄦ埛琛� 鏁版嵁灞�
+ * 
+ * @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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
new file mode 100644
index 0000000..2a6a720
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserPostMapper.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
new file mode 100644
index 0000000..0f14297
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/mapper/SysUserRoleMapper.java
@@ -0,0 +1,62 @@
+package com.ruoyi.system.mapper;
+
+import java.util.List;
+import com.ruoyi.system.domain.SysUserRole;
+import io.lettuce.core.dynamic.annotation.Param;
+
+/**
+ * 鐢ㄦ埛涓庤鑹插叧鑱旇〃 鏁版嵁灞�
+ * 
+ * @author ruoyi
+ */
+public interface SysUserRoleMapper
+{
+    /**
+     * 閫氳繃鐢ㄦ埛ID鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱�
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleByUserId(Long userId);
+
+    /**
+     * 鎵归噺鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱�
+     * 
+     * @param ids 闇�瑕佸垹闄ょ殑鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRole(Long[] ids);
+
+    /**
+     * 閫氳繃瑙掕壊ID鏌ヨ瑙掕壊浣跨敤鏁伴噺
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 缁撴灉
+     */
+    public int countUserRoleByRoleId(Long roleId);
+
+    /**
+     * 鎵归噺鏂板鐢ㄦ埛瑙掕壊淇℃伅
+     * 
+     * @param userRoleList 鐢ㄦ埛瑙掕壊鍒楄〃
+     * @return 缁撴灉
+     */
+    public int batchUserRole(List<SysUserRole> userRoleList);
+
+    /**
+     * 鍒犻櫎鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * 
+     * @param userRole 鐢ㄦ埛鍜岃鑹插叧鑱斾俊鎭�
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleInfo(SysUserRole userRole);
+
+    /**
+     * 鎵归噺鍙栨秷鎺堟潈鐢ㄦ埛瑙掕壊
+     * 
+     * @param roleId 瑙掕壊ID
+     * @param userIds 闇�瑕佸垹闄ょ殑鐢ㄦ埛鏁版嵁ID
+     * @return 缁撴灉
+     */
+    public int deleteUserRoleInfos(@Param("roleId") Long roleId, @Param("userIds") Long[] userIds);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
new file mode 100644
index 0000000..b307776
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysConfigService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
new file mode 100644
index 0000000..f228208
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDeptService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
new file mode 100644
index 0000000..9bc4f13
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictDataService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
new file mode 100644
index 0000000..01c1c1d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysDictTypeService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
new file mode 100644
index 0000000..ce3151d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysLogininforService.java
@@ -0,0 +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();
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
new file mode 100644
index 0000000..7d60696
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysMenuService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
new file mode 100644
index 0000000..47ce1b7
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysNoticeService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
new file mode 100644
index 0000000..e441675
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysOperLogService.java
@@ -0,0 +1,62 @@
+package com.ruoyi.system.service;
+
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+
+import com.ruoyi.system.domain.SysOperLog;
+import com.ruoyi.system.domain.vo.SysOperLogVO;
+
+/**
+ * 鎿嶄綔鏃ュ織 鏈嶅姟灞�
+ * 
+ * @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();
+
+    /**
+     * 鏌ヨ鏃堕棿娈靛唴姣忓ぉ鐨勬搷浣滄棩蹇�
+     */
+    public Map<String,List<SysOperLog>> queryByDate(SysOperLogVO logVO);
+
+    /**
+     * 绛涢�夋煡璇㈡搷浣滄棩蹇�
+     */
+    public List<SysOperLog> queryDataByTitle(SysOperLogVO logVO);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
new file mode 100644
index 0000000..84779bf
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysPostService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
new file mode 100644
index 0000000..9185cce
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysRoleService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
new file mode 100644
index 0000000..8eb5448
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserOnlineService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
new file mode 100644
index 0000000..10bc2ab
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/ISysUserService.java
@@ -0,0 +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);
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
new file mode 100644
index 0000000..6c8a182
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysConfigServiceImpl.java
@@ -0,0 +1,210 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.Collection;
+import java.util.List;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import jakarta.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 extends ServiceImpl<SysConfigMapper, SysConfig> 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 缂撳瓨閿甼ey
+     */
+    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/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
new file mode 100644
index 0000000..54b605d
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDeptServiceImpl.java
@@ -0,0 +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 鏂扮殑鐖禝D闆嗗悎
+     * @param oldAncestors 鏃х殑鐖禝D闆嗗悎
+     */
+    public void updateDeptChildren(Long deptId, String newAncestors, String oldAncestors)
+    {
+        List<SysDept> children = deptMapper.selectChildrenDeptById(deptId);
+        for (SysDept child : children)
+        {
+            child.setAncestors(child.getAncestors().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/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
new file mode 100644
index 0000000..fced569
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictDataServiceImpl.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
new file mode 100644
index 0000000..37928c4
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysDictTypeServiceImpl.java
@@ -0,0 +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 jakarta.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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
new file mode 100644
index 0000000..216aecb
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysLogininforServiceImpl.java
@@ -0,0 +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();
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
new file mode 100644
index 0000000..78a7830
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysMenuServiceImpl.java
@@ -0,0 +1,543 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+import com.ruoyi.common.constant.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;
+
+/**
+ * 鑿滃崟 涓氬姟灞傚鐞�
+ * 
+ * @author ruoyi
+ */
+@Service
+public class SysMenuServiceImpl implements ISysMenuService
+{
+    public static final String PREMISSION_STRING = "perms[\"{0}\"]";
+
+    @Autowired
+    private SysMenuMapper menuMapper;
+
+    @Autowired
+    private SysRoleMapper roleMapper;
+
+    @Autowired
+    private SysRoleMenuMapper roleMenuMapper;
+
+    /**
+     * 鏍规嵁鐢ㄦ埛鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuList(Long userId)
+    {
+        return selectMenuList(new SysMenu(), userId);
+    }
+
+    /**
+     * 鏌ヨ绯荤粺鑿滃崟鍒楄〃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuList(SysMenu menu, Long userId)
+    {
+        List<SysMenu> menuList = null;
+        // 绠$悊鍛樻樉绀烘墍鏈夎彍鍗曚俊鎭�
+        if (SysUser.isAdmin(userId))
+        {
+            menuList = menuMapper.selectMenuList(menu);
+        }
+        else
+        {
+            menu.getParams().put("userId", userId);
+            menuList = menuMapper.selectMenuListByUserId(menu);
+        }
+        return menuList;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鏉冮檺
+     * 
+     * @param userId 鐢ㄦ埛ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectMenuPermsByUserId(Long userId)
+    {
+        List<String> perms = menuMapper.selectMenuPermsByUserId(userId);
+        Set<String> permsSet = new HashSet<>();
+        for (String perm : perms)
+        {
+            if (StringUtils.isNotEmpty(perm))
+            {
+                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鏉冮檺
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 鏉冮檺鍒楄〃
+     */
+    @Override
+    public Set<String> selectMenuPermsByRoleId(Long roleId)
+    {
+        List<String> perms = menuMapper.selectMenuPermsByRoleId(roleId);
+        Set<String> permsSet = new HashSet<>();
+        for (String perm : perms)
+        {
+            if (StringUtils.isNotEmpty(perm))
+            {
+                permsSet.addAll(Arrays.asList(perm.trim().split(",")));
+            }
+        }
+        return permsSet;
+    }
+
+    /**
+     * 鏍规嵁鐢ㄦ埛ID鏌ヨ鑿滃崟
+     * 
+     * @param userId 鐢ㄦ埛鍚嶇О
+     * @return 鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<SysMenu> selectMenuTreeByUserId(Long userId)
+    {
+        List<SysMenu> menus = null;
+        if (SecurityUtils.isAdmin(userId))
+        {
+            menus = menuMapper.selectMenuTreeAll();
+        }
+        else
+        {
+            menus = menuMapper.selectMenuTreeByUserId(userId);
+        }
+        return getChildPerms(menus, 0);
+    }
+
+    /**
+     * 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戜俊鎭�
+     * 
+     * @param roleId 瑙掕壊ID
+     * @return 閫変腑鑿滃崟鍒楄〃
+     */
+    @Override
+    public List<Long> selectMenuListByRoleId(Long roleId)
+    {
+        SysRole role = roleMapper.selectRoleById(roleId);
+        return menuMapper.selectMenuListByRoleId(roleId, role.isMenuCheckStrictly());
+    }
+
+    /**
+     * 鏋勫缓鍓嶇璺敱鎵�闇�瑕佺殑鑿滃崟
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 璺敱鍒楄〃
+     */
+    @Override
+    public List<RouterVo> buildMenus(List<SysMenu> menus)
+    {
+        List<RouterVo> routers = new LinkedList<RouterVo>();
+        for (SysMenu menu : menus)
+        {
+            RouterVo router = new RouterVo();
+            router.setHidden("1".equals(menu.getVisible()));
+            router.setName(getRouteName(menu));
+            router.setPath(getRouterPath(menu));
+            router.setComponent(getComponent(menu));
+            router.setQuery(menu.getQuery());
+            router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+            List<SysMenu> cMenus = menu.getChildren();
+            if (StringUtils.isNotEmpty(cMenus) && UserConstants.TYPE_DIR.equals(menu.getMenuType()))
+            {
+                router.setAlwaysShow(true);
+                router.setRedirect("noRedirect");
+                router.setChildren(buildMenus(cMenus));
+            }
+            else if (isMenuFrame(menu))
+            {
+                router.setMeta(null);
+                List<RouterVo> childrenList = new ArrayList<RouterVo>();
+                RouterVo children = new RouterVo();
+                children.setPath(menu.getPath());
+                children.setComponent(menu.getComponent());
+                children.setName(getRouteName(menu.getRouteName(), menu.getPath()));
+                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), StringUtils.equals("1", menu.getIsCache()), menu.getPath()));
+                children.setQuery(menu.getQuery());
+                childrenList.add(children);
+                router.setChildren(childrenList);
+            }
+            else if (menu.getParentId().intValue() == 0 && isInnerLink(menu))
+            {
+                router.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon()));
+                router.setPath("/");
+                List<RouterVo> childrenList = new ArrayList<RouterVo>();
+                RouterVo children = new RouterVo();
+                String routerPath = innerLinkReplaceEach(menu.getPath());
+                children.setPath(routerPath);
+                children.setComponent(UserConstants.INNER_LINK);
+                children.setName(getRouteName(menu.getRouteName(), routerPath));
+                children.setMeta(new MetaVo(menu.getMenuName(), menu.getIcon(), menu.getPath()));
+                childrenList.add(children);
+                router.setChildren(childrenList);
+            }
+            routers.add(router);
+        }
+        return routers;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佹爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<SysMenu> buildMenuTree(List<SysMenu> menus)
+    {
+        List<SysMenu> returnList = new ArrayList<SysMenu>();
+        List<Long> tempList = menus.stream().map(SysMenu::getMenuId).collect(Collectors.toList());
+        for (Iterator<SysMenu> iterator = menus.iterator(); iterator.hasNext();)
+        {
+            SysMenu menu = (SysMenu) iterator.next();
+            // 濡傛灉鏄《绾ц妭鐐�, 閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (!tempList.contains(menu.getParentId()))
+            {
+                recursionFn(menus, menu);
+                returnList.add(menu);
+            }
+        }
+        if (returnList.isEmpty())
+        {
+            returnList = menus;
+        }
+        return returnList;
+    }
+
+    /**
+     * 鏋勫缓鍓嶇鎵�闇�瑕佷笅鎷夋爲缁撴瀯
+     * 
+     * @param menus 鑿滃崟鍒楄〃
+     * @return 涓嬫媺鏍戠粨鏋勫垪琛�
+     */
+    @Override
+    public List<TreeSelect> buildMenuTreeSelect(List<SysMenu> menus)
+    {
+        List<SysMenu> menuTrees = buildMenuTree(menus);
+        return menuTrees.stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    /**
+     * 鏍规嵁鑿滃崟ID鏌ヨ淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 鑿滃崟淇℃伅
+     */
+    @Override
+    public SysMenu selectMenuById(Long menuId)
+    {
+        return menuMapper.selectMenuById(menuId);
+    }
+
+    /**
+     * 鏄惁瀛樺湪鑿滃崟瀛愯妭鐐�
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean hasChildByMenuId(Long menuId)
+    {
+        int result = menuMapper.hasChildByMenuId(menuId);
+        return result > 0;
+    }
+
+    /**
+     * 鏌ヨ鑿滃崟浣跨敤鏁伴噺
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkMenuExistRole(Long menuId)
+    {
+        int result = roleMenuMapper.checkMenuExistRole(menuId);
+        return result > 0;
+    }
+
+    /**
+     * 鏂板淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int insertMenu(SysMenu menu)
+    {
+        return menuMapper.insertMenu(menu);
+    }
+
+    /**
+     * 淇敼淇濆瓨鑿滃崟淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public int updateMenu(SysMenu menu)
+    {
+        return menuMapper.updateMenu(menu);
+    }
+
+    /**
+     * 鍒犻櫎鑿滃崟绠$悊淇℃伅
+     * 
+     * @param menuId 鑿滃崟ID
+     * @return 缁撴灉
+     */
+    @Override
+    public int deleteMenuById(Long menuId)
+    {
+        return menuMapper.deleteMenuById(menuId);
+    }
+
+    /**
+     * 鏍¢獙鑿滃崟鍚嶇О鏄惁鍞竴
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    @Override
+    public boolean checkMenuNameUnique(SysMenu menu)
+    {
+        Long menuId = StringUtils.isNull(menu.getMenuId()) ? -1L : menu.getMenuId();
+        SysMenu info = menuMapper.checkMenuNameUnique(menu.getMenuName(), menu.getParentId());
+        if (StringUtils.isNotNull(info) && info.getMenuId().longValue() != menuId.longValue())
+        {
+            return UserConstants.NOT_UNIQUE;
+        }
+        return UserConstants.UNIQUE;
+    }
+
+    /**
+     * 鑾峰彇璺敱鍚嶇О
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 璺敱鍚嶇О
+     */
+    public String getRouteName(SysMenu menu)
+    {
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+        if (isMenuFrame(menu))
+        {
+            return StringUtils.EMPTY;
+        }
+        return getRouteName(menu.getRouteName(), menu.getPath());
+    }
+
+    /**
+     * 鑾峰彇璺敱鍚嶇О锛屽娌℃湁閰嶇疆璺敱鍚嶇О鍒欏彇璺敱鍦板潃
+     * 
+     * @param routerName 璺敱鍚嶇О
+     * @param path 璺敱鍦板潃
+     * @return 璺敱鍚嶇О锛堥┘宄版牸寮忥級
+     */
+    public String getRouteName(String name, String path)
+    {
+        String routerName = StringUtils.isNotEmpty(name) ? name : path;
+        return StringUtils.capitalize(routerName);
+    }
+
+    /**
+     * 鑾峰彇璺敱鍦板潃
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 璺敱鍦板潃
+     */
+    public String getRouterPath(SysMenu menu)
+    {
+        String routerPath = menu.getPath();
+        // 鍐呴摼鎵撳紑澶栫綉鏂瑰紡
+        if (menu.getParentId().intValue() != 0 && isInnerLink(menu))
+        {
+            routerPath = innerLinkReplaceEach(routerPath);
+        }
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓虹洰褰曪級
+        if (0 == menu.getParentId().intValue() && UserConstants.TYPE_DIR.equals(menu.getMenuType())
+                && UserConstants.NO_FRAME.equals(menu.getIsFrame()))
+        {
+            routerPath = "/" + menu.getPath();
+        }
+        // 闈炲閾惧苟涓旀槸涓�绾х洰褰曪紙绫诲瀷涓鸿彍鍗曪級
+        else if (isMenuFrame(menu))
+        {
+            routerPath = "/";
+        }
+        return routerPath;
+    }
+
+    /**
+     * 鑾峰彇缁勪欢淇℃伅
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁勪欢淇℃伅
+     */
+    public String getComponent(SysMenu menu)
+    {
+        String component = UserConstants.LAYOUT;
+        if (StringUtils.isNotEmpty(menu.getComponent()) && !isMenuFrame(menu))
+        {
+            component = menu.getComponent();
+        }
+        else if (StringUtils.isEmpty(menu.getComponent()) && menu.getParentId().intValue() != 0 && isInnerLink(menu))
+        {
+            component = UserConstants.INNER_LINK;
+        }
+        else if (StringUtils.isEmpty(menu.getComponent()) && isParentView(menu))
+        {
+            component = UserConstants.PARENT_VIEW;
+        }
+        return component;
+    }
+
+    /**
+     * 鏄惁涓鸿彍鍗曞唴閮ㄨ烦杞�
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public boolean isMenuFrame(SysMenu menu)
+    {
+        return menu.getParentId().intValue() == 0 && UserConstants.TYPE_MENU.equals(menu.getMenuType())
+                && menu.getIsFrame().equals(UserConstants.NO_FRAME);
+    }
+
+    /**
+     * 鏄惁涓哄唴閾剧粍浠�
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public boolean isInnerLink(SysMenu menu)
+    {
+        return menu.getIsFrame().equals(UserConstants.NO_FRAME) && StringUtils.ishttp(menu.getPath());
+    }
+
+    /**
+     * 鏄惁涓簆arent_view缁勪欢
+     * 
+     * @param menu 鑿滃崟淇℃伅
+     * @return 缁撴灉
+     */
+    public boolean isParentView(SysMenu menu)
+    {
+        return menu.getParentId().intValue() != 0 && UserConstants.TYPE_DIR.equals(menu.getMenuType());
+    }
+
+    /**
+     * 鏍规嵁鐖惰妭鐐圭殑ID鑾峰彇鎵�鏈夊瓙鑺傜偣
+     * 
+     * @param list 鍒嗙被琛�
+     * @param parentId 浼犲叆鐨勭埗鑺傜偣ID
+     * @return String
+     */
+    public List<SysMenu> getChildPerms(List<SysMenu> list, int parentId)
+    {
+        List<SysMenu> returnList = new ArrayList<SysMenu>();
+        for (Iterator<SysMenu> iterator = list.iterator(); iterator.hasNext();)
+        {
+            SysMenu t = (SysMenu) iterator.next();
+            // 涓�銆佹牴鎹紶鍏ョ殑鏌愪釜鐖惰妭鐐笽D,閬嶅巻璇ョ埗鑺傜偣鐨勬墍鏈夊瓙鑺傜偣
+            if (t.getParentId() == parentId)
+            {
+                recursionFn(list, t);
+                returnList.add(t);
+            }
+        }
+        return returnList;
+    }
+
+    /**
+     * 閫掑綊鍒楄〃
+     * 
+     * @param list 鍒嗙被琛�
+     * @param t 瀛愯妭鐐�
+     */
+    private void recursionFn(List<SysMenu> list, SysMenu t)
+    {
+        // 寰楀埌瀛愯妭鐐瑰垪琛�
+        List<SysMenu> childList = getChildList(list, t);
+        t.setChildren(childList);
+        for (SysMenu tChild : childList)
+        {
+            if (hasChild(list, tChild))
+            {
+                recursionFn(list, tChild);
+            }
+        }
+    }
+
+    /**
+     * 寰楀埌瀛愯妭鐐瑰垪琛�
+     */
+    private List<SysMenu> getChildList(List<SysMenu> list, SysMenu t)
+    {
+        List<SysMenu> tlist = new ArrayList<SysMenu>();
+        Iterator<SysMenu> it = list.iterator();
+        while (it.hasNext())
+        {
+            SysMenu n = (SysMenu) it.next();
+            if (n.getParentId().longValue() == t.getMenuId().longValue())
+            {
+                tlist.add(n);
+            }
+        }
+        return tlist;
+    }
+
+    /**
+     * 鍒ゆ柇鏄惁鏈夊瓙鑺傜偣
+     */
+    private boolean hasChild(List<SysMenu> list, SysMenu t)
+    {
+        return getChildList(list, t).size() > 0;
+    }
+
+    /**
+     * 鍐呴摼鍩熷悕鐗规畩瀛楃鏇挎崲
+     * 
+     * @return 鏇挎崲鍚庣殑鍐呴摼鍩熷悕
+     */
+    public String innerLinkReplaceEach(String path)
+    {
+        return StringUtils.replaceEach(path, new String[] { Constants.HTTP, Constants.HTTPS, Constants.WWW, ".", ":" },
+                new String[] { "", "", "", "/", "/" });
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
new file mode 100644
index 0000000..765438b
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysNoticeServiceImpl.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
new file mode 100644
index 0000000..a13f352
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysOperLogServiceImpl.java
@@ -0,0 +1,122 @@
+package com.ruoyi.system.service.impl;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
+import com.ruoyi.system.domain.vo.SysOperLogVO;
+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();
+    }
+
+    /**
+     * 鏌ヨ鏃堕棿娈靛唴姣忓ぉ鐨勬搷浣滄棩蹇�
+     */
+    @Override
+    public Map<String,List<SysOperLog>> queryByDate(SysOperLogVO logVO){
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
+        DateTimeFormatter dft = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
+        LocalDate startLocalDate = LocalDate.parse(logVO.getStartTime(),formatter);
+        LocalDate endLocalDate = LocalDate.parse(logVO.getEndTime(),formatter);
+        String title = logVO.getTitle();
+
+        Map<String,List<SysOperLog>> resMap = new LinkedHashMap<>();
+
+        while (!startLocalDate.isAfter(endLocalDate)){
+            LocalDateTime startOfDay = startLocalDate.atStartOfDay();
+            LocalDateTime endOfDay = startLocalDate.plusDays(1).atStartOfDay();
+            SysOperLogVO sysOperLogVO = new SysOperLogVO();
+            sysOperLogVO.setTitle(title);
+            sysOperLogVO.setStartTime(startOfDay.format(dft));
+            sysOperLogVO.setEndTime(endOfDay.format(dft));
+
+            List<SysOperLog> dailyList = operLogMapper.queryByDate(sysOperLogVO);
+
+            resMap.put(startLocalDate.format(formatter),dailyList);
+            startLocalDate = startLocalDate.plusDays(1);
+        }
+        return resMap;
+    }
+
+    /**
+     * 绛涢�夋煡璇㈡搷浣滄棩蹇�
+     */
+    @Override
+    public List<SysOperLog> queryDataByTitle(SysOperLogVO logVO){
+        return operLogMapper.queryData(logVO);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
new file mode 100644
index 0000000..5e5fe06
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysPostServiceImpl.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
new file mode 100644
index 0000000..e432bb1
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysRoleServiceImpl.java
@@ -0,0 +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);
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
new file mode 100644
index 0000000..f80a877
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserOnlineServiceImpl.java
@@ -0,0 +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;
+    }
+}
diff --git a/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
new file mode 100644
index 0000000..82c303a
--- /dev/null
+++ b/ruoyi-system/src/main/java/com/ruoyi/system/service/impl/SysUserServiceImpl.java
@@ -0,0 +1,550 @@
+package com.ruoyi.system.service.impl;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+import jakarta.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 + " 鏉℃暟鎹牸寮忎笉姝g‘锛岄敊璇涓嬶細");
+            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/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
new file mode 100644
index 0000000..fee4088
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysConfigMapper.xml
@@ -0,0 +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="com.ruoyi.system.domain.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="com.ruoyi.system.domain.SysConfig" resultMap="SysConfigResult">
+        <include refid="selectConfigVo"/>
+        <include refid="sqlwhereSearch"/>
+    </select>
+    
+    <select id="selectConfigList" parameterType="com.ruoyi.system.domain.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="com.ruoyi.system.domain.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="com.ruoyi.system.domain.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/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
new file mode 100644
index 0000000..cf439f6
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysDeptMapper.xml
@@ -0,0 +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>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
new file mode 100644
index 0000000..3b94b7f
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysDictDataMapper.xml
@@ -0,0 +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>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
new file mode 100644
index 0000000..438d484
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysDictTypeMapper.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.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/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
new file mode 100644
index 0000000..822d665
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysLogininforMapper.xml
@@ -0,0 +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>
+    
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
new file mode 100644
index 0000000..68b1ed6
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysMenuMapper.xml
@@ -0,0 +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>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
new file mode 100644
index 0000000..e36f74f
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysNoticeMapper.xml
@@ -0,0 +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(10000)) 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/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
new file mode 100644
index 0000000..b96faab
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysOperLogMapper.xml
@@ -0,0 +1,113 @@
+<?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>
+
+	<select id="queryByDate" parameterType="com.ruoyi.system.domain.vo.SysOperLogVO" resultMap="SysOperLogResult">
+		<include refid="selectOperLogVo"/>
+		<where>
+			<if test="title != null and title != ''">
+				AND title like concat('%', #{title}, '%')
+			</if>
+			<if test="startTime != null and startTime != ''">
+				AND oper_time &gt;= #{startTime}
+			</if>
+			<if test="endTime != null and endTime != ''">
+				AND oper_time &lt; #{endTime}
+			</if>
+		</where>
+		order by oper_id desc
+	</select>
+
+	<select id="queryData" parameterType="com.ruoyi.system.domain.vo.SysOperLogVO" resultMap="SysOperLogResult">
+		<include refid="selectOperLogVo"/>
+		<where>
+			<if test="title != null and title != ''">
+				AND title like concat('%', #{title}, '%')
+			</if>
+		</where>
+		order by oper_id desc
+	</select>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
new file mode 100644
index 0000000..227c459
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysPostMapper.xml
@@ -0,0 +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>
+
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
new file mode 100644
index 0000000..7c4139b
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysRoleDeptMapper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.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/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
new file mode 100644
index 0000000..955d4ee
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysRoleMapper.xml
@@ -0,0 +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>
+ 	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
new file mode 100644
index 0000000..cb60a85
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysRoleMenuMapper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.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/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
new file mode 100644
index 0000000..0856cb2
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserMapper.xml
@@ -0,0 +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>
+	
+</mapper> 
\ No newline at end of file
diff --git a/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml b/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
new file mode 100644
index 0000000..2b90bc4
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserPostMapper.xml
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.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/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
new file mode 100644
index 0000000..dd72689
--- /dev/null
+++ b/ruoyi-system/src/main/resources/mapper/system/SysUserRoleMapper.xml
@@ -0,0 +1,44 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper
+PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
+"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.ruoyi.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/ruoyi-ui/.editorconfig b/ruoyi-ui/.editorconfig
new file mode 100644
index 0000000..7034f9b
--- /dev/null
+++ b/ruoyi-ui/.editorconfig
@@ -0,0 +1,22 @@
+# 鍛婅瘔EditorConfig鎻掍欢锛岃繖鏄牴鏂囦欢锛屼笉鐢ㄧ户缁線涓婃煡鎵�
+root = true
+
+# 鍖归厤鍏ㄩ儴鏂囦欢
+[*]
+# 璁剧疆瀛楃闆�
+charset = utf-8
+# 缂╄繘椋庢牸锛屽彲閫塻pace銆乼ab
+indent_style = space
+# 缂╄繘鐨勭┖鏍兼暟
+indent_size = 2
+# 缁撳熬鎹㈣绗︼紝鍙�塴f銆乧r銆乧rlf
+end_of_line = lf
+# 鍦ㄦ枃浠剁粨灏炬彃鍏ユ柊琛�
+insert_final_newline = true
+# 鍒犻櫎涓�琛屼腑鐨勫墠鍚庣┖鏍�
+trim_trailing_whitespace = true
+
+# 鍖归厤md缁撳熬鐨勬枃浠�
+[*.md]
+insert_final_newline = false
+trim_trailing_whitespace = false
diff --git a/ruoyi-ui/.env.development b/ruoyi-ui/.env.development
new file mode 100644
index 0000000..302ecd1
--- /dev/null
+++ b/ruoyi-ui/.env.development
@@ -0,0 +1,11 @@
+# 椤甸潰鏍囬
+VUE_APP_TITLE = 鑻ヤ緷绠$悊绯荤粺
+
+# 寮�鍙戠幆澧冮厤缃�
+ENV = 'development'
+
+# 鑻ヤ緷绠$悊绯荤粺/寮�鍙戠幆澧�
+VUE_APP_BASE_API = '/dev-api'
+
+# 璺敱鎳掑姞杞�
+VUE_CLI_BABEL_TRANSPILE_MODULES = true
diff --git a/ruoyi-ui/.env.production b/ruoyi-ui/.env.production
new file mode 100644
index 0000000..b4893b0
--- /dev/null
+++ b/ruoyi-ui/.env.production
@@ -0,0 +1,8 @@
+# 椤甸潰鏍囬
+VUE_APP_TITLE = 鑻ヤ緷绠$悊绯荤粺
+
+# 鐢熶骇鐜閰嶇疆
+ENV = 'production'
+
+# 鑻ヤ緷绠$悊绯荤粺/鐢熶骇鐜
+VUE_APP_BASE_API = '/prod-api'
diff --git a/ruoyi-ui/.env.staging b/ruoyi-ui/.env.staging
new file mode 100644
index 0000000..209b64e
--- /dev/null
+++ b/ruoyi-ui/.env.staging
@@ -0,0 +1,12 @@
+# 椤甸潰鏍囬
+VUE_APP_TITLE = 鑻ヤ緷绠$悊绯荤粺
+
+BABEL_ENV = production
+
+NODE_ENV = production
+
+# 娴嬭瘯鐜閰嶇疆
+ENV = 'staging'
+
+# 鑻ヤ緷绠$悊绯荤粺/娴嬭瘯鐜
+VUE_APP_BASE_API = '/stage-api'
diff --git a/ruoyi-ui/.eslintignore b/ruoyi-ui/.eslintignore
new file mode 100644
index 0000000..89be6f6
--- /dev/null
+++ b/ruoyi-ui/.eslintignore
@@ -0,0 +1,10 @@
+# 蹇界暐build鐩綍涓嬬被鍨嬩负js鐨勬枃浠剁殑璇硶妫�鏌�
+build/*.js
+# 蹇界暐src/assets鐩綍涓嬫枃浠剁殑璇硶妫�鏌�
+src/assets
+# 蹇界暐public鐩綍涓嬫枃浠剁殑璇硶妫�鏌�
+public
+# 蹇界暐褰撳墠鐩綍涓嬩负js鐨勬枃浠剁殑璇硶妫�鏌�
+*.js
+# 蹇界暐褰撳墠鐩綍涓嬩负vue鐨勬枃浠剁殑璇硶妫�鏌�
+*.vue
\ No newline at end of file
diff --git a/ruoyi-ui/.eslintrc.js b/ruoyi-ui/.eslintrc.js
new file mode 100644
index 0000000..82bbdee
--- /dev/null
+++ b/ruoyi-ui/.eslintrc.js
@@ -0,0 +1,199 @@
+// ESlint 妫�鏌ラ厤缃�
+module.exports = {
+  root: true,
+  parserOptions: {
+    parser: 'babel-eslint',
+    sourceType: 'module'
+  },
+  env: {
+    browser: true,
+    node: true,
+    es6: true,
+  },
+  extends: ['plugin:vue/recommended', 'eslint:recommended'],
+
+  // add your custom rules here
+  //it is base on https://github.com/vuejs/eslint-config-vue
+  rules: {
+    "vue/max-attributes-per-line": [2, {
+      "singleline": 10,
+      "multiline": {
+        "max": 1,
+        "allowFirstLine": false
+      }
+    }],
+    "vue/singleline-html-element-content-newline": "off",
+    "vue/multiline-html-element-content-newline":"off",
+    "vue/name-property-casing": ["error", "PascalCase"],
+    "vue/no-v-html": "off",
+    'accessor-pairs': 2,
+    'arrow-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'block-spacing': [2, 'always'],
+    'brace-style': [2, '1tbs', {
+      'allowSingleLine': true
+    }],
+    'camelcase': [0, {
+      'properties': 'always'
+    }],
+    'comma-dangle': [2, 'never'],
+    'comma-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'comma-style': [2, 'last'],
+    'constructor-super': 2,
+    'curly': [2, 'multi-line'],
+    'dot-location': [2, 'property'],
+    'eol-last': 2,
+    'eqeqeq': ["error", "always", {"null": "ignore"}],
+    'generator-star-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'handle-callback-err': [2, '^(err|error)$'],
+    'indent': [2, 2, {
+      'SwitchCase': 1
+    }],
+    'jsx-quotes': [2, 'prefer-single'],
+    'key-spacing': [2, {
+      'beforeColon': false,
+      'afterColon': true
+    }],
+    'keyword-spacing': [2, {
+      'before': true,
+      'after': true
+    }],
+    'new-cap': [2, {
+      'newIsCap': true,
+      'capIsNew': false
+    }],
+    'new-parens': 2,
+    'no-array-constructor': 2,
+    'no-caller': 2,
+    'no-console': 'off',
+    'no-class-assign': 2,
+    'no-cond-assign': 2,
+    'no-const-assign': 2,
+    'no-control-regex': 0,
+    'no-delete-var': 2,
+    'no-dupe-args': 2,
+    'no-dupe-class-members': 2,
+    'no-dupe-keys': 2,
+    'no-duplicate-case': 2,
+    'no-empty-character-class': 2,
+    'no-empty-pattern': 2,
+    'no-eval': 2,
+    'no-ex-assign': 2,
+    'no-extend-native': 2,
+    'no-extra-bind': 2,
+    'no-extra-boolean-cast': 2,
+    'no-extra-parens': [2, 'functions'],
+    'no-fallthrough': 2,
+    'no-floating-decimal': 2,
+    'no-func-assign': 2,
+    'no-implied-eval': 2,
+    'no-inner-declarations': [2, 'functions'],
+    'no-invalid-regexp': 2,
+    'no-irregular-whitespace': 2,
+    'no-iterator': 2,
+    'no-label-var': 2,
+    'no-labels': [2, {
+      'allowLoop': false,
+      'allowSwitch': false
+    }],
+    'no-lone-blocks': 2,
+    'no-mixed-spaces-and-tabs': 2,
+    'no-multi-spaces': 2,
+    'no-multi-str': 2,
+    'no-multiple-empty-lines': [2, {
+      'max': 1
+    }],
+    'no-native-reassign': 2,
+    'no-negated-in-lhs': 2,
+    'no-new-object': 2,
+    'no-new-require': 2,
+    'no-new-symbol': 2,
+    'no-new-wrappers': 2,
+    'no-obj-calls': 2,
+    'no-octal': 2,
+    'no-octal-escape': 2,
+    'no-path-concat': 2,
+    'no-proto': 2,
+    'no-redeclare': 2,
+    'no-regex-spaces': 2,
+    'no-return-assign': [2, 'except-parens'],
+    'no-self-assign': 2,
+    'no-self-compare': 2,
+    'no-sequences': 2,
+    'no-shadow-restricted-names': 2,
+    'no-spaced-func': 2,
+    'no-sparse-arrays': 2,
+    'no-this-before-super': 2,
+    'no-throw-literal': 2,
+    'no-trailing-spaces': 2,
+    'no-undef': 2,
+    'no-undef-init': 2,
+    'no-unexpected-multiline': 2,
+    'no-unmodified-loop-condition': 2,
+    'no-unneeded-ternary': [2, {
+      'defaultAssignment': false
+    }],
+    'no-unreachable': 2,
+    'no-unsafe-finally': 2,
+    'no-unused-vars': [2, {
+      'vars': 'all',
+      'args': 'none'
+    }],
+    'no-useless-call': 2,
+    'no-useless-computed-key': 2,
+    'no-useless-constructor': 2,
+    'no-useless-escape': 0,
+    'no-whitespace-before-property': 2,
+    'no-with': 2,
+    'one-var': [2, {
+      'initialized': 'never'
+    }],
+    'operator-linebreak': [2, 'after', {
+      'overrides': {
+        '?': 'before',
+        ':': 'before'
+      }
+    }],
+    'padded-blocks': [2, 'never'],
+    'quotes': [2, 'single', {
+      'avoidEscape': true,
+      'allowTemplateLiterals': true
+    }],
+    'semi': [2, 'never'],
+    'semi-spacing': [2, {
+      'before': false,
+      'after': true
+    }],
+    'space-before-blocks': [2, 'always'],
+    'space-before-function-paren': [2, 'never'],
+    'space-in-parens': [2, 'never'],
+    'space-infix-ops': 2,
+    'space-unary-ops': [2, {
+      'words': true,
+      'nonwords': false
+    }],
+    'spaced-comment': [2, 'always', {
+      'markers': ['global', 'globals', 'eslint', 'eslint-disable', '*package', '!', ',']
+    }],
+    'template-curly-spacing': [2, 'never'],
+    'use-isnan': 2,
+    'valid-typeof': 2,
+    'wrap-iife': [2, 'any'],
+    'yield-star-spacing': [2, 'both'],
+    'yoda': [2, 'never'],
+    'prefer-const': 2,
+    'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0,
+    'object-curly-spacing': [2, 'always', {
+      objectsInObjects: false
+    }],
+    'array-bracket-spacing': [2, 'never']
+  }
+}
diff --git a/ruoyi-ui/.gitignore b/ruoyi-ui/.gitignore
new file mode 100644
index 0000000..78a752d
--- /dev/null
+++ b/ruoyi-ui/.gitignore
@@ -0,0 +1,23 @@
+.DS_Store
+node_modules/
+dist/
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+**/*.log
+
+tests/**/coverage/
+tests/e2e/reports
+selenium-debug.log
+
+# Editor directories and files
+.idea
+.vscode
+*.suo
+*.ntvs*
+*.njsproj
+*.sln
+*.local
+
+package-lock.json
+yarn.lock
diff --git a/ruoyi-ui/README.md b/ruoyi-ui/README.md
new file mode 100644
index 0000000..00c0ab8
--- /dev/null
+++ b/ruoyi-ui/README.md
@@ -0,0 +1,30 @@
+## 寮�鍙�
+
+```bash
+# 鍏嬮殕椤圭洰
+git clone https://gitee.com/y_project/RuoYi-Vue
+
+# 杩涘叆椤圭洰鐩綍
+cd ruoyi-ui
+
+# 瀹夎渚濊禆
+npm install
+
+# 寤鸿涓嶈鐩存帴浣跨敤 cnpm 瀹夎渚濊禆锛屼細鏈夊悇绉嶈寮傜殑 bug銆傚彲浠ラ�氳繃濡備笅鎿嶄綔瑙e喅 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/babel.config.js b/ruoyi-ui/babel.config.js
new file mode 100644
index 0000000..c8267b2
--- /dev/null
+++ b/ruoyi-ui/babel.config.js
@@ -0,0 +1,13 @@
+module.exports = {
+  presets: [
+    // https://github.com/vuejs/vue-cli/tree/master/packages/@vue/babel-preset-app
+    '@vue/cli-plugin-babel/preset'
+  ],
+  'env': {
+    'development': {
+      // babel-plugin-dynamic-import-node plugin only does one thing by converting all import() to require().
+      // This plugin can significantly increase the speed of hot updates, when you have a large number of pages.
+      'plugins': ['dynamic-import-node']
+    }
+  }
+}
\ No newline at end of file
diff --git a/ruoyi-ui/bin/build.bat b/ruoyi-ui/bin/build.bat
new file mode 100644
index 0000000..dda590d
--- /dev/null
+++ b/ruoyi-ui/bin/build.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成dist文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run build:prod
+
+pause
\ No newline at end of file
diff --git a/ruoyi-ui/bin/package.bat b/ruoyi-ui/bin/package.bat
new file mode 100644
index 0000000..0e5bc0f
--- /dev/null
+++ b/ruoyi-ui/bin/package.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 安装Web工程,生成node_modules文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm install --registry=https://registry.npmmirror.com
+
+pause
\ No newline at end of file
diff --git a/ruoyi-ui/bin/run-web.bat b/ruoyi-ui/bin/run-web.bat
new file mode 100644
index 0000000..d30deae
--- /dev/null
+++ b/ruoyi-ui/bin/run-web.bat
@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 使用 Vue CLI 命令运行 Web 工程。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+npm run dev
+
+pause
\ No newline at end of file
diff --git a/ruoyi-ui/build/index.js b/ruoyi-ui/build/index.js
new file mode 100644
index 0000000..0c57de2
--- /dev/null
+++ b/ruoyi-ui/build/index.js
@@ -0,0 +1,35 @@
+const { run } = require('runjs')
+const chalk = require('chalk')
+const config = require('../vue.config.js')
+const rawArgv = process.argv.slice(2)
+const args = rawArgv.join(' ')
+
+if (process.env.npm_config_preview || rawArgv.includes('--preview')) {
+  const report = rawArgv.includes('--report')
+
+  run(`vue-cli-service build ${args}`)
+
+  const port = 9526
+  const publicPath = config.publicPath
+
+  var connect = require('connect')
+  var serveStatic = require('serve-static')
+  const app = connect()
+
+  app.use(
+    publicPath,
+    serveStatic('./dist', {
+      index: ['index.html', '/']
+    })
+  )
+
+  app.listen(port, function () {
+    console.log(chalk.green(`> Preview at  http://localhost:${port}${publicPath}`))
+    if (report) {
+      console.log(chalk.green(`> Report at  http://localhost:${port}${publicPath}report.html`))
+    }
+
+  })
+} else {
+  run(`vue-cli-service build ${args}`)
+}
diff --git a/ruoyi-ui/package.json b/ruoyi-ui/package.json
new file mode 100644
index 0000000..392d7db
--- /dev/null
+++ b/ruoyi-ui/package.json
@@ -0,0 +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"
+  ]
+}
diff --git a/ruoyi-ui/public/favicon.ico b/ruoyi-ui/public/favicon.ico
new file mode 100644
index 0000000..e263760
--- /dev/null
+++ b/ruoyi-ui/public/favicon.ico
Binary files differ
diff --git a/ruoyi-ui/public/html/ie.html b/ruoyi-ui/public/html/ie.html
new file mode 100644
index 0000000..052ffcd
--- /dev/null
+++ b/ruoyi-ui/public/html/ie.html
@@ -0,0 +1,46 @@
+
+<!DOCTYPE html>
+<html lang="zh-CN">
+<head>
+    <meta charset="UTF-8" />
+    <title>璇峰崌绾ф偍鐨勬祻瑙堝櫒</title>
+    <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1" >
+    <meta name="renderer" content="webkit">
+    <base target="_blank" />
+    <style type="text/css">
+        html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,big,cite,code,del,dfn,em,img,ins,kbd,q,s,samp,small,strike,strong,sub,sup,tt,var,b,u,i,center,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,article,aside,canvas,details,embed,figure,figcaption,footer,header,hgroup,menu,nav,output,ruby,section,summary,time,mark,audio,video{border:0;font-size:100%;font:inherit;vertical-align:baseline;margin:0;padding:0}article,aside,details,figcaption,figure,footer,header,hgroup,menu,nav,section{display:block}body{line-height:1}ol,ul{list-style:none}blockquote,q{quotes:none}blockquote:before,blockquote:after,q:before,q:after{content:none}table{border-collapse:collapse;border-spacing:0}
+        a{text-decoration:none;color:#0072c6;}a:hover{text-decoration:none;color:#004d8c;}
+        body{width:960px;margin:0 auto;padding:10px;font-size:14px;line-height:24px;color:#454545;font-family:'Microsoft YaHei UI','Microsoft YaHei',DengXian,SimSun,'Segoe UI',Tahoma,Helvetica,sans-serif;overflow-y:scroll}
+        h1{font-size:40px;line-height:80px;font-weight:100;margin-bottom:10px;}
+        h2{font-size:20px;line-height:25px;font-weight:100;margin:10px 0;}
+        em{color:red}
+        p{margin-bottom:10px;}
+        hr{margin:20px 0;border:0;border-top:1px solid #dadada}
+        span{display:block;font-size:12px;line-height:12px;}
+        .clean{clear:both;}
+        .browser{padding:10px 10px;}
+        .browser li{width:auto;padding:0 80px;margin-top:30px;height:34px;line-height:22px;float:left;list-style:none;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACIAAADMCAYAAAAWCXEwAAAACXBIWXMAAAsTAAALEwEAmpwYAAAKTWlDQ1BQaG90b3Nob3AgSUNDIHByb2ZpbGUAAHjanVN3WJP3Fj7f92UPVkLY8LGXbIEAIiOsCMgQWaIQkgBhhBASQMWFiApWFBURnEhVxILVCkidiOKgKLhnQYqIWotVXDjuH9yntX167+3t+9f7vOec5/zOec8PgBESJpHmomoAOVKFPDrYH49PSMTJvYACFUjgBCAQ5svCZwXFAADwA3l4fnSwP/wBr28AAgBw1S4kEsfh/4O6UCZXACCRAOAiEucLAZBSAMguVMgUAMgYALBTs2QKAJQAAGx5fEIiAKoNAOz0ST4FANipk9wXANiiHKkIAI0BAJkoRyQCQLsAYFWBUiwCwMIAoKxAIi4EwK4BgFm2MkcCgL0FAHaOWJAPQGAAgJlCLMwAIDgCAEMeE80DIEwDoDDSv+CpX3CFuEgBAMDLlc2XS9IzFLiV0Bp38vDg4iHiwmyxQmEXKRBmCeQinJebIxNI5wNMzgwAABr50cH+OD+Q5+bk4eZm52zv9MWi/mvwbyI+IfHf/ryMAgQAEE7P79pf5eXWA3DHAbB1v2upWwDaVgBo3/ldM9sJoFoK0Hr5i3k4/EAenqFQyDwdHAoLC+0lYqG9MOOLPv8z4W/gi372/EAe/tt68ABxmkCZrcCjg/1xYW52rlKO58sEQjFu9+cj/seFf/2OKdHiNLFcLBWK8ViJuFAiTcd5uVKRRCHJleIS6X8y8R+W/QmTdw0ArIZPwE62B7XLbMB+7gECiw5Y0nYAQH7zLYwaC5EAEGc0Mnn3AACTv/mPQCsBAM2XpOMAALzoGFyolBdMxggAAESggSqwQQcMwRSswA6cwR28wBcCYQZEQAwkwDwQQgbkgBwKoRiWQRlUwDrYBLWwAxqgEZrhELTBMTgN5+ASXIHrcBcGYBiewhi8hgkEQcgIE2EhOogRYo7YIs4IF5mOBCJhSDSSgKQg6YgUUSLFyHKkAqlCapFdSCPyLXIUOY1cQPqQ28ggMor8irxHMZSBslED1AJ1QLmoHxqKxqBz0XQ0D12AlqJr0Rq0Hj2AtqKn0UvodXQAfYqOY4DRMQ5mjNlhXIyHRWCJWBomxxZj5Vg1Vo81Yx1YN3YVG8CeYe8IJAKLgBPsCF6EEMJsgpCQR1hMWEOoJewjtBK6CFcJg4Qxwicik6hPtCV6EvnEeGI6sZBYRqwm7iEeIZ4lXicOE1+TSCQOyZLkTgohJZAySQtJa0jbSC2kU6Q+0hBpnEwm65Btyd7kCLKArCCXkbeQD5BPkvvJw+S3FDrFiOJMCaIkUqSUEko1ZT/lBKWfMkKZoKpRzame1AiqiDqfWkltoHZQL1OHqRM0dZolzZsWQ8ukLaPV0JppZ2n3aC/pdLoJ3YMeRZfQl9Jr6Afp5+mD9HcMDYYNg8dIYigZaxl7GacYtxkvmUymBdOXmchUMNcyG5lnmA+Yb1VYKvYqfBWRyhKVOpVWlX6V56pUVXNVP9V5qgtUq1UPq15WfaZGVbNQ46kJ1Bar1akdVbupNq7OUndSj1DPUV+jvl/9gvpjDbKGhUaghkijVGO3xhmNIRbGMmXxWELWclYD6yxrmE1iW7L57Ex2Bfsbdi97TFNDc6pmrGaRZp3mcc0BDsax4PA52ZxKziHODc57LQMtPy2x1mqtZq1+rTfaetq+2mLtcu0W7eva73VwnUCdLJ31Om0693UJuja6UbqFutt1z+o+02PreekJ9cr1Dund0Uf1bfSj9Rfq79bv0R83MDQINpAZbDE4Y/DMkGPoa5hpuNHwhOGoEctoupHEaKPRSaMnuCbuh2fjNXgXPmasbxxirDTeZdxrPGFiaTLbpMSkxeS+Kc2Ua5pmutG003TMzMgs3KzYrMnsjjnVnGueYb7ZvNv8jYWlRZzFSos2i8eW2pZ8ywWWTZb3rJhWPlZ5VvVW16xJ1lzrLOtt1ldsUBtXmwybOpvLtqitm63Edptt3xTiFI8p0in1U27aMez87ArsmuwG7Tn2YfYl9m32zx3MHBId1jt0O3xydHXMdmxwvOuk4TTDqcSpw+lXZxtnoXOd8zUXpkuQyxKXdpcXU22niqdun3rLleUa7rrStdP1o5u7m9yt2W3U3cw9xX2r+00umxvJXcM970H08PdY4nHM452nm6fC85DnL152Xlle+70eT7OcJp7WMG3I28Rb4L3Le2A6Pj1l+s7pAz7GPgKfep+Hvqa+It89viN+1n6Zfgf8nvs7+sv9j/i/4XnyFvFOBWABwQHlAb2BGoGzA2sDHwSZBKUHNQWNBbsGLww+FUIMCQ1ZH3KTb8AX8hv5YzPcZyya0RXKCJ0VWhv6MMwmTB7WEY6GzwjfEH5vpvlM6cy2CIjgR2yIuB9pGZkX+X0UKSoyqi7qUbRTdHF09yzWrORZ+2e9jvGPqYy5O9tqtnJ2Z6xqbFJsY+ybuIC4qriBeIf4RfGXEnQTJAntieTE2MQ9ieNzAudsmjOc5JpUlnRjruXcorkX5unOy553PFk1WZB8OIWYEpeyP+WDIEJQLxhP5aduTR0T8oSbhU9FvqKNolGxt7hKPJLmnVaV9jjdO31D+miGT0Z1xjMJT1IreZEZkrkj801WRNberM/ZcdktOZSclJyjUg1plrQr1zC3KLdPZisrkw3keeZtyhuTh8r35CP5c/PbFWyFTNGjtFKuUA4WTC+oK3hbGFt4uEi9SFrUM99m/ur5IwuCFny9kLBQuLCz2Lh4WfHgIr9FuxYji1MXdy4xXVK6ZHhp8NJ9y2jLspb9UOJYUlXyannc8o5Sg9KlpUMrglc0lamUycturvRauWMVYZVkVe9ql9VbVn8qF5VfrHCsqK74sEa45uJXTl/VfPV5bdra3kq3yu3rSOuk626s91m/r0q9akHV0IbwDa0b8Y3lG19tSt50oXpq9Y7NtM3KzQM1YTXtW8y2rNvyoTaj9nqdf13LVv2tq7e+2Sba1r/dd3vzDoMdFTve75TsvLUreFdrvUV99W7S7oLdjxpiG7q/5n7duEd3T8Wej3ulewf2Re/ranRvbNyvv7+yCW1SNo0eSDpw5ZuAb9qb7Zp3tXBaKg7CQeXBJ9+mfHvjUOihzsPcw83fmX+39QjrSHkr0jq/dawto22gPaG97+iMo50dXh1Hvrf/fu8x42N1xzWPV56gnSg98fnkgpPjp2Snnp1OPz3Umdx590z8mWtdUV29Z0PPnj8XdO5Mt1/3yfPe549d8Lxw9CL3Ytslt0utPa49R35w/eFIr1tv62X3y+1XPK509E3rO9Hv03/6asDVc9f41y5dn3m978bsG7duJt0cuCW69fh29u0XdwruTNxdeo94r/y+2v3qB/oP6n+0/rFlwG3g+GDAYM/DWQ/vDgmHnv6U/9OH4dJHzEfVI0YjjY+dHx8bDRq98mTOk+GnsqcTz8p+Vv9563Or59/94vtLz1j82PAL+YvPv655qfNy76uprzrHI8cfvM55PfGm/K3O233vuO+638e9H5ko/ED+UPPR+mPHp9BP9z7nfP78L/eE8/sl0p8zAAAAIGNIUk0AAHolAACAgwAA+f8AAIDpAAB1MAAA6mAAADqYAAAXb5JfxUYAAC7ESURBVHja5Lx5dFRV1rBfgHwYRQQVtB26ZWhtabtfeUGxGxFbUGZF8RMHGkVbRkekVYiKisicVhE0gEwBokgDAhEMMSSQkAECwcxkrlRSqVTqJqnxzs/vj5t7qUyAvr9e37fWV2vtleSm6p6n9t5nn733OVU2RaUaEP5PiqJSbeMXPBTA5/Xhzk9Vnd9vo3HFx21E2LYJX9IRgh6npvyCe9uaqS4K4C3IpXHFx9S99CTuJ8Z0KLVjRlA7ZgTuJ8ZgXxmJL+kIlwAkXBQk6HFq9pWRVA8fSvXwodYgdS892a6EA1UNvouqwXdR99KTeAtyfz2IL+kI1cOHYh9wqwVwKWJqpXbMCOv19gG3Imzb1JF2OgZxfr/NukH4jcNVfyEAE8IU+4BbKet1PfaVke3BtA/i/H6b8aIBt7a4mWmaC0nr55vmqRp8F5V33Mm5LhHtwbQF8SUdsSDCb1I1+K42g1xIWgOYYh9wK+e6RCBs29QxSIWus37aJM51iWjx4so77mwD1d5AHQ1eecedlN9yuyVlva6nrNf14Q7cEmRn4W7u3T2E9ME3UX7L7W1uZg5Weced1s3sA2613ql5LXzQjuRclwjcT4wxTXQeRHC7GLdnHPeensiCVwa3e0PznZk3EbZtwluQa0kofz8NcVNxr++Ce30XnNuv61Bcu7viXt8Fvyu7JYipjfGHxzD+8Bh2j+7fAiZcC+Y0zPDIbCyD6DyV6DyVeDcIQR2C39J4oieNJ3oSOnkVcnZ35Ozu6MVdDHF0N6S4C43OqJYg/0ydzb27hzDx0FjuPT2R+asfa6OVsl7X40s6QoWus/CQk6fWZPHChhxe3lbMCxtyrN9TyxSQSwidvMoC0XK6tRGybPjSRmOuNUKVo4Zxe8YxIu4+Jh4ay/jDY7j39MQWWjnXJYLGFR9Toes8tSaLiavTrIHDxfxfapkCwW8hy9YuhCmhk1fR1FRnaCS1NM4yy8RDYy2tjIkZRXq/HtYsCnqc2sJDTkYsTrU00J6YkEJQR7M/eEGY0MmrcOenqjZA2JmyzTJLuJiOe65LBHUvPUmGR2bE4lQmrk7jqTVZHcrE1WkMWpRIdJ4KnpUXBCHLRl3e16EWIOEaMU00/vAY9na/gsYVH/NdgYe+8w9bMBeSQYsSWXjICcFvL2ga+dhlFwcJ10rjio/ZklprgbSWiavTWvzdd/5hXt5W/OtATC201sq9u4eQ+PVijmSW0nf+YQYtSmTQosR2gUYsTmXQokT6zj9saeRCpmkJ0hxD2gOZeGgsI+Lu45+ps7FXlFmDmDDtSd/5h+k7/zCpZQpa9cwOQciyIR+77LyzFhXlMyZmFOP2jLP8orVWRsTdR2ppHFtSa+k6ZZM1WHvSdcomwyxySceayO4OWTY88TdirygzUkWf18eL2//RQiutYcwYE/Q4tagDOUQ8uo6uUzbRZ3qMJV2nbCLi0XU8tSbrolNXzu6OfOyylgEN4NOkaO5acw/j9ozr0ET37h5imehIZimPL91rAfSZHsOQBfuISS7E7vaTETeX0MmrOoQInbwK+dhlNKWsahni0zPSuGvNPW1M1BrI1NrOwt0WkCn2ijJSS+MYt2ccuQk3oxd36RCi8URPY+HLT1VbgGiSzPsx71laCddMe2Yygf6ZOtuScXvG0XfJn/n8YL+LQnjibyQ34WZ8Xl/bfKSoKL+FVi4EYwKZcu/uIQzaPoExMaPQcrq1ADFX33AI1+6u1OV9HVI6ShU/TYqm75I/dwjTHtDEQ2MZt2ccg7ZPaGGScIDWEBlxc42UoSMQ00StYdoDCgcbtH0Cbx+8p40ZTIBwiFM7RmB3+y+exZvT2YRpDdR6ZoVrw1xRWwN44m/Euf06A6Ki7NLrmnDNmH7TEdSg7RP4/GA/yLK1GdwEKNzSk1M7RlDlqPl1JefOlG2MXTGmXaAxMaMsB/XE34h4tH+7ANlrB7T2iV8OAlDlqOH9mPcsIBPKlF3R16Ad7GwlxoVberYAKCrKv1ghfmkg5sPldLIzZVsLqLErxpC9doAlp3aMICNurlGyVpRdSAu/HqS1Q58rd1JUlI87P1UtKsrHXlGG3e1HCOoov+x2wiX3RxT+o49L1IgutXxVUCfDIxNfLraQDI+M3e3/NdCXbhohqBNfLrIsVzZqmoT6dmXG0SBLTrmJLxd/CVRLECXcDGFaSC1TmHE0yKg4B0P2uxiy38WoOAePHaptAfHYoVqG7HcxcGc5o+IcfFfgsbQUPoYoSa213BbE78oGucTSwpJTbobFFjNgbQHdvi6g8/Z6Om+vZ8h+VxsQE7T/97UMWFvA+Og0UvIryfDIZBQ4CeXvt8a5IAhAY/RImlJWUaHrPHaolhuXFXHN+8e58qNcbomq5P6t3xG973WePLzPgnnsUG0LiP7f1zJwZzk3LisyctfSOFxOJ4lfLzYToQubxu/KpmpWBFWzInguOokrP8ql7/zDRMxLpFfUabasHwlZNnITbmbgznI6b6+3Bu7/fa2lrW5fF9Ar6jQD1hYwLLaYx5fupdi+EiGok748koa4qa010xKkKWUV2UM7kd6vB7tH9yfpnUFkLzQiZOGWnmgHO9N4oie9ok5bA4YPbkqvqNNc8/5xIuYl8tSaLOLLRXambENXF+PxNJD0ziAanVHhYaEliH1lJD/1iqD0qSsIzu2M/N550TZ3QjvYmS3rR1qDtwdhgpgwnabGMj46zRjQsxJdXYw7P1X1pY0GuaRjkMKxPah5qxuV8y6nct7l1LzVDfdyo6miHexM+ou9mblwKfdv/Y77t37HNe8fbwMQDhIxL5FOU2PZklqLJjUYdU7wWxBuN+ricBAF0KQG6pcNovZpw0fCQao/MEBcu7tSOLYHjnu7EZzbmeDczqyfNokrP8ptMXi4XDnzAJ0n72TIgn1oUoMB4VlpgIjj24I0payi9KkrqHj+Ssth2wM5c38f8p68D2nbHKRtc3h86d42A/eZHsOVMw9Y0nXKJmxDvyS1NA70z8Gz0qh5hNvbzpr6ZYMofzyiBUwLkOVdjfR/eVcao0dSl/d1aHx0GhHzEi0TXDnzAJ2mxtJpaixdp2yypM/0GLrcs5D3Y94ztNDsK7qjuxmzDBBz2rYGqZoVQc1b3dr4yfppk+g8eWeLd91aAxGPrqPbyKV0G7mUiEfXMWdz+nmQ0Jsgn1AbT/SkMXrkeZC6vK9DpU9d0S5I5bzLqf6gq6UV7WBn5q9+zDJBuEQ8us4SE6LLPQvpcs9CjmSW4ndlo1XPNBxWLiE34WbSX+wNapEBEsrfT/njERSO7WGBmDA1b3Wj9KkrSO/Xg1WjBjJl/CT+8sQ8a0BT/eGDhwN0uWchXe94ia07YkE+oSLc3gxyQt2yfiSrRg0E+YRqgRSO7UHh2B4UT7ragqmcdznFk67mp14ROO7txpTxk7AN/bLFgN1GLsU29EvrejiACdG59xQjKgu3GzVP9UwIvcmCVwYb102NmBHVBDFNVDUrgjP39yF98E0E5xox5Dcj5lsDhwOYQObg4dK59xR2RV8D4njEo/0NIEd3dkVfgy9t9HkfMTWSO6pXG63kjupF8aSrqXj+SoJzO1M573KmjJ/Eb0bM5y9PzGPBK4Mp3GKUEFvWj+Q3I+a3AOjcewp/eWKesUQ0T1mz2att7oSU9+F5EE2SqXvpSbKHdrIGNmHCoapmRVgh33LezZ3QNncyloGDnVnwyuA2IFvWj0Q+dplREzu6Wy0r9/KubVvg9pWRpPfrwZn7+1haMSHCxdSM/J4RWWufjiC9Xw/m9PgtN9w0uo1JbrhpNI0njAXTrAIbT/TEvb4LjdEj2641vqQjpPfrQfrgm1qYKHxKlz51BbmjerFj4G2WtAYwtWDKglcGG2ZoXrldu43AWDUrAmnbnLaRVZMayHvyPn7qZThoa38pfeoKap+OIDi3M6tGDeSGm0a3GTT82g03jeaGm0bj3H4d8rHLrN0I93LDpDsG3kb68si2a425hfZTrwjSB9/UBiZcM+YM6ghoyvhJpL/Ym+yFhknc67tYQVF+z3gjc3r8Fuf32zpOFTMeHXpRGDNfMYF2j+7PqlEDWTVqIOkv9rZ8SNvcCff6LlTOu9yK1Okv9mZOj9+S8ehQNKmBDhs17vxU9adeES1gwoHKH49oFyhcwhfKynmXWzOu4vkryR7aieyhnQjl7+84QzNNJGzbxN7uV1gw7WmntYZaLw2mmNdrn44ge2gnztzfx9od7zBnDa9t0pdHtgsTDhRustaaCndwEyLj0aG481PVS9r3FSUJj6eBrConMZHvnodpntrh2gkHCgcLl/TBN7G3+xXGLMlIo0LXjU7ixeoaUZIQ3C7OlTtJya8kJvJddgy8DctvWgGFaylcHPd2Y2/3K5jT47esGjWQrTtiyapy4nI6jUrvUmpfUytFRfmkZ6SxdUcs66dNYsfA2ywNtQBrJeb/dgy8jZjId/kx4YgF4fP6Ln1L3uyhhWvnSGYpOw6lEBP5LuunTWLDAw+x4YGHrAi74YGHWD9tEuunTSIm8l227ohtAyBK0i8/pNDagTVJxuf1YXf7OVfuJKvKMF16RhrpGWkcySwlJb+SrCqn1awRgjqaJP9nO0b/Zxo1v+ahS0ZqKJ9QCX5rJMyhN42aRj6h/udB5BKjiAp+i64uNrJ2M0Vs3rUiy4aU92G42X49iCYZDZjUMoX4ctFIcILfGgVU6E0LwEyCxKP98aWNxpc2GvFof+RjlyHlfdjxWnOxh93tJya5kIWHnDx2qJbnopP4NCmaYvtKC0LL6WYkQps70RA3laaUVbjzU1V7RRn2ijK8BbkWUJsM7VIAog7k8MyuPKtD1AJA/9zQQpYN9/oubFk/kpkLl7J4a0KbtrdZa/vSRrfMWS8GcSSzlGd25TH5VIjptTpR9T5SS+OMsrHZD3RHd7SDnTm1YwSzY2KsTtL46DSei07iSGZpm/tKeR8a5gnf0+vI8zfE5zAstpjptTrvifBJeeZ5LTQDkGXDtbsr0fte59mjDmaWaUyv1ZlZpvH3XJlRcQ6Grj5OTHJhy/t7VhrpwMVAog7kMCrOwcs+nZWaccak2L7S0oLpC6d2jGDJiUyWN8E6FVZqsLwJ5ruwYO5O9jFoUSIb4nPOT+/gtxf3kZjkQobFFreAaHRGGZoQbm+hhWd25fHsUQevHilgbo7bAmoNM2S/i6Grj3Mks9Tolcgn1Hb39MzHuXInw9edZrJd4z3xPISuLrYgCrf0ZOuOWKLzVFLLFDIKmlfr5EJmHMxhfoWvDczkUyELxl5RduFUUZNkIvdm8+BpkZd9eocQPyYc6XDnocpRQ+TebObmuFmptdTK5FMhBqwt4K1vMi4cWTMKnIyKczDZrvFJeWaHEBdrbVc5aphxMIflTR1rJaPA2TFI1IEc7k72tZwdYRCLtyZc6h4MMcmF7WrlwRSRAWsLiNyb3T6Iz+vjmV15jIpztIHwxN/I7JgY4svFS47CHk9DG62Y5hm4s5zx0Wntb0CnlikMiy3m06ToFpFSO9iZnSnbeGZXHkcyS8kocF6SHMksZc7m9AuaJyW/si3IltRaZsfEGNM09KZVs2bEzWV5EyzLlXn1SEG7MuNgTruy5JS73dlzd7IvPMi1BIlJLmRnyjbLJFawar7ZHi5NdrSS9jRyd7KPXlGnzQDXyjSlcYY2mk1SuKUnS05kslI7f9M9/HKgdaoh74nn/cR02NV7M9t2A9A/t/qf2uZOvB/zHvNdxk3Mm0bV+36VzK8wxHTWVutPmEbkE6q1hjQ3/yefCvGeeB7k1SPGlLsUeeubDOtnezJnczpvfZPBuXJnGEjzAqSri9FyulG4pSf3b/3OCvErNQNmxsEczpU70ST5kuWXJc9yiZXemQ3du5N9TK/VedmnW1qZm+M+v3r+gpTS42nA42nA5XRa4vE0hFd8zSDBb63cInvtAAYtSuTuZB+T7ZoFYy7tz+zK6+igQZtHRoGTyL3ZLab4M7vyGB+dxpAF+1i8NaEliLmWyNndsa+MZPi60/T/vpaJhTKT7ZqllZWaoZW3vsnA42m4IMS5cifPRScxN8fNeyK87NOZXqszsdDITa55/3i4dgVb0OPUTG2IR/vjzk9Vt6Qau5R3J/uYWCi3MJEJM2dzOkcyS80Q3WKrPia50IIIX2cmnwrxYIpIr6jTPBed1Mo0apFgpv0NcVMR3C5ESWLO5nS6fV3Ag6fFdmHmV/iYcTCHyL3ZRB3IsSRybzbP7MpjfoWvXYj+39cyZME+c7aEgTQ36smy0RA31dostrv9DF193IIJ9xcTxgSam+O2xAQwg9fMMo2JhTIPnjYgBi1KbC+RPq8REyR8iT9X7rRgWptpvssYLBwqHGB6rc7fc2ULYsh+F4MWJbLjUErH09c8ytcaxNTMCxtyGLC2oIUDT6/VO5TJdkMLJsTAneUMWpTYNotvE0eaj3rKxy6zun2t69mdKdt4fOley4lN35ls11pIOIC51D8XnWQu9xcGUQCteibyscuM5n31TKNqD5fm1H9DfA7PRScxdPVxhsUWMyy22Dq4MGS/i2GxxQxfd9oC2HEopb1WVcdtCU2Sqcv7OmTWpGbRLOV9SCh/P0GPUwvPvDIKnMQkFxK5N5s5m9N5LjqJ56KTeOubDFbvzSQlv7LN1P5FxzZ8Xp918v8SWk5WsWStLbr0a5oLHRdY/+GjPP8vtq7+0yCiJOHz+hDcLlxOJ2bzxeV0Irhdlk/9x0B8Xh9VjhoEt6s5rZTaFU1qQHC7qHLU/PpZ05EGqhw1uJxO0CVESSIlv5KoAznM2ZxufTJgzuZ0og7kkJJfaR1mcjmdVDlqflkc6ahSs1eUWdMzJrmQQYsSrYMJNy4raiHmYQWzD2IC2SvKLpa/dAzi8/qsc6cZBU6GLNjHlTMPcEtUJVMSdd45qRGdp7KxDOvDPu+c1JhxNMgtUZVcOfMAQxbss0K7vaLsQqbq+GCtCbEhPodOU2O58qNcZhwNsrMK4t0Xlp1VMONokCs/yqXT1FgrE7sATPvbJK0hblxWxDsnNWugvc7zcqFry3JlbomqbANzSdskpk9kFDjpOmWTpQnzne6sMgbbWWWYY8kpN0tOuYnOU1v8z9TcOyc1blxWRNcpmwwz6dLFjxr7vD5rY+eO13YSMS+Rh/co1iAby4wBluXKLDnl5rsCD1lVxk7FdwUelpxysyxXbvHcjWUwYb9CxLxE7nhtp7X10spELUHMMiHqQA6dJ+9k8KYaJh1u6ZRLTrnZklrb+hS3lURtSa1lySm39fyNZTAlUWfwpho6T95p1rqtS5LzICapJsmWNkbEBpiSqLMs1/gY3DsntfAuT4tDlkrYtci92bxzUmNjmaG9KYk6I2IDbbTStsBqjhma1EBKfiVdp2xiwNoCHt6jMOmwxjsnNev46KWUkaIksfCQk2W5Mu+c1Jh0WGPCfoUBawvoOmWT1d4Miy3nQczIuXpvJp2mxjJ4Uw0T9hsg09KM6fhcdBIxyYWXJM9FJzHjaJBpaTDpsAEzeFMNnabGGhVec+RtA1LlqAFd4vGley0Q8wZTEnWmpWGdWX3sUC3PHnW0K+b/n0qoZ1oaTEszfCQc5PGle0GXwv0k7PxI87S9EMjMMo35rvMdILPDbErrzlA4iOmw4SBh0/iXgUxLg8mnQvw9V2Zmmdau/D1XtpoxpiYe3qPw8B6FW6IqreOCvwpkWhqMinMwaFEi46PTfrFMXG38HLr6OHe8ttPykXZNYzrr4q0JdJoay4C1BS2cdfCmGuZsTrd6Hv/T5ozZJ7no9L1xWZE1fU0bD193unXx3GESFZNcyIb4nDazaUN8Dh6PkTy1O307CmgT9itM2K9YWnkuOumi26wTV6dZR43NXOXKj3LpPHknEY+us0DaDWiWnwCr92bSdcomBm+q4eE9ShsThTXh2jRn5mxOZ/CmmjYzZkRsgE5TY40Q33bhu/iiF66VcJjh604TuTfbUnnk3myGrzttQZgzZtJhzQrvfabHWGNccNELnz2tfSUcJjxADVhbwIC1BdYsMyOp+fyH9yhWGnAks/TS0gDTV4qK8q2NxU5TY7klqrIFTDhQ6+gZ/hwzdoSbpKgo/9LPj5hnR8yUwEwVw810MRkRG7BSRXPpLyrKv/RUsT2YI5mlLZLnEbEBK1q2lhGxASt5vuO1nZY5ioryL5TJX7icENwuioryjV1rr4+oAzkMWbDvouXEkAX7iDqQg8/rQ5MaLgZxaQWWJslWSWkWWBkFzl9UYP2PvgjFPNrj8/osM/2YcIQfE46QnpFmfL7K7SLocWpBj1Mz6+D0jLQWzzPb3b/6aI8SVnCbvXTTVOZxno6kqCjfKlPNUH4pIP9XPGz/N319UFnrf2iKLGi6LmggqCBoIOi6JuiqIqCrgqIrgqyrgoYu6JpiiK4LKgigCpquCCEdQdVVAU0VdP2iMGW29tplmtbcQNQ1QEXXNDQdQGsWHZBbvdQsKkTQfaiaBJrc/PyLPpQ2zqqbL9U10GV0TUbTZUCyQAoaJPaVinx5RmbVKZnVWRpf56r8WKlQFww2Q4bf8VdMXwsEtfkdGb97xSAb8yRG7df4zYYQ3deEsK2WsK1UsK1U6LIqxJWfKQzcEODVw0GS7KbG1F8Pout6C7WuL5Dpv1PBtlLEFgWXfyHTY61Ery91rvkiwLWfB7h6jcxV/5LoskLF9gl0+tjLI7FesuuxzKnrHeqneQdL143Bjacj6wqg4ZFUph8JYvusCdsXIldvhGvXi/T+SuS6dQrXrZO4fp3Ib76UuH5NiD6fi1z/mcgNnwa5epWMbbHG1StEvsoSjbeoq2i60h6MYNN1XTAhNF1vdlBoVFSG7/Nh+1Ti2o1Brl8v03uDyDVfN3DDVz5u+FKh15cKvdbp9FoHvT5X6PW5wjVr4LrPda6NkugTJdL1EwXbIpkVx5sdGaXZ8S9gGgNIJ6ipPHgghO3TED23h+ixTafXZpmb1ofos0ml+9dw1VcaV3wapMvKIF1WSVz+qULPzxV6faZw9Wc613yq0Xt1iN9Ehei+WMG2QObz03JHDtxsGk07P2XRmZ/hx7ZG5rqtMjdubqTHFonrNov8doPMZRvA9pmPqz8X+MNWhb/tkrg/VuGWaJXLPmmk85Imen6m0+sz6BMlcsNqP9etVujysU63jwIcrwy1N6UFm6Zrgma4KKBxrE7lyq999PnaT58dcMNWjV5bFa7d6sP2lcj/+szP6/FNHK2SqQtpSKqIKItUN2psyJH52yYXtkV+uq9UuP5fMj1XqVy9WuWGFSE6LQgxbHMQv6kVXW92B12wKZouSEjGNNMVJvwgYdugcGOsym+2q/TZqnD9dh3bVz5u3h4guVJtnpJa808zkJlBMMS7SQG6vB/gimUKvVdK9Fmu0nu5zLXLZGzvaWzLDhggmoysqwYIKoKqG+rKqVO5douP62JUfvutxg2xCn1iZTpv0rgpRuF0XQAIgRJElSUURUWWZWRZRpFlgrIKeIEg7yaC7X2FXkslei+XDVkmY1sQ4pFNDaA3hwcdNF0XbGjNZwNQWXZaxrZV5XexMjftFLnpW4ne34rYNvjZUywBQUJqEEkMoEk6oqIgySqipCCKEt6Qis8fRNEaAB+TtijYInV6Lwtx7VKRPstkIj5S6PGBRGFtwFCgApquCDYFTQANXZeZkiARsVPnlu9kfhcr0/cbiYivA4w94DM0oet4VQVJUQiJGiFRIiTKBEMSAX+QhoBIvU/C1SQCfpIKGrl8kZerFitcu0Tkuk9ErlsiYXtDYuMpYyobE0gVbIouC6DiDsgMiwtx406Z/rs0+u6WGPCNSI8tIZbnSoCCEvITkBRkWSMUkAgEJbz+EE2+IA3eAPUNjTR6fNTWSni9PuoFN/d8KtBpkcg1n3jp82GQ3h/6sc33seAHb/P6pYOmCTY0VQCNEkHhrgMhfrdL5k/fafT/XqT/boU+sRI/2r0AhESFYFDCF1TwBSWa/CE8TQHcjQFcDX6cdQGq63w43PWU1AoEmup4emMjtvl+enzop/d7Aa57N4Btvo/Z37jCHBzBpuqaAHDOHWDo/iD99in8+XuZO/er/H6fxsB/h0irDgGqoYGAhOAL0eALUd/oo87TRK2nCUddI3anQKXTTUl1DUVVNXga6nh2mwvb6066L3Bz3btOekU2YXtd5MVNDmuVVtEFm6brAmiUu4OMPODnjv0idx+UGHpQ4q6DEnf928+h0iCg0egN0OgXqW8MUCd4cXm81LgbqHIJlDs9lFd5KK90U1hWQ3GlgLOqlrs/rsQ2q45rFjq57q0yukc6sL3iYc62akBDR0fRNcGmq5oAQYSAyuQEibsPhnjgkMYD8T4ePOTnv/ZrfJrtBTWE4A3ibvRTJ3hx1jdRXddApbOeMoebEruL3Ao3p8vqOVVSR1JuDZkFtbywvgDb0zl0eqmanm+Wct2bFdhmlvP2Po/hH6qIrmiCTdNUAVVElTVeyfTz10My435UGHNE5JGfJIYf1ZiV4kFo8uILBKirD+LwBHC43Dhq6ymurqfAUU9ORS05RSU0NHmQVRW/JCMqOho6354U6DEri04z8+nxWim2fxSx8ZgLEAlJCqoiCzZZUwVZVECDjUVNDD8s8sRRlSmJOs8mwbPHZJ466iO2yI8aDNJU56a8tpGqaicOZx2FVfWcLa8lq7CMBn8IHfAGZQKSik/SQAoBOjEZtdiezqTTS/l0fzmPrFIBNB9CUCcoSYJN0TTBKymgS5TXBXn8pwCTj8lMT1WZmarx+nGR2Rk680+GOFleh9/bgMtZR3V1HYWVLvJKajiTV0pVjRsV8IVEgrLaLApeERSCAAx5/xS2+48zZvlZAmKIQFMTHq+PppAi2DRdFQIyyKIfRImoMz6ePO7lpUyJl08r/PN0iMjTEh9kS6zNEUgp92GvaaDAXstZh4DLG0JoChAMyviDMn5Jxi/K+EISIVnFr0h4JWPZ33a8mNteSCI6vhpZbMDhaqChyYfHHxRsmhYURBECoRDoMvkukVfTFN7IlHk7W+aDXIlVOSHW5ob4qhi2F4v8WNLIiSov5wLgkVVERSUYMqa2LyTjF1UCkkpQ1vGLImJAxCsai2SdKFJQ6aG0ooqK+gBuVxOCTxBsuq4IkqQSFCVCkgyqzg8lXt5J9/H+WViVJ7G+KMSOEoVdJSp77DJxdRrH3Rq5goLDJyMERRqCIt6QbPiHqBAQFSRJJSCrhGSZJklDUs/nIefsNRRXe3DWefE0NjUf21BURFEiGDRWVH9I5Nu8Rt7Pk/lXocbWIpFvKzT2VSr8YJdIcEqk1Svke2TsPhV3SMYTEmkISngDCr6QTFBSCUkqQUnFL2kEJUNLflFF1aGuyUepow6HuxG34DdyVkVRkCQFUVLxBWR0ScEfFPmuuIG1hTIxpSr/rpA46FBIqJHJdGmcqVPJa1Co9MrUBiTcQQlPQKYhoNAUUvCJCn5JJSApBCTZEr8oEVJU/IpKiaOOmnov9Q1+QyOqqiErGqKiIYk6/mAATQ4QalRItPvZU+EnvkrmxxqJRJdIVp1KTr1GQaNChVei2idTE9BwBRTqAzKeoEyjKNMkKvglhaCkNAMZogAeX4DS6npcDQE8jYHmM0aajqLqyLJOSNbwSTJev0woEKCxyU9OdZCEkgAJ1UGSBYWsBo3cRihq0qj0KVT5ZBwBjdqQRn1IRhBVGiWVRlklqOiIikZQ1hAV4ytjJE2n0ummqt6LU/AjNAYEm64jaBqoqo6iaEiKhiirBESVhkAQr9eH0ChSUu3nVGkdGY4mUmt8ZLoC5DWoFDUplHpVKnw6VT6ZWn+IuqCEJ6TQEFINzUgSflXFJ8nUe304XALVdQ3UNwaob/TT5A0ZILoO4TCyrBKSZHxBGcEfxNPgpdETwO32U+ZoIKesnrPlHrLtbn6urCfPXk+B3U2R3cO5qgbOVTVQUilwrkKgtEqguLKe4sp6yhwNlNg9VLkEhKYgjd4QTX6RYFA+X2Dpuo6maaiqiqqqKIqGKKn4QwrekERjIIC70YenMUBjk0S9EKK23our3ovb48Xj8SI0BfD4ROq9IdyNQeoa/Lg8AZxuPzV1PuobRASfguAN0egP4Q1KBEMykqwKNkAxMnpDNM1oSxhQGrKiI6oqTapIkyTiDYUIiDLBkEwoICOGjHghKxqKqqCoEooqEVJFgkqIkBIiKIsEpBB+MYA/FMAXkgiICiHRmK2KoilWo6bZRIKu61bjRdd1QdEQVBVBkzRBlVRBFhVBVTRBUXRBknVB1hAUECQQNF0XUHVB13RB0XRBVDRBUjRBUTVBUlRBlBRBlGQhJGuCJOuCouiCpuqCqqpl/7Eemqor5HnS2Ja/hPezpvCP1PuYlfo3vvo5EnfA0baH9qs+CKZpBIIh7DUuyuw1lNprqHDU4mnwoqoamq5xyn2YVTkv8cKJO3n+TH+eTB7Ao/H9eSr+TnbmrfyfgdiddZzKKaK0yklhuYN6oWVfvabay+6Tu3gzaSJPpPZm9E9XMmnvH1n60wKSanZypuEg35WuZlrCMLb9vPSXgzicdWTkFLX7vya5Dq/spk62s8v1AW+cu53ns29kSd6z/Fi9mZ/L8tpqVFfZeHYxBe7MSwdJy85v8Xd1oJwDFRtZlTeTD88+wcKsMSzMGsv8rL8wNbMnc7LuJN6xg6AcsF6TW1xBkzfQct9P8pDrSkfT1QuDKKrKz8UV1t+V3kKi89/m1YyhvHlyMPOz/ouFZ4fwYe59fJAzjLfO3s66wuep8p7jbF0iUTkzOe76/rzZ6jxUVteGtch06gL2C4PIikJFtcv6e3/ZeuamDOHNU//NivwxfFY8jnXlE/iyYiKflz/Eh4WD2Gv/CL/YQIJjI2+dvJvXTt7FtJS+LPt5OvVBY383KEoUlFaGzSz5wqb5ubC0WSsyG3PfZUbKnXzw8wOsKX6EdWUT+NI+nq8cY1nrGMnikjuJd0Xhld1sr3iTt37+IyuLHmZN0WMszxnPzLSBvJnxMMWNPxv7vUITLrdw8VlzMswnNud+xD+O3cGy3LF8ce5R1pZN4IuKsXzlGM0X1SP4uPJ2jgpraJAcfFb+CJHnbuOz8pF8UT6OL0om8nnRJFblPcrLaXfxxolROHzGd2idq7xIHBEavTQFQwAcLNvMP5Lu5JOcsawpmsRnJROIKnuYtVWjWVP9Vz6q7McRz0pUTSa2Zh6LSgeytOJPfGa/j3UVY1lTMoFPz01kdcEjLM95hNmp/8UHmU+j6MYnlrJyz3UMknHW0IbDW8rLyfexIGs4nxU8zqqi8Xx07gGiKkfyheN+ltnvJEFYGdYOFWlUqjniWcGK8iFElQ1jTek4Pi2awOqCR1iZ9wgfnx3Hs4l9+aHc+BqH2voGRFFqC+JpaEKSjOR2Y84iZqX8majcx1ieN57Xc+/hvXPD+aziAZaX30VGY0yH0/1s00E+KR7KquL7+ezceFbnT2BFzkSW5Uzg7VP38UbKQ3hCdc1aKWoLktHsG06/nbnJ9/H+6VGsyJnIC9l38kreMNaUPsKSkkHsdy26aABMcK3lw4L/5l9FY1mdP56lOeP55Ox4Psh+mOeT7+BAyUZj17O8qiWIKMkUlNoBOFQaw4zkQSw+M5bZp+7in7mPsKnkFVade4DPSsfTJNVeFCSk+lhbPIVl+Q+wMnccS8+OY/GZsXxwZjTTj9/OkqwXACi3O/H5A+dBKhy1lFQac33t2bf5R/KdvJnxFxadnkSyYzuf5j3BssIR/Kt4DBvLp/NF2dOsqXiSNRVPsKbyCeNnxZN8XjaFz4ufJrr4Bf5V8Agr8h5iWc5YPs4ey4enR/P+6YeYnfZn3kh9CAUfqgz2Gtd5kLOFpZTYjUMHH516jmlJA3jjxHCO2XexteBtFpwZyqqC0awo+huLCv7Eu4W38V7x73mvtD/vl/Xl/bJ+vFfye94tuo2F+X/g3dw/szT/b6zIHcMnZ0fz0ZmHWXT6ISKzRvJq5mBeSh5MSeNZyzyyrBggWTlFlNsNssiMKYz9oQe7i/9FmmM/r6bezZKfx7Is5yGW5f+NFYUjWHXuflaXDmN12V+JKhtGVNkwVpX9lZXFw1lRNILl+Q/ySc6DfHRmFIuyRhF5ciRvZ/6NNzPvZ3baIJ5N+AM/1xsfXcg9V47XH2wLMidpFE/9eAcVQg7Lsp7j9fShfHTmIT4+M4rIrKG8ljGAeSf78eaZfszP7sc/z/bln9n9mH+mH29m9eO1jP7MPfF7ZibfxvSE3zP1UD+eiruVxw/cxIT9fRj+764Mje3M6bqjAOQVl+MPhgyQvHPllFQapnkhfgRf5y7haNV3PJvwe945+QDvnnyAf2bcQ0zR22S7fySzbj+Z7n2cdO/jZP1eTtbvI9O9j8y6fWS49pHm3Edq9T6OV+0luXIPRyt2k1C+i/jybzhYupUfSrfjV40wX1zhQNN0A8RR66bEbjjr5p+Xc9IRz9snJvJ88h94O/N+3s64j1dS7mJLXuT/v0e/vT6qa93nnVXXdXLOlRtJi6qSWLmL8Yd682rGvcxLG8qbJ4byRuoQXj56L+UNuRcdoDHk5kDJNvaXbuZA2Rb2l21hX9nX7C3byNaCKJKr4pqnbw3+QLBlQDttxn4dPsh4hseP3sjcjP/m5dRBvJYymNdTBjMtvh8rT865KMja0wsZvqsr4/f3ZNyBnjx88CpGxV3BiAM2bt5iY8PPKwz/KKlsG1lDooTgCRJAYPKR/jyb2pcZaQOZdfyPzDn+J145/l/MSfojU364lW05yzuE2F30FU/80JcZSQN5+fifmH38Tmam3MGM1Dt4LOE6pv90DyHFCGLZ+SXtL3pn88rJCR5hbPy1TEq6jqnJv2XGsduZdfwPzD52By8n/5FZSX9g8sGbeDflGU7VHMUTqKMhVM/Z2hMsSZ/JY3G38I/E25l77I/MOv4HZhy/nRkptzE1+Rbu+beNhMrvjLEKSi+cj0T+8AaPZfTi2eQ/8Gj89fz96C3MSB7AjOTfMzPpNmYn3c7MowN4/IdrmXKoPy8l3MtLP/2Fpw7fxiMHr+HFxH7MTrqNmUm/56XkAbyY3I/pyb/jr/tsRJ542hqnOGydaRdkxv6J/DXBxvflX/Fd0Rru2W3jmYTrmZnUnxlJ/ZhxtB+zjg5g1tH+vJBwM1Pjr+fZ+Ot5PuFmZiX2Y9ZR43kvJfXlpeR+PJ90M3/da2Nm4gME5MZ2c5F2QV5OeYA/7rZxrOYgANE/f8S933ViTFxXZiX1ZfbRvsxK7MusxFuZnXgrs8JkZuKtzEi8lZlHf8espL48Gd+Lu3fbeDVpLA1BY+kvc7T7ZTktQUQlyLQjg/nzv20cyo+zrsdX7OKR/bcybLeNp368hpd+uok5ib9lbuKtzfI75ib+jtmJv2PGT7fwfMJveOj7zty/O4JPs+YjKsYUdTc04Wloav/YRusLz/04lAeTIsgsPENewfnc0is1EH32Qx47MICH913F+O//F+O/t/H4wW7877gIHtnfhXHfd2Hs91cyZl9v3k19lgLPaev15TV1NDR6Oz4/0vrC26ceYVhcL45X/GB4d2Eljf7Q+cJI9pHqiGPVqVeZd+wRZicOZ0bCvbyS9DAfpD3PnnNfUuO3ny9NVI2T+eVI8oVPGrUB2ZsfzX1HehJTtMK6FgyJZOYW0+gXf1EIz8wro9LhvKTn2lrugkMoFOS5n/7C0APXYK8tb3GepMrh5HB8Cmknz5JbXEpBSQVlFbVU2N0UlVWRW1RK1s95/JCQzMkzPyPLMpqm4ff7CQQChEIhJElCURQ0TcPsVOm6fn6tCT+oUOkq4bGE27n/qzv4KeMIwVCQQCBAbV0ttXW1VFRWkJ19lrS0DJKSj5F4NInk5OOcPHmK/Px8amtrcbvd1NTU4HQ6cbvdNDU1WTCyLKOqaguYDmvfgNzE4bIYdpWv4UT5EezuMkQl9B877PT/DQC7cLwx8LR3hQAAAABJRU5ErkJggg==) no-repeat;padding-left:40px}
+        .browser .browser-firefox{background-position:0 -34px}
+        .browser .browser-ie{background-position:0 -68px;margin-left:0px}
+        .browser .browser-360{background-position:0 -170px;margin-left: -27px}
+    </style>
+</head>
+<body style="margin-top:50px">
+<h1>璇峰崌绾ф偍鐨勬祻瑙堝櫒锛屼互渚挎垜浠洿濂界殑涓烘偍鎻愪緵鏈嶅姟锛�</h1>
+<p>鎮ㄦ鍦ㄤ娇鐢� Internet Explorer 鐨勬棭鏈熺増鏈紙IE11浠ヤ笅鐗堟湰鎴栦娇鐢ㄨ鍐呮牳鐨勬祻瑙堝櫒锛夈�傝繖鎰忓懗鐫�鍦ㄥ崌绾ф祻瑙堝櫒鍓嶏紝鎮ㄥ皢鏃犳硶璁块棶姝ょ綉绔欍��</p>
+<hr>
+<h2>璇锋敞鎰忥細寰蒋鍏徃瀵筗indows XP 鍙� Internet Explorer 鏃╂湡鐗堟湰鐨勬敮鎸佸凡缁忕粨鏉�</h2>
+<p>鑷� 2016 骞� 1 鏈� 12 鏃ヨ捣锛孧icrosoft 涓嶅啀涓� IE 11 浠ヤ笅鐗堟湰鎻愪緵鐩稿簲鏀寔鍜屾洿鏂般�傛病鏈夊叧閿殑娴忚鍣ㄥ畨鍏ㄦ洿鏂帮紝鎮ㄧ殑鐢佃剳鍙兘鏄撳彈鏈夊鐥呮瘨銆侀棿璋嶈蒋浠跺拰鍏朵粬鎭舵剰杞欢鐨勬敾鍑伙紝瀹冧滑鍙互绐冨彇鎴栨崯瀹虫偍鐨勪笟鍔℃暟鎹拰淇℃伅銆傝鍙傞槄 <a href="https://www.microsoft.com/zh-cn/WindowsForBusiness/End-of-IE-support">寰蒋瀵� Internet Explorer 鏃╂湡鐗堟湰鐨勬敮鎸佸皢浜� 2016 骞� 1 鏈� 12 鏃ョ粨鏉熺殑璇存槑</a> 銆�</p>
+<hr>
+<h2>鎮ㄥ彲浠ラ�夋嫨鏇村厛杩涚殑娴忚鍣�</h2>
+<p>鎺ㄨ崘浣跨敤浠ヤ笅娴忚鍣ㄧ殑鏈�鏂扮増鏈�傚鏋滄偍鐨勭數鑴戝凡鏈変互涓嬫祻瑙堝櫒鐨勬渶鏂扮増鏈垯鐩存帴浣跨敤璇ユ祻瑙堝櫒璁块棶鍗冲彲銆�</p>
+<ul class="browser">
+    <li class="browser-chrome"><a href="https://www.google.cn/chrome/browser/desktop/index.html?hl=zh-CN&standalone=1"> 璋锋瓕娴忚鍣�<span>Google Chrome</span></a></li>
+    <li class="browser-firefox"><a href="https://www.mozilla.org/zh-CN/firefox/new/"> 鐏嫄娴忚鍣�<span>Mozilla Firefox</span></a></li>
+    <li class="browser-ie"><a href="https://windows.microsoft.com/zh-cn/internet-explorer/download-ie"> IE 11 娴忚鍣�<span>Internet Explorer</span></a></li>
+    <li class="browser-360"><a href="http://se.360.cn/"> 360瀹夊叏娴忚鍣�<span>360 Chrome</span></a></li>
+    <div class="clean"></div>
+</ul>
+<hr>
+</body>
+</html>
\ No newline at end of file
diff --git a/ruoyi-ui/public/index.html b/ruoyi-ui/public/index.html
new file mode 100644
index 0000000..925455c
--- /dev/null
+++ b/ruoyi-ui/public/index.html
@@ -0,0 +1,208 @@
+<!DOCTYPE html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
+    <meta name="renderer" content="webkit">
+    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
+    <link rel="icon" href="<%= BASE_URL %>favicon.ico">
+    <title><%= webpackConfig.name %></title>
+    <!--[if lt IE 11]><script>window.location.href='/html/ie.html';</script><![endif]-->
+	  <style>
+    html,
+    body,
+    #app {
+      height: 100%;
+      margin: 0px;
+      padding: 0px;
+    }
+    .chromeframe {
+      margin: 0.2em 0;
+      background: #ccc;
+      color: #000;
+      padding: 0.2em 0;
+    }
+
+    #loader-wrapper {
+      position: fixed;
+      top: 0;
+      left: 0;
+      width: 100%;
+      height: 100%;
+      z-index: 999999;
+    }
+
+    #loader {
+      display: block;
+      position: relative;
+      left: 50%;
+      top: 50%;
+      width: 150px;
+      height: 150px;
+      margin: -75px 0 0 -75px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 2s linear infinite;
+      -ms-animation: spin 2s linear infinite;
+      -moz-animation: spin 2s linear infinite;
+      -o-animation: spin 2s linear infinite;
+      animation: spin 2s linear infinite;
+      z-index: 1001;
+    }
+
+    #loader:before {
+      content: "";
+      position: absolute;
+      top: 5px;
+      left: 5px;
+      right: 5px;
+      bottom: 5px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -webkit-animation: spin 3s linear infinite;
+      -moz-animation: spin 3s linear infinite;
+      -o-animation: spin 3s linear infinite;
+      -ms-animation: spin 3s linear infinite;
+      animation: spin 3s linear infinite;
+    }
+
+    #loader:after {
+      content: "";
+      position: absolute;
+      top: 15px;
+      left: 15px;
+      right: 15px;
+      bottom: 15px;
+      border-radius: 50%;
+      border: 3px solid transparent;
+      border-top-color: #FFF;
+      -moz-animation: spin 1.5s linear infinite;
+      -o-animation: spin 1.5s linear infinite;
+      -ms-animation: spin 1.5s linear infinite;
+      -webkit-animation: spin 1.5s linear infinite;
+      animation: spin 1.5s linear infinite;
+    }
+
+
+    @-webkit-keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+    @keyframes spin {
+      0% {
+        -webkit-transform: rotate(0deg);
+        -ms-transform: rotate(0deg);
+        transform: rotate(0deg);
+      }
+      100% {
+        -webkit-transform: rotate(360deg);
+        -ms-transform: rotate(360deg);
+        transform: rotate(360deg);
+      }
+    }
+
+
+    #loader-wrapper .loader-section {
+      position: fixed;
+      top: 0;
+      width: 51%;
+      height: 100%;
+      background: #7171C6;
+      z-index: 1000;
+      -webkit-transform: translateX(0);
+      -ms-transform: translateX(0);
+      transform: translateX(0);
+    }
+
+    #loader-wrapper .loader-section.section-left {
+      left: 0;
+    }
+
+    #loader-wrapper .loader-section.section-right {
+      right: 0;
+    }
+
+
+    .loaded #loader-wrapper .loader-section.section-left {
+      -webkit-transform: translateX(-100%);
+      -ms-transform: translateX(-100%);
+      transform: translateX(-100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader-wrapper .loader-section.section-right {
+      -webkit-transform: translateX(100%);
+      -ms-transform: translateX(100%);
+      transform: translateX(100%);
+      -webkit-transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+      transition: all 0.7s 0.3s cubic-bezier(0.645, 0.045, 0.355, 1.000);
+    }
+
+    .loaded #loader {
+      opacity: 0;
+      -webkit-transition: all 0.3s ease-out;
+      transition: all 0.3s ease-out;
+    }
+
+    .loaded #loader-wrapper {
+      visibility: hidden;
+      -webkit-transform: translateY(-100%);
+      -ms-transform: translateY(-100%);
+      transform: translateY(-100%);
+      -webkit-transition: all 0.3s 1s ease-out;
+      transition: all 0.3s 1s ease-out;
+    }
+
+    .no-js #loader-wrapper {
+      display: none;
+    }
+
+    .no-js h1 {
+      color: #222222;
+    }
+
+    #loader-wrapper .load_title {
+      font-family: 'Open Sans';
+      color: #FFF;
+      font-size: 19px;
+      width: 100%;
+      text-align: center;
+      z-index: 9999999999999;
+      position: absolute;
+      top: 60%;
+      opacity: 1;
+      line-height: 30px;
+    }
+
+    #loader-wrapper .load_title span {
+      font-weight: normal;
+      font-style: italic;
+      font-size: 13px;
+      color: #FFF;
+      opacity: 0.5;
+    }
+  </style>
+  </head>
+  <body>
+    <div id="app">
+	    <div id="loader-wrapper">
+		    <div id="loader"></div>
+		    <div class="loader-section section-left"></div>
+		    <div class="loader-section section-right"></div>
+		    <div class="load_title">姝e湪鍔犺浇绯荤粺璧勬簮锛岃鑰愬績绛夊緟</div>
+        </div>
+	</div>
+  </body>
+</html>
diff --git a/ruoyi-ui/public/robots.txt b/ruoyi-ui/public/robots.txt
new file mode 100644
index 0000000..77470cb
--- /dev/null
+++ b/ruoyi-ui/public/robots.txt
@@ -0,0 +1,2 @@
+User-agent: *
+Disallow: /
\ No newline at end of file
diff --git a/ruoyi-ui/public/styles/theme-chalk/index.css b/ruoyi-ui/public/styles/theme-chalk/index.css
new file mode 100644
index 0000000..b78d5a9
--- /dev/null
+++ b/ruoyi-ui/public/styles/theme-chalk/index.css
@@ -0,0 +1 @@
+@charset "UTF-8";[class*=" el-icon-"],[class^=el-icon-]{font-family:element-icons!important;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;vertical-align:baseline;display:inline-block;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-icon-ice-cream-round:before{content:"\e6a0"}.el-icon-ice-cream-square:before{content:"\e6a3"}.el-icon-lollipop:before{content:"\e6a4"}.el-icon-potato-strips:before{content:"\e6a5"}.el-icon-milk-tea:before{content:"\e6a6"}.el-icon-ice-drink:before{content:"\e6a7"}.el-icon-ice-tea:before{content:"\e6a9"}.el-icon-coffee:before{content:"\e6aa"}.el-icon-orange:before{content:"\e6ab"}.el-icon-pear:before{content:"\e6ac"}.el-icon-apple:before{content:"\e6ad"}.el-icon-cherry:before{content:"\e6ae"}.el-icon-watermelon:before{content:"\e6af"}.el-icon-grape:before{content:"\e6b0"}.el-icon-refrigerator:before{content:"\e6b1"}.el-icon-goblet-square-full:before{content:"\e6b2"}.el-icon-goblet-square:before{content:"\e6b3"}.el-icon-goblet-full:before{content:"\e6b4"}.el-icon-goblet:before{content:"\e6b5"}.el-icon-cold-drink:before{content:"\e6b6"}.el-icon-coffee-cup:before{content:"\e6b8"}.el-icon-water-cup:before{content:"\e6b9"}.el-icon-hot-water:before{content:"\e6ba"}.el-icon-ice-cream:before{content:"\e6bb"}.el-icon-dessert:before{content:"\e6bc"}.el-icon-sugar:before{content:"\e6bd"}.el-icon-tableware:before{content:"\e6be"}.el-icon-burger:before{content:"\e6bf"}.el-icon-knife-fork:before{content:"\e6c1"}.el-icon-fork-spoon:before{content:"\e6c2"}.el-icon-chicken:before{content:"\e6c3"}.el-icon-food:before{content:"\e6c4"}.el-icon-dish-1:before{content:"\e6c5"}.el-icon-dish:before{content:"\e6c6"}.el-icon-moon-night:before{content:"\e6ee"}.el-icon-moon:before{content:"\e6f0"}.el-icon-cloudy-and-sunny:before{content:"\e6f1"}.el-icon-partly-cloudy:before{content:"\e6f2"}.el-icon-cloudy:before{content:"\e6f3"}.el-icon-sunny:before{content:"\e6f6"}.el-icon-sunset:before{content:"\e6f7"}.el-icon-sunrise-1:before{content:"\e6f8"}.el-icon-sunrise:before{content:"\e6f9"}.el-icon-heavy-rain:before{content:"\e6fa"}.el-icon-lightning:before{content:"\e6fb"}.el-icon-light-rain:before{content:"\e6fc"}.el-icon-wind-power:before{content:"\e6fd"}.el-icon-baseball:before{content:"\e712"}.el-icon-soccer:before{content:"\e713"}.el-icon-football:before{content:"\e715"}.el-icon-basketball:before{content:"\e716"}.el-icon-ship:before{content:"\e73f"}.el-icon-truck:before{content:"\e740"}.el-icon-bicycle:before{content:"\e741"}.el-icon-mobile-phone:before{content:"\e6d3"}.el-icon-service:before{content:"\e6d4"}.el-icon-key:before{content:"\e6e2"}.el-icon-unlock:before{content:"\e6e4"}.el-icon-lock:before{content:"\e6e5"}.el-icon-watch:before{content:"\e6fe"}.el-icon-watch-1:before{content:"\e6ff"}.el-icon-timer:before{content:"\e702"}.el-icon-alarm-clock:before{content:"\e703"}.el-icon-map-location:before{content:"\e704"}.el-icon-delete-location:before{content:"\e705"}.el-icon-add-location:before{content:"\e706"}.el-icon-location-information:before{content:"\e707"}.el-icon-location-outline:before{content:"\e708"}.el-icon-location:before{content:"\e79e"}.el-icon-place:before{content:"\e709"}.el-icon-discover:before{content:"\e70a"}.el-icon-first-aid-kit:before{content:"\e70b"}.el-icon-trophy-1:before{content:"\e70c"}.el-icon-trophy:before{content:"\e70d"}.el-icon-medal:before{content:"\e70e"}.el-icon-medal-1:before{content:"\e70f"}.el-icon-stopwatch:before{content:"\e710"}.el-icon-mic:before{content:"\e711"}.el-icon-copy-document:before{content:"\e718"}.el-icon-full-screen:before{content:"\e719"}.el-icon-switch-button:before{content:"\e71b"}.el-icon-aim:before{content:"\e71c"}.el-icon-crop:before{content:"\e71d"}.el-icon-odometer:before{content:"\e71e"}.el-icon-time:before{content:"\e71f"}.el-icon-bangzhu:before{content:"\e724"}.el-icon-close-notification:before{content:"\e726"}.el-icon-microphone:before{content:"\e727"}.el-icon-turn-off-microphone:before{content:"\e728"}.el-icon-position:before{content:"\e729"}.el-icon-postcard:before{content:"\e72a"}.el-icon-message:before{content:"\e72b"}.el-icon-chat-line-square:before{content:"\e72d"}.el-icon-chat-dot-square:before{content:"\e72e"}.el-icon-chat-dot-round:before{content:"\e72f"}.el-icon-chat-square:before{content:"\e730"}.el-icon-chat-line-round:before{content:"\e731"}.el-icon-chat-round:before{content:"\e732"}.el-icon-set-up:before{content:"\e733"}.el-icon-turn-off:before{content:"\e734"}.el-icon-open:before{content:"\e735"}.el-icon-connection:before{content:"\e736"}.el-icon-link:before{content:"\e737"}.el-icon-cpu:before{content:"\e738"}.el-icon-thumb:before{content:"\e739"}.el-icon-female:before{content:"\e73a"}.el-icon-male:before{content:"\e73b"}.el-icon-guide:before{content:"\e73c"}.el-icon-news:before{content:"\e73e"}.el-icon-price-tag:before{content:"\e744"}.el-icon-discount:before{content:"\e745"}.el-icon-wallet:before{content:"\e747"}.el-icon-coin:before{content:"\e748"}.el-icon-money:before{content:"\e749"}.el-icon-bank-card:before{content:"\e74a"}.el-icon-box:before{content:"\e74b"}.el-icon-present:before{content:"\e74c"}.el-icon-sell:before{content:"\e6d5"}.el-icon-sold-out:before{content:"\e6d6"}.el-icon-shopping-bag-2:before{content:"\e74d"}.el-icon-shopping-bag-1:before{content:"\e74e"}.el-icon-shopping-cart-2:before{content:"\e74f"}.el-icon-shopping-cart-1:before{content:"\e750"}.el-icon-shopping-cart-full:before{content:"\e751"}.el-icon-smoking:before{content:"\e752"}.el-icon-no-smoking:before{content:"\e753"}.el-icon-house:before{content:"\e754"}.el-icon-table-lamp:before{content:"\e755"}.el-icon-school:before{content:"\e756"}.el-icon-office-building:before{content:"\e757"}.el-icon-toilet-paper:before{content:"\e758"}.el-icon-notebook-2:before{content:"\e759"}.el-icon-notebook-1:before{content:"\e75a"}.el-icon-files:before{content:"\e75b"}.el-icon-collection:before{content:"\e75c"}.el-icon-receiving:before{content:"\e75d"}.el-icon-suitcase-1:before{content:"\e760"}.el-icon-suitcase:before{content:"\e761"}.el-icon-film:before{content:"\e763"}.el-icon-collection-tag:before{content:"\e765"}.el-icon-data-analysis:before{content:"\e766"}.el-icon-pie-chart:before{content:"\e767"}.el-icon-data-board:before{content:"\e768"}.el-icon-data-line:before{content:"\e76d"}.el-icon-reading:before{content:"\e769"}.el-icon-magic-stick:before{content:"\e76a"}.el-icon-coordinate:before{content:"\e76b"}.el-icon-mouse:before{content:"\e76c"}.el-icon-brush:before{content:"\e76e"}.el-icon-headset:before{content:"\e76f"}.el-icon-umbrella:before{content:"\e770"}.el-icon-scissors:before{content:"\e771"}.el-icon-mobile:before{content:"\e773"}.el-icon-attract:before{content:"\e774"}.el-icon-monitor:before{content:"\e775"}.el-icon-search:before{content:"\e778"}.el-icon-takeaway-box:before{content:"\e77a"}.el-icon-paperclip:before{content:"\e77d"}.el-icon-printer:before{content:"\e77e"}.el-icon-document-add:before{content:"\e782"}.el-icon-document:before{content:"\e785"}.el-icon-document-checked:before{content:"\e786"}.el-icon-document-copy:before{content:"\e787"}.el-icon-document-delete:before{content:"\e788"}.el-icon-document-remove:before{content:"\e789"}.el-icon-tickets:before{content:"\e78b"}.el-icon-folder-checked:before{content:"\e77f"}.el-icon-folder-delete:before{content:"\e780"}.el-icon-folder-remove:before{content:"\e781"}.el-icon-folder-add:before{content:"\e783"}.el-icon-folder-opened:before{content:"\e784"}.el-icon-folder:before{content:"\e78a"}.el-icon-edit-outline:before{content:"\e764"}.el-icon-edit:before{content:"\e78c"}.el-icon-date:before{content:"\e78e"}.el-icon-c-scale-to-original:before{content:"\e7c6"}.el-icon-view:before{content:"\e6ce"}.el-icon-loading:before{content:"\e6cf"}.el-icon-rank:before{content:"\e6d1"}.el-icon-sort-down:before{content:"\e7c4"}.el-icon-sort-up:before{content:"\e7c5"}.el-icon-sort:before{content:"\e6d2"}.el-icon-finished:before{content:"\e6cd"}.el-icon-refresh-left:before{content:"\e6c7"}.el-icon-refresh-right:before{content:"\e6c8"}.el-icon-refresh:before{content:"\e6d0"}.el-icon-video-play:before{content:"\e7c0"}.el-icon-video-pause:before{content:"\e7c1"}.el-icon-d-arrow-right:before{content:"\e6dc"}.el-icon-d-arrow-left:before{content:"\e6dd"}.el-icon-arrow-up:before{content:"\e6e1"}.el-icon-arrow-down:before{content:"\e6df"}.el-icon-arrow-right:before{content:"\e6e0"}.el-icon-arrow-left:before{content:"\e6de"}.el-icon-top-right:before{content:"\e6e7"}.el-icon-top-left:before{content:"\e6e8"}.el-icon-top:before{content:"\e6e6"}.el-icon-bottom:before{content:"\e6eb"}.el-icon-right:before{content:"\e6e9"}.el-icon-back:before{content:"\e6ea"}.el-icon-bottom-right:before{content:"\e6ec"}.el-icon-bottom-left:before{content:"\e6ed"}.el-icon-caret-top:before{content:"\e78f"}.el-icon-caret-bottom:before{content:"\e790"}.el-icon-caret-right:before{content:"\e791"}.el-icon-caret-left:before{content:"\e792"}.el-icon-d-caret:before{content:"\e79a"}.el-icon-share:before{content:"\e793"}.el-icon-menu:before{content:"\e798"}.el-icon-s-grid:before{content:"\e7a6"}.el-icon-s-check:before{content:"\e7a7"}.el-icon-s-data:before{content:"\e7a8"}.el-icon-s-opportunity:before{content:"\e7aa"}.el-icon-s-custom:before{content:"\e7ab"}.el-icon-s-claim:before{content:"\e7ad"}.el-icon-s-finance:before{content:"\e7ae"}.el-icon-s-comment:before{content:"\e7af"}.el-icon-s-flag:before{content:"\e7b0"}.el-icon-s-marketing:before{content:"\e7b1"}.el-icon-s-shop:before{content:"\e7b4"}.el-icon-s-open:before{content:"\e7b5"}.el-icon-s-management:before{content:"\e7b6"}.el-icon-s-ticket:before{content:"\e7b7"}.el-icon-s-release:before{content:"\e7b8"}.el-icon-s-home:before{content:"\e7b9"}.el-icon-s-promotion:before{content:"\e7ba"}.el-icon-s-operation:before{content:"\e7bb"}.el-icon-s-unfold:before{content:"\e7bc"}.el-icon-s-fold:before{content:"\e7a9"}.el-icon-s-platform:before{content:"\e7bd"}.el-icon-s-order:before{content:"\e7be"}.el-icon-s-cooperation:before{content:"\e7bf"}.el-icon-bell:before{content:"\e725"}.el-icon-message-solid:before{content:"\e799"}.el-icon-video-camera:before{content:"\e772"}.el-icon-video-camera-solid:before{content:"\e796"}.el-icon-camera:before{content:"\e779"}.el-icon-camera-solid:before{content:"\e79b"}.el-icon-download:before{content:"\e77c"}.el-icon-upload2:before{content:"\e77b"}.el-icon-upload:before{content:"\e7c3"}.el-icon-picture-outline-round:before{content:"\e75f"}.el-icon-picture-outline:before{content:"\e75e"}.el-icon-picture:before{content:"\e79f"}.el-icon-close:before{content:"\e6db"}.el-icon-check:before{content:"\e6da"}.el-icon-plus:before{content:"\e6d9"}.el-icon-minus:before{content:"\e6d8"}.el-icon-help:before{content:"\e73d"}.el-icon-s-help:before{content:"\e7b3"}.el-icon-circle-close:before{content:"\e78d"}.el-icon-circle-check:before{content:"\e720"}.el-icon-circle-plus-outline:before{content:"\e723"}.el-icon-remove-outline:before{content:"\e722"}.el-icon-zoom-out:before{content:"\e776"}.el-icon-zoom-in:before{content:"\e777"}.el-icon-error:before{content:"\e79d"}.el-icon-success:before{content:"\e79c"}.el-icon-circle-plus:before{content:"\e7a0"}.el-icon-remove:before{content:"\e7a2"}.el-icon-info:before{content:"\e7a1"}.el-icon-question:before{content:"\e7a4"}.el-icon-warning-outline:before{content:"\e6c9"}.el-icon-warning:before{content:"\e7a3"}.el-icon-goods:before{content:"\e7c2"}.el-icon-s-goods:before{content:"\e7b2"}.el-icon-star-off:before{content:"\e717"}.el-icon-star-on:before{content:"\e797"}.el-icon-more-outline:before{content:"\e6cc"}.el-icon-more:before{content:"\e794"}.el-icon-phone-outline:before{content:"\e6cb"}.el-icon-phone:before{content:"\e795"}.el-icon-user:before{content:"\e6e3"}.el-icon-user-solid:before{content:"\e7a5"}.el-icon-setting:before{content:"\e6ca"}.el-icon-s-tools:before{content:"\e7ac"}.el-icon-delete:before{content:"\e6d7"}.el-icon-delete-solid:before{content:"\e7c9"}.el-icon-eleme:before{content:"\e7c7"}.el-icon-platform-eleme:before{content:"\e7ca"}.el-icon-loading{-webkit-animation:rotating 2s linear infinite;animation:rotating 2s linear infinite}.el-icon--right{margin-left:5px}.el-icon--left{margin-right:5px}@-webkit-keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}@keyframes rotating{0%{-webkit-transform:rotateZ(0);transform:rotateZ(0)}100%{-webkit-transform:rotateZ(360deg);transform:rotateZ(360deg)}}.el-pagination{white-space:nowrap;padding:2px 5px;color:#303133;font-weight:700}.el-pagination::after,.el-pagination::before{display:table;content:""}.el-pagination::after{clear:both}.el-pagination button,.el-pagination span:not([class*=suffix]){display:inline-block;font-size:13px;min-width:35.5px;height:28px;line-height:28px;vertical-align:top;-webkit-box-sizing:border-box;box-sizing:border-box}.el-pagination .el-input__inner{text-align:center;-moz-appearance:textfield;line-height:normal}.el-pagination .el-input__suffix{right:0;-webkit-transform:scale(.8);transform:scale(.8)}.el-pagination .el-select .el-input{width:100px;margin:0 5px}.el-pagination .el-select .el-input .el-input__inner{padding-right:25px;border-radius:3px}.el-pagination button{border:none;padding:0 6px;background:0 0}.el-pagination button:focus{outline:0}.el-pagination button:hover{color:#409EFF}.el-pagination button:disabled{color:#C0C4CC;background-color:#FFF;cursor:not-allowed}.el-pagination .btn-next,.el-pagination .btn-prev{background:center center no-repeat #FFF;background-size:16px;cursor:pointer;margin:0;color:#303133}.el-pagination .btn-next .el-icon,.el-pagination .btn-prev .el-icon{display:block;font-size:12px;font-weight:700}.el-pagination .btn-prev{padding-right:12px}.el-pagination .btn-next{padding-left:12px}.el-pagination .el-pager li.disabled{color:#C0C4CC;cursor:not-allowed}.el-pager li,.el-pager li.btn-quicknext:hover,.el-pager li.btn-quickprev:hover{cursor:pointer}.el-pagination--small .btn-next,.el-pagination--small .btn-prev,.el-pagination--small .el-pager li,.el-pagination--small .el-pager li.btn-quicknext,.el-pagination--small .el-pager li.btn-quickprev,.el-pagination--small .el-pager li:last-child{border-color:transparent;font-size:12px;line-height:22px;height:22px;min-width:22px}.el-pagination--small .arrow.disabled{visibility:hidden}.el-pagination--small .more::before,.el-pagination--small li.more::before{line-height:24px}.el-pagination--small button,.el-pagination--small span:not([class*=suffix]){height:22px;line-height:22px}.el-pagination--small .el-pagination__editor,.el-pagination--small .el-pagination__editor.el-input .el-input__inner{height:22px}.el-pagination__sizes{margin:0 10px 0 0;font-weight:400;color:#606266}.el-pagination__sizes .el-input .el-input__inner{font-size:13px;padding-left:8px}.el-pagination__sizes .el-input .el-input__inner:hover{border-color:#409EFF}.el-pagination__total{margin-right:10px;font-weight:400;color:#606266}.el-pagination__jump{margin-left:24px;font-weight:400;color:#606266}.el-pagination__jump .el-input__inner{padding:0 3px}.el-pagination__rightwrapper{float:right}.el-pagination__editor{line-height:18px;padding:0 2px;height:28px;text-align:center;margin:0 2px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:3px}.el-pager,.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev{padding:0}.el-dialog,.el-pager li{-webkit-box-sizing:border-box}.el-pagination__editor.el-input{width:50px}.el-pagination__editor.el-input .el-input__inner{height:28px}.el-pagination__editor .el-input__inner::-webkit-inner-spin-button,.el-pagination__editor .el-input__inner::-webkit-outer-spin-button{-webkit-appearance:none;margin:0}.el-pagination.is-background .btn-next,.el-pagination.is-background .btn-prev,.el-pagination.is-background .el-pager li{margin:0 5px;background-color:#f4f4f5;color:#606266;min-width:30px;border-radius:2px}.el-pagination.is-background .btn-next.disabled,.el-pagination.is-background .btn-next:disabled,.el-pagination.is-background .btn-prev.disabled,.el-pagination.is-background .btn-prev:disabled,.el-pagination.is-background .el-pager li.disabled{color:#C0C4CC}.el-pagination.is-background .el-pager li:not(.disabled):hover{color:#409EFF}.el-pagination.is-background .el-pager li:not(.disabled).active{background-color:#409EFF;color:#FFF}.el-pagination.is-background.el-pagination--small .btn-next,.el-pagination.is-background.el-pagination--small .btn-prev,.el-pagination.is-background.el-pagination--small .el-pager li{margin:0 3px;min-width:22px}.el-pager,.el-pager li{vertical-align:top;margin:0;display:inline-block}.el-pager{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;list-style:none;font-size:0}.el-pager .more::before{line-height:30px}.el-pager li{padding:0 4px;background:#FFF;font-size:13px;min-width:35.5px;height:28px;line-height:28px;box-sizing:border-box;text-align:center}.el-pager li.btn-quicknext,.el-pager li.btn-quickprev{line-height:28px;color:#303133}.el-pager li.btn-quicknext.disabled,.el-pager li.btn-quickprev.disabled{color:#C0C4CC}.el-pager li.active+li{border-left:0}.el-pager li:hover{color:#409EFF}.el-pager li.active{color:#409EFF;cursor:default}@-webkit-keyframes v-modal-in{0%{opacity:0}}@-webkit-keyframes v-modal-out{100%{opacity:0}}.el-dialog{position:relative;margin:0 auto 50px;background:#FFF;border-radius:2px;-webkit-box-shadow:0 1px 3px rgba(0,0,0,.3);box-shadow:0 1px 3px rgba(0,0,0,.3);box-sizing:border-box;width:50%}.el-dialog.is-fullscreen{width:100%;margin-top:0;margin-bottom:0;height:100%;overflow:auto}.el-dialog__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:auto;margin:0}.el-dialog__header{padding:20px 20px 10px}.el-dialog__headerbtn{position:absolute;top:20px;right:20px;padding:0;background:0 0;border:none;outline:0;cursor:pointer;font-size:16px}.el-dialog__headerbtn .el-dialog__close{color:#909399}.el-dialog__headerbtn:focus .el-dialog__close,.el-dialog__headerbtn:hover .el-dialog__close{color:#409EFF}.el-dialog__title{line-height:24px;font-size:18px;color:#303133}.el-dialog__body{padding:30px 20px;color:#606266;font-size:14px;word-break:break-all}.el-dialog__footer{padding:10px 20px 20px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-dialog--center{text-align:center}.el-dialog--center .el-dialog__body{text-align:initial;padding:25px 25px 30px}.el-dialog--center .el-dialog__footer{text-align:inherit}.dialog-fade-enter-active{-webkit-animation:dialog-fade-in .3s;animation:dialog-fade-in .3s}.dialog-fade-leave-active{-webkit-animation:dialog-fade-out .3s;animation:dialog-fade-out .3s}@-webkit-keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes dialog-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes dialog-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-autocomplete{position:relative;display:inline-block}.el-autocomplete-suggestion{margin:5px 0;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:4px;border:1px solid #E4E7ED;-webkit-box-sizing:border-box;box-sizing:border-box;background-color:#FFF}.el-autocomplete-suggestion__wrap{max-height:280px;padding:10px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-autocomplete-suggestion__list{margin:0;padding:0}.el-autocomplete-suggestion li{padding:0 20px;margin:0;line-height:34px;cursor:pointer;color:#606266;font-size:14px;list-style:none;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-autocomplete-suggestion li.highlighted,.el-autocomplete-suggestion li:hover{background-color:#F5F7FA}.el-autocomplete-suggestion li.divider{margin-top:6px;border-top:1px solid #000}.el-autocomplete-suggestion li.divider:last-child{margin-bottom:-6px}.el-autocomplete-suggestion.is-loading li{text-align:center;height:100px;line-height:100px;font-size:20px;color:#999}.el-autocomplete-suggestion.is-loading li::after{display:inline-block;content:"";height:100%;vertical-align:middle}.el-autocomplete-suggestion.is-loading li:hover{background-color:#FFF}.el-autocomplete-suggestion.is-loading .el-icon-loading{vertical-align:middle}.el-dropdown{display:inline-block;position:relative;color:#606266;font-size:14px}.el-dropdown .el-button-group{display:block}.el-dropdown .el-button-group .el-button{float:none}.el-dropdown .el-dropdown__caret-button{padding-left:5px;padding-right:5px;position:relative;border-left:none}.el-dropdown .el-dropdown__caret-button::before{content:'';position:absolute;display:block;width:1px;top:5px;bottom:5px;left:0;background:rgba(255,255,255,.5)}.el-dropdown .el-dropdown__caret-button.el-button--default::before{background:rgba(220,223,230,.5)}.el-dropdown .el-dropdown__caret-button:hover:not(.is-disabled)::before{top:0;bottom:0}.el-dropdown .el-dropdown__caret-button .el-dropdown__icon{padding-left:0}.el-dropdown__icon{font-size:12px;margin:0 3px}.el-dropdown .el-dropdown-selfdefine:focus:active,.el-dropdown .el-dropdown-selfdefine:focus:not(.focusing){outline-width:0}.el-dropdown [disabled]{cursor:not-allowed;color:#bbb}.el-dropdown-menu{position:absolute;top:0;left:0;z-index:10;padding:10px 0;margin:5px 0;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-dropdown-menu__item,.el-menu-item{font-size:14px;padding:0 20px;cursor:pointer}.el-dropdown-menu__item{list-style:none;line-height:36px;margin:0;color:#606266;outline:0}.el-dropdown-menu__item:focus,.el-dropdown-menu__item:not(.is-disabled):hover{background-color:#ecf5ff;color:#66b1ff}.el-dropdown-menu__item i{margin-right:5px}.el-dropdown-menu__item--divided{position:relative;margin-top:6px;border-top:1px solid #EBEEF5}.el-dropdown-menu__item--divided:before{content:'';height:6px;display:block;margin:0 -20px;background-color:#FFF}.el-dropdown-menu__item.is-disabled{cursor:default;color:#bbb;pointer-events:none}.el-dropdown-menu--medium{padding:6px 0}.el-dropdown-menu--medium .el-dropdown-menu__item{line-height:30px;padding:0 17px;font-size:14px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:6px}.el-dropdown-menu--medium .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:6px;margin:0 -17px}.el-dropdown-menu--small{padding:6px 0}.el-dropdown-menu--small .el-dropdown-menu__item{line-height:27px;padding:0 15px;font-size:13px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:4px}.el-dropdown-menu--small .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:4px;margin:0 -15px}.el-dropdown-menu--mini{padding:3px 0}.el-dropdown-menu--mini .el-dropdown-menu__item{line-height:24px;padding:0 10px;font-size:12px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided{margin-top:3px}.el-dropdown-menu--mini .el-dropdown-menu__item.el-dropdown-menu__item--divided:before{height:3px;margin:0 -10px}.el-menu{border-right:solid 1px #e6e6e6;list-style:none;position:relative;margin:0;padding-left:0;background-color:#FFF}.el-menu--horizontal>.el-menu-item:not(.is-disabled):focus,.el-menu--horizontal>.el-menu-item:not(.is-disabled):hover,.el-menu--horizontal>.el-submenu .el-submenu__title:hover{background-color:#fff}.el-menu::after,.el-menu::before{display:table;content:""}.el-breadcrumb__item:last-child .el-breadcrumb__separator,.el-menu--collapse>.el-menu-item .el-submenu__icon-arrow,.el-menu--collapse>.el-submenu>.el-submenu__title .el-submenu__icon-arrow{display:none}.el-menu::after{clear:both}.el-menu.el-menu--horizontal{border-bottom:solid 1px #e6e6e6}.el-menu--horizontal{border-right:none}.el-menu--horizontal>.el-menu-item{float:left;height:60px;line-height:60px;margin:0;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-menu-item a,.el-menu--horizontal>.el-menu-item a:hover{color:inherit}.el-menu--horizontal>.el-submenu{float:left}.el-menu--horizontal>.el-submenu:focus,.el-menu--horizontal>.el-submenu:hover{outline:0}.el-menu--horizontal>.el-submenu:focus .el-submenu__title,.el-menu--horizontal>.el-submenu:hover .el-submenu__title{color:#303133}.el-menu--horizontal>.el-submenu.is-active .el-submenu__title{border-bottom:2px solid #409EFF;color:#303133}.el-menu--horizontal>.el-submenu .el-submenu__title{height:60px;line-height:60px;border-bottom:2px solid transparent;color:#909399}.el-menu--horizontal>.el-submenu .el-submenu__icon-arrow{position:static;vertical-align:middle;margin-left:8px;margin-top:-3px}.el-menu--collapse .el-submenu,.el-menu-item{position:relative}.el-menu--horizontal .el-menu .el-menu-item,.el-menu--horizontal .el-menu .el-submenu__title{background-color:#FFF;float:none;height:36px;line-height:36px;padding:0 10px;color:#909399}.el-menu--horizontal .el-menu .el-menu-item.is-active,.el-menu--horizontal .el-menu .el-submenu.is-active>.el-submenu__title{color:#303133}.el-menu--horizontal .el-menu-item:not(.is-disabled):focus,.el-menu--horizontal .el-menu-item:not(.is-disabled):hover{outline:0;color:#303133}.el-menu--horizontal>.el-menu-item.is-active{border-bottom:2px solid #409EFF;color:#303133}.el-menu--collapse{width:64px}.el-menu--collapse>.el-menu-item [class^=el-icon-],.el-menu--collapse>.el-submenu>.el-submenu__title [class^=el-icon-]{margin:0;vertical-align:middle;width:24px;text-align:center}.el-menu--collapse>.el-menu-item span,.el-menu--collapse>.el-submenu>.el-submenu__title span{height:0;width:0;overflow:hidden;visibility:hidden;display:inline-block}.el-menu-item,.el-submenu__title{height:56px;line-height:56px;list-style:none}.el-menu--collapse>.el-menu-item.is-active i{color:inherit}.el-menu--collapse .el-menu .el-submenu{min-width:200px}.el-menu--collapse .el-submenu .el-menu{position:absolute;margin-left:5px;top:0;left:100%;z-index:10;border:1px solid #E4E7ED;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--collapse .el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:none;transform:none}.el-menu--popup{z-index:100;min-width:200px;border:none;padding:5px 0;border-radius:2px;-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-menu--popup-bottom-start{margin-top:5px}.el-menu--popup-right-start{margin-left:5px;margin-right:5px}.el-menu-item{color:#303133;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;-webkit-box-sizing:border-box;box-sizing:border-box;white-space:nowrap}.el-radio-button__inner,.el-submenu__title{-webkit-box-sizing:border-box;position:relative;white-space:nowrap}.el-menu-item *{vertical-align:middle}.el-menu-item i{color:#909399}.el-menu-item:focus,.el-menu-item:hover{outline:0;background-color:#ecf5ff}.el-menu-item.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-menu-item [class^=el-icon-]{margin-right:5px;width:24px;text-align:center;font-size:18px;vertical-align:middle}.el-menu-item.is-active{color:#409EFF}.el-menu-item.is-active i{color:inherit}.el-submenu{list-style:none;margin:0;padding-left:0}.el-submenu__title{font-size:14px;color:#303133;padding:0 20px;cursor:pointer;-webkit-transition:border-color .3s,background-color .3s,color .3s;transition:border-color .3s,background-color .3s,color .3s;box-sizing:border-box}.el-submenu__title *{vertical-align:middle}.el-submenu__title i{color:#909399}.el-submenu__title:focus,.el-submenu__title:hover{outline:0;background-color:#ecf5ff}.el-submenu__title.is-disabled{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu__title:hover{background-color:#ecf5ff}.el-submenu .el-menu{border:none}.el-submenu .el-menu-item{height:50px;line-height:50px;padding:0 45px;min-width:200px}.el-submenu__icon-arrow{position:absolute;top:50%;right:20px;margin-top:-7px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:12px}.el-submenu.is-active .el-submenu__title{border-bottom-color:#409EFF}.el-submenu.is-opened>.el-submenu__title .el-submenu__icon-arrow{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-submenu.is-disabled .el-menu-item,.el-submenu.is-disabled .el-submenu__title{opacity:.25;cursor:not-allowed;background:0 0!important}.el-submenu [class^=el-icon-]{vertical-align:middle;margin-right:5px;width:24px;text-align:center;font-size:18px}.el-menu-item-group>ul{padding:0}.el-menu-item-group__title{padding:7px 0 7px 20px;line-height:normal;font-size:12px;color:#909399}.el-radio-button__inner,.el-radio-group{display:inline-block;line-height:1;vertical-align:middle}.horizontal-collapse-transition .el-submenu__title .el-submenu__icon-arrow{-webkit-transition:.2s;transition:.2s;opacity:0}.el-radio-group{font-size:0}.el-radio-button{position:relative;display:inline-block;outline:0}.el-radio-button__inner{background:#FFF;border:1px solid #DCDFE6;font-weight:500;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;box-sizing:border-box;outline:0;margin:0;cursor:pointer;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-radio-button__inner.is-round{padding:12px 20px}.el-radio-button__inner:hover{color:#409EFF}.el-radio-button__inner [class*=el-icon-]{line-height:.9}.el-radio-button__inner [class*=el-icon-]+span{margin-left:5px}.el-radio-button:first-child .el-radio-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-radio-button__orig-radio{opacity:0;outline:0;position:absolute;z-index:-1}.el-radio-button__orig-radio:checked+.el-radio-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #409EFF;box-shadow:-1px 0 0 0 #409EFF}.el-radio-button__orig-radio:disabled+.el-radio-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-radio-button__orig-radio:disabled:checked+.el-radio-button__inner{background-color:#F2F6FC}.el-radio-button:last-child .el-radio-button__inner{border-radius:0 4px 4px 0}.el-radio-button:first-child:last-child .el-radio-button__inner{border-radius:4px}.el-radio-button--medium .el-radio-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-radio-button--medium .el-radio-button__inner.is-round{padding:10px 20px}.el-radio-button--small .el-radio-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-radio-button--small .el-radio-button__inner.is-round{padding:9px 15px}.el-radio-button--mini .el-radio-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-radio-button--mini .el-radio-button__inner.is-round{padding:7px 15px}.el-radio-button:focus:not(.is-focus):not(:active):not(.is-disabled){-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-picker-panel,.el-popover,.el-select-dropdown,.el-table-filter,.el-time-panel{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-switch{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;font-size:14px;line-height:20px;height:20px;vertical-align:middle}.el-switch__core,.el-switch__label{display:inline-block;cursor:pointer}.el-switch.is-disabled .el-switch__core,.el-switch.is-disabled .el-switch__label{cursor:not-allowed}.el-switch__label{-webkit-transition:.2s;transition:.2s;height:20px;font-size:14px;font-weight:500;vertical-align:middle;color:#303133}.el-switch__label.is-active{color:#409EFF}.el-switch__label--left{margin-right:10px}.el-switch__label--right{margin-left:10px}.el-switch__label *{line-height:1;font-size:14px;display:inline-block}.el-switch__input{position:absolute;width:0;height:0;opacity:0;margin:0}.el-switch__core{margin:0;position:relative;width:40px;height:20px;border:1px solid #DCDFE6;outline:0;border-radius:10px;-webkit-box-sizing:border-box;box-sizing:border-box;background:#DCDFE6;-webkit-transition:border-color .3s,background-color .3s;transition:border-color .3s,background-color .3s;vertical-align:middle}.el-input__prefix,.el-input__suffix{-webkit-transition:all .3s;color:#C0C4CC}.el-switch__core:after{content:"";position:absolute;top:1px;left:1px;border-radius:100%;-webkit-transition:all .3s;transition:all .3s;width:16px;height:16px;background-color:#FFF}.el-switch.is-checked .el-switch__core{border-color:#409EFF;background-color:#409EFF}.el-switch.is-checked .el-switch__core::after{left:100%;margin-left:-17px}.el-switch.is-disabled{opacity:.6}.el-switch--wide .el-switch__label.el-switch__label--left span{left:10px}.el-switch--wide .el-switch__label.el-switch__label--right span{right:10px}.el-switch .label-fade-enter,.el-switch .label-fade-leave-active{opacity:0}.el-select-dropdown{position:absolute;z-index:1001;border:1px solid #E4E7ED;border-radius:4px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-box-sizing:border-box;box-sizing:border-box;margin:5px 0}.el-select-dropdown.is-multiple .el-select-dropdown__item{padding-right:40px}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected{color:#409EFF;background-color:#FFF}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected.hover{background-color:#F5F7FA}.el-select-dropdown.is-multiple .el-select-dropdown__item.selected::after{position:absolute;right:20px;font-family:element-icons;content:"\e6da";font-size:12px;font-weight:700;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.el-select-dropdown .el-scrollbar.is-empty .el-select-dropdown__list{padding:0}.el-select-dropdown__empty{padding:10px 0;margin:0;text-align:center;color:#999;font-size:14px}.el-select-dropdown__wrap{max-height:274px}.el-select-dropdown__list{list-style:none;padding:6px 0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-select-dropdown__item{font-size:14px;padding:0 20px;position:relative;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;color:#606266;height:34px;line-height:34px;-webkit-box-sizing:border-box;box-sizing:border-box;cursor:pointer}.el-select-dropdown__item.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-select-dropdown__item.is-disabled:hover{background-color:#FFF}.el-select-dropdown__item.hover,.el-select-dropdown__item:hover{background-color:#F5F7FA}.el-select-dropdown__item.selected{color:#409EFF;font-weight:700}.el-select-group{margin:0;padding:0}.el-select-group__wrap{position:relative;list-style:none;margin:0;padding:0}.el-select-group__wrap:not(:last-of-type){padding-bottom:24px}.el-select-group__wrap:not(:last-of-type)::after{content:'';position:absolute;display:block;left:20px;right:20px;bottom:12px;height:1px;background:#E4E7ED}.el-select-group__title{padding-left:20px;font-size:12px;color:#909399;line-height:30px}.el-select-group .el-select-dropdown__item{padding-left:20px}.el-select{display:inline-block;position:relative}.el-select .el-select__tags>span{display:contents}.el-select:hover .el-input__inner{border-color:#C0C4CC}.el-select .el-input__inner{cursor:pointer;padding-right:35px}.el-select .el-input__inner:focus{border-color:#409EFF}.el-select .el-input .el-select__caret{color:#C0C4CC;font-size:14px;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);cursor:pointer}.el-select .el-input .el-select__caret.is-reverse{-webkit-transform:rotateZ(0);transform:rotateZ(0)}.el-select .el-input .el-select__caret.is-show-close{font-size:14px;text-align:center;-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg);border-radius:100%;color:#C0C4CC;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-select .el-input .el-select__caret.is-show-close:hover{color:#909399}.el-select .el-input.is-disabled .el-input__inner{cursor:not-allowed}.el-select .el-input.is-disabled .el-input__inner:hover{border-color:#E4E7ED}.el-range-editor.is-active,.el-range-editor.is-active:hover,.el-select .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-select>.el-input{display:block}.el-select__input{border:none;outline:0;padding:0;margin-left:15px;color:#666;font-size:14px;-webkit-appearance:none;-moz-appearance:none;appearance:none;height:28px;background-color:transparent}.el-select__input.is-mini{height:14px}.el-select__close{cursor:pointer;position:absolute;top:8px;z-index:1000;right:25px;color:#C0C4CC;line-height:18px;font-size:14px}.el-select__close:hover{color:#909399}.el-select__tags{position:absolute;line-height:normal;white-space:normal;z-index:1;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-select__tags-text{overflow:hidden;text-overflow:ellipsis}.el-select .el-tag{-webkit-box-sizing:border-box;box-sizing:border-box;border-color:transparent;margin:2px 0 2px 6px;background-color:#f0f2f5;display:-webkit-box;display:-ms-flexbox;display:flex;max-width:100%;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-select .el-tag__close.el-icon-close{background-color:#C0C4CC;top:0;color:#FFF;-ms-flex-negative:0;flex-shrink:0}.el-select .el-tag__close.el-icon-close:hover{background-color:#909399}.el-table,.el-table__expanded-cell{background-color:#FFF}.el-select .el-tag__close.el-icon-close::before{display:block;-webkit-transform:translate(0,.5px);transform:translate(0,.5px)}.el-table{position:relative;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1;flex:1;width:100%;max-width:100%;font-size:14px;color:#606266}.el-table__empty-block{min-height:60px;text-align:center;width:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-table__empty-text{line-height:60px;width:50%;color:#909399}.el-table__expand-column .cell{padding:0;text-align:center}.el-table__expand-icon{position:relative;cursor:pointer;color:#666;font-size:12px;-webkit-transition:-webkit-transform .2s ease-in-out;transition:-webkit-transform .2s ease-in-out;transition:transform .2s ease-in-out;transition:transform .2s ease-in-out,-webkit-transform .2s ease-in-out;height:20px}.el-table__expand-icon--expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-table__expand-icon>.el-icon{position:absolute;left:50%;top:50%;margin-left:-5px;margin-top:-5px}.el-table__expanded-cell[class*=cell]{padding:20px 50px}.el-table__expanded-cell:hover{background-color:transparent!important}.el-table__placeholder{display:inline-block;width:20px}.el-table__append-wrapper{overflow:hidden}.el-table--fit{border-right:0;border-bottom:0}.el-table--fit .el-table__cell.gutter{border-right-width:1px}.el-table--scrollable-x .el-table__body-wrapper{overflow-x:auto}.el-table--scrollable-y .el-table__body-wrapper{overflow-y:auto}.el-table thead{color:#909399;font-weight:500}.el-table thead.is-group th.el-table__cell{background:#F5F7FA}.el-table .el-table__cell{padding:12px 0;min-width:0;-webkit-box-sizing:border-box;box-sizing:border-box;text-overflow:ellipsis;vertical-align:middle;position:relative;text-align:left}.el-table .el-table__cell.is-center{text-align:center}.el-table .el-table__cell.is-right{text-align:right}.el-table .el-table__cell.gutter{width:15px;border-right-width:0;border-bottom-width:0;padding:0}.el-table .el-table__cell.is-hidden>*{visibility:hidden}.el-table--medium .el-table__cell{padding:10px 0}.el-table--small{font-size:12px}.el-table--small .el-table__cell{padding:8px 0}.el-table--mini{font-size:12px}.el-table--mini .el-table__cell{padding:6px 0}.el-table tr{background-color:#FFF}.el-table tr input[type=checkbox]{margin:0}.el-table td.el-table__cell,.el-table th.el-table__cell.is-leaf{border-bottom:1px solid #EBEEF5}.el-table th.el-table__cell.is-sortable{cursor:pointer}.el-table th.el-table__cell{overflow:hidden;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;background-color:#FFF}.el-table th.el-table__cell>.cell{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;position:relative;vertical-align:middle;padding-left:10px;padding-right:10px;width:100%}.el-table th.el-table__cell>.cell.highlight{color:#409EFF}.el-table th.el-table__cell.required>div::before{display:inline-block;content:"";width:8px;height:8px;border-radius:50%;background:#ff4d51;margin-right:5px;vertical-align:middle}.el-table td.el-table__cell div{-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td,.el-table .cell,.el-table-filter{-webkit-box-sizing:border-box}.el-table td.el-table__cell.gutter{width:0}.el-table .cell{box-sizing:border-box;overflow:hidden;text-overflow:ellipsis;white-space:normal;word-break:break-all;line-height:23px;padding-left:10px;padding-right:10px}.el-table .cell.el-tooltip{white-space:nowrap;min-width:50px}.el-table--border,.el-table--group{border:1px solid #EBEEF5}.el-table--border::after,.el-table--group::after,.el-table::before{content:'';position:absolute;background-color:#EBEEF5;z-index:1}.el-table--border::after,.el-table--group::after{top:0;right:0;width:1px;height:100%}.el-table::before{left:0;bottom:0;width:100%;height:1px}.el-table--border{border-right:none;border-bottom:none}.el-table--border.el-loading-parent--relative{border-color:transparent}.el-table--border .el-table__cell,.el-table__body-wrapper .el-table--border.is-scrolling-left~.el-table__fixed{border-right:1px solid #EBEEF5}.el-table--border .el-table__cell:first-child .cell{padding-left:10px}.el-table--border th.el-table__cell.gutter:last-of-type{border-bottom:1px solid #EBEEF5;border-bottom-width:1px}.el-table--border th.el-table__cell,.el-table__fixed-right-patch{border-bottom:1px solid #EBEEF5}.el-table--hidden{visibility:hidden}.el-table__fixed,.el-table__fixed-right{position:absolute;top:0;left:0;overflow-x:hidden;overflow-y:hidden;-webkit-box-shadow:0 0 10px rgba(0,0,0,.12);box-shadow:0 0 10px rgba(0,0,0,.12)}.el-table__fixed-right::before,.el-table__fixed::before{content:'';position:absolute;left:0;bottom:0;width:100%;height:1px;background-color:#EBEEF5;z-index:4}.el-table__fixed-right-patch{position:absolute;top:-1px;right:0;background-color:#FFF}.el-table__fixed-right{top:0;left:auto;right:0}.el-table__fixed-right .el-table__fixed-body-wrapper,.el-table__fixed-right .el-table__fixed-footer-wrapper,.el-table__fixed-right .el-table__fixed-header-wrapper{left:auto;right:0}.el-table__fixed-header-wrapper{position:absolute;left:0;top:0;z-index:3}.el-table__fixed-footer-wrapper{position:absolute;left:0;bottom:0;z-index:3}.el-table__fixed-footer-wrapper tbody td.el-table__cell{border-top:1px solid #EBEEF5;background-color:#F5F7FA;color:#606266}.el-table__fixed-body-wrapper{position:absolute;left:0;top:37px;overflow:hidden;z-index:3}.el-table__body-wrapper,.el-table__footer-wrapper,.el-table__header-wrapper{width:100%}.el-table__footer-wrapper{margin-top:-1px}.el-table__footer-wrapper td.el-table__cell{border-top:1px solid #EBEEF5}.el-table__body,.el-table__footer,.el-table__header{table-layout:fixed;border-collapse:separate}.el-table__footer-wrapper,.el-table__header-wrapper{overflow:hidden}.el-table__footer-wrapper tbody td.el-table__cell,.el-table__header-wrapper tbody td.el-table__cell{background-color:#F5F7FA;color:#606266}.el-table__body-wrapper{overflow:hidden;position:relative}.el-table__body-wrapper.is-scrolling-left~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed,.el-table__body-wrapper.is-scrolling-none~.el-table__fixed-right,.el-table__body-wrapper.is-scrolling-right~.el-table__fixed-right{-webkit-box-shadow:none;box-shadow:none}.el-table__body-wrapper .el-table--border.is-scrolling-right~.el-table__fixed-right{border-left:1px solid #EBEEF5}.el-table .caret-wrapper{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;width:24px;vertical-align:middle;cursor:pointer;overflow:initial;position:relative}.el-table .sort-caret{width:0;height:0;border:5px solid transparent;position:absolute;left:7px}.el-table .sort-caret.ascending{border-bottom-color:#C0C4CC;top:5px}.el-table .sort-caret.descending{border-top-color:#C0C4CC;bottom:7px}.el-table .ascending .sort-caret.ascending{border-bottom-color:#409EFF}.el-table .descending .sort-caret.descending{border-top-color:#409EFF}.el-table .hidden-columns{visibility:hidden;position:absolute;z-index:-1}.el-table--striped .el-table__body tr.el-table__row--striped td.el-table__cell{background:#FAFAFA}.el-table--striped .el-table__body tr.el-table__row--striped.current-row td.el-table__cell,.el-table--striped .el-table__body tr.el-table__row--striped.selection-row td.el-table__cell{background-color:#ecf5ff}.el-table__body tr.hover-row.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.current-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped.selection-row>td.el-table__cell,.el-table__body tr.hover-row.el-table__row--striped>td.el-table__cell,.el-table__body tr.hover-row.selection-row>td.el-table__cell,.el-table__body tr.hover-row>td.el-table__cell{background-color:#F5F7FA}.el-table__body tr.current-row>td.el-table__cell,.el-table__body tr.selection-row>td.el-table__cell{background-color:#ecf5ff}.el-table__column-resize-proxy{position:absolute;left:200px;top:0;bottom:0;width:0;border-left:1px solid #EBEEF5;z-index:10}.el-table__column-filter-trigger{display:inline-block;line-height:34px;cursor:pointer}.el-table__column-filter-trigger i{color:#909399;font-size:12px;-webkit-transform:scale(.75);transform:scale(.75)}.el-table--enable-row-transition .el-table__body td.el-table__cell{-webkit-transition:background-color .25s ease;transition:background-color .25s ease}.el-table--enable-row-hover .el-table__body tr:hover>td.el-table__cell{background-color:#F5F7FA}.el-table--fluid-height .el-table__fixed,.el-table--fluid-height .el-table__fixed-right{bottom:0;overflow:hidden}.el-table [class*=el-table__row--level] .el-table__expand-icon{display:inline-block;width:20px;line-height:20px;height:20px;text-align:center;margin-right:3px}.el-table-column--selection .cell{padding-left:14px;padding-right:14px}.el-table-filter{border:1px solid #EBEEF5;border-radius:2px;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);box-sizing:border-box;margin:2px 0}.el-table-filter__list{padding:5px 0;margin:0;list-style:none;min-width:100px}.el-table-filter__list-item{line-height:36px;padding:0 10px;cursor:pointer;font-size:14px}.el-table-filter__list-item:hover{background-color:#ecf5ff;color:#66b1ff}.el-table-filter__list-item.is-active{background-color:#409EFF;color:#FFF}.el-table-filter__content{min-width:100px}.el-table-filter__bottom{border-top:1px solid #EBEEF5;padding:8px}.el-table-filter__bottom button{background:0 0;border:none;color:#606266;cursor:pointer;font-size:13px;padding:0 3px}.el-date-table td.in-range div,.el-date-table td.in-range div:hover,.el-date-table.is-week-mode .el-date-table__row.current div,.el-date-table.is-week-mode .el-date-table__row:hover div{background-color:#F2F6FC}.el-table-filter__bottom button:hover{color:#409EFF}.el-table-filter__bottom button:focus{outline:0}.el-table-filter__bottom button.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-table-filter__wrap{max-height:280px}.el-table-filter__checkbox-group{padding:10px}.el-table-filter__checkbox-group label.el-checkbox{display:block;margin-right:5px;margin-bottom:8px;margin-left:5px}.el-table-filter__checkbox-group .el-checkbox:last-child{margin-bottom:0}.el-date-table{font-size:12px;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none}.el-date-table.is-week-mode .el-date-table__row:hover td.available:hover{color:#606266}.el-date-table.is-week-mode .el-date-table__row:hover td:first-child div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table.is-week-mode .el-date-table__row:hover td:last-child div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td{width:32px;height:30px;padding:4px 0;box-sizing:border-box;text-align:center;cursor:pointer;position:relative}.el-date-table td div{height:30px;padding:3px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-table td span{width:24px;height:24px;display:block;margin:0 auto;line-height:24px;position:absolute;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%);border-radius:50%}.el-date-table td.next-month,.el-date-table td.prev-month{color:#C0C4CC}.el-date-table td.today{position:relative}.el-date-table td.today span{color:#409EFF;font-weight:700}.el-date-table td.today.end-date span,.el-date-table td.today.start-date span{color:#FFF}.el-date-table td.available:hover{color:#409EFF}.el-date-table td.current:not(.disabled) span{color:#FFF;background-color:#409EFF}.el-date-table td.end-date div,.el-date-table td.start-date div{color:#FFF}.el-date-table td.end-date span,.el-date-table td.start-date span{background-color:#409EFF}.el-date-table td.start-date div{margin-left:5px;border-top-left-radius:15px;border-bottom-left-radius:15px}.el-date-table td.end-date div{margin-right:5px;border-top-right-radius:15px;border-bottom-right-radius:15px}.el-date-table td.disabled div{background-color:#F5F7FA;opacity:1;cursor:not-allowed;color:#C0C4CC}.el-date-table td.selected div{margin-left:5px;margin-right:5px;background-color:#F2F6FC;border-radius:15px}.el-date-table td.selected div:hover{background-color:#F2F6FC}.el-date-table td.selected span{background-color:#409EFF;color:#FFF;border-radius:15px}.el-date-table td.week{font-size:80%;color:#606266}.el-month-table,.el-year-table{font-size:12px;border-collapse:collapse}.el-date-table th{padding:5px;color:#606266;font-weight:400;border-bottom:solid 1px #EBEEF5}.el-month-table{margin:-1px}.el-month-table td{text-align:center;padding:8px 0;cursor:pointer}.el-month-table td div{height:48px;padding:6px 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-month-table td.today .cell{color:#409EFF;font-weight:700}.el-month-table td.today.end-date .cell,.el-month-table td.today.start-date .cell{color:#FFF}.el-month-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-month-table td.disabled .cell:hover{color:#C0C4CC}.el-month-table td .cell{width:60px;height:36px;display:block;line-height:36px;color:#606266;margin:0 auto;border-radius:18px}.el-month-table td .cell:hover{color:#409EFF}.el-month-table td.in-range div,.el-month-table td.in-range div:hover{background-color:#F2F6FC}.el-month-table td.end-date div,.el-month-table td.start-date div{color:#FFF}.el-month-table td.end-date .cell,.el-month-table td.start-date .cell{color:#FFF;background-color:#409EFF}.el-month-table td.start-date div{border-top-left-radius:24px;border-bottom-left-radius:24px}.el-month-table td.end-date div{border-top-right-radius:24px;border-bottom-right-radius:24px}.el-month-table td.current:not(.disabled) .cell{color:#409EFF}.el-year-table{margin:-1px}.el-year-table .el-icon{color:#303133}.el-year-table td{text-align:center;padding:20px 3px;cursor:pointer}.el-year-table td.today .cell{color:#409EFF;font-weight:700}.el-year-table td.disabled .cell{background-color:#F5F7FA;cursor:not-allowed;color:#C0C4CC}.el-year-table td.disabled .cell:hover{color:#C0C4CC}.el-year-table td .cell{width:48px;height:32px;display:block;line-height:32px;color:#606266;margin:0 auto}.el-year-table td .cell:hover,.el-year-table td.current:not(.disabled) .cell{color:#409EFF}.el-date-range-picker{width:646px}.el-date-range-picker.has-sidebar{width:756px}.el-date-range-picker table{table-layout:fixed;width:100%}.el-date-range-picker .el-picker-panel__body{min-width:513px}.el-date-range-picker .el-picker-panel__content{margin:0}.el-date-range-picker__header{position:relative;text-align:center;height:28px}.el-date-range-picker__header [class*=arrow-left]{float:left}.el-date-range-picker__header [class*=arrow-right]{float:right}.el-date-range-picker__header div{font-size:16px;font-weight:500;margin-right:50px}.el-date-range-picker__content{float:left;width:50%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:16px}.el-date-range-picker__content.is-left{border-right:1px solid #e4e4e4}.el-date-range-picker__content .el-date-range-picker__header div{margin-left:50px;margin-right:50px}.el-date-range-picker__editors-wrap{-webkit-box-sizing:border-box;box-sizing:border-box;display:table-cell}.el-date-range-picker__editors-wrap.is-right{text-align:right}.el-date-range-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-range-picker__time-header>.el-icon-arrow-right{font-size:20px;vertical-align:middle;display:table-cell;color:#303133}.el-date-range-picker__time-picker-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-range-picker__time-picker-wrap .el-picker-panel{position:absolute;top:13px;right:0;z-index:1;background:#FFF}.el-date-picker{width:322px}.el-date-picker.has-sidebar.has-time{width:434px}.el-date-picker.has-sidebar{width:438px}.el-date-picker.has-time .el-picker-panel__body-wrapper{position:relative}.el-date-picker .el-picker-panel__content{width:292px}.el-date-picker table{table-layout:fixed;width:100%}.el-date-picker__editor-wrap{position:relative;display:table-cell;padding:0 5px}.el-date-picker__time-header{position:relative;border-bottom:1px solid #e4e4e4;font-size:12px;padding:8px 5px 5px;display:table;width:100%;-webkit-box-sizing:border-box;box-sizing:border-box}.el-date-picker__header{margin:12px;text-align:center}.el-date-picker__header--bordered{margin-bottom:0;padding-bottom:12px;border-bottom:solid 1px #EBEEF5}.el-date-picker__header--bordered+.el-picker-panel__content{margin-top:0}.el-date-picker__header-label{font-size:16px;font-weight:500;padding:0 5px;line-height:22px;text-align:center;cursor:pointer;color:#606266}.el-date-picker__header-label.active,.el-date-picker__header-label:hover{color:#409EFF}.el-date-picker__prev-btn{float:left}.el-date-picker__next-btn{float:right}.el-date-picker__time-wrap{padding:10px;text-align:center}.el-date-picker__time-label{float:left;cursor:pointer;line-height:30px;margin-left:10px}.time-select{margin:5px 0;min-width:0}.time-select .el-picker-panel__content{max-height:200px;margin:0}.time-select-item{padding:8px 10px;font-size:14px;line-height:20px}.time-select-item.selected:not(.disabled){color:#409EFF;font-weight:700}.time-select-item.disabled{color:#E4E7ED;cursor:not-allowed}.time-select-item:hover{background-color:#F5F7FA;font-weight:700;cursor:pointer}.el-date-editor{position:relative;display:inline-block;text-align:left}.el-date-editor.el-input,.el-date-editor.el-input__inner{width:220px}.el-date-editor--monthrange.el-input,.el-date-editor--monthrange.el-input__inner{width:300px}.el-date-editor--daterange.el-input,.el-date-editor--daterange.el-input__inner,.el-date-editor--timerange.el-input,.el-date-editor--timerange.el-input__inner{width:350px}.el-date-editor--datetimerange.el-input,.el-date-editor--datetimerange.el-input__inner{width:400px}.el-date-editor--dates .el-input__inner{text-overflow:ellipsis;white-space:nowrap}.el-date-editor .el-icon-circle-close{cursor:pointer}.el-date-editor .el-range__icon{font-size:14px;margin-left:-5px;color:#C0C4CC;float:left;line-height:32px}.el-date-editor .el-range-input{-webkit-appearance:none;-moz-appearance:none;appearance:none;border:none;outline:0;display:inline-block;height:100%;margin:0;padding:0;width:39%;text-align:center;font-size:14px;color:#606266}.el-date-editor .el-range-input::-webkit-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input:-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::-ms-input-placeholder{color:#C0C4CC}.el-date-editor .el-range-input::placeholder{color:#C0C4CC}.el-date-editor .el-range-separator{display:inline-block;height:100%;padding:0 5px;margin:0;text-align:center;line-height:32px;font-size:14px;width:5%;color:#303133}.el-date-editor .el-range__close-icon{font-size:14px;color:#C0C4CC;width:25px;display:inline-block;float:right;line-height:32px}.el-range-editor.el-input__inner{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:3px 10px}.el-range-editor .el-range-input{line-height:1}.el-range-editor--medium.el-input__inner{height:36px}.el-range-editor--medium .el-range-separator{line-height:28px;font-size:14px}.el-range-editor--medium .el-range-input{font-size:14px}.el-range-editor--medium .el-range__close-icon,.el-range-editor--medium .el-range__icon{line-height:28px}.el-range-editor--small.el-input__inner{height:32px}.el-range-editor--small .el-range-separator{line-height:24px;font-size:13px}.el-range-editor--small .el-range-input{font-size:13px}.el-range-editor--small .el-range__close-icon,.el-range-editor--small .el-range__icon{line-height:24px}.el-range-editor--mini.el-input__inner{height:28px}.el-range-editor--mini .el-range-separator{line-height:20px;font-size:12px}.el-range-editor--mini .el-range-input{font-size:12px}.el-range-editor--mini .el-range__close-icon,.el-range-editor--mini .el-range__icon{line-height:20px}.el-range-editor.is-disabled{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled:focus,.el-range-editor.is-disabled:hover{border-color:#E4E7ED}.el-range-editor.is-disabled input{background-color:#F5F7FA;color:#C0C4CC;cursor:not-allowed}.el-range-editor.is-disabled input::-webkit-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input:-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::-ms-input-placeholder{color:#C0C4CC}.el-range-editor.is-disabled input::placeholder{color:#C0C4CC}.el-range-editor.is-disabled .el-range-separator{color:#C0C4CC}.el-picker-panel{color:#606266;border:1px solid #E4E7ED;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);background:#FFF;border-radius:4px;line-height:30px;margin:5px 0}.el-picker-panel__body-wrapper::after,.el-picker-panel__body::after{content:"";display:table;clear:both}.el-picker-panel__content{position:relative;margin:15px}.el-picker-panel__footer{border-top:1px solid #e4e4e4;padding:4px;text-align:right;background-color:#FFF;position:relative;font-size:0}.el-picker-panel__shortcut{display:block;width:100%;border:0;background-color:transparent;line-height:28px;font-size:14px;color:#606266;padding-left:12px;text-align:left;outline:0;cursor:pointer}.el-picker-panel__shortcut:hover{color:#409EFF}.el-picker-panel__shortcut.active{background-color:#e6f1fe;color:#409EFF}.el-picker-panel__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-picker-panel__btn[disabled]{color:#ccc;cursor:not-allowed}.el-picker-panel__icon-btn{font-size:12px;color:#303133;border:0;background:0 0;cursor:pointer;outline:0;margin-top:8px}.el-picker-panel__icon-btn:hover{color:#409EFF}.el-picker-panel__icon-btn.is-disabled{color:#bbb}.el-picker-panel__icon-btn.is-disabled:hover{cursor:not-allowed}.el-picker-panel__link-btn{vertical-align:middle}.el-picker-panel [slot=sidebar],.el-picker-panel__sidebar{position:absolute;top:0;bottom:0;width:110px;border-right:1px solid #e4e4e4;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;background-color:#FFF;overflow:auto}.el-picker-panel [slot=sidebar]+.el-picker-panel__body,.el-picker-panel__sidebar+.el-picker-panel__body{margin-left:110px}.el-time-spinner.has-seconds .el-time-spinner__wrapper{width:33.3%}.el-time-spinner__wrapper{max-height:190px;overflow:auto;display:inline-block;width:50%;vertical-align:top;position:relative}.el-time-spinner__wrapper .el-scrollbar__wrap:not(.el-scrollbar__wrap--hidden-default){padding-bottom:15px}.el-time-spinner__input.el-input .el-input__inner,.el-time-spinner__list{padding:0;text-align:center}.el-time-spinner__wrapper.is-arrow{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden}.el-time-spinner__wrapper.is-arrow .el-time-spinner__list{-webkit-transform:translateY(-32px);transform:translateY(-32px)}.el-time-spinner__wrapper.is-arrow .el-time-spinner__item:hover:not(.disabled):not(.active){background:#FFF;cursor:default}.el-time-spinner__arrow{font-size:12px;color:#909399;position:absolute;left:0;width:100%;z-index:1;text-align:center;height:30px;line-height:30px;cursor:pointer}.el-time-spinner__arrow:hover{color:#409EFF}.el-time-spinner__arrow.el-icon-arrow-up{top:10px}.el-time-spinner__arrow.el-icon-arrow-down{bottom:10px}.el-time-spinner__input.el-input{width:70%}.el-time-spinner__list{margin:0;list-style:none}.el-time-spinner__list::after,.el-time-spinner__list::before{content:'';display:block;width:100%;height:80px}.el-time-spinner__item{height:32px;line-height:32px;font-size:12px;color:#606266}.el-time-spinner__item:hover:not(.disabled):not(.active){background:#F5F7FA;cursor:pointer}.el-time-spinner__item.active:not(.disabled){color:#303133;font-weight:700}.el-time-spinner__item.disabled{color:#C0C4CC;cursor:not-allowed}.el-time-panel{margin:5px 0;border:1px solid #E4E7ED;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);border-radius:2px;position:absolute;width:180px;left:0;z-index:1000;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;-webkit-box-sizing:content-box;box-sizing:content-box}.el-time-panel__content{font-size:0;position:relative;overflow:hidden}.el-time-panel__content::after,.el-time-panel__content::before{content:"";top:50%;position:absolute;margin-top:-15px;height:32px;z-index:-1;left:0;right:0;-webkit-box-sizing:border-box;box-sizing:border-box;padding-top:6px;text-align:left;border-top:1px solid #E4E7ED;border-bottom:1px solid #E4E7ED}.el-time-panel__content::after{left:50%;margin-left:12%;margin-right:12%}.el-time-panel__content::before{padding-left:50%;margin-right:12%;margin-left:12%}.el-time-panel__content.has-seconds::after{left:calc(100% / 3 * 2)}.el-time-panel__content.has-seconds::before{padding-left:calc(100% / 3)}.el-time-panel__footer{border-top:1px solid #e4e4e4;padding:4px;height:36px;line-height:25px;text-align:right;-webkit-box-sizing:border-box;box-sizing:border-box}.el-time-panel__btn{border:none;line-height:28px;padding:0 5px;margin:0 5px;cursor:pointer;background-color:transparent;outline:0;font-size:12px;color:#303133}.el-time-panel__btn.confirm{font-weight:800;color:#409EFF}.el-time-range-picker{width:354px;overflow:visible}.el-time-range-picker__content{position:relative;text-align:center;padding:10px}.el-time-range-picker__cell{-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:4px 7px 7px;width:50%;display:inline-block}.el-time-range-picker__header{margin-bottom:5px;text-align:center;font-size:14px}.el-time-range-picker__body{border-radius:2px;border:1px solid #E4E7ED}.el-popover{position:absolute;background:#FFF;min-width:150px;border-radius:4px;border:1px solid #EBEEF5;padding:12px;z-index:2000;color:#606266;line-height:1.4;text-align:justify;font-size:14px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);word-break:break-all}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover,.el-cascader__dropdown,.el-color-picker__panel,.el-message-box,.el-notification{-webkit-box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-popover--plain{padding:18px 20px}.el-popover__title{color:#303133;font-size:16px;line-height:1;margin-bottom:12px}.el-popover:focus,.el-popover:focus:active,.el-popover__reference:focus:hover,.el-popover__reference:focus:not(.focusing){outline-width:0}.v-modal-enter{-webkit-animation:v-modal-in .2s ease;animation:v-modal-in .2s ease}.v-modal-leave{-webkit-animation:v-modal-out .2s ease forwards;animation:v-modal-out .2s ease forwards}@keyframes v-modal-in{0%{opacity:0}}@keyframes v-modal-out{100%{opacity:0}}.v-modal{position:fixed;left:0;top:0;width:100%;height:100%;opacity:.5;background:#000}.el-popup-parent--hidden{overflow:hidden}.el-message-box{display:inline-block;width:420px;padding-bottom:10px;vertical-align:middle;background-color:#FFF;border-radius:4px;border:1px solid #EBEEF5;font-size:18px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);text-align:left;overflow:hidden;-webkit-backface-visibility:hidden;backface-visibility:hidden}.el-message-box__wrapper{position:fixed;top:0;bottom:0;left:0;right:0;text-align:center}.el-message-box__wrapper::after{content:"";display:inline-block;height:100%;width:0;vertical-align:middle}.el-message-box__header{position:relative;padding:15px 15px 10px}.el-message-box__title{padding-left:0;margin-bottom:0;font-size:18px;line-height:1;color:#303133}.el-message-box__headerbtn{position:absolute;top:15px;right:15px;padding:0;border:none;outline:0;background:0 0;font-size:16px;cursor:pointer}.el-form-item.is-error .el-input__inner,.el-form-item.is-error .el-input__inner:focus,.el-form-item.is-error .el-textarea__inner,.el-form-item.is-error .el-textarea__inner:focus,.el-message-box__input input.invalid,.el-message-box__input input.invalid:focus{border-color:#F56C6C}.el-message-box__headerbtn .el-message-box__close{color:#909399}.el-message-box__headerbtn:focus .el-message-box__close,.el-message-box__headerbtn:hover .el-message-box__close{color:#409EFF}.el-message-box__content{padding:10px 15px;color:#606266;font-size:14px}.el-message-box__container{position:relative}.el-message-box__input{padding-top:15px}.el-message-box__status{position:absolute;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);font-size:24px!important}.el-message-box__status::before{padding-left:1px}.el-message-box__status+.el-message-box__message{padding-left:36px;padding-right:12px}.el-message-box__status.el-icon-success{color:#67C23A}.el-message-box__status.el-icon-info{color:#909399}.el-message-box__status.el-icon-warning{color:#E6A23C}.el-message-box__status.el-icon-error{color:#F56C6C}.el-message-box__message{margin:0}.el-message-box__message p{margin:0;line-height:24px}.el-message-box__errormsg{color:#F56C6C;font-size:12px;min-height:18px;margin-top:2px}.el-message-box__btns{padding:5px 15px 0;text-align:right}.el-message-box__btns button:nth-child(2){margin-left:10px}.el-message-box__btns-reverse{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.el-message-box--center{padding-bottom:30px}.el-message-box--center .el-message-box__header{padding-top:30px}.el-message-box--center .el-message-box__title{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message-box--center .el-message-box__status{position:relative;top:auto;padding-right:5px;text-align:center;-webkit-transform:translateY(-1px);transform:translateY(-1px)}.el-message-box--center .el-message-box__message{margin-left:0}.el-message-box--center .el-message-box__btns,.el-message-box--center .el-message-box__content{text-align:center}.el-message-box--center .el-message-box__content{padding-left:27px;padding-right:27px}.msgbox-fade-enter-active{-webkit-animation:msgbox-fade-in .3s;animation:msgbox-fade-in .3s}.msgbox-fade-leave-active{-webkit-animation:msgbox-fade-out .3s;animation:msgbox-fade-out .3s}@-webkit-keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes msgbox-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes msgbox-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-breadcrumb{font-size:14px;line-height:1}.el-breadcrumb::after,.el-breadcrumb::before{display:table;content:""}.el-breadcrumb::after{clear:both}.el-breadcrumb__separator{margin:0 9px;font-weight:700;color:#C0C4CC}.el-breadcrumb__separator[class*=icon]{margin:0 6px;font-weight:400}.el-breadcrumb__item{float:left}.el-breadcrumb__inner{color:#606266}.el-breadcrumb__inner a,.el-breadcrumb__inner.is-link{font-weight:700;text-decoration:none;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1);color:#303133}.el-breadcrumb__inner a:hover,.el-breadcrumb__inner.is-link:hover{color:#409EFF;cursor:pointer}.el-breadcrumb__item:last-child .el-breadcrumb__inner,.el-breadcrumb__item:last-child .el-breadcrumb__inner a,.el-breadcrumb__item:last-child .el-breadcrumb__inner a:hover,.el-breadcrumb__item:last-child .el-breadcrumb__inner:hover{font-weight:400;color:#606266;cursor:text}.el-form--label-left .el-form-item__label{text-align:left}.el-form--label-top .el-form-item__label{float:none;display:inline-block;text-align:left;padding:0 0 10px}.el-form--inline .el-form-item{display:inline-block;margin-right:10px;vertical-align:top}.el-form--inline .el-form-item__label{float:none;display:inline-block}.el-form--inline .el-form-item__content{display:inline-block;vertical-align:top}.el-form--inline.el-form--label-top .el-form-item__content{display:block}.el-form-item{margin-bottom:22px}.el-form-item::after,.el-form-item::before{display:table;content:""}.el-form-item::after{clear:both}.el-form-item .el-form-item{margin-bottom:0}.el-form-item--mini.el-form-item,.el-form-item--small.el-form-item{margin-bottom:18px}.el-form-item .el-input__validateIcon{display:none}.el-form-item--medium .el-form-item__content,.el-form-item--medium .el-form-item__label{line-height:36px}.el-form-item--small .el-form-item__content,.el-form-item--small .el-form-item__label{line-height:32px}.el-form-item--small .el-form-item__error{padding-top:2px}.el-form-item--mini .el-form-item__content,.el-form-item--mini .el-form-item__label{line-height:28px}.el-form-item--mini .el-form-item__error{padding-top:1px}.el-form-item__label-wrap{float:left}.el-form-item__label-wrap .el-form-item__label{display:inline-block;float:none}.el-form-item__label{text-align:right;vertical-align:middle;float:left;font-size:14px;color:#606266;line-height:40px;padding:0 12px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-form-item__content{line-height:40px;position:relative;font-size:14px}.el-form-item__content::after,.el-form-item__content::before{display:table;content:""}.el-form-item__content::after{clear:both}.el-form-item__content .el-input-group{vertical-align:top}.el-form-item__error{color:#F56C6C;font-size:12px;line-height:1;padding-top:4px;position:absolute;top:100%;left:0}.el-form-item__error--inline{position:relative;top:auto;left:auto;display:inline-block;margin-left:10px}.el-form-item.is-required:not(.is-no-asterisk) .el-form-item__label-wrap>.el-form-item__label:before,.el-form-item.is-required:not(.is-no-asterisk)>.el-form-item__label:before{content:'*';color:#F56C6C;margin-right:4px}.el-form-item.is-error .el-input-group__append .el-input__inner,.el-form-item.is-error .el-input-group__prepend .el-input__inner{border-color:transparent}.el-form-item.is-error .el-input__validateIcon{color:#F56C6C}.el-form-item--feedback .el-input__validateIcon{display:inline-block}.el-tabs__header{padding:0;position:relative;margin:0 0 15px}.el-tabs__active-bar{position:absolute;bottom:0;left:0;height:2px;background-color:#409EFF;z-index:1;-webkit-transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:-webkit-transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1);transition:transform .3s cubic-bezier(.645,.045,.355,1),-webkit-transform .3s cubic-bezier(.645,.045,.355,1);list-style:none}.el-tabs__new-tab{float:right;border:1px solid #d3dce6;height:18px;width:18px;line-height:18px;margin:12px 0 9px 10px;border-radius:3px;text-align:center;font-size:12px;color:#d3dce6;cursor:pointer;-webkit-transition:all .15s;transition:all .15s}.el-tabs__new-tab .el-icon-plus{-webkit-transform:scale(.8,.8);transform:scale(.8,.8)}.el-tabs__new-tab:hover{color:#409EFF}.el-tabs__nav-wrap{overflow:hidden;margin-bottom:-1px;position:relative}.el-tabs__nav-wrap::after{content:"";position:absolute;left:0;bottom:0;width:100%;height:2px;background-color:#E4E7ED;z-index:1}.el-tabs__nav-wrap.is-scrollable{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs__nav-scroll{overflow:hidden}.el-tabs__nav-next,.el-tabs__nav-prev{position:absolute;cursor:pointer;line-height:44px;font-size:12px;color:#909399}.el-tabs__nav-next{right:0}.el-tabs__nav-prev{left:0}.el-tabs__nav{white-space:nowrap;position:relative;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;float:left;z-index:2}.el-tabs__nav.is-stretch{min-width:100%;display:-webkit-box;display:-ms-flexbox;display:flex}.el-tabs__nav.is-stretch>*{-webkit-box-flex:1;-ms-flex:1;flex:1;text-align:center}.el-tabs__item{padding:0 20px;height:40px;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:40px;display:inline-block;list-style:none;font-size:14px;font-weight:500;color:#303133;position:relative}.el-tabs__item:focus,.el-tabs__item:focus:active{outline:0}.el-tabs__item:focus.is-active.is-focus:not(:active){-webkit-box-shadow:0 0 2px 2px #409EFF inset;box-shadow:0 0 2px 2px #409EFF inset;border-radius:3px}.el-tabs__item .el-icon-close{border-radius:50%;text-align:center;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);margin-left:5px}.el-tabs__item .el-icon-close:before{-webkit-transform:scale(.9);transform:scale(.9);display:inline-block}.el-tabs--card>.el-tabs__header .el-tabs__active-bar,.el-tabs--left.el-tabs--card .el-tabs__active-bar.is-left,.el-tabs--right.el-tabs--card .el-tabs__active-bar.is-right{display:none}.el-tabs__item .el-icon-close:hover{background-color:#C0C4CC;color:#FFF}.el-tabs__item.is-active{color:#409EFF}.el-tabs__item:hover{color:#409EFF;cursor:pointer}.el-tabs__item.is-disabled{color:#C0C4CC;cursor:default}.el-tabs__content{overflow:hidden;position:relative}.el-tabs--card>.el-tabs__header{border-bottom:1px solid #E4E7ED}.el-tabs--card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--card>.el-tabs__header .el-tabs__nav{border:1px solid #E4E7ED;border-bottom:none;border-radius:4px 4px 0 0;-webkit-box-sizing:border-box;box-sizing:border-box}.el-tabs--card>.el-tabs__header .el-tabs__item .el-icon-close{position:relative;font-size:12px;width:0;height:14px;vertical-align:middle;line-height:15px;overflow:hidden;top:-1px;right:-2px;-webkit-transform-origin:100% 50%;transform-origin:100% 50%}.el-tabs--card>.el-tabs__header .el-tabs__item{border-bottom:1px solid transparent;border-left:1px solid #E4E7ED;-webkit-transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1);transition:color .3s cubic-bezier(.645,.045,.355,1),padding .3s cubic-bezier(.645,.045,.355,1)}.el-tabs--card>.el-tabs__header .el-tabs__item:first-child{border-left:none}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover{padding-left:13px;padding-right:13px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-closable:hover .el-icon-close{width:14px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active{border-bottom-color:#FFF}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable{padding-left:20px;padding-right:20px}.el-tabs--card>.el-tabs__header .el-tabs__item.is-active.is-closable .el-icon-close{width:14px}.el-tabs--border-card{background:#FFF;border:1px solid #DCDFE6;-webkit-box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04);box-shadow:0 2px 4px 0 rgba(0,0,0,.12),0 0 6px 0 rgba(0,0,0,.04)}.el-tabs--border-card>.el-tabs__content{padding:15px}.el-tabs--border-card>.el-tabs__header{background-color:#F5F7FA;border-bottom:1px solid #E4E7ED;margin:0}.el-tabs--border-card>.el-tabs__header .el-tabs__nav-wrap::after{content:none}.el-tabs--border-card>.el-tabs__header .el-tabs__item{-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);border:1px solid transparent;margin-top:-1px;color:#909399}.el-tabs--border-card>.el-tabs__header .el-tabs__item+.el-tabs__item,.el-tabs--border-card>.el-tabs__header .el-tabs__item:first-child{margin-left:-1px}.el-col-offset-0,.el-tabs--border-card>.el-tabs__header .is-scrollable .el-tabs__item:first-child{margin-left:0}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-active{color:#409EFF;background-color:#FFF;border-right-color:#DCDFE6;border-left-color:#DCDFE6}.el-tabs--border-card>.el-tabs__header .el-tabs__item:not(.is-disabled):hover{color:#409EFF}.el-tabs--border-card>.el-tabs__header .el-tabs__item.is-disabled{color:#C0C4CC}.el-tabs--bottom .el-tabs__item.is-bottom:nth-child(2),.el-tabs--bottom .el-tabs__item.is-top:nth-child(2),.el-tabs--top .el-tabs__item.is-bottom:nth-child(2),.el-tabs--top .el-tabs__item.is-top:nth-child(2){padding-left:0}.el-tabs--bottom .el-tabs__item.is-bottom:last-child,.el-tabs--bottom .el-tabs__item.is-top:last-child,.el-tabs--top .el-tabs__item.is-bottom:last-child,.el-tabs--top .el-tabs__item.is-top:last-child{padding-right:0}.el-cascader-menu:last-child .el-cascader-node,.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:last-child,.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:last-child{padding-right:20px}.el-tabs--bottom .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--bottom.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--left>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top .el-tabs--right>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--border-card>.el-tabs__header .el-tabs__item:nth-child(2),.el-tabs--top.el-tabs--card>.el-tabs__header .el-tabs__item:nth-child(2){padding-left:20px}.el-tabs--bottom .el-tabs__header.is-bottom{margin-bottom:0;margin-top:10px}.el-tabs--bottom.el-tabs--border-card .el-tabs__header.is-bottom{border-bottom:0;border-top:1px solid #DCDFE6}.el-tabs--bottom.el-tabs--border-card .el-tabs__nav-wrap.is-bottom{margin-top:-1px;margin-bottom:0}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom:not(.is-active){border:1px solid transparent}.el-tabs--bottom.el-tabs--border-card .el-tabs__item.is-bottom{margin:0 -1px -1px}.el-tabs--left,.el-tabs--right{overflow:hidden}.el-tabs--left .el-tabs__header.is-left,.el-tabs--left .el-tabs__header.is-right,.el-tabs--left .el-tabs__nav-scroll,.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__header.is-left,.el-tabs--right .el-tabs__header.is-right,.el-tabs--right .el-tabs__nav-scroll,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{height:100%}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__active-bar.is-right,.el-tabs--right .el-tabs__active-bar.is-left,.el-tabs--right .el-tabs__active-bar.is-right{top:0;bottom:auto;width:2px;height:auto}.el-tabs--left .el-tabs__nav-wrap.is-left,.el-tabs--left .el-tabs__nav-wrap.is-right,.el-tabs--right .el-tabs__nav-wrap.is-left,.el-tabs--right .el-tabs__nav-wrap.is-right{margin-bottom:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{height:30px;line-height:30px;width:100%;text-align:center;cursor:pointer}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next i,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev i{-webkit-transform:rotateZ(90deg);transform:rotateZ(90deg)}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-prev,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-prev{left:auto;top:0}.el-tabs--left .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--left .el-tabs__nav-wrap.is-right>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-left>.el-tabs__nav-next,.el-tabs--right .el-tabs__nav-wrap.is-right>.el-tabs__nav-next{right:auto;bottom:0}.el-tabs--left .el-tabs__active-bar.is-left,.el-tabs--left .el-tabs__nav-wrap.is-left::after{right:0;left:auto}.el-tabs--left .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--left .el-tabs__nav-wrap.is-right.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-left.is-scrollable,.el-tabs--right .el-tabs__nav-wrap.is-right.is-scrollable{padding:30px 0}.el-tabs--left .el-tabs__nav-wrap.is-left::after,.el-tabs--left .el-tabs__nav-wrap.is-right::after,.el-tabs--right .el-tabs__nav-wrap.is-left::after,.el-tabs--right .el-tabs__nav-wrap.is-right::after{height:100%;width:2px;bottom:auto;top:0}.el-tabs--left .el-tabs__nav.is-left,.el-tabs--left .el-tabs__nav.is-right,.el-tabs--right .el-tabs__nav.is-left,.el-tabs--right .el-tabs__nav.is-right{float:none}.el-tabs--left .el-tabs__item.is-left,.el-tabs--left .el-tabs__item.is-right,.el-tabs--right .el-tabs__item.is-left,.el-tabs--right .el-tabs__item.is-right{display:block}.el-tabs--left .el-tabs__header.is-left{float:left;margin-bottom:0;margin-right:10px}.el-button-group>.el-button:not(:last-child),.el-tabs--left .el-tabs__nav-wrap.is-left{margin-right:-1px}.el-tabs--left .el-tabs__item.is-left{text-align:right}.el-tabs--left.el-tabs--card .el-tabs__item.is-left{border-left:none;border-right:1px solid #E4E7ED;border-bottom:none;border-top:1px solid #E4E7ED;text-align:left}.el-tabs--left.el-tabs--card .el-tabs__item.is-left:first-child{border-right:1px solid #E4E7ED;border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active{border:1px solid #E4E7ED;border-right-color:#fff;border-left:none;border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:first-child{border-top:none}.el-tabs--left.el-tabs--card .el-tabs__item.is-left.is-active:last-child{border-bottom:none}.el-tabs--left.el-tabs--card .el-tabs__nav{border-radius:4px 0 0 4px;border-bottom:1px solid #E4E7ED;border-right:none}.el-tabs--left.el-tabs--card .el-tabs__new-tab{float:none}.el-tabs--left.el-tabs--border-card .el-tabs__header.is-left{border-right:1px solid #dfe4ed}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left{border:1px solid transparent;margin:-1px 0 -1px -1px}.el-tabs--left.el-tabs--border-card .el-tabs__item.is-left.is-active{border-color:#d1dbe5 transparent}.el-tabs--right .el-tabs__header.is-right{float:right;margin-bottom:0;margin-left:10px}.el-tabs--right .el-tabs__nav-wrap.is-right{margin-left:-1px}.el-tabs--right .el-tabs__nav-wrap.is-right::after{left:0;right:auto}.el-tabs--right .el-tabs__active-bar.is-right{left:0}.el-tabs--right.el-tabs--card .el-tabs__item.is-right{border-bottom:none;border-top:1px solid #E4E7ED}.el-tabs--right.el-tabs--card .el-tabs__item.is-right:first-child{border-left:1px solid #E4E7ED;border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active{border:1px solid #E4E7ED;border-left-color:#fff;border-right:none;border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:first-child{border-top:none}.el-tabs--right.el-tabs--card .el-tabs__item.is-right.is-active:last-child{border-bottom:none}.el-tabs--right.el-tabs--card .el-tabs__nav{border-radius:0 4px 4px 0;border-bottom:1px solid #E4E7ED;border-left:none}.el-tabs--right.el-tabs--border-card .el-tabs__header.is-right{border-left:1px solid #dfe4ed}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right{border:1px solid transparent;margin:-1px -1px -1px 0}.el-tabs--right.el-tabs--border-card .el-tabs__item.is-right.is-active{border-color:#d1dbe5 transparent}.slideInLeft-transition,.slideInRight-transition{display:inline-block}.slideInRight-enter{-webkit-animation:slideInRight-enter .3s;animation:slideInRight-enter .3s}.slideInRight-leave{position:absolute;left:0;right:0;-webkit-animation:slideInRight-leave .3s;animation:slideInRight-leave .3s}.slideInLeft-enter{-webkit-animation:slideInLeft-enter .3s;animation:slideInLeft-enter .3s}.slideInLeft-leave{position:absolute;left:0;right:0;-webkit-animation:slideInLeft-leave .3s;animation:slideInLeft-leave .3s}@-webkit-keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInRight-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@keyframes slideInRight-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(100%);transform:translateX(100%);opacity:0}}@-webkit-keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@keyframes slideInLeft-enter{0%{opacity:0;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}to{opacity:1;-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0)}}@-webkit-keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}@keyframes slideInLeft-leave{0%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(0);transform:translateX(0);opacity:1}100%{-webkit-transform-origin:0 0;transform-origin:0 0;-webkit-transform:translateX(-100%);transform:translateX(-100%);opacity:0}}.el-tree{position:relative;cursor:default;background:#FFF;color:#606266}.el-tree__empty-block{position:relative;min-height:60px;text-align:center;width:100%;height:100%}.el-tree__empty-text{position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);color:#909399;font-size:14px}.el-tree__drop-indicator{position:absolute;left:0;right:0;height:1px;background-color:#409EFF}.el-tree-node{white-space:nowrap;outline:0}.el-tree-node:focus>.el-tree-node__content{background-color:#F5F7FA}.el-tree-node.is-drop-inner>.el-tree-node__content .el-tree-node__label{background-color:#409EFF;color:#fff}.el-tree-node__content:hover,.el-upload-list__item:hover{background-color:#F5F7FA}.el-tree-node__content{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:26px;cursor:pointer}.el-tree-node__content>.el-tree-node__expand-icon{padding:6px}.el-tree-node__content>label.el-checkbox{margin-right:8px}.el-tree.is-dragging .el-tree-node__content{cursor:move}.el-tree.is-dragging .el-tree-node__content *{pointer-events:none}.el-tree.is-dragging.is-drop-not-allow .el-tree-node__content{cursor:not-allowed}.el-tree-node__expand-icon{cursor:pointer;color:#C0C4CC;font-size:12px;-webkit-transform:rotate(0);transform:rotate(0);-webkit-transition:-webkit-transform .3s ease-in-out;transition:-webkit-transform .3s ease-in-out;transition:transform .3s ease-in-out;transition:transform .3s ease-in-out,-webkit-transform .3s ease-in-out}.el-tree-node__expand-icon.expanded{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-tree-node__expand-icon.is-leaf{color:transparent;cursor:default}.el-tree-node__label{font-size:14px}.el-tree-node__loading-icon{margin-right:8px;font-size:14px;color:#C0C4CC}.el-tree-node>.el-tree-node__children{overflow:hidden;background-color:transparent}.el-tree-node.is-expanded>.el-tree-node__children{display:block}.el-tree--highlight-current .el-tree-node.is-current>.el-tree-node__content{background-color:#f0f7ff}.el-alert{width:100%;padding:8px 16px;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;position:relative;background-color:#FFF;overflow:hidden;opacity:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-transition:opacity .2s;transition:opacity .2s}.el-alert.is-light .el-alert__closebtn{color:#C0C4CC}.el-alert.is-dark .el-alert__closebtn,.el-alert.is-dark .el-alert__description{color:#FFF}.el-alert.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-alert--success.is-light{background-color:#f0f9eb;color:#67C23A}.el-alert--success.is-light .el-alert__description{color:#67C23A}.el-alert--success.is-dark{background-color:#67C23A;color:#FFF}.el-alert--info.is-light{background-color:#f4f4f5;color:#909399}.el-alert--info.is-dark{background-color:#909399;color:#FFF}.el-alert--info .el-alert__description{color:#909399}.el-alert--warning.is-light{background-color:#fdf6ec;color:#E6A23C}.el-alert--warning.is-light .el-alert__description{color:#E6A23C}.el-alert--warning.is-dark{background-color:#E6A23C;color:#FFF}.el-alert--error.is-light{background-color:#fef0f0;color:#F56C6C}.el-alert--error.is-light .el-alert__description{color:#F56C6C}.el-alert--error.is-dark{background-color:#F56C6C;color:#FFF}.el-alert__content{display:table-cell;padding:0 8px}.el-alert__icon{font-size:16px;width:16px}.el-alert__icon.is-big{font-size:28px;width:28px}.el-alert__title{font-size:13px;line-height:18px}.el-alert__title.is-bold{font-weight:700}.el-alert .el-alert__description{font-size:12px;margin:5px 0 0}.el-alert__closebtn{font-size:12px;opacity:1;position:absolute;top:12px;right:15px;cursor:pointer}.el-alert-fade-enter,.el-alert-fade-leave-active,.el-loading-fade-enter,.el-loading-fade-leave-active,.el-notification-fade-leave-active,.el-upload iframe{opacity:0}.el-carousel__arrow--right,.el-notification.right{right:16px}.el-alert__closebtn.is-customed{font-style:normal;font-size:13px;top:9px}.el-notification{display:-webkit-box;display:-ms-flexbox;display:flex;width:330px;padding:14px 26px 14px 13px;border-radius:8px;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #EBEEF5;position:fixed;background-color:#FFF;box-shadow:0 2px 12px 0 rgba(0,0,0,.1);-webkit-transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s;transition:opacity .3s,transform .3s,left .3s,right .3s,top .4s,bottom .3s,-webkit-transform .3s;overflow:hidden}.el-notification.left{left:16px}.el-notification__group{margin-left:13px;margin-right:8px}.el-notification__title{font-weight:700;font-size:16px;color:#303133;margin:0}.el-notification__content{font-size:14px;line-height:21px;margin:6px 0 0;color:#606266;text-align:justify}.el-notification__content p{margin:0}.el-notification__icon{height:24px;width:24px;font-size:24px}.el-notification__closeBtn{position:absolute;top:18px;right:15px;cursor:pointer;color:#909399;font-size:16px}.el-notification__closeBtn:hover{color:#606266}.el-notification .el-icon-success{color:#67C23A}.el-notification .el-icon-error{color:#F56C6C}.el-notification .el-icon-info{color:#909399}.el-notification .el-icon-warning{color:#E6A23C}.el-notification-fade-enter.right{right:0;-webkit-transform:translateX(100%);transform:translateX(100%)}.el-notification-fade-enter.left{left:0;-webkit-transform:translateX(-100%);transform:translateX(-100%)}.el-input-number{position:relative;display:inline-block;width:180px;line-height:38px}.el-input-number .el-input{display:block}.el-input-number .el-input__inner{-webkit-appearance:none;padding-left:50px;padding-right:50px;text-align:center}.el-input-number__decrease,.el-input-number__increase{position:absolute;z-index:1;top:1px;width:40px;height:auto;text-align:center;background:#F5F7FA;color:#606266;cursor:pointer;font-size:13px}.el-input-number__decrease:hover,.el-input-number__increase:hover{color:#409EFF}.el-input-number__decrease:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled),.el-input-number__increase:hover:not(.is-disabled)~.el-input .el-input__inner:not(.is-disabled){border-color:#409EFF}.el-input-number__decrease.is-disabled,.el-input-number__increase.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-input-number__increase{right:1px;border-radius:0 4px 4px 0;border-left:1px solid #DCDFE6}.el-input-number__decrease{left:1px;border-radius:4px 0 0 4px;border-right:1px solid #DCDFE6}.el-input-number.is-disabled .el-input-number__decrease,.el-input-number.is-disabled .el-input-number__increase{border-color:#E4E7ED;color:#E4E7ED}.el-input-number.is-disabled .el-input-number__decrease:hover,.el-input-number.is-disabled .el-input-number__increase:hover{color:#E4E7ED;cursor:not-allowed}.el-input-number--medium{width:200px;line-height:34px}.el-input-number--medium .el-input-number__decrease,.el-input-number--medium .el-input-number__increase{width:36px;font-size:14px}.el-input-number--medium .el-input__inner{padding-left:43px;padding-right:43px}.el-input-number--small{width:130px;line-height:30px}.el-input-number--small .el-input-number__decrease,.el-input-number--small .el-input-number__increase{width:32px;font-size:13px}.el-input-number--small .el-input-number__decrease [class*=el-icon],.el-input-number--small .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.9);transform:scale(.9)}.el-input-number--small .el-input__inner{padding-left:39px;padding-right:39px}.el-input-number--mini{width:130px;line-height:26px}.el-input-number--mini .el-input-number__decrease,.el-input-number--mini .el-input-number__increase{width:28px;font-size:12px}.el-input-number--mini .el-input-number__decrease [class*=el-icon],.el-input-number--mini .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number--mini .el-input__inner{padding-left:35px;padding-right:35px}.el-input-number.is-without-controls .el-input__inner{padding-left:15px;padding-right:15px}.el-input-number.is-controls-right .el-input__inner{padding-left:15px;padding-right:50px}.el-input-number.is-controls-right .el-input-number__decrease,.el-input-number.is-controls-right .el-input-number__increase{height:auto;line-height:19px}.el-input-number.is-controls-right .el-input-number__decrease [class*=el-icon],.el-input-number.is-controls-right .el-input-number__increase [class*=el-icon]{-webkit-transform:scale(.8);transform:scale(.8)}.el-input-number.is-controls-right .el-input-number__increase{border-radius:0 4px 0 0;border-bottom:1px solid #DCDFE6}.el-input-number.is-controls-right .el-input-number__decrease{right:1px;bottom:1px;top:auto;left:auto;border-right:none;border-left:1px solid #DCDFE6;border-radius:0 0 4px}.el-input-number.is-controls-right[class*=medium] [class*=decrease],.el-input-number.is-controls-right[class*=medium] [class*=increase]{line-height:17px}.el-input-number.is-controls-right[class*=small] [class*=decrease],.el-input-number.is-controls-right[class*=small] [class*=increase]{line-height:15px}.el-input-number.is-controls-right[class*=mini] [class*=decrease],.el-input-number.is-controls-right[class*=mini] [class*=increase]{line-height:13px}.el-tooltip:focus:hover,.el-tooltip:focus:not(.focusing){outline-width:0}.el-tooltip__popper{position:absolute;border-radius:4px;padding:10px;z-index:2000;font-size:12px;line-height:1.2;min-width:10px;word-wrap:break-word}.el-tooltip__popper .popper__arrow,.el-tooltip__popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-tooltip__popper .popper__arrow{border-width:6px}.el-tooltip__popper .popper__arrow::after{content:" ";border-width:5px}.el-button-group::after,.el-button-group::before,.el-color-dropdown__main-wrapper::after,.el-link.is-underline:hover:after,.el-page-header__left::after,.el-progress-bar__inner::after,.el-row::after,.el-row::before,.el-slider::after,.el-slider::before,.el-slider__button-wrapper::after,.el-transfer-panel .el-transfer-panel__footer::after,.el-upload-cover::after,.el-upload-list--picture-card .el-upload-list__item-actions::after{content:""}.el-tooltip__popper[x-placement^=top]{margin-bottom:12px}.el-tooltip__popper[x-placement^=top] .popper__arrow{bottom:-6px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-5px;border-top-color:#303133;border-bottom-width:0}.el-tooltip__popper[x-placement^=bottom]{margin-top:12px}.el-tooltip__popper[x-placement^=bottom] .popper__arrow{top:-6px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-5px;border-top-width:0;border-bottom-color:#303133}.el-tooltip__popper[x-placement^=right]{margin-left:12px}.el-tooltip__popper[x-placement^=right] .popper__arrow{left:-6px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=right] .popper__arrow::after{bottom:-5px;left:1px;border-right-color:#303133;border-left-width:0}.el-tooltip__popper[x-placement^=left]{margin-right:12px}.el-tooltip__popper[x-placement^=left] .popper__arrow{right:-6px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-5px;margin-left:-5px;border-right-width:0;border-left-color:#303133}.el-tooltip__popper.is-dark{background:#303133;color:#FFF}.el-tooltip__popper.is-light{background:#FFF;border:1px solid #303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow{border-top-color:#303133}.el-tooltip__popper.is-light[x-placement^=top] .popper__arrow::after{border-top-color:#FFF}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow{border-bottom-color:#303133}.el-tooltip__popper.is-light[x-placement^=bottom] .popper__arrow::after{border-bottom-color:#FFF}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow{border-left-color:#303133}.el-tooltip__popper.is-light[x-placement^=left] .popper__arrow::after{border-left-color:#FFF}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow{border-right-color:#303133}.el-tooltip__popper.is-light[x-placement^=right] .popper__arrow::after{border-right-color:#FFF}.el-slider::after,.el-slider::before{display:table}.el-slider__button-wrapper .el-tooltip,.el-slider__button-wrapper::after{display:inline-block;vertical-align:middle}.el-slider::after{clear:both}.el-slider__runway{width:100%;height:6px;margin:16px 0;background-color:#E4E7ED;border-radius:3px;position:relative;cursor:pointer;vertical-align:middle}.el-slider__runway.show-input{margin-right:160px;width:auto}.el-slider__runway.disabled{cursor:default}.el-slider__runway.disabled .el-slider__bar{background-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button{border-color:#C0C4CC}.el-slider__runway.disabled .el-slider__button-wrapper.dragging,.el-slider__runway.disabled .el-slider__button-wrapper.hover,.el-slider__runway.disabled .el-slider__button-wrapper:hover{cursor:not-allowed}.el-slider__runway.disabled .el-slider__button.dragging,.el-slider__runway.disabled .el-slider__button.hover,.el-slider__runway.disabled .el-slider__button:hover{-webkit-transform:scale(1);transform:scale(1);cursor:not-allowed}.el-slider__button-wrapper,.el-slider__stop{-webkit-transform:translateX(-50%);position:absolute}.el-slider__input{float:right;margin-top:3px;width:130px}.el-slider__input.el-input-number--mini{margin-top:5px}.el-slider__input.el-input-number--medium{margin-top:0}.el-slider__input.el-input-number--large{margin-top:-2px}.el-slider__bar{height:6px;background-color:#409EFF;border-top-left-radius:3px;border-bottom-left-radius:3px;position:absolute}.el-slider__button-wrapper{height:36px;width:36px;z-index:1001;top:-15px;transform:translateX(-50%);background-color:transparent;text-align:center;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;line-height:normal}.el-image-viewer__btn,.el-slider__button,.el-step__icon-inner{-moz-user-select:none;-ms-user-select:none}.el-slider__button-wrapper::after{height:100%}.el-slider__button-wrapper.hover,.el-slider__button-wrapper:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button-wrapper.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__button{width:16px;height:16px;border:2px solid #409EFF;background-color:#FFF;border-radius:50%;-webkit-transition:.2s;transition:.2s;-webkit-user-select:none;user-select:none}.el-slider__button.dragging,.el-slider__button.hover,.el-slider__button:hover{-webkit-transform:scale(1.2);transform:scale(1.2)}.el-slider__button.hover,.el-slider__button:hover{cursor:-webkit-grab;cursor:grab}.el-slider__button.dragging{cursor:-webkit-grabbing;cursor:grabbing}.el-slider__stop{height:6px;width:6px;border-radius:100%;background-color:#FFF;transform:translateX(-50%)}.el-slider__marks{top:0;left:12px;width:18px;height:100%}.el-slider__marks-text{position:absolute;-webkit-transform:translateX(-50%);transform:translateX(-50%);font-size:14px;color:#909399;margin-top:15px}.el-slider.is-vertical{position:relative}.el-slider.is-vertical .el-slider__runway{width:6px;height:100%;margin:0 16px}.el-slider.is-vertical .el-slider__bar{width:6px;height:auto;border-radius:0 0 3px 3px}.el-slider.is-vertical .el-slider__button-wrapper{top:auto;left:-15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical .el-slider__stop{-webkit-transform:translateY(50%);transform:translateY(50%)}.el-slider.is-vertical.el-slider--with-input{padding-bottom:58px}.el-slider.is-vertical.el-slider--with-input .el-slider__input{overflow:visible;float:none;position:absolute;bottom:22px;width:36px;margin-top:15px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input__inner{text-align:center;padding-left:5px;padding-right:5px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{top:32px;margin-top:-1px;border:1px solid #DCDFE6;line-height:20px;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__decrease{width:18px;right:18px;border-bottom-left-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase{width:19px;border-bottom-right-radius:4px}.el-slider.is-vertical.el-slider--with-input .el-slider__input .el-input-number__increase~.el-input .el-input__inner{border-bottom-left-radius:0;border-bottom-right-radius:0}.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:hover .el-input-number__increase{border-color:#C0C4CC}.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__decrease,.el-slider.is-vertical.el-slider--with-input .el-slider__input:active .el-input-number__increase{border-color:#409EFF}.el-slider.is-vertical .el-slider__marks-text{margin-top:0;left:15px;-webkit-transform:translateY(50%);transform:translateY(50%)}.el-loading-parent--relative{position:relative!important}.el-loading-parent--hidden{overflow:hidden!important}.el-loading-mask{position:absolute;z-index:2000;background-color:rgba(255,255,255,.9);margin:0;top:0;right:0;bottom:0;left:0;-webkit-transition:opacity .3s;transition:opacity .3s}.el-loading-mask.is-fullscreen{position:fixed}.el-loading-mask.is-fullscreen .el-loading-spinner{margin-top:-25px}.el-loading-mask.is-fullscreen .el-loading-spinner .circular{height:50px;width:50px}.el-loading-spinner{top:50%;margin-top:-21px;width:100%;text-align:center;position:absolute}.el-col-pull-0,.el-col-pull-1,.el-col-pull-10,.el-col-pull-11,.el-col-pull-12,.el-col-pull-13,.el-col-pull-14,.el-col-pull-15,.el-col-pull-16,.el-col-pull-17,.el-col-pull-18,.el-col-pull-19,.el-col-pull-2,.el-col-pull-20,.el-col-pull-21,.el-col-pull-22,.el-col-pull-23,.el-col-pull-24,.el-col-pull-3,.el-col-pull-4,.el-col-pull-5,.el-col-pull-6,.el-col-pull-7,.el-col-pull-8,.el-col-pull-9,.el-col-push-0,.el-col-push-1,.el-col-push-10,.el-col-push-11,.el-col-push-12,.el-col-push-13,.el-col-push-14,.el-col-push-15,.el-col-push-16,.el-col-push-17,.el-col-push-18,.el-col-push-19,.el-col-push-2,.el-col-push-20,.el-col-push-21,.el-col-push-22,.el-col-push-23,.el-col-push-24,.el-col-push-3,.el-col-push-4,.el-col-push-5,.el-col-push-6,.el-col-push-7,.el-col-push-8,.el-col-push-9,.el-row,.el-upload-dragger,.el-upload-list__item{position:relative}.el-loading-spinner .el-loading-text{color:#409EFF;margin:3px 0;font-size:14px}.el-loading-spinner .circular{height:42px;width:42px;-webkit-animation:loading-rotate 2s linear infinite;animation:loading-rotate 2s linear infinite}.el-loading-spinner .path{-webkit-animation:loading-dash 1.5s ease-in-out infinite;animation:loading-dash 1.5s ease-in-out infinite;stroke-dasharray:90,150;stroke-dashoffset:0;stroke-width:2;stroke:#409EFF;stroke-linecap:round}.el-loading-spinner i{color:#409EFF}@-webkit-keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes loading-rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}@keyframes loading-dash{0%{stroke-dasharray:1,200;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-40px}100%{stroke-dasharray:90,150;stroke-dashoffset:-120px}}.el-row{-webkit-box-sizing:border-box;box-sizing:border-box}.el-row::after,.el-row::before{display:table}.el-row::after{clear:both}.el-row--flex{display:-webkit-box;display:-ms-flexbox;display:flex}.el-col-0,.el-row--flex:after,.el-row--flex:before{display:none}.el-row--flex.is-justify-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-row--flex.is-justify-end{-webkit-box-pack:end;-ms-flex-pack:end;justify-content:flex-end}.el-row--flex.is-justify-space-between{-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between}.el-row--flex.is-justify-space-around{-ms-flex-pack:distribute;justify-content:space-around}.el-row--flex.is-align-top{-webkit-box-align:start;-ms-flex-align:start;align-items:flex-start}.el-row--flex.is-align-middle{-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-row--flex.is-align-bottom{-webkit-box-align:end;-ms-flex-align:end;align-items:flex-end}[class*=el-col-]{float:left;-webkit-box-sizing:border-box;box-sizing:border-box}.el-col-0{width:0%}.el-col-pull-0{right:0}.el-col-push-0{left:0}.el-col-1{width:4.16667%}.el-col-offset-1{margin-left:4.16667%}.el-col-pull-1{right:4.16667%}.el-col-push-1{left:4.16667%}.el-col-2{width:8.33333%}.el-col-offset-2{margin-left:8.33333%}.el-col-pull-2{right:8.33333%}.el-col-push-2{left:8.33333%}.el-col-3{width:12.5%}.el-col-offset-3{margin-left:12.5%}.el-col-pull-3{right:12.5%}.el-col-push-3{left:12.5%}.el-col-4{width:16.66667%}.el-col-offset-4{margin-left:16.66667%}.el-col-pull-4{right:16.66667%}.el-col-push-4{left:16.66667%}.el-col-5{width:20.83333%}.el-col-offset-5{margin-left:20.83333%}.el-col-pull-5{right:20.83333%}.el-col-push-5{left:20.83333%}.el-col-6{width:25%}.el-col-offset-6{margin-left:25%}.el-col-pull-6{right:25%}.el-col-push-6{left:25%}.el-col-7{width:29.16667%}.el-col-offset-7{margin-left:29.16667%}.el-col-pull-7{right:29.16667%}.el-col-push-7{left:29.16667%}.el-col-8{width:33.33333%}.el-col-offset-8{margin-left:33.33333%}.el-col-pull-8{right:33.33333%}.el-col-push-8{left:33.33333%}.el-col-9{width:37.5%}.el-col-offset-9{margin-left:37.5%}.el-col-pull-9{right:37.5%}.el-col-push-9{left:37.5%}.el-col-10{width:41.66667%}.el-col-offset-10{margin-left:41.66667%}.el-col-pull-10{right:41.66667%}.el-col-push-10{left:41.66667%}.el-col-11{width:45.83333%}.el-col-offset-11{margin-left:45.83333%}.el-col-pull-11{right:45.83333%}.el-col-push-11{left:45.83333%}.el-col-12{width:50%}.el-col-offset-12{margin-left:50%}.el-col-pull-12{right:50%}.el-col-push-12{left:50%}.el-col-13{width:54.16667%}.el-col-offset-13{margin-left:54.16667%}.el-col-pull-13{right:54.16667%}.el-col-push-13{left:54.16667%}.el-col-14{width:58.33333%}.el-col-offset-14{margin-left:58.33333%}.el-col-pull-14{right:58.33333%}.el-col-push-14{left:58.33333%}.el-col-15{width:62.5%}.el-col-offset-15{margin-left:62.5%}.el-col-pull-15{right:62.5%}.el-col-push-15{left:62.5%}.el-col-16{width:66.66667%}.el-col-offset-16{margin-left:66.66667%}.el-col-pull-16{right:66.66667%}.el-col-push-16{left:66.66667%}.el-col-17{width:70.83333%}.el-col-offset-17{margin-left:70.83333%}.el-col-pull-17{right:70.83333%}.el-col-push-17{left:70.83333%}.el-col-18{width:75%}.el-col-offset-18{margin-left:75%}.el-col-pull-18{right:75%}.el-col-push-18{left:75%}.el-col-19{width:79.16667%}.el-col-offset-19{margin-left:79.16667%}.el-col-pull-19{right:79.16667%}.el-col-push-19{left:79.16667%}.el-col-20{width:83.33333%}.el-col-offset-20{margin-left:83.33333%}.el-col-pull-20{right:83.33333%}.el-col-push-20{left:83.33333%}.el-col-21{width:87.5%}.el-col-offset-21{margin-left:87.5%}.el-col-pull-21{right:87.5%}.el-col-push-21{left:87.5%}.el-col-22{width:91.66667%}.el-col-offset-22{margin-left:91.66667%}.el-col-pull-22{right:91.66667%}.el-col-push-22{left:91.66667%}.el-col-23{width:95.83333%}.el-col-offset-23{margin-left:95.83333%}.el-col-pull-23{right:95.83333%}.el-col-push-23{left:95.83333%}.el-col-24{width:100%}.el-col-offset-24{margin-left:100%}.el-col-pull-24{right:100%}.el-col-push-24{left:100%}@media only screen and (max-width:767px){.el-col-xs-0{display:none;width:0%}.el-col-xs-offset-0{margin-left:0}.el-col-xs-pull-0{position:relative;right:0}.el-col-xs-push-0{position:relative;left:0}.el-col-xs-1{width:4.16667%}.el-col-xs-offset-1{margin-left:4.16667%}.el-col-xs-pull-1{position:relative;right:4.16667%}.el-col-xs-push-1{position:relative;left:4.16667%}.el-col-xs-2{width:8.33333%}.el-col-xs-offset-2{margin-left:8.33333%}.el-col-xs-pull-2{position:relative;right:8.33333%}.el-col-xs-push-2{position:relative;left:8.33333%}.el-col-xs-3{width:12.5%}.el-col-xs-offset-3{margin-left:12.5%}.el-col-xs-pull-3{position:relative;right:12.5%}.el-col-xs-push-3{position:relative;left:12.5%}.el-col-xs-4{width:16.66667%}.el-col-xs-offset-4{margin-left:16.66667%}.el-col-xs-pull-4{position:relative;right:16.66667%}.el-col-xs-push-4{position:relative;left:16.66667%}.el-col-xs-5{width:20.83333%}.el-col-xs-offset-5{margin-left:20.83333%}.el-col-xs-pull-5{position:relative;right:20.83333%}.el-col-xs-push-5{position:relative;left:20.83333%}.el-col-xs-6{width:25%}.el-col-xs-offset-6{margin-left:25%}.el-col-xs-pull-6{position:relative;right:25%}.el-col-xs-push-6{position:relative;left:25%}.el-col-xs-7{width:29.16667%}.el-col-xs-offset-7{margin-left:29.16667%}.el-col-xs-pull-7{position:relative;right:29.16667%}.el-col-xs-push-7{position:relative;left:29.16667%}.el-col-xs-8{width:33.33333%}.el-col-xs-offset-8{margin-left:33.33333%}.el-col-xs-pull-8{position:relative;right:33.33333%}.el-col-xs-push-8{position:relative;left:33.33333%}.el-col-xs-9{width:37.5%}.el-col-xs-offset-9{margin-left:37.5%}.el-col-xs-pull-9{position:relative;right:37.5%}.el-col-xs-push-9{position:relative;left:37.5%}.el-col-xs-10{width:41.66667%}.el-col-xs-offset-10{margin-left:41.66667%}.el-col-xs-pull-10{position:relative;right:41.66667%}.el-col-xs-push-10{position:relative;left:41.66667%}.el-col-xs-11{width:45.83333%}.el-col-xs-offset-11{margin-left:45.83333%}.el-col-xs-pull-11{position:relative;right:45.83333%}.el-col-xs-push-11{position:relative;left:45.83333%}.el-col-xs-12{width:50%}.el-col-xs-offset-12{margin-left:50%}.el-col-xs-pull-12{position:relative;right:50%}.el-col-xs-push-12{position:relative;left:50%}.el-col-xs-13{width:54.16667%}.el-col-xs-offset-13{margin-left:54.16667%}.el-col-xs-pull-13{position:relative;right:54.16667%}.el-col-xs-push-13{position:relative;left:54.16667%}.el-col-xs-14{width:58.33333%}.el-col-xs-offset-14{margin-left:58.33333%}.el-col-xs-pull-14{position:relative;right:58.33333%}.el-col-xs-push-14{position:relative;left:58.33333%}.el-col-xs-15{width:62.5%}.el-col-xs-offset-15{margin-left:62.5%}.el-col-xs-pull-15{position:relative;right:62.5%}.el-col-xs-push-15{position:relative;left:62.5%}.el-col-xs-16{width:66.66667%}.el-col-xs-offset-16{margin-left:66.66667%}.el-col-xs-pull-16{position:relative;right:66.66667%}.el-col-xs-push-16{position:relative;left:66.66667%}.el-col-xs-17{width:70.83333%}.el-col-xs-offset-17{margin-left:70.83333%}.el-col-xs-pull-17{position:relative;right:70.83333%}.el-col-xs-push-17{position:relative;left:70.83333%}.el-col-xs-18{width:75%}.el-col-xs-offset-18{margin-left:75%}.el-col-xs-pull-18{position:relative;right:75%}.el-col-xs-push-18{position:relative;left:75%}.el-col-xs-19{width:79.16667%}.el-col-xs-offset-19{margin-left:79.16667%}.el-col-xs-pull-19{position:relative;right:79.16667%}.el-col-xs-push-19{position:relative;left:79.16667%}.el-col-xs-20{width:83.33333%}.el-col-xs-offset-20{margin-left:83.33333%}.el-col-xs-pull-20{position:relative;right:83.33333%}.el-col-xs-push-20{position:relative;left:83.33333%}.el-col-xs-21{width:87.5%}.el-col-xs-offset-21{margin-left:87.5%}.el-col-xs-pull-21{position:relative;right:87.5%}.el-col-xs-push-21{position:relative;left:87.5%}.el-col-xs-22{width:91.66667%}.el-col-xs-offset-22{margin-left:91.66667%}.el-col-xs-pull-22{position:relative;right:91.66667%}.el-col-xs-push-22{position:relative;left:91.66667%}.el-col-xs-23{width:95.83333%}.el-col-xs-offset-23{margin-left:95.83333%}.el-col-xs-pull-23{position:relative;right:95.83333%}.el-col-xs-push-23{position:relative;left:95.83333%}.el-col-xs-24{width:100%}.el-col-xs-offset-24{margin-left:100%}.el-col-xs-pull-24{position:relative;right:100%}.el-col-xs-push-24{position:relative;left:100%}}@media only screen and (min-width:768px){.el-col-sm-0{display:none;width:0%}.el-col-sm-offset-0{margin-left:0}.el-col-sm-pull-0{position:relative;right:0}.el-col-sm-push-0{position:relative;left:0}.el-col-sm-1{width:4.16667%}.el-col-sm-offset-1{margin-left:4.16667%}.el-col-sm-pull-1{position:relative;right:4.16667%}.el-col-sm-push-1{position:relative;left:4.16667%}.el-col-sm-2{width:8.33333%}.el-col-sm-offset-2{margin-left:8.33333%}.el-col-sm-pull-2{position:relative;right:8.33333%}.el-col-sm-push-2{position:relative;left:8.33333%}.el-col-sm-3{width:12.5%}.el-col-sm-offset-3{margin-left:12.5%}.el-col-sm-pull-3{position:relative;right:12.5%}.el-col-sm-push-3{position:relative;left:12.5%}.el-col-sm-4{width:16.66667%}.el-col-sm-offset-4{margin-left:16.66667%}.el-col-sm-pull-4{position:relative;right:16.66667%}.el-col-sm-push-4{position:relative;left:16.66667%}.el-col-sm-5{width:20.83333%}.el-col-sm-offset-5{margin-left:20.83333%}.el-col-sm-pull-5{position:relative;right:20.83333%}.el-col-sm-push-5{position:relative;left:20.83333%}.el-col-sm-6{width:25%}.el-col-sm-offset-6{margin-left:25%}.el-col-sm-pull-6{position:relative;right:25%}.el-col-sm-push-6{position:relative;left:25%}.el-col-sm-7{width:29.16667%}.el-col-sm-offset-7{margin-left:29.16667%}.el-col-sm-pull-7{position:relative;right:29.16667%}.el-col-sm-push-7{position:relative;left:29.16667%}.el-col-sm-8{width:33.33333%}.el-col-sm-offset-8{margin-left:33.33333%}.el-col-sm-pull-8{position:relative;right:33.33333%}.el-col-sm-push-8{position:relative;left:33.33333%}.el-col-sm-9{width:37.5%}.el-col-sm-offset-9{margin-left:37.5%}.el-col-sm-pull-9{position:relative;right:37.5%}.el-col-sm-push-9{position:relative;left:37.5%}.el-col-sm-10{width:41.66667%}.el-col-sm-offset-10{margin-left:41.66667%}.el-col-sm-pull-10{position:relative;right:41.66667%}.el-col-sm-push-10{position:relative;left:41.66667%}.el-col-sm-11{width:45.83333%}.el-col-sm-offset-11{margin-left:45.83333%}.el-col-sm-pull-11{position:relative;right:45.83333%}.el-col-sm-push-11{position:relative;left:45.83333%}.el-col-sm-12{width:50%}.el-col-sm-offset-12{margin-left:50%}.el-col-sm-pull-12{position:relative;right:50%}.el-col-sm-push-12{position:relative;left:50%}.el-col-sm-13{width:54.16667%}.el-col-sm-offset-13{margin-left:54.16667%}.el-col-sm-pull-13{position:relative;right:54.16667%}.el-col-sm-push-13{position:relative;left:54.16667%}.el-col-sm-14{width:58.33333%}.el-col-sm-offset-14{margin-left:58.33333%}.el-col-sm-pull-14{position:relative;right:58.33333%}.el-col-sm-push-14{position:relative;left:58.33333%}.el-col-sm-15{width:62.5%}.el-col-sm-offset-15{margin-left:62.5%}.el-col-sm-pull-15{position:relative;right:62.5%}.el-col-sm-push-15{position:relative;left:62.5%}.el-col-sm-16{width:66.66667%}.el-col-sm-offset-16{margin-left:66.66667%}.el-col-sm-pull-16{position:relative;right:66.66667%}.el-col-sm-push-16{position:relative;left:66.66667%}.el-col-sm-17{width:70.83333%}.el-col-sm-offset-17{margin-left:70.83333%}.el-col-sm-pull-17{position:relative;right:70.83333%}.el-col-sm-push-17{position:relative;left:70.83333%}.el-col-sm-18{width:75%}.el-col-sm-offset-18{margin-left:75%}.el-col-sm-pull-18{position:relative;right:75%}.el-col-sm-push-18{position:relative;left:75%}.el-col-sm-19{width:79.16667%}.el-col-sm-offset-19{margin-left:79.16667%}.el-col-sm-pull-19{position:relative;right:79.16667%}.el-col-sm-push-19{position:relative;left:79.16667%}.el-col-sm-20{width:83.33333%}.el-col-sm-offset-20{margin-left:83.33333%}.el-col-sm-pull-20{position:relative;right:83.33333%}.el-col-sm-push-20{position:relative;left:83.33333%}.el-col-sm-21{width:87.5%}.el-col-sm-offset-21{margin-left:87.5%}.el-col-sm-pull-21{position:relative;right:87.5%}.el-col-sm-push-21{position:relative;left:87.5%}.el-col-sm-22{width:91.66667%}.el-col-sm-offset-22{margin-left:91.66667%}.el-col-sm-pull-22{position:relative;right:91.66667%}.el-col-sm-push-22{position:relative;left:91.66667%}.el-col-sm-23{width:95.83333%}.el-col-sm-offset-23{margin-left:95.83333%}.el-col-sm-pull-23{position:relative;right:95.83333%}.el-col-sm-push-23{position:relative;left:95.83333%}.el-col-sm-24{width:100%}.el-col-sm-offset-24{margin-left:100%}.el-col-sm-pull-24{position:relative;right:100%}.el-col-sm-push-24{position:relative;left:100%}}@media only screen and (min-width:992px){.el-col-md-0{display:none;width:0%}.el-col-md-offset-0{margin-left:0}.el-col-md-pull-0{position:relative;right:0}.el-col-md-push-0{position:relative;left:0}.el-col-md-1{width:4.16667%}.el-col-md-offset-1{margin-left:4.16667%}.el-col-md-pull-1{position:relative;right:4.16667%}.el-col-md-push-1{position:relative;left:4.16667%}.el-col-md-2{width:8.33333%}.el-col-md-offset-2{margin-left:8.33333%}.el-col-md-pull-2{position:relative;right:8.33333%}.el-col-md-push-2{position:relative;left:8.33333%}.el-col-md-3{width:12.5%}.el-col-md-offset-3{margin-left:12.5%}.el-col-md-pull-3{position:relative;right:12.5%}.el-col-md-push-3{position:relative;left:12.5%}.el-col-md-4{width:16.66667%}.el-col-md-offset-4{margin-left:16.66667%}.el-col-md-pull-4{position:relative;right:16.66667%}.el-col-md-push-4{position:relative;left:16.66667%}.el-col-md-5{width:20.83333%}.el-col-md-offset-5{margin-left:20.83333%}.el-col-md-pull-5{position:relative;right:20.83333%}.el-col-md-push-5{position:relative;left:20.83333%}.el-col-md-6{width:25%}.el-col-md-offset-6{margin-left:25%}.el-col-md-pull-6{position:relative;right:25%}.el-col-md-push-6{position:relative;left:25%}.el-col-md-7{width:29.16667%}.el-col-md-offset-7{margin-left:29.16667%}.el-col-md-pull-7{position:relative;right:29.16667%}.el-col-md-push-7{position:relative;left:29.16667%}.el-col-md-8{width:33.33333%}.el-col-md-offset-8{margin-left:33.33333%}.el-col-md-pull-8{position:relative;right:33.33333%}.el-col-md-push-8{position:relative;left:33.33333%}.el-col-md-9{width:37.5%}.el-col-md-offset-9{margin-left:37.5%}.el-col-md-pull-9{position:relative;right:37.5%}.el-col-md-push-9{position:relative;left:37.5%}.el-col-md-10{width:41.66667%}.el-col-md-offset-10{margin-left:41.66667%}.el-col-md-pull-10{position:relative;right:41.66667%}.el-col-md-push-10{position:relative;left:41.66667%}.el-col-md-11{width:45.83333%}.el-col-md-offset-11{margin-left:45.83333%}.el-col-md-pull-11{position:relative;right:45.83333%}.el-col-md-push-11{position:relative;left:45.83333%}.el-col-md-12{width:50%}.el-col-md-offset-12{margin-left:50%}.el-col-md-pull-12{position:relative;right:50%}.el-col-md-push-12{position:relative;left:50%}.el-col-md-13{width:54.16667%}.el-col-md-offset-13{margin-left:54.16667%}.el-col-md-pull-13{position:relative;right:54.16667%}.el-col-md-push-13{position:relative;left:54.16667%}.el-col-md-14{width:58.33333%}.el-col-md-offset-14{margin-left:58.33333%}.el-col-md-pull-14{position:relative;right:58.33333%}.el-col-md-push-14{position:relative;left:58.33333%}.el-col-md-15{width:62.5%}.el-col-md-offset-15{margin-left:62.5%}.el-col-md-pull-15{position:relative;right:62.5%}.el-col-md-push-15{position:relative;left:62.5%}.el-col-md-16{width:66.66667%}.el-col-md-offset-16{margin-left:66.66667%}.el-col-md-pull-16{position:relative;right:66.66667%}.el-col-md-push-16{position:relative;left:66.66667%}.el-col-md-17{width:70.83333%}.el-col-md-offset-17{margin-left:70.83333%}.el-col-md-pull-17{position:relative;right:70.83333%}.el-col-md-push-17{position:relative;left:70.83333%}.el-col-md-18{width:75%}.el-col-md-offset-18{margin-left:75%}.el-col-md-pull-18{position:relative;right:75%}.el-col-md-push-18{position:relative;left:75%}.el-col-md-19{width:79.16667%}.el-col-md-offset-19{margin-left:79.16667%}.el-col-md-pull-19{position:relative;right:79.16667%}.el-col-md-push-19{position:relative;left:79.16667%}.el-col-md-20{width:83.33333%}.el-col-md-offset-20{margin-left:83.33333%}.el-col-md-pull-20{position:relative;right:83.33333%}.el-col-md-push-20{position:relative;left:83.33333%}.el-col-md-21{width:87.5%}.el-col-md-offset-21{margin-left:87.5%}.el-col-md-pull-21{position:relative;right:87.5%}.el-col-md-push-21{position:relative;left:87.5%}.el-col-md-22{width:91.66667%}.el-col-md-offset-22{margin-left:91.66667%}.el-col-md-pull-22{position:relative;right:91.66667%}.el-col-md-push-22{position:relative;left:91.66667%}.el-col-md-23{width:95.83333%}.el-col-md-offset-23{margin-left:95.83333%}.el-col-md-pull-23{position:relative;right:95.83333%}.el-col-md-push-23{position:relative;left:95.83333%}.el-col-md-24{width:100%}.el-col-md-offset-24{margin-left:100%}.el-col-md-pull-24{position:relative;right:100%}.el-col-md-push-24{position:relative;left:100%}}@media only screen and (min-width:1200px){.el-col-lg-0{display:none;width:0%}.el-col-lg-offset-0{margin-left:0}.el-col-lg-pull-0{position:relative;right:0}.el-col-lg-push-0{position:relative;left:0}.el-col-lg-1{width:4.16667%}.el-col-lg-offset-1{margin-left:4.16667%}.el-col-lg-pull-1{position:relative;right:4.16667%}.el-col-lg-push-1{position:relative;left:4.16667%}.el-col-lg-2{width:8.33333%}.el-col-lg-offset-2{margin-left:8.33333%}.el-col-lg-pull-2{position:relative;right:8.33333%}.el-col-lg-push-2{position:relative;left:8.33333%}.el-col-lg-3{width:12.5%}.el-col-lg-offset-3{margin-left:12.5%}.el-col-lg-pull-3{position:relative;right:12.5%}.el-col-lg-push-3{position:relative;left:12.5%}.el-col-lg-4{width:16.66667%}.el-col-lg-offset-4{margin-left:16.66667%}.el-col-lg-pull-4{position:relative;right:16.66667%}.el-col-lg-push-4{position:relative;left:16.66667%}.el-col-lg-5{width:20.83333%}.el-col-lg-offset-5{margin-left:20.83333%}.el-col-lg-pull-5{position:relative;right:20.83333%}.el-col-lg-push-5{position:relative;left:20.83333%}.el-col-lg-6{width:25%}.el-col-lg-offset-6{margin-left:25%}.el-col-lg-pull-6{position:relative;right:25%}.el-col-lg-push-6{position:relative;left:25%}.el-col-lg-7{width:29.16667%}.el-col-lg-offset-7{margin-left:29.16667%}.el-col-lg-pull-7{position:relative;right:29.16667%}.el-col-lg-push-7{position:relative;left:29.16667%}.el-col-lg-8{width:33.33333%}.el-col-lg-offset-8{margin-left:33.33333%}.el-col-lg-pull-8{position:relative;right:33.33333%}.el-col-lg-push-8{position:relative;left:33.33333%}.el-col-lg-9{width:37.5%}.el-col-lg-offset-9{margin-left:37.5%}.el-col-lg-pull-9{position:relative;right:37.5%}.el-col-lg-push-9{position:relative;left:37.5%}.el-col-lg-10{width:41.66667%}.el-col-lg-offset-10{margin-left:41.66667%}.el-col-lg-pull-10{position:relative;right:41.66667%}.el-col-lg-push-10{position:relative;left:41.66667%}.el-col-lg-11{width:45.83333%}.el-col-lg-offset-11{margin-left:45.83333%}.el-col-lg-pull-11{position:relative;right:45.83333%}.el-col-lg-push-11{position:relative;left:45.83333%}.el-col-lg-12{width:50%}.el-col-lg-offset-12{margin-left:50%}.el-col-lg-pull-12{position:relative;right:50%}.el-col-lg-push-12{position:relative;left:50%}.el-col-lg-13{width:54.16667%}.el-col-lg-offset-13{margin-left:54.16667%}.el-col-lg-pull-13{position:relative;right:54.16667%}.el-col-lg-push-13{position:relative;left:54.16667%}.el-col-lg-14{width:58.33333%}.el-col-lg-offset-14{margin-left:58.33333%}.el-col-lg-pull-14{position:relative;right:58.33333%}.el-col-lg-push-14{position:relative;left:58.33333%}.el-col-lg-15{width:62.5%}.el-col-lg-offset-15{margin-left:62.5%}.el-col-lg-pull-15{position:relative;right:62.5%}.el-col-lg-push-15{position:relative;left:62.5%}.el-col-lg-16{width:66.66667%}.el-col-lg-offset-16{margin-left:66.66667%}.el-col-lg-pull-16{position:relative;right:66.66667%}.el-col-lg-push-16{position:relative;left:66.66667%}.el-col-lg-17{width:70.83333%}.el-col-lg-offset-17{margin-left:70.83333%}.el-col-lg-pull-17{position:relative;right:70.83333%}.el-col-lg-push-17{position:relative;left:70.83333%}.el-col-lg-18{width:75%}.el-col-lg-offset-18{margin-left:75%}.el-col-lg-pull-18{position:relative;right:75%}.el-col-lg-push-18{position:relative;left:75%}.el-col-lg-19{width:79.16667%}.el-col-lg-offset-19{margin-left:79.16667%}.el-col-lg-pull-19{position:relative;right:79.16667%}.el-col-lg-push-19{position:relative;left:79.16667%}.el-col-lg-20{width:83.33333%}.el-col-lg-offset-20{margin-left:83.33333%}.el-col-lg-pull-20{position:relative;right:83.33333%}.el-col-lg-push-20{position:relative;left:83.33333%}.el-col-lg-21{width:87.5%}.el-col-lg-offset-21{margin-left:87.5%}.el-col-lg-pull-21{position:relative;right:87.5%}.el-col-lg-push-21{position:relative;left:87.5%}.el-col-lg-22{width:91.66667%}.el-col-lg-offset-22{margin-left:91.66667%}.el-col-lg-pull-22{position:relative;right:91.66667%}.el-col-lg-push-22{position:relative;left:91.66667%}.el-col-lg-23{width:95.83333%}.el-col-lg-offset-23{margin-left:95.83333%}.el-col-lg-pull-23{position:relative;right:95.83333%}.el-col-lg-push-23{position:relative;left:95.83333%}.el-col-lg-24{width:100%}.el-col-lg-offset-24{margin-left:100%}.el-col-lg-pull-24{position:relative;right:100%}.el-col-lg-push-24{position:relative;left:100%}}@media only screen and (min-width:1920px){.el-col-xl-0{display:none;width:0%}.el-col-xl-offset-0{margin-left:0}.el-col-xl-pull-0{position:relative;right:0}.el-col-xl-push-0{position:relative;left:0}.el-col-xl-1{width:4.16667%}.el-col-xl-offset-1{margin-left:4.16667%}.el-col-xl-pull-1{position:relative;right:4.16667%}.el-col-xl-push-1{position:relative;left:4.16667%}.el-col-xl-2{width:8.33333%}.el-col-xl-offset-2{margin-left:8.33333%}.el-col-xl-pull-2{position:relative;right:8.33333%}.el-col-xl-push-2{position:relative;left:8.33333%}.el-col-xl-3{width:12.5%}.el-col-xl-offset-3{margin-left:12.5%}.el-col-xl-pull-3{position:relative;right:12.5%}.el-col-xl-push-3{position:relative;left:12.5%}.el-col-xl-4{width:16.66667%}.el-col-xl-offset-4{margin-left:16.66667%}.el-col-xl-pull-4{position:relative;right:16.66667%}.el-col-xl-push-4{position:relative;left:16.66667%}.el-col-xl-5{width:20.83333%}.el-col-xl-offset-5{margin-left:20.83333%}.el-col-xl-pull-5{position:relative;right:20.83333%}.el-col-xl-push-5{position:relative;left:20.83333%}.el-col-xl-6{width:25%}.el-col-xl-offset-6{margin-left:25%}.el-col-xl-pull-6{position:relative;right:25%}.el-col-xl-push-6{position:relative;left:25%}.el-col-xl-7{width:29.16667%}.el-col-xl-offset-7{margin-left:29.16667%}.el-col-xl-pull-7{position:relative;right:29.16667%}.el-col-xl-push-7{position:relative;left:29.16667%}.el-col-xl-8{width:33.33333%}.el-col-xl-offset-8{margin-left:33.33333%}.el-col-xl-pull-8{position:relative;right:33.33333%}.el-col-xl-push-8{position:relative;left:33.33333%}.el-col-xl-9{width:37.5%}.el-col-xl-offset-9{margin-left:37.5%}.el-col-xl-pull-9{position:relative;right:37.5%}.el-col-xl-push-9{position:relative;left:37.5%}.el-col-xl-10{width:41.66667%}.el-col-xl-offset-10{margin-left:41.66667%}.el-col-xl-pull-10{position:relative;right:41.66667%}.el-col-xl-push-10{position:relative;left:41.66667%}.el-col-xl-11{width:45.83333%}.el-col-xl-offset-11{margin-left:45.83333%}.el-col-xl-pull-11{position:relative;right:45.83333%}.el-col-xl-push-11{position:relative;left:45.83333%}.el-col-xl-12{width:50%}.el-col-xl-offset-12{margin-left:50%}.el-col-xl-pull-12{position:relative;right:50%}.el-col-xl-push-12{position:relative;left:50%}.el-col-xl-13{width:54.16667%}.el-col-xl-offset-13{margin-left:54.16667%}.el-col-xl-pull-13{position:relative;right:54.16667%}.el-col-xl-push-13{position:relative;left:54.16667%}.el-col-xl-14{width:58.33333%}.el-col-xl-offset-14{margin-left:58.33333%}.el-col-xl-pull-14{position:relative;right:58.33333%}.el-col-xl-push-14{position:relative;left:58.33333%}.el-col-xl-15{width:62.5%}.el-col-xl-offset-15{margin-left:62.5%}.el-col-xl-pull-15{position:relative;right:62.5%}.el-col-xl-push-15{position:relative;left:62.5%}.el-col-xl-16{width:66.66667%}.el-col-xl-offset-16{margin-left:66.66667%}.el-col-xl-pull-16{position:relative;right:66.66667%}.el-col-xl-push-16{position:relative;left:66.66667%}.el-col-xl-17{width:70.83333%}.el-col-xl-offset-17{margin-left:70.83333%}.el-col-xl-pull-17{position:relative;right:70.83333%}.el-col-xl-push-17{position:relative;left:70.83333%}.el-col-xl-18{width:75%}.el-col-xl-offset-18{margin-left:75%}.el-col-xl-pull-18{position:relative;right:75%}.el-col-xl-push-18{position:relative;left:75%}.el-col-xl-19{width:79.16667%}.el-col-xl-offset-19{margin-left:79.16667%}.el-col-xl-pull-19{position:relative;right:79.16667%}.el-col-xl-push-19{position:relative;left:79.16667%}.el-col-xl-20{width:83.33333%}.el-col-xl-offset-20{margin-left:83.33333%}.el-col-xl-pull-20{position:relative;right:83.33333%}.el-col-xl-push-20{position:relative;left:83.33333%}.el-col-xl-21{width:87.5%}.el-col-xl-offset-21{margin-left:87.5%}.el-col-xl-pull-21{position:relative;right:87.5%}.el-col-xl-push-21{position:relative;left:87.5%}.el-col-xl-22{width:91.66667%}.el-col-xl-offset-22{margin-left:91.66667%}.el-col-xl-pull-22{position:relative;right:91.66667%}.el-col-xl-push-22{position:relative;left:91.66667%}.el-col-xl-23{width:95.83333%}.el-col-xl-offset-23{margin-left:95.83333%}.el-col-xl-pull-23{position:relative;right:95.83333%}.el-col-xl-push-23{position:relative;left:95.83333%}.el-col-xl-24{width:100%}.el-col-xl-offset-24{margin-left:100%}.el-col-xl-pull-24{position:relative;right:100%}.el-col-xl-push-24{position:relative;left:100%}}@-webkit-keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-upload{display:inline-block;text-align:center;cursor:pointer;outline:0}.el-upload__input{display:none}.el-upload__tip{font-size:12px;color:#606266;margin-top:7px}.el-upload iframe{position:absolute;z-index:-1;top:0;left:0;filter:alpha(opacity=0)}.el-upload--picture-card{background-color:#fbfdff;border:1px dashed #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;cursor:pointer;line-height:146px;vertical-align:top}.el-upload--picture-card i{font-size:28px;color:#8c939d}.el-upload--picture-card:hover,.el-upload:focus{border-color:#409EFF;color:#409EFF}.el-upload:focus .el-upload-dragger{border-color:#409EFF}.el-upload-dragger{background-color:#fff;border:1px dashed #d9d9d9;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:360px;height:180px;text-align:center;cursor:pointer;overflow:hidden}.el-upload-dragger .el-icon-upload{font-size:67px;color:#C0C4CC;margin:40px 0 16px;line-height:50px}.el-upload-dragger+.el-upload__tip{text-align:center}.el-upload-dragger~.el-upload__files{border-top:1px solid #DCDFE6;margin-top:7px;padding-top:5px}.el-upload-dragger .el-upload__text{color:#606266;font-size:14px;text-align:center}.el-upload-dragger .el-upload__text em{color:#409EFF;font-style:normal}.el-upload-dragger:hover{border-color:#409EFF}.el-upload-dragger.is-dragover{background-color:rgba(32,159,255,.06);border:2px dashed #409EFF}.el-upload-list{margin:0;padding:0;list-style:none}.el-upload-list__item{-webkit-transition:all .5s cubic-bezier(.55,0,.1,1);transition:all .5s cubic-bezier(.55,0,.1,1);font-size:14px;color:#606266;line-height:1.8;margin-top:5px;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:4px;width:100%}.el-upload-list__item .el-progress{position:absolute;top:20px;width:100%}.el-upload-list__item .el-progress__text{position:absolute;right:0;top:-13px}.el-upload-list__item .el-progress-bar{margin-right:0;padding-right:0}.el-upload-list__item:first-child{margin-top:10px}.el-upload-list__item .el-icon-upload-success{color:#67C23A}.el-upload-list__item .el-icon-close{display:none;position:absolute;top:5px;right:5px;cursor:pointer;opacity:.75;color:#606266}.el-upload-list__item .el-icon-close:hover{opacity:1}.el-upload-list__item .el-icon-close-tip{display:none;position:absolute;top:5px;right:5px;font-size:12px;cursor:pointer;opacity:1;color:#409EFF}.el-upload-list__item:hover .el-icon-close{display:inline-block}.el-upload-list__item:hover .el-progress__text{display:none}.el-upload-list__item.is-success .el-upload-list__item-status-label{display:block}.el-upload-list__item.is-success .el-upload-list__item-name:focus,.el-upload-list__item.is-success .el-upload-list__item-name:hover{color:#409EFF;cursor:pointer}.el-upload-list__item.is-success:focus:not(:hover) .el-icon-close-tip{display:inline-block}.el-upload-list__item.is-success:active,.el-upload-list__item.is-success:not(.focusing):focus{outline-width:0}.el-upload-list__item.is-success:active .el-icon-close-tip,.el-upload-list__item.is-success:focus .el-upload-list__item-status-label,.el-upload-list__item.is-success:hover .el-upload-list__item-status-label,.el-upload-list__item.is-success:not(.focusing):focus .el-icon-close-tip{display:none}.el-upload-list.is-disabled .el-upload-list__item:hover .el-upload-list__item-status-label{display:block}.el-upload-list__item-name{color:#606266;display:block;margin-right:40px;overflow:hidden;padding-left:4px;text-overflow:ellipsis;-webkit-transition:color .3s;transition:color .3s;white-space:nowrap}.el-upload-list__item-name [class^=el-icon]{height:100%;margin-right:7px;color:#909399;line-height:inherit}.el-upload-list__item-status-label{position:absolute;right:5px;top:0;line-height:inherit;display:none}.el-upload-list__item-delete{position:absolute;right:10px;top:0;font-size:12px;color:#606266;display:none}.el-upload-list__item-delete:hover{color:#409EFF}.el-upload-list--picture-card{margin:0;display:inline;vertical-align:top}.el-upload-list--picture-card .el-upload-list__item{overflow:hidden;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;width:148px;height:148px;margin:0 8px 8px 0;display:inline-block}.el-upload-list--picture-card .el-upload-list__item .el-icon-check,.el-upload-list--picture-card .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture-card .el-upload-list__item .el-icon-close,.el-upload-list--picture-card .el-upload-list__item:hover .el-upload-list__item-status-label{display:none}.el-upload-list--picture-card .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture-card .el-upload-list__item-name{display:none}.el-upload-list--picture-card .el-upload-list__item-thumbnail{width:100%;height:100%}.el-upload-list--picture-card .el-upload-list__item-status-label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-list--picture-card .el-upload-list__item-status-label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture-card .el-upload-list__item-actions{position:absolute;width:100%;height:100%;left:0;top:0;cursor:default;text-align:center;color:#fff;opacity:0;font-size:20px;background-color:rgba(0,0,0,.5);-webkit-transition:opacity .3s;transition:opacity .3s}.el-upload-list--picture-card .el-upload-list__item-actions::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-list--picture-card .el-upload-list__item-actions span{display:none;cursor:pointer}.el-upload-list--picture-card .el-upload-list__item-actions span+span{margin-left:15px}.el-upload-list--picture-card .el-upload-list__item-actions .el-upload-list__item-delete{position:static;font-size:inherit;color:inherit}.el-upload-list--picture-card .el-upload-list__item-actions:hover{opacity:1}.el-upload-list--picture-card .el-upload-list__item-actions:hover span{display:inline-block}.el-upload-list--picture-card .el-progress{top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);bottom:auto;width:126px}.el-upload-list--picture-card .el-progress .el-progress__text{top:50%}.el-upload-list--picture .el-upload-list__item{overflow:hidden;z-index:0;background-color:#fff;border:1px solid #c0ccda;border-radius:6px;-webkit-box-sizing:border-box;box-sizing:border-box;margin-top:10px;padding:10px 10px 10px 90px;height:92px}.el-upload-list--picture .el-upload-list__item .el-icon-check,.el-upload-list--picture .el-upload-list__item .el-icon-circle-check{color:#FFF}.el-upload-list--picture .el-upload-list__item:hover .el-upload-list__item-status-label{background:0 0;-webkit-box-shadow:none;box-shadow:none;top:-2px;right:-12px}.el-upload-list--picture .el-upload-list__item:hover .el-progress__text{display:block}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name{line-height:70px;margin-top:0}.el-upload-list--picture .el-upload-list__item.is-success .el-upload-list__item-name i{display:none}.el-upload-list--picture .el-upload-list__item-thumbnail{vertical-align:middle;display:inline-block;width:70px;height:70px;float:left;position:relative;z-index:1;margin-left:-80px;background-color:#FFF}.el-upload-list--picture .el-upload-list__item-name{display:block;margin-top:20px}.el-upload-list--picture .el-upload-list__item-name i{font-size:70px;line-height:1;position:absolute;left:9px;top:10px}.el-upload-list--picture .el-upload-list__item-status-label{position:absolute;right:-17px;top:-7px;width:46px;height:26px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 1px 1px #ccc;box-shadow:0 1px 1px #ccc}.el-upload-list--picture .el-upload-list__item-status-label i{font-size:12px;margin-top:12px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg)}.el-upload-list--picture .el-progress{position:relative;top:-7px}.el-upload-cover{position:absolute;left:0;top:0;width:100%;height:100%;overflow:hidden;z-index:10;cursor:default}.el-upload-cover::after{display:inline-block;height:100%;vertical-align:middle}.el-upload-cover img{display:block;width:100%;height:100%}.el-upload-cover__label{position:absolute;right:-15px;top:-6px;width:40px;height:24px;background:#13ce66;text-align:center;-webkit-transform:rotate(45deg);transform:rotate(45deg);-webkit-box-shadow:0 0 1pc 1px rgba(0,0,0,.2);box-shadow:0 0 1pc 1px rgba(0,0,0,.2)}.el-upload-cover__label i{font-size:12px;margin-top:11px;-webkit-transform:rotate(-45deg);transform:rotate(-45deg);color:#fff}.el-upload-cover__progress{display:inline-block;vertical-align:middle;position:static;width:243px}.el-upload-cover__progress+.el-upload__inner{opacity:0}.el-upload-cover__content{position:absolute;top:0;left:0;width:100%;height:100%}.el-upload-cover__interact{position:absolute;bottom:0;left:0;width:100%;height:100%;background-color:rgba(0,0,0,.72);text-align:center}.el-upload-cover__interact .btn{display:inline-block;color:#FFF;font-size:14px;cursor:pointer;vertical-align:middle;-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);margin-top:60px}.el-upload-cover__interact .btn span{opacity:0;-webkit-transition:opacity .15s linear;transition:opacity .15s linear}.el-upload-cover__interact .btn:not(:first-child){margin-left:35px}.el-upload-cover__interact .btn:hover{-webkit-transform:translateY(-13px);transform:translateY(-13px)}.el-upload-cover__interact .btn:hover span{opacity:1}.el-upload-cover__interact .btn i{color:#FFF;display:block;font-size:24px;line-height:inherit;margin:0 auto 5px}.el-upload-cover__title{position:absolute;bottom:0;left:0;background-color:#FFF;height:36px;width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-weight:400;text-align:left;padding:0 10px;margin:0;line-height:36px;font-size:14px;color:#303133}.el-upload-cover+.el-upload__inner{opacity:0;position:relative;z-index:1}.el-progress{position:relative;line-height:1}.el-progress__text{font-size:14px;color:#606266;display:inline-block;vertical-align:middle;margin-left:10px;line-height:1}.el-progress__text i{vertical-align:middle;display:block}.el-progress--circle,.el-progress--dashboard{display:inline-block}.el-progress--circle .el-progress__text,.el-progress--dashboard .el-progress__text{position:absolute;top:50%;left:0;width:100%;text-align:center;margin:0;-webkit-transform:translate(0,-50%);transform:translate(0,-50%)}.el-progress--circle .el-progress__text i,.el-progress--dashboard .el-progress__text i{vertical-align:middle;display:inline-block}.el-progress--without-text .el-progress__text{display:none}.el-progress--without-text .el-progress-bar{padding-right:0;margin-right:0;display:block}.el-progress--text-inside .el-progress-bar{padding-right:0;margin-right:0}.el-progress.is-success .el-progress-bar__inner{background-color:#67C23A}.el-progress.is-success .el-progress__text{color:#67C23A}.el-progress.is-warning .el-progress-bar__inner{background-color:#E6A23C}.el-badge__content,.el-progress.is-exception .el-progress-bar__inner{background-color:#F56C6C}.el-progress.is-warning .el-progress__text{color:#E6A23C}.el-progress.is-exception .el-progress__text{color:#F56C6C}.el-progress-bar{padding-right:50px;display:inline-block;vertical-align:middle;width:100%;margin-right:-55px;-webkit-box-sizing:border-box;box-sizing:border-box}.el-card__header,.el-message,.el-step__icon{-webkit-box-sizing:border-box}.el-progress-bar__outer{height:6px;border-radius:100px;background-color:#EBEEF5;overflow:hidden;position:relative;vertical-align:middle}.el-progress-bar__inner{position:absolute;left:0;top:0;height:100%;background-color:#409EFF;text-align:right;border-radius:100px;line-height:1;white-space:nowrap;-webkit-transition:width .6s ease;transition:width .6s ease}.el-progress-bar__inner::after{display:inline-block;height:100%;vertical-align:middle}.el-progress-bar__innerText{display:inline-block;vertical-align:middle;color:#FFF;font-size:12px;margin:0 5px}@keyframes progress{0%{background-position:0 0}100%{background-position:32px 0}}.el-time-spinner{width:100%;white-space:nowrap}.el-spinner{display:inline-block;vertical-align:middle}.el-spinner-inner{-webkit-animation:rotate 2s linear infinite;animation:rotate 2s linear infinite;width:50px;height:50px}.el-spinner-inner .path{stroke:#ececec;stroke-linecap:round;-webkit-animation:dash 1.5s ease-in-out infinite;animation:dash 1.5s ease-in-out infinite}@-webkit-keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@keyframes rotate{100%{-webkit-transform:rotate(360deg);transform:rotate(360deg)}}@-webkit-keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}@keyframes dash{0%{stroke-dasharray:1,150;stroke-dashoffset:0}50%{stroke-dasharray:90,150;stroke-dashoffset:-35}100%{stroke-dasharray:90,150;stroke-dashoffset:-124}}.el-message{min-width:380px;box-sizing:border-box;border-radius:4px;border-width:1px;border-style:solid;border-color:#EBEEF5;position:fixed;left:50%;top:20px;-webkit-transform:translateX(-50%);transform:translateX(-50%);background-color:#edf2fc;-webkit-transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,top .4s,-webkit-transform .4s;transition:opacity .3s,transform .4s,top .4s;transition:opacity .3s,transform .4s,top .4s,-webkit-transform .4s;overflow:hidden;padding:15px 15px 15px 20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-message.is-center{-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-message.is-closable .el-message__content{padding-right:16px}.el-message p{margin:0}.el-message--info .el-message__content{color:#909399}.el-message--success{background-color:#f0f9eb;border-color:#e1f3d8}.el-message--success .el-message__content{color:#67C23A}.el-message--warning{background-color:#fdf6ec;border-color:#faecd8}.el-message--warning .el-message__content{color:#E6A23C}.el-message--error{background-color:#fef0f0;border-color:#fde2e2}.el-message--error .el-message__content{color:#F56C6C}.el-message__icon{margin-right:10px}.el-message__content{padding:0;font-size:14px;line-height:1}.el-message__content:focus{outline-width:0}.el-message__closeBtn{position:absolute;top:50%;right:15px;-webkit-transform:translateY(-50%);transform:translateY(-50%);cursor:pointer;color:#C0C4CC;font-size:16px}.el-message__closeBtn:focus{outline-width:0}.el-message__closeBtn:hover{color:#909399}.el-message .el-icon-success{color:#67C23A}.el-message .el-icon-error{color:#F56C6C}.el-message .el-icon-info{color:#909399}.el-message .el-icon-warning{color:#E6A23C}.el-message-fade-enter,.el-message-fade-leave-active{opacity:0;-webkit-transform:translate(-50%,-100%);transform:translate(-50%,-100%)}.el-badge{position:relative;vertical-align:middle;display:inline-block}.el-badge__content{border-radius:10px;color:#FFF;display:inline-block;font-size:12px;height:18px;line-height:18px;padding:0 6px;text-align:center;white-space:nowrap;border:1px solid #FFF}.el-badge__content.is-fixed{position:absolute;top:0;right:10px;-webkit-transform:translateY(-50%) translateX(100%);transform:translateY(-50%) translateX(100%)}.el-rate__icon,.el-rate__item{position:relative;display:inline-block}.el-badge__content.is-fixed.is-dot{right:5px}.el-badge__content.is-dot{height:8px;width:8px;padding:0;right:0;border-radius:50%}.el-badge__content--primary{background-color:#409EFF}.el-badge__content--success{background-color:#67C23A}.el-badge__content--warning{background-color:#E6A23C}.el-badge__content--info{background-color:#909399}.el-badge__content--danger{background-color:#F56C6C}.el-card{border-radius:4px;border:1px solid #EBEEF5;background-color:#FFF;overflow:hidden;color:#303133;-webkit-transition:.3s;transition:.3s}.el-card.is-always-shadow,.el-card.is-hover-shadow:focus,.el-card.is-hover-shadow:hover{box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-card__header{padding:18px 20px;border-bottom:1px solid #EBEEF5;box-sizing:border-box}.el-card__body,.el-main{padding:20px}.el-rate{height:20px;line-height:1}.el-rate:active,.el-rate:focus{outline-width:0}.el-rate__item{font-size:0;vertical-align:middle}.el-rate__icon{font-size:18px;margin-right:6px;color:#C0C4CC;-webkit-transition:.3s;transition:.3s}.el-rate__decimal,.el-rate__icon .path2{position:absolute;top:0;left:0}.el-rate__icon.hover{-webkit-transform:scale(1.15);transform:scale(1.15)}.el-rate__decimal{display:inline-block;overflow:hidden}.el-step.is-vertical,.el-steps{display:-webkit-box;display:-ms-flexbox}.el-rate__text{font-size:14px;vertical-align:middle}.el-steps{display:flex}.el-steps--simple{padding:13px 8%;border-radius:4px;background:#F5F7FA}.el-steps--horizontal{white-space:nowrap}.el-steps--vertical{height:100%;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-flow:column;flex-flow:column}.el-step{position:relative;-ms-flex-negative:1;flex-shrink:1}.el-step:last-of-type .el-step__line{display:none}.el-step:last-of-type.is-flex{-ms-flex-preferred-size:auto!important;flex-basis:auto!important;-ms-flex-negative:0;flex-shrink:0;-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.el-step:last-of-type .el-step__description,.el-step:last-of-type .el-step__main{padding-right:0}.el-step__head{position:relative;width:100%}.el-step__head.is-process{color:#303133;border-color:#303133}.el-step__head.is-wait{color:#C0C4CC;border-color:#C0C4CC}.el-step__head.is-success{color:#67C23A;border-color:#67C23A}.el-step__head.is-error{color:#F56C6C;border-color:#F56C6C}.el-step__head.is-finish{color:#409EFF;border-color:#409EFF}.el-step__icon{position:relative;z-index:1;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;width:24px;height:24px;font-size:14px;box-sizing:border-box;background:#FFF;-webkit-transition:.15s ease-out;transition:.15s ease-out}.el-step.is-horizontal,.el-step__icon-inner{display:inline-block}.el-step__icon.is-text{border-radius:50%;border:2px solid;border-color:inherit}.el-step__icon.is-icon{width:40px}.el-step__icon-inner{-webkit-user-select:none;user-select:none;text-align:center;font-weight:700;line-height:1;color:inherit}.el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:25px;font-weight:400}.el-step__icon-inner.is-status{-webkit-transform:translateY(1px);transform:translateY(1px)}.el-step__line{position:absolute;border-color:inherit;background-color:#C0C4CC}.el-step__line-inner{display:block;border-width:1px;border-style:solid;border-color:inherit;-webkit-transition:.15s ease-out;transition:.15s ease-out;-webkit-box-sizing:border-box;box-sizing:border-box;width:0;height:0}.el-step__main{white-space:normal;text-align:left}.el-step__title{font-size:16px;line-height:38px}.el-step__title.is-process{font-weight:700;color:#303133}.el-step__title.is-wait{color:#C0C4CC}.el-step__title.is-success{color:#67C23A}.el-step__title.is-error{color:#F56C6C}.el-step__title.is-finish{color:#409EFF}.el-step__description{padding-right:10%;margin-top:-5px;font-size:12px;line-height:20px;font-weight:400}.el-step__description.is-process{color:#303133}.el-step__description.is-wait{color:#C0C4CC}.el-step__description.is-success{color:#67C23A}.el-step__description.is-error{color:#F56C6C}.el-step__description.is-finish{color:#409EFF}.el-step.is-horizontal .el-step__line{height:2px;top:11px;left:0;right:0}.el-step.is-vertical{display:flex}.el-step.is-vertical .el-step__head{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;width:24px}.el-step.is-vertical .el-step__main{padding-left:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-vertical .el-step__title{line-height:24px;padding-bottom:8px}.el-step.is-vertical .el-step__line{width:2px;top:0;bottom:0;left:11px}.el-step.is-vertical .el-step__icon.is-icon{width:24px}.el-step.is-center .el-step__head,.el-step.is-center .el-step__main{text-align:center}.el-step.is-center .el-step__description{padding-left:20%;padding-right:20%}.el-step.is-center .el-step__line{left:50%;right:-50%}.el-step.is-simple{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-step.is-simple .el-step__head{width:auto;font-size:0;padding-right:10px}.el-step.is-simple .el-step__icon{background:0 0;width:16px;height:16px;font-size:12px}.el-step.is-simple .el-step__icon-inner[class*=el-icon]:not(.is-status){font-size:18px}.el-step.is-simple .el-step__icon-inner.is-status{-webkit-transform:scale(.8) translateY(1px);transform:scale(.8) translateY(1px)}.el-step.is-simple .el-step__main{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:stretch;-ms-flex-align:stretch;align-items:stretch;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1}.el-step.is-simple .el-step__title{font-size:16px;line-height:20px}.el-step.is-simple:not(:last-of-type) .el-step__title{max-width:50%;word-break:break-all}.el-step.is-simple .el-step__arrow{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center}.el-step.is-simple .el-step__arrow::after,.el-step.is-simple .el-step__arrow::before{content:'';display:inline-block;position:absolute;height:15px;width:1px;background:#C0C4CC}.el-step.is-simple .el-step__arrow::before{-webkit-transform:rotate(-45deg) translateY(-4px);transform:rotate(-45deg) translateY(-4px);-webkit-transform-origin:0 0;transform-origin:0 0}.el-step.is-simple .el-step__arrow::after{-webkit-transform:rotate(45deg) translateY(4px);transform:rotate(45deg) translateY(4px);-webkit-transform-origin:100% 100%;transform-origin:100% 100%}.el-step.is-simple:last-of-type .el-step__arrow{display:none}.el-carousel{position:relative}.el-carousel--horizontal{overflow-x:hidden}.el-carousel--vertical{overflow-y:hidden}.el-carousel__container{position:relative;height:300px}.el-carousel__arrow{border:none;outline:0;padding:0;margin:0;height:36px;width:36px;cursor:pointer;-webkit-transition:.3s;transition:.3s;border-radius:50%;background-color:rgba(31,45,61,.11);color:#FFF;position:absolute;top:50%;z-index:10;-webkit-transform:translateY(-50%);transform:translateY(-50%);text-align:center;font-size:12px}.el-carousel__arrow--left{left:16px}.el-carousel__arrow:hover{background-color:rgba(31,45,61,.23)}.el-carousel__arrow i{cursor:pointer}.el-carousel__indicators{position:absolute;list-style:none;margin:0;padding:0;z-index:2}.el-carousel__indicators--horizontal{bottom:0;left:50%;-webkit-transform:translateX(-50%);transform:translateX(-50%)}.el-carousel__indicators--vertical{right:0;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-carousel__indicators--outside{bottom:26px;text-align:center;position:static;-webkit-transform:none;transform:none}.el-carousel__indicators--outside .el-carousel__indicator:hover button{opacity:.64}.el-carousel__indicators--outside button{background-color:#C0C4CC;opacity:.24}.el-carousel__indicators--labels{left:0;right:0;-webkit-transform:none;transform:none;text-align:center}.el-carousel__indicators--labels .el-carousel__button{height:auto;width:auto;padding:2px 18px;font-size:12px}.el-carousel__indicators--labels .el-carousel__indicator{padding:6px 4px}.el-carousel__indicator{background-color:transparent;cursor:pointer}.el-carousel__indicator:hover button{opacity:.72}.el-carousel__indicator--horizontal{display:inline-block;padding:12px 4px}.el-carousel__indicator--vertical{padding:4px 12px}.el-carousel__indicator--vertical .el-carousel__button{width:2px;height:15px}.el-carousel__indicator.is-active button{opacity:1}.el-carousel__button{display:block;opacity:.48;width:30px;height:2px;background-color:#FFF;border:none;outline:0;padding:0;margin:0;cursor:pointer;-webkit-transition:.3s;transition:.3s}.el-carousel__item,.el-carousel__mask{height:100%;position:absolute;top:0;left:0}.carousel-arrow-left-enter,.carousel-arrow-left-leave-active{-webkit-transform:translateY(-50%) translateX(-10px);transform:translateY(-50%) translateX(-10px);opacity:0}.carousel-arrow-right-enter,.carousel-arrow-right-leave-active{-webkit-transform:translateY(-50%) translateX(10px);transform:translateY(-50%) translateX(10px);opacity:0}.el-carousel__item{width:100%;display:inline-block;overflow:hidden;z-index:0}.el-carousel__item.is-active{z-index:2}.el-carousel__item.is-animating{-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card{width:50%;-webkit-transition:-webkit-transform .4s ease-in-out;transition:-webkit-transform .4s ease-in-out;transition:transform .4s ease-in-out;transition:transform .4s ease-in-out,-webkit-transform .4s ease-in-out}.el-carousel__item--card.is-in-stage{cursor:pointer;z-index:1}.el-carousel__item--card.is-in-stage.is-hover .el-carousel__mask,.el-carousel__item--card.is-in-stage:hover .el-carousel__mask{opacity:.12}.el-carousel__item--card.is-active{z-index:2}.el-carousel__mask{width:100%;background-color:#FFF;opacity:.24;-webkit-transition:.2s;transition:.2s}.fade-in-linear-enter-active,.fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.fade-in-linear-enter,.fade-in-linear-leave,.fade-in-linear-leave-active{opacity:0}.el-fade-in-linear-enter-active,.el-fade-in-linear-leave-active{-webkit-transition:opacity .2s linear;transition:opacity .2s linear}.el-fade-in-linear-enter,.el-fade-in-linear-leave,.el-fade-in-linear-leave-active{opacity:0}.el-fade-in-enter-active,.el-fade-in-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-fade-in-enter,.el-fade-in-leave-active{opacity:0}.el-zoom-in-center-enter-active,.el-zoom-in-center-leave-active{-webkit-transition:all .3s cubic-bezier(.55,0,.1,1);transition:all .3s cubic-bezier(.55,0,.1,1)}.el-zoom-in-center-enter,.el-zoom-in-center-leave-active{opacity:0;-webkit-transform:scaleX(0);transform:scaleX(0)}.el-zoom-in-top-enter-active,.el-zoom-in-top-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center top;transform-origin:center top}.el-zoom-in-top-enter,.el-zoom-in-top-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-bottom-enter-active,.el-zoom-in-bottom-leave-active{opacity:1;-webkit-transform:scaleY(1);transform:scaleY(1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:center bottom;transform-origin:center bottom}.el-zoom-in-bottom-enter,.el-zoom-in-bottom-leave-active{opacity:0;-webkit-transform:scaleY(0);transform:scaleY(0)}.el-zoom-in-left-enter-active,.el-zoom-in-left-leave-active{opacity:1;-webkit-transform:scale(1,1);transform:scale(1,1);-webkit-transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1);transition:transform .3s cubic-bezier(.23,1,.32,1),opacity .3s cubic-bezier(.23,1,.32,1),-webkit-transform .3s cubic-bezier(.23,1,.32,1);-webkit-transform-origin:top left;transform-origin:top left}.el-zoom-in-left-enter,.el-zoom-in-left-leave-active{opacity:0;-webkit-transform:scale(.45,.45);transform:scale(.45,.45)}.collapse-transition{-webkit-transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out;transition:.3s height ease-in-out,.3s padding-top ease-in-out,.3s padding-bottom ease-in-out}.horizontal-collapse-transition{-webkit-transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out;transition:.3s width ease-in-out,.3s padding-left ease-in-out,.3s padding-right ease-in-out}.el-list-enter-active,.el-list-leave-active{-webkit-transition:all 1s;transition:all 1s}.el-list-enter,.el-list-leave-active{opacity:0;-webkit-transform:translateY(-30px);transform:translateY(-30px)}.el-opacity-transition{-webkit-transition:opacity .3s cubic-bezier(.55,0,.1,1);transition:opacity .3s cubic-bezier(.55,0,.1,1)}.el-collapse{border-top:1px solid #EBEEF5;border-bottom:1px solid #EBEEF5}.el-collapse-item.is-disabled .el-collapse-item__header{color:#bbb;cursor:not-allowed}.el-collapse-item__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:48px;line-height:48px;background-color:#FFF;color:#303133;cursor:pointer;border-bottom:1px solid #EBEEF5;font-size:13px;font-weight:500;-webkit-transition:border-bottom-color .3s;transition:border-bottom-color .3s;outline:0}.el-collapse-item__arrow{margin:0 8px 0 auto;-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-weight:300}.el-collapse-item__arrow.is-active{-webkit-transform:rotate(90deg);transform:rotate(90deg)}.el-collapse-item__header.focusing:focus:not(:hover){color:#409EFF}.el-collapse-item__header.is-active{border-bottom-color:transparent}.el-collapse-item__wrap{will-change:height;background-color:#FFF;overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;border-bottom:1px solid #EBEEF5}.el-cascader__search-input,.el-cascader__tags,.el-tag{-webkit-box-sizing:border-box}.el-collapse-item__content{padding-bottom:25px;font-size:13px;color:#303133;line-height:1.769230769230769}.el-collapse-item:last-child{margin-bottom:-1px}.el-popper .popper__arrow,.el-popper .popper__arrow::after{position:absolute;display:block;width:0;height:0;border-color:transparent;border-style:solid}.el-cascader,.el-tag{display:inline-block}.el-popper .popper__arrow{border-width:6px;-webkit-filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03));filter:drop-shadow(0 2px 12px rgba(0, 0, 0, .03))}.el-popper .popper__arrow::after{content:" ";border-width:6px}.el-popper[x-placement^=top]{margin-bottom:12px}.el-popper[x-placement^=top] .popper__arrow{bottom:-6px;left:50%;margin-right:3px;border-top-color:#EBEEF5;border-bottom-width:0}.el-popper[x-placement^=top] .popper__arrow::after{bottom:1px;margin-left:-6px;border-top-color:#FFF;border-bottom-width:0}.el-popper[x-placement^=bottom]{margin-top:12px}.el-popper[x-placement^=bottom] .popper__arrow{top:-6px;left:50%;margin-right:3px;border-top-width:0;border-bottom-color:#EBEEF5}.el-popper[x-placement^=bottom] .popper__arrow::after{top:1px;margin-left:-6px;border-top-width:0;border-bottom-color:#FFF}.el-popper[x-placement^=right]{margin-left:12px}.el-popper[x-placement^=right] .popper__arrow{top:50%;left:-6px;margin-bottom:3px;border-right-color:#EBEEF5;border-left-width:0}.el-popper[x-placement^=right] .popper__arrow::after{bottom:-6px;left:1px;border-right-color:#FFF;border-left-width:0}.el-popper[x-placement^=left]{margin-right:12px}.el-popper[x-placement^=left] .popper__arrow{top:50%;right:-6px;margin-bottom:3px;border-right-width:0;border-left-color:#EBEEF5}.el-popper[x-placement^=left] .popper__arrow::after{right:1px;bottom:-6px;margin-left:-6px;border-right-width:0;border-left-color:#FFF}.el-tag{background-color:#ecf5ff;border-color:#d9ecff;height:32px;padding:0 10px;line-height:30px;font-size:12px;color:#409EFF;border-width:1px;border-style:solid;border-radius:4px;box-sizing:border-box;white-space:nowrap}.el-tag.is-hit{border-color:#409EFF}.el-tag .el-tag__close{color:#409eff}.el-tag .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag.el-tag--info{background-color:#f4f4f5;border-color:#e9e9eb;color:#909399}.el-tag.el-tag--info.is-hit{border-color:#909399}.el-tag.el-tag--info .el-tag__close{color:#909399}.el-tag.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag.el-tag--success{background-color:#f0f9eb;border-color:#e1f3d8;color:#67c23a}.el-tag.el-tag--success.is-hit{border-color:#67C23A}.el-tag.el-tag--success .el-tag__close{color:#67c23a}.el-tag.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag.el-tag--warning{background-color:#fdf6ec;border-color:#faecd8;color:#e6a23c}.el-tag.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag.el-tag--danger{background-color:#fef0f0;border-color:#fde2e2;color:#f56c6c}.el-tag.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag .el-icon-close{border-radius:50%;text-align:center;position:relative;cursor:pointer;font-size:12px;height:16px;width:16px;line-height:16px;vertical-align:middle;top:-1px;right:-5px}.el-tag .el-icon-close::before{display:block}.el-tag--dark{background-color:#409eff;border-color:#409eff;color:#fff}.el-tag--dark.is-hit{border-color:#409EFF}.el-tag--dark .el-tag__close{color:#fff}.el-tag--dark .el-tag__close:hover{color:#FFF;background-color:#66b1ff}.el-tag--dark.el-tag--info{background-color:#909399;border-color:#909399;color:#fff}.el-tag--dark.el-tag--info.is-hit{border-color:#909399}.el-tag--dark.el-tag--info .el-tag__close{color:#fff}.el-tag--dark.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#a6a9ad}.el-tag--dark.el-tag--success{background-color:#67c23a;border-color:#67c23a;color:#fff}.el-tag--dark.el-tag--success.is-hit{border-color:#67C23A}.el-tag--dark.el-tag--success .el-tag__close{color:#fff}.el-tag--dark.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#85ce61}.el-tag--dark.el-tag--warning{background-color:#e6a23c;border-color:#e6a23c;color:#fff}.el-tag--dark.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--dark.el-tag--warning .el-tag__close{color:#fff}.el-tag--dark.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#ebb563}.el-tag--dark.el-tag--danger{background-color:#f56c6c;border-color:#f56c6c;color:#fff}.el-tag--dark.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--dark.el-tag--danger .el-tag__close{color:#fff}.el-tag--dark.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f78989}.el-tag--plain{background-color:#fff;border-color:#b3d8ff;color:#409eff}.el-tag--plain.is-hit{border-color:#409EFF}.el-tag--plain .el-tag__close{color:#409eff}.el-tag--plain .el-tag__close:hover{color:#FFF;background-color:#409eff}.el-tag--plain.el-tag--info{background-color:#fff;border-color:#d3d4d6;color:#909399}.el-tag--plain.el-tag--info.is-hit{border-color:#909399}.el-tag--plain.el-tag--info .el-tag__close{color:#909399}.el-tag--plain.el-tag--info .el-tag__close:hover{color:#FFF;background-color:#909399}.el-tag--plain.el-tag--success{background-color:#fff;border-color:#c2e7b0;color:#67c23a}.el-tag--plain.el-tag--success.is-hit{border-color:#67C23A}.el-tag--plain.el-tag--success .el-tag__close{color:#67c23a}.el-tag--plain.el-tag--success .el-tag__close:hover{color:#FFF;background-color:#67c23a}.el-tag--plain.el-tag--warning{background-color:#fff;border-color:#f5dab1;color:#e6a23c}.el-tag--plain.el-tag--warning.is-hit{border-color:#E6A23C}.el-tag--plain.el-tag--warning .el-tag__close{color:#e6a23c}.el-tag--plain.el-tag--warning .el-tag__close:hover{color:#FFF;background-color:#e6a23c}.el-tag--plain.el-tag--danger{background-color:#fff;border-color:#fbc4c4;color:#f56c6c}.el-tag--plain.el-tag--danger.is-hit{border-color:#F56C6C}.el-tag--plain.el-tag--danger .el-tag__close{color:#f56c6c}.el-tag--plain.el-tag--danger .el-tag__close:hover{color:#FFF;background-color:#f56c6c}.el-tag--medium{height:28px;line-height:26px}.el-tag--medium .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--small{height:24px;padding:0 8px;line-height:22px}.el-tag--small .el-icon-close{-webkit-transform:scale(.8);transform:scale(.8)}.el-tag--mini{height:20px;padding:0 5px;line-height:19px}.el-tag--mini .el-icon-close{margin-left:-3px;-webkit-transform:scale(.7);transform:scale(.7)}.el-cascader{position:relative;font-size:14px;line-height:40px}.el-cascader:not(.is-disabled):hover .el-input__inner{cursor:pointer;border-color:#C0C4CC}.el-cascader .el-input .el-input__inner:focus,.el-cascader .el-input.is-focus .el-input__inner{border-color:#409EFF}.el-cascader .el-input{cursor:pointer}.el-cascader .el-input .el-input__inner{text-overflow:ellipsis}.el-cascader .el-input .el-icon-arrow-down{-webkit-transition:-webkit-transform .3s;transition:-webkit-transform .3s;transition:transform .3s;transition:transform .3s,-webkit-transform .3s;font-size:14px}.el-cascader .el-input .el-icon-arrow-down.is-reverse{-webkit-transform:rotateZ(180deg);transform:rotateZ(180deg)}.el-cascader .el-input .el-icon-circle-close:hover{color:#909399}.el-cascader--medium{font-size:14px;line-height:36px}.el-cascader--small{font-size:13px;line-height:32px}.el-cascader--mini{font-size:12px;line-height:28px}.el-cascader.is-disabled .el-cascader__label{z-index:2;color:#C0C4CC}.el-cascader__dropdown{margin:5px 0;font-size:14px;background:#FFF;border:1px solid #E4E7ED;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-cascader__tags{position:absolute;left:0;right:30px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap;line-height:normal;text-align:left;box-sizing:border-box}.el-cascader__tags .el-tag{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;max-width:100%;margin:2px 0 2px 6px;text-overflow:ellipsis;background:#f0f2f5}.el-cascader__tags .el-tag:not(.is-hit){border-color:transparent}.el-cascader__tags .el-tag>span{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:hidden;text-overflow:ellipsis}.el-cascader__tags .el-tag .el-icon-close{-webkit-box-flex:0;-ms-flex:none;flex:none;background-color:#C0C4CC;color:#FFF}.el-cascader__tags .el-tag .el-icon-close:hover{background-color:#909399}.el-cascader__suggestion-panel{border-radius:4px}.el-cascader__suggestion-list{max-height:204px;margin:0;padding:6px 0;font-size:14px;color:#606266;text-align:center}.el-cascader__suggestion-item{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;height:34px;padding:0 15px;text-align:left;outline:0;cursor:pointer}.el-cascader__suggestion-item:focus,.el-cascader__suggestion-item:hover{background:#F5F7FA}.el-cascader__suggestion-item.is-checked{color:#409EFF;font-weight:700}.el-cascader__suggestion-item>span{margin-right:10px}.el-cascader__empty-text{margin:10px 0;color:#C0C4CC}.el-cascader__search-input{-webkit-box-flex:1;-ms-flex:1;flex:1;height:24px;min-width:60px;margin:2px 0 2px 15px;padding:0;color:#606266;border:none;outline:0;box-sizing:border-box}.el-cascader__search-input::-webkit-input-placeholder{color:#C0C4CC}.el-cascader__search-input:-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::-ms-input-placeholder{color:#C0C4CC}.el-cascader__search-input::placeholder{color:#C0C4CC}.el-color-predefine{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;margin-top:8px;width:280px}.el-color-predefine__colors{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-wrap:wrap;flex-wrap:wrap}.el-color-predefine__color-selector{margin:0 0 8px 8px;width:20px;height:20px;border-radius:4px;cursor:pointer}.el-color-predefine__color-selector:nth-child(10n+1){margin-left:0}.el-color-predefine__color-selector.selected{-webkit-box-shadow:0 0 3px 2px #409EFF;box-shadow:0 0 3px 2px #409EFF}.el-color-predefine__color-selector>div{display:-webkit-box;display:-ms-flexbox;display:flex;height:100%;border-radius:3px}.el-color-predefine__color-selector.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-hue-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background-color:red;padding:0 2px}.el-color-hue-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to right,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%);height:100%}.el-color-hue-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-hue-slider.is-vertical{width:12px;height:180px;padding:2px 0}.el-color-hue-slider.is-vertical .el-color-hue-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(red),color-stop(17%,#ff0),color-stop(33%,#0f0),color-stop(50%,#0ff),color-stop(67%,#00f),color-stop(83%,#f0f),to(red));background:linear-gradient(to bottom,red 0,#ff0 17%,#0f0 33%,#0ff 50%,#00f 67%,#f0f 83%,red 100%)}.el-color-hue-slider.is-vertical .el-color-hue-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-svpanel{position:relative;width:280px;height:180px}.el-color-svpanel__black,.el-color-svpanel__white{position:absolute;top:0;left:0;right:0;bottom:0}.el-color-svpanel__white{background:-webkit-gradient(linear,left top,right top,from(#fff),to(rgba(255,255,255,0)));background:linear-gradient(to right,#fff,rgba(255,255,255,0))}.el-color-svpanel__black{background:-webkit-gradient(linear,left bottom,left top,from(#000),to(rgba(0,0,0,0)));background:linear-gradient(to top,#000,rgba(0,0,0,0))}.el-color-svpanel__cursor{position:absolute}.el-color-svpanel__cursor>div{cursor:head;width:4px;height:4px;-webkit-box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);box-shadow:0 0 0 1.5px #fff,inset 0 0 1px 1px rgba(0,0,0,.3),0 0 1px 2px rgba(0,0,0,.4);border-radius:50%;-webkit-transform:translate(-2px,-2px);transform:translate(-2px,-2px)}.el-color-alpha-slider{position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:280px;height:12px;background:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-alpha-slider__bar{position:relative;background:-webkit-gradient(linear,left top,right top,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to right,rgba(255,255,255,0) 0,#fff 100%);height:100%}.el-color-alpha-slider__thumb{position:absolute;cursor:pointer;-webkit-box-sizing:border-box;box-sizing:border-box;left:0;top:0;width:4px;height:100%;border-radius:1px;background:#fff;border:1px solid #f0f0f0;-webkit-box-shadow:0 0 2px rgba(0,0,0,.6);box-shadow:0 0 2px rgba(0,0,0,.6);z-index:1}.el-color-alpha-slider.is-vertical{width:20px;height:180px}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__bar{background:-webkit-gradient(linear,left top,left bottom,from(rgba(255,255,255,0)),to(white));background:linear-gradient(to bottom,rgba(255,255,255,0) 0,#fff 100%)}.el-color-alpha-slider.is-vertical .el-color-alpha-slider__thumb{left:0;top:0;width:100%;height:4px}.el-color-dropdown{width:300px}.el-color-dropdown__main-wrapper{margin-bottom:6px}.el-color-dropdown__main-wrapper::after{display:table;clear:both}.el-color-dropdown__btns{margin-top:6px;text-align:right}.el-color-dropdown__value{float:left;line-height:26px;font-size:12px;color:#000;width:160px}.el-color-dropdown__btn{border:1px solid #dcdcdc;color:#333;line-height:24px;border-radius:2px;padding:0 20px;cursor:pointer;background-color:transparent;outline:0;font-size:12px}.el-color-dropdown__btn[disabled]{color:#ccc;cursor:not-allowed}.el-color-dropdown__btn:hover{color:#409EFF;border-color:#409EFF}.el-color-dropdown__link-btn{cursor:pointer;color:#409EFF;text-decoration:none;padding:15px;font-size:12px}.el-color-dropdown__link-btn:hover{color:tint(#409EFF,20%)}.el-color-picker{display:inline-block;position:relative;line-height:normal;height:40px}.el-color-picker.is-disabled .el-color-picker__trigger{cursor:not-allowed}.el-color-picker--medium{height:36px}.el-color-picker--medium .el-color-picker__trigger{height:36px;width:36px}.el-color-picker--medium .el-color-picker__mask{height:34px;width:34px}.el-color-picker--small{height:32px}.el-color-picker--small .el-color-picker__trigger{height:32px;width:32px}.el-color-picker--small .el-color-picker__mask{height:30px;width:30px}.el-color-picker--small .el-color-picker__empty,.el-color-picker--small .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker--mini{height:28px}.el-color-picker--mini .el-color-picker__trigger{height:28px;width:28px}.el-color-picker--mini .el-color-picker__mask{height:26px;width:26px}.el-color-picker--mini .el-color-picker__empty,.el-color-picker--mini .el-color-picker__icon{-webkit-transform:translate3d(-50%,-50%,0) scale(.8);transform:translate3d(-50%,-50%,0) scale(.8)}.el-color-picker__mask{height:38px;width:38px;border-radius:4px;position:absolute;top:1px;left:1px;z-index:1;cursor:not-allowed;background-color:rgba(255,255,255,.7)}.el-color-picker__trigger{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px;width:40px;padding:4px;border:1px solid #e6e6e6;border-radius:4px;font-size:0;position:relative;cursor:pointer}.el-color-picker__color{position:relative;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;border:1px solid #999;border-radius:2px;width:100%;height:100%;text-align:center}.el-color-picker__icon,.el-input,.el-textarea{display:inline-block;width:100%}.el-color-picker__color.is-alpha{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==)}.el-color-picker__color-inner{position:absolute;left:0;top:0;right:0;bottom:0}.el-color-picker__empty{font-size:12px;color:#999;position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.el-color-picker__icon{position:absolute;top:50%;left:50%;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0);color:#FFF;text-align:center;font-size:12px}.el-input__prefix,.el-input__suffix{position:absolute;top:0;text-align:center}.el-color-picker__panel{position:absolute;z-index:10;padding:6px;-webkit-box-sizing:content-box;box-sizing:content-box;background-color:#FFF;border:1px solid #EBEEF5;border-radius:4px;box-shadow:0 2px 12px 0 rgba(0,0,0,.1)}.el-input__inner,.el-textarea__inner,.el-transfer-panel{-webkit-box-sizing:border-box}.el-textarea{position:relative;vertical-align:bottom;font-size:14px}.el-textarea__inner{display:block;resize:vertical;padding:5px 15px;line-height:1.5;box-sizing:border-box;width:100%;font-size:inherit;color:#606266;background-color:#FFF;background-image:none;border:1px solid #DCDFE6;border-radius:4px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1)}.el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea__inner:hover{border-color:#C0C4CC}.el-textarea__inner:focus{outline:0;border-color:#409EFF}.el-textarea .el-input__count{color:#909399;background:#FFF;position:absolute;font-size:12px;bottom:5px;right:10px}.el-textarea.is-disabled .el-textarea__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-textarea.is-disabled .el-textarea__inner::-webkit-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner:-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::-ms-input-placeholder{color:#C0C4CC}.el-textarea.is-disabled .el-textarea__inner::placeholder{color:#C0C4CC}.el-textarea.is-exceed .el-textarea__inner{border-color:#F56C6C}.el-textarea.is-exceed .el-input__count{color:#F56C6C}.el-input{position:relative;font-size:14px}.el-input::-webkit-scrollbar{z-index:11;width:6px}.el-input::-webkit-scrollbar:horizontal{height:6px}.el-input::-webkit-scrollbar-thumb{border-radius:5px;width:6px;background:#b4bccc}.el-input::-webkit-scrollbar-corner{background:#fff}.el-input::-webkit-scrollbar-track{background:#fff}.el-input::-webkit-scrollbar-track-piece{background:#fff;width:6px}.el-input .el-input__clear{color:#C0C4CC;font-size:14px;cursor:pointer;-webkit-transition:color .2s cubic-bezier(.645,.045,.355,1);transition:color .2s cubic-bezier(.645,.045,.355,1)}.el-input .el-input__clear:hover{color:#909399}.el-input .el-input__count{height:100%;display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#909399;font-size:12px}.el-input-group__append .el-button,.el-input-group__append .el-input,.el-input-group__prepend .el-button,.el-input-group__prepend .el-input,.el-input__inner{font-size:inherit}.el-input .el-input__count .el-input__count-inner{background:#FFF;line-height:initial;display:inline-block;padding:0 5px}.el-input__inner{-webkit-appearance:none;background-color:#FFF;background-image:none;border-radius:4px;border:1px solid #DCDFE6;box-sizing:border-box;color:#606266;display:inline-block;height:40px;line-height:40px;outline:0;padding:0 15px;-webkit-transition:border-color .2s cubic-bezier(.645,.045,.355,1);transition:border-color .2s cubic-bezier(.645,.045,.355,1);width:100%}.el-input__inner::-ms-reveal{display:none}.el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input__inner::placeholder{color:#C0C4CC}.el-input__inner:hover{border-color:#C0C4CC}.el-input.is-active .el-input__inner,.el-input__inner:focus{border-color:#409EFF;outline:0}.el-input__suffix{height:100%;right:5px;transition:all .3s;pointer-events:none}.el-input__suffix-inner{pointer-events:all}.el-input__prefix{height:100%;left:5px;transition:all .3s}.el-input__icon{height:100%;width:25px;text-align:center;-webkit-transition:all .3s;transition:all .3s;line-height:40px}.el-input__icon:after{content:'';height:100%;width:0;display:inline-block;vertical-align:middle}.el-input__validateIcon{pointer-events:none}.el-input.is-disabled .el-input__inner{background-color:#F5F7FA;border-color:#E4E7ED;color:#C0C4CC;cursor:not-allowed}.el-input.is-disabled .el-input__inner::-webkit-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner:-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::-ms-input-placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__inner::placeholder{color:#C0C4CC}.el-input.is-disabled .el-input__icon{cursor:not-allowed}.el-image-viewer__btn,.el-image__preview,.el-link,.el-transfer-panel__filter .el-icon-circle-close{cursor:pointer}.el-input.is-exceed .el-input__inner{border-color:#F56C6C}.el-input.is-exceed .el-input__suffix .el-input__count{color:#F56C6C}.el-input--suffix .el-input__inner{padding-right:30px}.el-input--prefix .el-input__inner{padding-left:30px}.el-input--medium{font-size:14px}.el-input--medium .el-input__inner{height:36px;line-height:36px}.el-input--medium .el-input__icon{line-height:36px}.el-input--small{font-size:13px}.el-input--small .el-input__inner{height:32px;line-height:32px}.el-input--small .el-input__icon{line-height:32px}.el-input--mini{font-size:12px}.el-input--mini .el-input__inner{height:28px;line-height:28px}.el-input--mini .el-input__icon{line-height:28px}.el-input-group{line-height:normal;display:inline-table;width:100%;border-collapse:separate;border-spacing:0}.el-input-group>.el-input__inner{vertical-align:middle;display:table-cell}.el-input-group__append,.el-input-group__prepend{background-color:#F5F7FA;color:#909399;vertical-align:middle;display:table-cell;position:relative;border:1px solid #DCDFE6;border-radius:4px;padding:0 20px;width:1px;white-space:nowrap}.el-input-group--append .el-input__inner,.el-input-group__prepend{border-top-right-radius:0;border-bottom-right-radius:0}.el-input-group__append:focus,.el-input-group__prepend:focus{outline:0}.el-input-group__append .el-button,.el-input-group__append .el-select,.el-input-group__prepend .el-button,.el-input-group__prepend .el-select{display:inline-block;margin:-10px -20px}.el-input-group__append button.el-button,.el-input-group__append div.el-select .el-input__inner,.el-input-group__append div.el-select:hover .el-input__inner,.el-input-group__prepend button.el-button,.el-input-group__prepend div.el-select .el-input__inner,.el-input-group__prepend div.el-select:hover .el-input__inner{border-color:transparent;background-color:transparent;color:inherit;border-top:0;border-bottom:0}.el-input-group__prepend{border-right:0}.el-input-group__append{border-left:0;border-top-left-radius:0;border-bottom-left-radius:0}.el-input-group--append .el-select .el-input.is-focus .el-input__inner,.el-input-group--prepend .el-select .el-input.is-focus .el-input__inner{border-color:transparent}.el-input-group--prepend .el-input__inner{border-top-left-radius:0;border-bottom-left-radius:0}.el-input__inner::-ms-clear{display:none;width:0;height:0}.el-transfer{font-size:14px}.el-transfer__buttons{display:inline-block;vertical-align:middle;padding:0 30px}.el-transfer__button{display:block;margin:0 auto;padding:10px;border-radius:50%;color:#FFF;background-color:#409EFF;font-size:0}.el-button-group>.el-button+.el-button,.el-transfer-panel__item+.el-transfer-panel__item,.el-transfer__button [class*=el-icon-]+span{margin-left:0}.el-divider__text,.el-image__error,.el-link,.el-timeline,.el-transfer__button i,.el-transfer__button span{font-size:14px}.el-transfer__button.is-with-texts{border-radius:4px}.el-transfer__button.is-disabled,.el-transfer__button.is-disabled:hover{border:1px solid #DCDFE6;background-color:#F5F7FA;color:#C0C4CC}.el-transfer__button:first-child{margin-bottom:10px}.el-transfer__button:nth-child(2){margin:0}.el-transfer-panel{border:1px solid #EBEEF5;border-radius:4px;overflow:hidden;background:#FFF;display:inline-block;vertical-align:middle;width:200px;max-height:100%;box-sizing:border-box;position:relative}.el-transfer-panel__body{height:246px}.el-transfer-panel__body.is-with-footer{padding-bottom:40px}.el-transfer-panel__list{margin:0;padding:6px 0;list-style:none;height:246px;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-transfer-panel__list.is-filterable{height:194px;padding-top:0}.el-transfer-panel__item{height:30px;line-height:30px;padding-left:15px;display:block!important}.el-transfer-panel__item.el-checkbox{color:#606266}.el-transfer-panel__item:hover{color:#409EFF}.el-transfer-panel__item.el-checkbox .el-checkbox__label{width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;display:block;-webkit-box-sizing:border-box;box-sizing:border-box;padding-left:24px;line-height:30px}.el-transfer-panel__item .el-checkbox__input{position:absolute;top:8px}.el-transfer-panel__filter{text-align:center;margin:15px;-webkit-box-sizing:border-box;box-sizing:border-box;display:block;width:auto}.el-transfer-panel__filter .el-input__inner{height:32px;width:100%;font-size:12px;display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;border-radius:16px;padding-right:10px;padding-left:30px}.el-transfer-panel__filter .el-input__icon{margin-left:5px}.el-transfer-panel .el-transfer-panel__header{height:40px;line-height:40px;background:#F5F7FA;margin:0;padding-left:15px;border-bottom:1px solid #EBEEF5;-webkit-box-sizing:border-box;box-sizing:border-box;color:#000}.el-container,.el-header{-webkit-box-sizing:border-box}.el-transfer-panel .el-transfer-panel__header .el-checkbox{display:block;line-height:40px}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label{font-size:16px;color:#303133;font-weight:400}.el-transfer-panel .el-transfer-panel__header .el-checkbox .el-checkbox__label span{position:absolute;right:15px;color:#909399;font-size:12px;font-weight:400}.el-transfer-panel .el-transfer-panel__footer{height:40px;background:#FFF;margin:0;padding:0;border-top:1px solid #EBEEF5;position:absolute;bottom:0;left:0;width:100%;z-index:1}.el-transfer-panel .el-transfer-panel__footer::after{display:inline-block;height:100%;vertical-align:middle}.el-container,.el-timeline-item__node{display:-webkit-box;display:-ms-flexbox}.el-transfer-panel .el-transfer-panel__footer .el-checkbox{padding-left:20px;color:#606266}.el-transfer-panel .el-transfer-panel__empty{margin:0;height:30px;line-height:30px;padding:6px 15px 0;color:#909399;text-align:center}.el-transfer-panel .el-checkbox__label{padding-left:8px}.el-transfer-panel .el-checkbox__inner{height:14px;width:14px;border-radius:3px}.el-transfer-panel .el-checkbox__inner::after{height:6px;width:3px;left:4px}.el-container{display:flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;box-sizing:border-box;min-width:0}.el-container.is-vertical,.el-drawer,.el-empty,.el-result{-webkit-box-orient:vertical;-webkit-box-direction:normal}.el-container.is-vertical{-ms-flex-direction:column;flex-direction:column}.el-header{padding:0 20px;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-aside{overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-main{display:block;-webkit-box-flex:1;-ms-flex:1;flex:1;-ms-flex-preferred-size:auto;flex-basis:auto;overflow:auto;-webkit-box-sizing:border-box;box-sizing:border-box}.el-footer{padding:0 20px;-webkit-box-sizing:border-box;box-sizing:border-box;-ms-flex-negative:0;flex-shrink:0}.el-timeline{margin:0;list-style:none}.el-timeline .el-timeline-item:last-child .el-timeline-item__tail{display:none}.el-timeline-item{position:relative;padding-bottom:20px}.el-timeline-item__wrapper{position:relative;padding-left:28px;top:-3px}.el-timeline-item__tail{position:absolute;left:4px;height:100%;border-left:2px solid #E4E7ED}.el-timeline-item__icon{color:#FFF;font-size:13px}.el-timeline-item__node{position:absolute;background-color:#E4E7ED;border-radius:50%;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image__error,.el-timeline-item__dot{display:-webkit-box;display:-ms-flexbox}.el-timeline-item__node--normal{left:-1px;width:12px;height:12px}.el-timeline-item__node--large{left:-2px;width:14px;height:14px}.el-timeline-item__node--primary{background-color:#409EFF}.el-timeline-item__node--success{background-color:#67C23A}.el-timeline-item__node--warning{background-color:#E6A23C}.el-timeline-item__node--danger{background-color:#F56C6C}.el-timeline-item__node--info{background-color:#909399}.el-timeline-item__dot{position:absolute;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-timeline-item__content{color:#303133}.el-timeline-item__timestamp{color:#909399;line-height:1;font-size:13px}.el-timeline-item__timestamp.is-top{margin-bottom:8px;padding-top:4px}.el-timeline-item__timestamp.is-bottom{margin-top:8px}.el-link{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-orient:horizontal;-webkit-box-direction:normal;-ms-flex-direction:row;flex-direction:row;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;vertical-align:middle;position:relative;text-decoration:none;outline:0;padding:0;font-weight:500}.el-link.is-underline:hover:after{position:absolute;left:0;right:0;height:0;bottom:0;border-bottom:1px solid #409EFF}.el-link.el-link--default:after,.el-link.el-link--primary.is-underline:hover:after,.el-link.el-link--primary:after{border-color:#409EFF}.el-link.is-disabled{cursor:not-allowed}.el-link [class*=el-icon-]+span{margin-left:5px}.el-link.el-link--default{color:#606266}.el-link.el-link--default:hover{color:#409EFF}.el-link.el-link--default.is-disabled{color:#C0C4CC}.el-link.el-link--primary{color:#409EFF}.el-link.el-link--primary:hover{color:#66b1ff}.el-link.el-link--primary.is-disabled{color:#a0cfff}.el-link.el-link--danger.is-underline:hover:after,.el-link.el-link--danger:after{border-color:#F56C6C}.el-link.el-link--danger{color:#F56C6C}.el-link.el-link--danger:hover{color:#f78989}.el-link.el-link--danger.is-disabled{color:#fab6b6}.el-link.el-link--success.is-underline:hover:after,.el-link.el-link--success:after{border-color:#67C23A}.el-link.el-link--success{color:#67C23A}.el-link.el-link--success:hover{color:#85ce61}.el-link.el-link--success.is-disabled{color:#b3e19d}.el-link.el-link--warning.is-underline:hover:after,.el-link.el-link--warning:after{border-color:#E6A23C}.el-link.el-link--warning{color:#E6A23C}.el-link.el-link--warning:hover{color:#ebb563}.el-link.el-link--warning.is-disabled{color:#f3d19e}.el-link.el-link--info.is-underline:hover:after,.el-link.el-link--info:after{border-color:#909399}.el-link.el-link--info{color:#909399}.el-link.el-link--info:hover{color:#a6a9ad}.el-link.el-link--info.is-disabled{color:#c8c9cc}.el-divider{background-color:#DCDFE6;position:relative}.el-divider--horizontal{display:block;height:1px;width:100%;margin:24px 0}.el-divider--vertical{display:inline-block;width:1px;height:1em;margin:0 8px;vertical-align:middle;position:relative}.el-divider__text{position:absolute;background-color:#FFF;padding:0 20px;font-weight:500;color:#303133}.el-image__error,.el-image__placeholder{background:#F5F7FA}.el-divider__text.is-left{left:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-divider__text.is-center{left:50%;-webkit-transform:translateX(-50%) translateY(-50%);transform:translateX(-50%) translateY(-50%)}.el-divider__text.is-right{right:20px;-webkit-transform:translateY(-50%);transform:translateY(-50%)}.el-image__error,.el-image__inner,.el-image__placeholder{width:100%;height:100%}.el-image{position:relative;display:inline-block;overflow:hidden}.el-image__inner{vertical-align:top}.el-image__inner--center{position:relative;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);display:block}.el-image__error{display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#C0C4CC;vertical-align:middle}.el-image-viewer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0}.el-image-viewer__btn{position:absolute;z-index:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:50%;opacity:.8;-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-user-select:none;user-select:none}.el-button,.el-checkbox,.el-checkbox-button__inner,.el-empty__image img,.el-radio{-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}.el-image-viewer__close{top:40px;right:40px;width:40px;height:40px;font-size:24px;color:#fff;background-color:#606266}.el-image-viewer__canvas{width:100%;height:100%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.el-image-viewer__actions{left:50%;bottom:30px;-webkit-transform:translateX(-50%);transform:translateX(-50%);width:282px;height:44px;padding:0 23px;background-color:#606266;border-color:#fff;border-radius:22px}.el-image-viewer__actions__inner{width:100%;height:100%;text-align:justify;cursor:default;font-size:23px;color:#fff;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-pack:distribute;justify-content:space-around}.el-image-viewer__next,.el-image-viewer__prev{width:44px;height:44px;font-size:24px;color:#fff;background-color:#606266;border-color:#fff;top:50%}.el-image-viewer__prev{-webkit-transform:translateY(-50%);transform:translateY(-50%);left:40px}.el-image-viewer__next{-webkit-transform:translateY(-50%);transform:translateY(-50%);right:40px;text-indent:2px}.el-image-viewer__mask{position:absolute;width:100%;height:100%;top:0;left:0;opacity:.5;background:#000}.viewer-fade-enter-active{-webkit-animation:viewer-fade-in .3s;animation:viewer-fade-in .3s}.viewer-fade-leave-active{-webkit-animation:viewer-fade-out .3s;animation:viewer-fade-out .3s}@-webkit-keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@keyframes viewer-fade-in{0%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}100%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}}@-webkit-keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}@keyframes viewer-fade-out{0%{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0);opacity:1}100%{-webkit-transform:translate3d(0,-20px,0);transform:translate3d(0,-20px,0);opacity:0}}.el-button{display:inline-block;line-height:1;white-space:nowrap;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:.1s;transition:.1s;font-weight:500;padding:12px 20px;font-size:14px;border-radius:4px}.el-button+.el-button,.el-checkbox.is-bordered+.el-checkbox.is-bordered{margin-left:10px}.el-button:focus,.el-button:hover{color:#409EFF;border-color:#c6e2ff;background-color:#ecf5ff}.el-button:active{color:#3a8ee6;border-color:#3a8ee6;outline:0}.el-button::-moz-focus-inner{border:0}.el-button [class*=el-icon-]+span{margin-left:5px}.el-button.is-plain:focus,.el-button.is-plain:hover{background:#FFF;border-color:#409EFF;color:#409EFF}.el-button.is-active,.el-button.is-plain:active{color:#3a8ee6;border-color:#3a8ee6}.el-button.is-plain:active{background:#FFF;outline:0}.el-button.is-disabled,.el-button.is-disabled:focus,.el-button.is-disabled:hover{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5}.el-button.is-disabled.el-button--text{background-color:transparent}.el-button.is-disabled.is-plain,.el-button.is-disabled.is-plain:focus,.el-button.is-disabled.is-plain:hover{background-color:#FFF;border-color:#EBEEF5;color:#C0C4CC}.el-button.is-loading{position:relative;pointer-events:none}.el-button.is-loading:before{pointer-events:none;content:'';position:absolute;left:-1px;top:-1px;right:-1px;bottom:-1px;border-radius:inherit;background-color:rgba(255,255,255,.35)}.el-button.is-round{border-radius:20px;padding:12px 23px}.el-button.is-circle{border-radius:50%;padding:12px}.el-button--primary{color:#FFF;background-color:#409EFF;border-color:#409EFF}.el-button--primary:focus,.el-button--primary:hover{background:#66b1ff;border-color:#66b1ff;color:#FFF}.el-button--primary.is-active,.el-button--primary:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF}.el-button--primary:active{outline:0}.el-button--primary.is-disabled,.el-button--primary.is-disabled:active,.el-button--primary.is-disabled:focus,.el-button--primary.is-disabled:hover{color:#FFF;background-color:#a0cfff;border-color:#a0cfff}.el-button--primary.is-plain{color:#409EFF;background:#ecf5ff;border-color:#b3d8ff}.el-button--primary.is-plain:focus,.el-button--primary.is-plain:hover{background:#409EFF;border-color:#409EFF;color:#FFF}.el-button--primary.is-plain:active{background:#3a8ee6;border-color:#3a8ee6;color:#FFF;outline:0}.el-button--primary.is-plain.is-disabled,.el-button--primary.is-plain.is-disabled:active,.el-button--primary.is-plain.is-disabled:focus,.el-button--primary.is-plain.is-disabled:hover{color:#8cc5ff;background-color:#ecf5ff;border-color:#d9ecff}.el-button--success{color:#FFF;background-color:#67C23A;border-color:#67C23A}.el-button--success:focus,.el-button--success:hover{background:#85ce61;border-color:#85ce61;color:#FFF}.el-button--success.is-active,.el-button--success:active{background:#5daf34;border-color:#5daf34;color:#FFF}.el-button--success:active{outline:0}.el-button--success.is-disabled,.el-button--success.is-disabled:active,.el-button--success.is-disabled:focus,.el-button--success.is-disabled:hover{color:#FFF;background-color:#b3e19d;border-color:#b3e19d}.el-button--success.is-plain{color:#67C23A;background:#f0f9eb;border-color:#c2e7b0}.el-button--success.is-plain:focus,.el-button--success.is-plain:hover{background:#67C23A;border-color:#67C23A;color:#FFF}.el-button--success.is-plain:active{background:#5daf34;border-color:#5daf34;color:#FFF;outline:0}.el-button--success.is-plain.is-disabled,.el-button--success.is-plain.is-disabled:active,.el-button--success.is-plain.is-disabled:focus,.el-button--success.is-plain.is-disabled:hover{color:#a4da89;background-color:#f0f9eb;border-color:#e1f3d8}.el-button--warning{color:#FFF;background-color:#E6A23C;border-color:#E6A23C}.el-button--warning:focus,.el-button--warning:hover{background:#ebb563;border-color:#ebb563;color:#FFF}.el-button--warning.is-active,.el-button--warning:active{background:#cf9236;border-color:#cf9236;color:#FFF}.el-button--warning:active{outline:0}.el-button--warning.is-disabled,.el-button--warning.is-disabled:active,.el-button--warning.is-disabled:focus,.el-button--warning.is-disabled:hover{color:#FFF;background-color:#f3d19e;border-color:#f3d19e}.el-button--warning.is-plain{color:#E6A23C;background:#fdf6ec;border-color:#f5dab1}.el-button--warning.is-plain:focus,.el-button--warning.is-plain:hover{background:#E6A23C;border-color:#E6A23C;color:#FFF}.el-button--warning.is-plain:active{background:#cf9236;border-color:#cf9236;color:#FFF;outline:0}.el-button--warning.is-plain.is-disabled,.el-button--warning.is-plain.is-disabled:active,.el-button--warning.is-plain.is-disabled:focus,.el-button--warning.is-plain.is-disabled:hover{color:#f0c78a;background-color:#fdf6ec;border-color:#faecd8}.el-button--danger{color:#FFF;background-color:#F56C6C;border-color:#F56C6C}.el-button--danger:focus,.el-button--danger:hover{background:#f78989;border-color:#f78989;color:#FFF}.el-button--danger.is-active,.el-button--danger:active{background:#dd6161;border-color:#dd6161;color:#FFF}.el-button--danger:active{outline:0}.el-button--danger.is-disabled,.el-button--danger.is-disabled:active,.el-button--danger.is-disabled:focus,.el-button--danger.is-disabled:hover{color:#FFF;background-color:#fab6b6;border-color:#fab6b6}.el-button--danger.is-plain{color:#F56C6C;background:#fef0f0;border-color:#fbc4c4}.el-button--danger.is-plain:focus,.el-button--danger.is-plain:hover{background:#F56C6C;border-color:#F56C6C;color:#FFF}.el-button--danger.is-plain:active{background:#dd6161;border-color:#dd6161;color:#FFF;outline:0}.el-button--danger.is-plain.is-disabled,.el-button--danger.is-plain.is-disabled:active,.el-button--danger.is-plain.is-disabled:focus,.el-button--danger.is-plain.is-disabled:hover{color:#f9a7a7;background-color:#fef0f0;border-color:#fde2e2}.el-button--info{color:#FFF;background-color:#909399;border-color:#909399}.el-button--info:focus,.el-button--info:hover{background:#a6a9ad;border-color:#a6a9ad;color:#FFF}.el-button--info.is-active,.el-button--info:active{background:#82848a;border-color:#82848a;color:#FFF}.el-button--info:active{outline:0}.el-button--info.is-disabled,.el-button--info.is-disabled:active,.el-button--info.is-disabled:focus,.el-button--info.is-disabled:hover{color:#FFF;background-color:#c8c9cc;border-color:#c8c9cc}.el-button--info.is-plain{color:#909399;background:#f4f4f5;border-color:#d3d4d6}.el-button--info.is-plain:focus,.el-button--info.is-plain:hover{background:#909399;border-color:#909399;color:#FFF}.el-button--info.is-plain:active{background:#82848a;border-color:#82848a;color:#FFF;outline:0}.el-button--info.is-plain.is-disabled,.el-button--info.is-plain.is-disabled:active,.el-button--info.is-plain.is-disabled:focus,.el-button--info.is-plain.is-disabled:hover{color:#bcbec2;background-color:#f4f4f5;border-color:#e9e9eb}.el-button--medium{padding:10px 20px;font-size:14px;border-radius:4px}.el-button--medium.is-round{padding:10px 20px}.el-button--medium.is-circle{padding:10px}.el-button--small{padding:9px 15px;font-size:12px;border-radius:3px}.el-button--small.is-round{padding:9px 15px}.el-button--small.is-circle{padding:9px}.el-button--mini,.el-button--mini.is-round{padding:7px 15px}.el-button--mini{font-size:12px;border-radius:3px}.el-button--mini.is-circle{padding:7px}.el-button--text{border-color:transparent;color:#409EFF;background:0 0;padding-left:0;padding-right:0}.el-button--text:focus,.el-button--text:hover{color:#66b1ff;border-color:transparent;background-color:transparent}.el-button--text:active{color:#3a8ee6;border-color:transparent;background-color:transparent}.el-button--text.is-disabled,.el-button--text.is-disabled:focus,.el-button--text.is-disabled:hover{border-color:transparent}.el-button-group .el-button--danger:last-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:last-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:last-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:last-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:last-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child),.el-button-group>.el-dropdown>.el-button{border-left-color:rgba(255,255,255,.5)}.el-button-group .el-button--danger:first-child,.el-button-group .el-button--danger:not(:first-child):not(:last-child),.el-button-group .el-button--info:first-child,.el-button-group .el-button--info:not(:first-child):not(:last-child),.el-button-group .el-button--primary:first-child,.el-button-group .el-button--primary:not(:first-child):not(:last-child),.el-button-group .el-button--success:first-child,.el-button-group .el-button--success:not(:first-child):not(:last-child),.el-button-group .el-button--warning:first-child,.el-button-group .el-button--warning:not(:first-child):not(:last-child){border-right-color:rgba(255,255,255,.5)}.el-button-group{display:inline-block;vertical-align:middle}.el-button-group::after,.el-button-group::before{display:table}.el-button-group::after{clear:both}.el-button-group>.el-button{float:left;position:relative}.el-button-group>.el-button.is-disabled{z-index:1}.el-button-group>.el-button:first-child{border-top-right-radius:0;border-bottom-right-radius:0}.el-button-group>.el-button:last-child{border-top-left-radius:0;border-bottom-left-radius:0}.el-button-group>.el-button:first-child:last-child{border-radius:4px}.el-button-group>.el-button:first-child:last-child.is-round{border-radius:20px}.el-button-group>.el-button:first-child:last-child.is-circle{border-radius:50%}.el-button-group>.el-button:not(:first-child):not(:last-child){border-radius:0}.el-button-group>.el-button.is-active,.el-button-group>.el-button:not(.is-disabled):active,.el-button-group>.el-button:not(.is-disabled):focus,.el-button-group>.el-button:not(.is-disabled):hover{z-index:1}.el-button-group>.el-dropdown>.el-button{border-top-left-radius:0;border-bottom-left-radius:0}.el-calendar{background-color:#fff}.el-calendar__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;padding:12px 20px;border-bottom:1px solid #EBEEF5}.el-backtop,.el-page-header{display:-webkit-box;display:-ms-flexbox}.el-calendar__title{color:#000;-ms-flex-item-align:center;align-self:center}.el-calendar__body{padding:12px 20px 35px}.el-calendar-table{table-layout:fixed;width:100%}.el-calendar-table thead th{padding:12px 0;color:#606266;font-weight:400}.el-calendar-table:not(.is-range) td.next,.el-calendar-table:not(.is-range) td.prev{color:#C0C4CC}.el-backtop,.el-calendar-table td.is-today{color:#409EFF}.el-calendar-table td{border-bottom:1px solid #EBEEF5;border-right:1px solid #EBEEF5;vertical-align:top;-webkit-transition:background-color .2s ease;transition:background-color .2s ease}.el-calendar-table td.is-selected{background-color:#F2F8FE}.el-calendar-table tr:first-child td{border-top:1px solid #EBEEF5}.el-calendar-table tr td:first-child{border-left:1px solid #EBEEF5}.el-calendar-table tr.el-calendar-table__row--hide-border td{border-top:none}.el-calendar-table .el-calendar-day{-webkit-box-sizing:border-box;box-sizing:border-box;padding:8px;height:85px}.el-calendar-table .el-calendar-day:hover{cursor:pointer;background-color:#F2F8FE}.el-backtop{position:fixed;background-color:#FFF;width:40px;height:40px;border-radius:50%;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;font-size:20px;-webkit-box-shadow:0 0 6px rgba(0,0,0,.12);box-shadow:0 0 6px rgba(0,0,0,.12);cursor:pointer;z-index:5}.el-backtop:hover{background-color:#F2F6FC}.el-page-header{display:flex;line-height:24px}.el-page-header__left{display:-webkit-box;display:-ms-flexbox;display:flex;cursor:pointer;margin-right:40px;position:relative}.el-page-header__left::after{position:absolute;width:1px;height:16px;right:-20px;top:50%;-webkit-transform:translateY(-50%);transform:translateY(-50%);background-color:#DCDFE6}.el-checkbox,.el-checkbox__input{display:inline-block;position:relative;white-space:nowrap}.el-page-header__left .el-icon-back{font-size:18px;margin-right:6px;-ms-flex-item-align:center;align-self:center}.el-page-header__title{font-size:14px;font-weight:500}.el-page-header__content{font-size:18px;color:#303133}.el-checkbox{color:#606266;font-weight:500;font-size:14px;cursor:pointer;user-select:none;margin-right:30px}.el-checkbox.is-bordered{padding:9px 20px 9px 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;line-height:normal;height:40px}.el-checkbox.is-bordered.is-checked{border-color:#409EFF}.el-checkbox.is-bordered.is-disabled{border-color:#EBEEF5;cursor:not-allowed}.el-checkbox.is-bordered.el-checkbox--medium{padding:7px 20px 7px 10px;border-radius:4px;height:36px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__label{line-height:17px;font-size:14px}.el-checkbox.is-bordered.el-checkbox--medium .el-checkbox__inner{height:14px;width:14px}.el-checkbox.is-bordered.el-checkbox--small{padding:5px 15px 5px 10px;border-radius:3px;height:32px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__label{line-height:15px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--small .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox.is-bordered.el-checkbox--mini{padding:3px 15px 3px 10px;border-radius:3px;height:28px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__label{line-height:12px;font-size:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner{height:12px;width:12px}.el-checkbox.is-bordered.el-checkbox--mini .el-checkbox__inner::after{height:6px;width:2px}.el-checkbox__input{cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-checkbox__input.is-disabled .el-checkbox__inner{background-color:#edf2fc;border-color:#DCDFE6;cursor:not-allowed}.el-checkbox__input.is-disabled .el-checkbox__inner::after{cursor:not-allowed;border-color:#C0C4CC}.el-checkbox__input.is-disabled .el-checkbox__inner+.el-checkbox__label{cursor:not-allowed}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-checked .el-checkbox__inner::after{border-color:#C0C4CC}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner{background-color:#F2F6FC;border-color:#DCDFE6}.el-checkbox__input.is-disabled.is-indeterminate .el-checkbox__inner::before{background-color:#C0C4CC;border-color:#C0C4CC}.el-checkbox__input.is-checked .el-checkbox__inner,.el-checkbox__input.is-indeterminate .el-checkbox__inner{background-color:#409EFF;border-color:#409EFF}.el-checkbox__input.is-disabled+span.el-checkbox__label{color:#C0C4CC;cursor:not-allowed}.el-checkbox__input.is-checked .el-checkbox__inner::after{-webkit-transform:rotate(45deg) scaleY(1);transform:rotate(45deg) scaleY(1)}.el-checkbox__input.is-checked+.el-checkbox__label{color:#409EFF}.el-checkbox__input.is-focus .el-checkbox__inner{border-color:#409EFF}.el-checkbox__input.is-indeterminate .el-checkbox__inner::before{content:'';position:absolute;display:block;background-color:#FFF;height:2px;-webkit-transform:scale(.5);transform:scale(.5);left:0;right:0;top:5px}.el-checkbox__input.is-indeterminate .el-checkbox__inner::after{display:none}.el-checkbox__inner{display:inline-block;position:relative;border:1px solid #DCDFE6;border-radius:2px;-webkit-box-sizing:border-box;box-sizing:border-box;width:14px;height:14px;background-color:#FFF;z-index:1;-webkit-transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46);transition:border-color .25s cubic-bezier(.71,-.46,.29,1.46),background-color .25s cubic-bezier(.71,-.46,.29,1.46)}.el-checkbox__inner:hover{border-color:#409EFF}.el-checkbox__inner::after{-webkit-box-sizing:content-box;box-sizing:content-box;content:"";border:1px solid #FFF;border-left:0;border-top:0;height:7px;left:4px;position:absolute;top:1px;-webkit-transform:rotate(45deg) scaleY(0);transform:rotate(45deg) scaleY(0);width:3px;-webkit-transition:-webkit-transform .15s ease-in .05s;transition:-webkit-transform .15s ease-in .05s;transition:transform .15s ease-in .05s;transition:transform .15s ease-in .05s,-webkit-transform .15s ease-in .05s;-webkit-transform-origin:center;transform-origin:center}.el-checkbox__original{opacity:0;outline:0;position:absolute;margin:0;width:0;height:0;z-index:-1}.el-checkbox-button,.el-checkbox-button__inner{display:inline-block;position:relative}.el-checkbox__label{display:inline-block;padding-left:10px;line-height:19px;font-size:14px}.el-checkbox:last-of-type{margin-right:0}.el-checkbox-button__inner{line-height:1;font-weight:500;white-space:nowrap;vertical-align:middle;cursor:pointer;background:#FFF;border:1px solid #DCDFE6;border-left:0;color:#606266;-webkit-appearance:none;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;outline:0;margin:0;-webkit-transition:all .3s cubic-bezier(.645,.045,.355,1);transition:all .3s cubic-bezier(.645,.045,.355,1);padding:12px 20px;font-size:14px;border-radius:0}.el-checkbox-button__inner.is-round{padding:12px 20px}.el-checkbox-button__inner:hover{color:#409EFF}.el-checkbox-button__inner [class*=el-icon-]{line-height:.9}.el-checkbox-button__inner [class*=el-icon-]+span{margin-left:5px}.el-checkbox-button__original{opacity:0;outline:0;position:absolute;margin:0;z-index:-1}.el-radio,.el-radio__inner,.el-radio__input{position:relative;display:inline-block}.el-checkbox-button.is-checked .el-checkbox-button__inner{color:#FFF;background-color:#409EFF;border-color:#409EFF;-webkit-box-shadow:-1px 0 0 0 #8cc5ff;box-shadow:-1px 0 0 0 #8cc5ff}.el-checkbox-button.is-checked:first-child .el-checkbox-button__inner{border-left-color:#409EFF}.el-checkbox-button.is-disabled .el-checkbox-button__inner{color:#C0C4CC;cursor:not-allowed;background-image:none;background-color:#FFF;border-color:#EBEEF5;-webkit-box-shadow:none;box-shadow:none}.el-checkbox-button.is-disabled:first-child .el-checkbox-button__inner{border-left-color:#EBEEF5}.el-checkbox-button:first-child .el-checkbox-button__inner{border-left:1px solid #DCDFE6;border-radius:4px 0 0 4px;-webkit-box-shadow:none!important;box-shadow:none!important}.el-checkbox-button.is-focus .el-checkbox-button__inner{border-color:#409EFF}.el-checkbox-button:last-child .el-checkbox-button__inner{border-radius:0 4px 4px 0}.el-checkbox-button--medium .el-checkbox-button__inner{padding:10px 20px;font-size:14px;border-radius:0}.el-checkbox-button--medium .el-checkbox-button__inner.is-round{padding:10px 20px}.el-checkbox-button--small .el-checkbox-button__inner{padding:9px 15px;font-size:12px;border-radius:0}.el-checkbox-button--small .el-checkbox-button__inner.is-round{padding:9px 15px}.el-checkbox-button--mini .el-checkbox-button__inner{padding:7px 15px;font-size:12px;border-radius:0}.el-checkbox-button--mini .el-checkbox-button__inner.is-round{padding:7px 15px}.el-checkbox-group{font-size:0}.el-avatar,.el-cascader-panel,.el-radio,.el-radio--medium.is-bordered .el-radio__label,.el-radio__label{font-size:14px}.el-radio{color:#606266;font-weight:500;line-height:1;cursor:pointer;white-space:nowrap;outline:0;margin-right:30px}.el-cascader-node>.el-radio,.el-radio:last-child{margin-right:0}.el-radio.is-bordered{padding:12px 20px 0 10px;border-radius:4px;border:1px solid #DCDFE6;-webkit-box-sizing:border-box;box-sizing:border-box;height:40px}.el-cascader-menu,.el-cascader-menu__list,.el-radio__inner{-webkit-box-sizing:border-box}.el-radio.is-bordered.is-checked{border-color:#409EFF}.el-radio.is-bordered.is-disabled{cursor:not-allowed;border-color:#EBEEF5}.el-radio__input.is-disabled .el-radio__inner,.el-radio__input.is-disabled.is-checked .el-radio__inner{background-color:#F5F7FA;border-color:#E4E7ED}.el-radio.is-bordered+.el-radio.is-bordered{margin-left:10px}.el-radio--medium.is-bordered{padding:10px 20px 0 10px;border-radius:4px;height:36px}.el-radio--mini.is-bordered .el-radio__label,.el-radio--small.is-bordered .el-radio__label{font-size:12px}.el-radio--medium.is-bordered .el-radio__inner{height:14px;width:14px}.el-radio--small.is-bordered{padding:8px 15px 0 10px;border-radius:3px;height:32px}.el-radio--small.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio--mini.is-bordered{padding:6px 15px 0 10px;border-radius:3px;height:28px}.el-radio--mini.is-bordered .el-radio__inner{height:12px;width:12px}.el-radio__input{white-space:nowrap;cursor:pointer;outline:0;line-height:1;vertical-align:middle}.el-radio__input.is-disabled .el-radio__inner{cursor:not-allowed}.el-radio__input.is-disabled .el-radio__inner::after{cursor:not-allowed;background-color:#F5F7FA}.el-radio__input.is-disabled .el-radio__inner+.el-radio__label{cursor:not-allowed}.el-radio__input.is-disabled.is-checked .el-radio__inner::after{background-color:#C0C4CC}.el-radio__input.is-disabled+span.el-radio__label{color:#C0C4CC;cursor:not-allowed}.el-radio__input.is-checked .el-radio__inner{border-color:#409EFF;background:#409EFF}.el-radio__input.is-checked .el-radio__inner::after{-webkit-transform:translate(-50%,-50%) scale(1);transform:translate(-50%,-50%) scale(1)}.el-radio__input.is-checked+.el-radio__label{color:#409EFF}.el-radio__input.is-focus .el-radio__inner{border-color:#409EFF}.el-radio__inner{border:1px solid #DCDFE6;border-radius:100%;width:14px;height:14px;background-color:#FFF;cursor:pointer;box-sizing:border-box}.el-radio__inner:hover{border-color:#409EFF}.el-radio__inner::after{width:4px;height:4px;border-radius:100%;background-color:#FFF;content:"";position:absolute;left:50%;top:50%;-webkit-transform:translate(-50%,-50%) scale(0);transform:translate(-50%,-50%) scale(0);-webkit-transition:-webkit-transform .15s ease-in;transition:-webkit-transform .15s ease-in;transition:transform .15s ease-in;transition:transform .15s ease-in,-webkit-transform .15s ease-in}.el-radio__original{opacity:0;outline:0;position:absolute;z-index:-1;top:0;left:0;right:0;bottom:0;margin:0}.el-radio:focus:not(.is-focus):not(:active):not(.is-disabled) .el-radio__inner{-webkit-box-shadow:0 0 2px 2px #409EFF;box-shadow:0 0 2px 2px #409EFF}.el-radio__label{padding-left:10px}.el-scrollbar{overflow:hidden;position:relative}.el-scrollbar:active>.el-scrollbar__bar,.el-scrollbar:focus>.el-scrollbar__bar,.el-scrollbar:hover>.el-scrollbar__bar{opacity:1;-webkit-transition:opacity 340ms ease-out;transition:opacity 340ms ease-out}.el-scrollbar__wrap{overflow:scroll;height:100%}.el-scrollbar__wrap--hidden-default{scrollbar-width:none}.el-scrollbar__wrap--hidden-default::-webkit-scrollbar{width:0;height:0}.el-scrollbar__thumb{position:relative;display:block;width:0;height:0;cursor:pointer;border-radius:inherit;background-color:rgba(144,147,153,.3);-webkit-transition:.3s background-color;transition:.3s background-color}.el-scrollbar__thumb:hover{background-color:rgba(144,147,153,.5)}.el-scrollbar__bar{position:absolute;right:2px;bottom:2px;z-index:1;border-radius:4px;opacity:0;-webkit-transition:opacity 120ms ease-out;transition:opacity 120ms ease-out}.el-scrollbar__bar.is-vertical{width:6px;top:2px}.el-scrollbar__bar.is-vertical>div{width:100%}.el-scrollbar__bar.is-horizontal{height:6px;left:2px}.el-scrollbar__bar.is-horizontal>div{height:100%}.el-cascader-panel{display:-webkit-box;display:-ms-flexbox;display:flex;border-radius:4px}.el-cascader-panel.is-bordered{border:1px solid #E4E7ED;border-radius:4px}.el-cascader-menu{min-width:180px;box-sizing:border-box;color:#606266;border-right:solid 1px #E4E7ED}.el-cascader-menu:last-child{border-right:none}.el-cascader-menu__wrap{height:204px}.el-cascader-menu__list{position:relative;min-height:100%;margin:0;padding:6px 0;list-style:none;box-sizing:border-box}.el-cascader-menu__hover-zone{position:absolute;top:0;left:0;width:100%;height:100%;pointer-events:none}.el-cascader-menu__empty-text{position:absolute;top:50%;left:50%;-webkit-transform:translate(-50%,-50%);transform:translate(-50%,-50%);text-align:center;color:#C0C4CC}.el-cascader-node{position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;padding:0 30px 0 20px;height:34px;line-height:34px;outline:0}.el-cascader-node.is-selectable.in-active-path{color:#606266}.el-cascader-node.in-active-path,.el-cascader-node.is-active,.el-cascader-node.is-selectable.in-checked-path{color:#409EFF;font-weight:700}.el-cascader-node:not(.is-disabled){cursor:pointer}.el-cascader-node:not(.is-disabled):focus,.el-cascader-node:not(.is-disabled):hover{background:#F5F7FA}.el-cascader-node.is-disabled{color:#C0C4CC;cursor:not-allowed}.el-cascader-node__prefix{position:absolute;left:10px}.el-cascader-node__postfix{position:absolute;right:10px}.el-cascader-node__label{-webkit-box-flex:1;-ms-flex:1;flex:1;padding:0 10px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.el-cascader-node>.el-radio .el-radio__label{padding-left:0}.el-avatar{display:inline-block;-webkit-box-sizing:border-box;box-sizing:border-box;text-align:center;overflow:hidden;color:#fff;background:#C0C4CC;width:40px;height:40px;line-height:40px}.el-drawer,.el-drawer__body>*{-webkit-box-sizing:border-box}.el-avatar>img{display:block;height:100%;vertical-align:middle}.el-empty__image img,.el-empty__image svg{vertical-align:top;height:100%;width:100%}.el-avatar--circle{border-radius:50%}.el-avatar--square{border-radius:4px}.el-avatar--icon{font-size:18px}.el-avatar--large{width:40px;height:40px;line-height:40px}.el-avatar--medium{width:36px;height:36px;line-height:36px}.el-avatar--small{width:28px;height:28px;line-height:28px}@-webkit-keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@keyframes el-drawer-fade-in{0%{opacity:0}100%{opacity:1}}@-webkit-keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes rtl-drawer-in{0%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@keyframes rtl-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(100%,0);transform:translate(100%,0)}}@-webkit-keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ltr-drawer-in{0%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@keyframes ltr-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(-100%,0);transform:translate(-100%,0)}}@-webkit-keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes ttb-drawer-in{0%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@keyframes ttb-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,-100%);transform:translate(0,-100%)}}@-webkit-keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@keyframes btt-drawer-in{0%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}100%{-webkit-transform:translate(0,0);transform:translate(0,0)}}@-webkit-keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}@keyframes btt-drawer-out{0%{-webkit-transform:translate(0,0);transform:translate(0,0)}100%{-webkit-transform:translate(0,100%);transform:translate(0,100%)}}.el-drawer{position:absolute;box-sizing:border-box;background-color:#FFF;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;-webkit-box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);box-shadow:0 8px 10px -5px rgba(0,0,0,.2),0 16px 24px 2px rgba(0,0,0,.14),0 6px 30px 5px rgba(0,0,0,.12);overflow:hidden;outline:0}.el-drawer.rtl{-webkit-animation:rtl-drawer-out .3s;animation:rtl-drawer-out .3s;right:0}.el-drawer__open .el-drawer.rtl{-webkit-animation:rtl-drawer-in .3s 1ms;animation:rtl-drawer-in .3s 1ms}.el-drawer.ltr{-webkit-animation:ltr-drawer-out .3s;animation:ltr-drawer-out .3s;left:0}.el-drawer__open .el-drawer.ltr{-webkit-animation:ltr-drawer-in .3s 1ms;animation:ltr-drawer-in .3s 1ms}.el-drawer.ttb{-webkit-animation:ttb-drawer-out .3s;animation:ttb-drawer-out .3s;top:0}.el-drawer__open .el-drawer.ttb{-webkit-animation:ttb-drawer-in .3s 1ms;animation:ttb-drawer-in .3s 1ms}.el-drawer.btt{-webkit-animation:btt-drawer-out .3s;animation:btt-drawer-out .3s;bottom:0}.el-drawer__open .el-drawer.btt{-webkit-animation:btt-drawer-in .3s 1ms;animation:btt-drawer-in .3s 1ms}.el-drawer__wrapper{position:fixed;top:0;right:0;bottom:0;left:0;overflow:hidden;margin:0}.el-drawer__header{-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#72767b;display:-webkit-box;display:-ms-flexbox;display:flex;margin-bottom:32px;padding:20px 20px 0}.el-drawer__header>:first-child{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-drawer__title{margin:0;-webkit-box-flex:1;-ms-flex:1;flex:1;line-height:inherit;font-size:1rem}.el-drawer__close-btn{border:none;cursor:pointer;font-size:20px;color:inherit;background-color:transparent}.el-drawer__body{-webkit-box-flex:1;-ms-flex:1;flex:1;overflow:auto}.el-drawer__body>*{box-sizing:border-box}.el-drawer.ltr,.el-drawer.rtl{height:100%;top:0;bottom:0}.el-drawer.btt,.el-drawer.ttb{width:100%;left:0;right:0}.el-drawer__container{position:relative;left:0;right:0;top:0;bottom:0;height:100%;width:100%}.el-drawer-fade-enter-active{-webkit-animation:el-drawer-fade-in .3s;animation:el-drawer-fade-in .3s}.el-drawer-fade-leave-active{animation:el-drawer-fade-in .3s reverse}.el-statistic{width:100%;-webkit-box-sizing:border-box;box-sizing:border-box;margin:0;padding:0;color:#000;font-variant:tabular-nums;list-style:none;-webkit-font-feature-settings:"tnum";font-feature-settings:"tnum";text-align:center}.el-statistic .head{margin-bottom:4px;color:#606266;font-size:13px}.el-statistic .con{font-family:Sans-serif;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;color:#303133}.el-statistic .con .number{font-size:20px;padding:0 4px}.el-statistic .con span{display:inline-block;margin:0;line-height:100%}.el-popconfirm__main,.el-skeleton__image{display:-ms-flexbox;-webkit-box-align:center;display:-webkit-box}.el-popconfirm__main{display:flex;-ms-flex-align:center;align-items:center}.el-popconfirm__icon{margin-right:5px}.el-popconfirm__action{text-align:right;margin:0}@-webkit-keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}@keyframes el-skeleton-loading{0%{background-position:100% 50%}100%{background-position:0 50%}}.el-skeleton{width:100%}.el-skeleton__first-line,.el-skeleton__paragraph{height:16px;margin-top:16px;background:#f2f2f2}.el-skeleton.is-animated .el-skeleton__item{background:-webkit-gradient(linear,left top,right top,color-stop(25%,#f2f2f2),color-stop(37%,#e6e6e6),color-stop(63%,#f2f2f2));background:linear-gradient(90deg,#f2f2f2 25%,#e6e6e6 37%,#f2f2f2 63%);background-size:400% 100%;-webkit-animation:el-skeleton-loading 1.4s ease infinite;animation:el-skeleton-loading 1.4s ease infinite}.el-skeleton__item{background:#f2f2f2;display:inline-block;height:16px;border-radius:4px;width:100%}.el-skeleton__circle{border-radius:50%;width:36px;height:36px;line-height:36px}.el-skeleton__circle--lg{width:40px;height:40px;line-height:40px}.el-skeleton__circle--md{width:28px;height:28px;line-height:28px}.el-skeleton__button{height:40px;width:64px;border-radius:4px}.el-skeleton__p{width:100%}.el-skeleton__p.is-last{width:61%}.el-skeleton__p.is-first{width:33%}.el-skeleton__text{width:100%;height:13px}.el-skeleton__caption{height:12px}.el-skeleton__h1{height:20px}.el-skeleton__h3{height:18px}.el-skeleton__h5{height:16px}.el-skeleton__image{width:unset;display:flex;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;border-radius:0}.el-skeleton__image svg{fill:#DCDDE0;width:22%;height:22%}.el-empty{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 0}.el-empty__image{width:160px}.el-empty__image img{user-select:none;-o-object-fit:contain;object-fit:contain}.el-empty__image svg{fill:#DCDDE0}.el-empty__description{margin-top:20px}.el-empty__description p{margin:0;font-size:14px;color:#909399}.el-empty__bottom,.el-result__title{margin-top:20px}.el-descriptions{-webkit-box-sizing:border-box;box-sizing:border-box;font-size:14px;color:#303133}.el-descriptions__header{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:justify;-ms-flex-pack:justify;justify-content:space-between;-webkit-box-align:center;-ms-flex-align:center;align-items:center;margin-bottom:20px}.el-descriptions__title{font-size:16px;font-weight:700}.el-descriptions--mini,.el-descriptions--small{font-size:12px}.el-descriptions__body{color:#606266;background-color:#FFF}.el-descriptions__body .el-descriptions__table{border-collapse:collapse;width:100%;table-layout:fixed}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell{-webkit-box-sizing:border-box;box-sizing:border-box;text-align:left;font-weight:400;line-height:1.5}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-left{text-align:left}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-center{text-align:center}.el-descriptions__body .el-descriptions__table .el-descriptions-item__cell.is-right{text-align:right}.el-descriptions .is-bordered{table-layout:auto}.el-descriptions .is-bordered .el-descriptions-item__cell{border:1px solid #EBEEF5;padding:12px 10px}.el-descriptions :not(.is-bordered) .el-descriptions-item__cell{padding-bottom:12px}.el-descriptions--medium.is-bordered .el-descriptions-item__cell{padding:10px}.el-descriptions--medium:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:10px}.el-descriptions--small.is-bordered .el-descriptions-item__cell{padding:8px 10px}.el-descriptions--small:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:8px}.el-descriptions--mini.is-bordered .el-descriptions-item__cell{padding:6px 10px}.el-descriptions--mini:not(.is-bordered) .el-descriptions-item__cell{padding-bottom:6px}.el-descriptions-item{vertical-align:top}.el-descriptions-item__container{display:-webkit-box;display:-ms-flexbox;display:flex}.el-descriptions-item__container .el-descriptions-item__content,.el-descriptions-item__container .el-descriptions-item__label{display:-webkit-inline-box;display:-ms-inline-flexbox;display:inline-flex;-webkit-box-align:baseline;-ms-flex-align:baseline;align-items:baseline}.el-descriptions-item__container .el-descriptions-item__content{-webkit-box-flex:1;-ms-flex:1;flex:1}.el-descriptions-item__label.has-colon::after{content:':';position:relative;top:-.5px}.el-descriptions-item__label.is-bordered-label{font-weight:700;color:#909399;background:#fafafa}.el-descriptions-item__label:not(.is-bordered-label){margin-right:10px}.el-descriptions-item__content{word-break:break-word;overflow-wrap:break-word}.el-result{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-ms-flex-direction:column;flex-direction:column;text-align:center;-webkit-box-sizing:border-box;box-sizing:border-box;padding:40px 30px}.el-result__icon svg{width:64px;height:64px}.el-result__title p{margin:0;font-size:20px;color:#303133;line-height:1.3}.el-result__subtitle{margin-top:10px}.el-result__subtitle p{margin:0;font-size:14px;color:#606266;line-height:1.3}.el-result__extra{margin-top:30px }.el-result .icon-success{fill:#67C23A}.el-result .icon-error{fill:#F56C6C}.el-result .icon-info{fill:#909399}.el-result .icon-warning{fill:#E6A23C}
\ No newline at end of file
diff --git a/ruoyi-ui/src/App.vue b/ruoyi-ui/src/App.vue
new file mode 100644
index 0000000..b92ea37
--- /dev/null
+++ b/ruoyi-ui/src/App.vue
@@ -0,0 +1,28 @@
+<template>
+  <div id="app">
+    <router-view />
+    <theme-picker />
+  </div>
+</template>
+
+<script>
+import ThemePicker from "@/components/ThemePicker";
+
+export default {
+  name: "App",
+  components: { ThemePicker },
+  metaInfo() {
+    return {
+      title: this.$store.state.settings.dynamicTitle && this.$store.state.settings.title,
+      titleTemplate: title => {
+        return title ? `${title} - ${process.env.VUE_APP_TITLE}` : process.env.VUE_APP_TITLE
+      }
+    }
+  }
+};
+</script>
+<style scoped>
+#app .theme-picker {
+  display: none;
+}
+</style>
diff --git a/ruoyi-ui/src/api/login.js b/ruoyi-ui/src/api/login.js
new file mode 100644
index 0000000..7b7388f
--- /dev/null
+++ b/ruoyi-ui/src/api/login.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鐧诲綍鏂规硶
+export function login(username, password, code, uuid) {
+  const data = {
+    username,
+    password,
+    code,
+    uuid
+  }
+  return request({
+    url: '/login',
+    headers: {
+      isToken: false,
+      repeatSubmit: false
+    },
+    method: 'post',
+    data: data
+  })
+}
+
+// 娉ㄥ唽鏂规硶
+export function register(data) {
+  return request({
+    url: '/register',
+    headers: {
+      isToken: false
+    },
+    method: 'post',
+    data: data
+  })
+}
+
+// 鑾峰彇鐢ㄦ埛璇︾粏淇℃伅
+export function getInfo() {
+  return request({
+    url: '/getInfo',
+    method: 'get'
+  })
+}
+
+// 閫�鍑烘柟娉�
+export function logout() {
+  return request({
+    url: '/logout',
+    method: 'post'
+  })
+}
+
+// 鑾峰彇楠岃瘉鐮�
+export function getCodeImg() {
+  return request({
+    url: '/captchaImage',
+    headers: {
+      isToken: false
+    },
+    method: 'get',
+    timeout: 20000
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/menu.js b/ruoyi-ui/src/api/menu.js
new file mode 100644
index 0000000..faef101
--- /dev/null
+++ b/ruoyi-ui/src/api/menu.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 鑾峰彇璺敱
+export const getRouters = () => {
+  return request({
+    url: '/getRouters',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/cache.js b/ruoyi-ui/src/api/monitor/cache.js
new file mode 100644
index 0000000..72c5f6a
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/cache.js
@@ -0,0 +1,57 @@
+import request from '@/utils/request'
+
+// 鏌ヨ缂撳瓨璇︾粏
+export function getCache() {
+  return request({
+    url: '/monitor/cache',
+    method: 'get'
+  })
+}
+
+// 鏌ヨ缂撳瓨鍚嶇О鍒楄〃
+export function listCacheName() {
+  return request({
+    url: '/monitor/cache/getNames',
+    method: 'get'
+  })
+}
+
+// 鏌ヨ缂撳瓨閿悕鍒楄〃
+export function listCacheKey(cacheName) {
+  return request({
+    url: '/monitor/cache/getKeys/' + cacheName,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ缂撳瓨鍐呭
+export function getCacheValue(cacheName, cacheKey) {
+  return request({
+    url: '/monitor/cache/getValue/' + cacheName + '/' + cacheKey,
+    method: 'get'
+  })
+}
+
+// 娓呯悊鎸囧畾鍚嶇О缂撳瓨
+export function clearCacheName(cacheName) {
+  return request({
+    url: '/monitor/cache/clearCacheName/' + cacheName,
+    method: 'delete'
+  })
+}
+
+// 娓呯悊鎸囧畾閿悕缂撳瓨
+export function clearCacheKey(cacheKey) {
+  return request({
+    url: '/monitor/cache/clearCacheKey/' + cacheKey,
+    method: 'delete'
+  })
+}
+
+// 娓呯悊鍏ㄩ儴缂撳瓨
+export function clearCacheAll() {
+  return request({
+    url: '/monitor/cache/clearCacheAll',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/monitor/job.js b/ruoyi-ui/src/api/monitor/job.js
new file mode 100644
index 0000000..3815569
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/job.js
@@ -0,0 +1,71 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀹氭椂浠诲姟璋冨害鍒楄〃
+export function listJob(query) {
+  return request({
+    url: '/monitor/job/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瀹氭椂浠诲姟璋冨害璇︾粏
+export function getJob(jobId) {
+  return request({
+    url: '/monitor/job/' + jobId,
+    method: 'get'
+  })
+}
+
+// 鏂板瀹氭椂浠诲姟璋冨害
+export function addJob(data) {
+  return request({
+    url: '/monitor/job',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瀹氭椂浠诲姟璋冨害
+export function updateJob(data) {
+  return request({
+    url: '/monitor/job',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瀹氭椂浠诲姟璋冨害
+export function delJob(jobId) {
+  return request({
+    url: '/monitor/job/' + jobId,
+    method: 'delete'
+  })
+}
+
+// 浠诲姟鐘舵�佷慨鏀�
+export function changeJobStatus(jobId, status) {
+  const data = {
+    jobId,
+    status
+  }
+  return request({
+    url: '/monitor/job/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+
+// 瀹氭椂浠诲姟绔嬪嵆鎵ц涓�娆�
+export function runJob(jobId, jobGroup) {
+  const data = {
+    jobId,
+    jobGroup
+  }
+  return request({
+    url: '/monitor/job/run',
+    method: 'put',
+    data: data
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/monitor/jobLog.js b/ruoyi-ui/src/api/monitor/jobLog.js
new file mode 100644
index 0000000..6e0be61
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/jobLog.js
@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+// 鏌ヨ璋冨害鏃ュ織鍒楄〃
+export function listJobLog(query) {
+  return request({
+    url: '/monitor/jobLog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鍒犻櫎璋冨害鏃ュ織
+export function delJobLog(jobLogId) {
+  return request({
+    url: '/monitor/jobLog/' + jobLogId,
+    method: 'delete'
+  })
+}
+
+// 娓呯┖璋冨害鏃ュ織
+export function cleanJobLog() {
+  return request({
+    url: '/monitor/jobLog/clean',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/monitor/logininfor.js b/ruoyi-ui/src/api/monitor/logininfor.js
new file mode 100644
index 0000000..4d112b7
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/logininfor.js
@@ -0,0 +1,34 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鐧诲綍鏃ュ織鍒楄〃
+export function list(query) {
+  return request({
+    url: '/monitor/logininfor/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鍒犻櫎鐧诲綍鏃ュ織
+export function delLogininfor(infoId) {
+  return request({
+    url: '/monitor/logininfor/' + infoId,
+    method: 'delete'
+  })
+}
+
+// 瑙i攣鐢ㄦ埛鐧诲綍鐘舵��
+export function unlockLogininfor(userName) {
+  return request({
+    url: '/monitor/logininfor/unlock/' + userName,
+    method: 'get'
+  })
+}
+
+// 娓呯┖鐧诲綍鏃ュ織
+export function cleanLogininfor() {
+  return request({
+    url: '/monitor/logininfor/clean',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/monitor/online.js b/ruoyi-ui/src/api/monitor/online.js
new file mode 100644
index 0000000..bd22137
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/online.js
@@ -0,0 +1,18 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍦ㄧ嚎鐢ㄦ埛鍒楄〃
+export function list(query) {
+  return request({
+    url: '/monitor/online/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 寮洪��鐢ㄦ埛
+export function forceLogout(tokenId) {
+  return request({
+    url: '/monitor/online/' + tokenId,
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/monitor/operlog.js b/ruoyi-ui/src/api/monitor/operlog.js
new file mode 100644
index 0000000..a04bca8
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/operlog.js
@@ -0,0 +1,26 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鎿嶄綔鏃ュ織鍒楄〃
+export function list(query) {
+  return request({
+    url: '/monitor/operlog/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鍒犻櫎鎿嶄綔鏃ュ織
+export function delOperlog(operId) {
+  return request({
+    url: '/monitor/operlog/' + operId,
+    method: 'delete'
+  })
+}
+
+// 娓呯┖鎿嶄綔鏃ュ織
+export function cleanOperlog() {
+  return request({
+    url: '/monitor/operlog/clean',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/monitor/server.js b/ruoyi-ui/src/api/monitor/server.js
new file mode 100644
index 0000000..e1f9ca2
--- /dev/null
+++ b/ruoyi-ui/src/api/monitor/server.js
@@ -0,0 +1,9 @@
+import request from '@/utils/request'
+
+// 鑾峰彇鏈嶅姟淇℃伅
+export function getServer() {
+  return request({
+    url: '/monitor/server',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/config.js b/ruoyi-ui/src/api/system/config.js
new file mode 100644
index 0000000..a404d82
--- /dev/null
+++ b/ruoyi-ui/src/api/system/config.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍙傛暟鍒楄〃
+export function listConfig(query) {
+  return request({
+    url: '/system/config/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鍙傛暟璇︾粏
+export function getConfig(configId) {
+  return request({
+    url: '/system/config/' + configId,
+    method: 'get'
+  })
+}
+
+// 鏍规嵁鍙傛暟閿悕鏌ヨ鍙傛暟鍊�
+export function getConfigKey(configKey) {
+  return request({
+    url: '/system/config/configKey/' + configKey,
+    method: 'get'
+  })
+}
+
+// 鏂板鍙傛暟閰嶇疆
+export function addConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鍙傛暟閰嶇疆
+export function updateConfig(data) {
+  return request({
+    url: '/system/config',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鍙傛暟閰嶇疆
+export function delConfig(configId) {
+  return request({
+    url: '/system/config/' + configId,
+    method: 'delete'
+  })
+}
+
+// 鍒锋柊鍙傛暟缂撳瓨
+export function refreshCache() {
+  return request({
+    url: '/system/config/refreshCache',
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/system/dept.js b/ruoyi-ui/src/api/system/dept.js
new file mode 100644
index 0000000..fc943cd
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dept.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 鏌ヨ閮ㄩ棬鍒楄〃
+export function listDept(query) {
+  return request({
+    url: '/system/dept/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ閮ㄩ棬鍒楄〃锛堟帓闄よ妭鐐癸級
+export function listDeptExcludeChild(deptId) {
+  return request({
+    url: '/system/dept/list/exclude/' + deptId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ閮ㄩ棬璇︾粏
+export function getDept(deptId) {
+  return request({
+    url: '/system/dept/' + deptId,
+    method: 'get'
+  })
+}
+
+// 鏂板閮ㄩ棬
+export function addDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼閮ㄩ棬
+export function updateDept(data) {
+  return request({
+    url: '/system/dept',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎閮ㄩ棬
+export function delDept(deptId) {
+  return request({
+    url: '/system/dept/' + deptId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/dict/data.js b/ruoyi-ui/src/api/system/dict/data.js
new file mode 100644
index 0000000..6c9eb79
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dict/data.js
@@ -0,0 +1,52 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀛楀吀鏁版嵁鍒楄〃
+export function listData(query) {
+  return request({
+    url: '/system/dict/data/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瀛楀吀鏁版嵁璇︾粏
+export function getData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'get'
+  })
+}
+
+// 鏍规嵁瀛楀吀绫诲瀷鏌ヨ瀛楀吀鏁版嵁淇℃伅
+export function getDicts(dictType) {
+  return request({
+    url: '/system/dict/data/type/' + dictType,
+    method: 'get'
+  })
+}
+
+// 鏂板瀛楀吀鏁版嵁
+export function addData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瀛楀吀鏁版嵁
+export function updateData(data) {
+  return request({
+    url: '/system/dict/data',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瀛楀吀鏁版嵁
+export function delData(dictCode) {
+  return request({
+    url: '/system/dict/data/' + dictCode,
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/system/dict/type.js b/ruoyi-ui/src/api/system/dict/type.js
new file mode 100644
index 0000000..a7a6e01
--- /dev/null
+++ b/ruoyi-ui/src/api/system/dict/type.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瀛楀吀绫诲瀷鍒楄〃
+export function listType(query) {
+  return request({
+    url: '/system/dict/type/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瀛楀吀绫诲瀷璇︾粏
+export function getType(dictId) {
+  return request({
+    url: '/system/dict/type/' + dictId,
+    method: 'get'
+  })
+}
+
+// 鏂板瀛楀吀绫诲瀷
+export function addType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瀛楀吀绫诲瀷
+export function updateType(data) {
+  return request({
+    url: '/system/dict/type',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瀛楀吀绫诲瀷
+export function delType(dictId) {
+  return request({
+    url: '/system/dict/type/' + dictId,
+    method: 'delete'
+  })
+}
+
+// 鍒锋柊瀛楀吀缂撳瓨
+export function refreshCache() {
+  return request({
+    url: '/system/dict/type/refreshCache',
+    method: 'delete'
+  })
+}
+
+// 鑾峰彇瀛楀吀閫夋嫨妗嗗垪琛�
+export function optionselect() {
+  return request({
+    url: '/system/dict/type/optionselect',
+    method: 'get'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/menu.js b/ruoyi-ui/src/api/system/menu.js
new file mode 100644
index 0000000..f6415c6
--- /dev/null
+++ b/ruoyi-ui/src/api/system/menu.js
@@ -0,0 +1,60 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鑿滃崟鍒楄〃
+export function listMenu(query) {
+  return request({
+    url: '/system/menu/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鑿滃崟璇︾粏
+export function getMenu(menuId) {
+  return request({
+    url: '/system/menu/' + menuId,
+    method: 'get'
+  })
+}
+
+// 鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋�
+export function treeselect() {
+  return request({
+    url: '/system/menu/treeselect',
+    method: 'get'
+  })
+}
+
+// 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋�
+export function roleMenuTreeselect(roleId) {
+  return request({
+    url: '/system/menu/roleMenuTreeselect/' + roleId,
+    method: 'get'
+  })
+}
+
+// 鏂板鑿滃崟
+export function addMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鑿滃崟
+export function updateMenu(data) {
+  return request({
+    url: '/system/menu',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鑿滃崟
+export function delMenu(menuId) {
+  return request({
+    url: '/system/menu/' + menuId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/notice.js b/ruoyi-ui/src/api/system/notice.js
new file mode 100644
index 0000000..c274ea5
--- /dev/null
+++ b/ruoyi-ui/src/api/system/notice.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鍏憡鍒楄〃
+export function listNotice(query) {
+  return request({
+    url: '/system/notice/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ鍏憡璇︾粏
+export function getNotice(noticeId) {
+  return request({
+    url: '/system/notice/' + noticeId,
+    method: 'get'
+  })
+}
+
+// 鏂板鍏憡
+export function addNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼鍏憡
+export function updateNotice(data) {
+  return request({
+    url: '/system/notice',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎鍏憡
+export function delNotice(noticeId) {
+  return request({
+    url: '/system/notice/' + noticeId,
+    method: 'delete'
+  })
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/api/system/post.js b/ruoyi-ui/src/api/system/post.js
new file mode 100644
index 0000000..1a8e9ca
--- /dev/null
+++ b/ruoyi-ui/src/api/system/post.js
@@ -0,0 +1,44 @@
+import request from '@/utils/request'
+
+// 鏌ヨ宀椾綅鍒楄〃
+export function listPost(query) {
+  return request({
+    url: '/system/post/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ宀椾綅璇︾粏
+export function getPost(postId) {
+  return request({
+    url: '/system/post/' + postId,
+    method: 'get'
+  })
+}
+
+// 鏂板宀椾綅
+export function addPost(data) {
+  return request({
+    url: '/system/post',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼宀椾綅
+export function updatePost(data) {
+  return request({
+    url: '/system/post',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎宀椾綅
+export function delPost(postId) {
+  return request({
+    url: '/system/post/' + postId,
+    method: 'delete'
+  })
+}
diff --git a/ruoyi-ui/src/api/system/role.js b/ruoyi-ui/src/api/system/role.js
new file mode 100644
index 0000000..f13e6f4
--- /dev/null
+++ b/ruoyi-ui/src/api/system/role.js
@@ -0,0 +1,119 @@
+import request from '@/utils/request'
+
+// 鏌ヨ瑙掕壊鍒楄〃
+export function listRole(query) {
+  return request({
+    url: '/system/role/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瑙掕壊璇︾粏
+export function getRole(roleId) {
+  return request({
+    url: '/system/role/' + roleId,
+    method: 'get'
+  })
+}
+
+// 鏂板瑙掕壊
+export function addRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'post',
+    data: data
+  })
+}
+
+// 淇敼瑙掕壊
+export function updateRole(data) {
+  return request({
+    url: '/system/role',
+    method: 'put',
+    data: data
+  })
+}
+
+// 瑙掕壊鏁版嵁鏉冮檺
+export function dataScope(data) {
+  return request({
+    url: '/system/role/dataScope',
+    method: 'put',
+    data: data
+  })
+}
+
+// 瑙掕壊鐘舵�佷慨鏀�
+export function changeRoleStatus(roleId, status) {
+  const data = {
+    roleId,
+    status
+  }
+  return request({
+    url: '/system/role/changeStatus',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鍒犻櫎瑙掕壊
+export function delRole(roleId) {
+  return request({
+    url: '/system/role/' + roleId,
+    method: 'delete'
+  })
+}
+
+// 鏌ヨ瑙掕壊宸叉巿鏉冪敤鎴峰垪琛�
+export function allocatedUserList(query) {
+  return request({
+    url: '/system/role/authUser/allocatedList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ瑙掕壊鏈巿鏉冪敤鎴峰垪琛�
+export function unallocatedUserList(query) {
+  return request({
+    url: '/system/role/authUser/unallocatedList',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鍙栨秷鐢ㄦ埛鎺堟潈瑙掕壊
+export function authUserCancel(data) {
+  return request({
+    url: '/system/role/authUser/cancel',
+    method: 'put',
+    data: data
+  })
+}
+
+// 鎵归噺鍙栨秷鐢ㄦ埛鎺堟潈瑙掕壊
+export function authUserCancelAll(data) {
+  return request({
+    url: '/system/role/authUser/cancelAll',
+    method: 'put',
+    params: data
+  })
+}
+
+// 鎺堟潈鐢ㄦ埛閫夋嫨
+export function authUserSelectAll(data) {
+  return request({
+    url: '/system/role/authUser/selectAll',
+    method: 'put',
+    params: data
+  })
+}
+
+// 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戠粨鏋�
+export function deptTreeSelect(roleId) {
+  return request({
+    url: '/system/role/deptTree/' + roleId,
+    method: 'get'
+  })
+}
diff --git a/ruoyi-ui/src/api/system/user.js b/ruoyi-ui/src/api/system/user.js
new file mode 100644
index 0000000..b5e3edd
--- /dev/null
+++ b/ruoyi-ui/src/api/system/user.js
@@ -0,0 +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'
+  })
+}
diff --git a/ruoyi-ui/src/api/tool/gen.js b/ruoyi-ui/src/api/tool/gen.js
new file mode 100644
index 0000000..2075677
--- /dev/null
+++ b/ruoyi-ui/src/api/tool/gen.js
@@ -0,0 +1,85 @@
+import request from '@/utils/request'
+
+// 鏌ヨ鐢熸垚琛ㄦ暟鎹�
+export function listTable(query) {
+  return request({
+    url: '/tool/gen/list',
+    method: 'get',
+    params: query
+  })
+}
+// 鏌ヨdb鏁版嵁搴撳垪琛�
+export function listDbTable(query) {
+  return request({
+    url: '/tool/gen/db/list',
+    method: 'get',
+    params: query
+  })
+}
+
+// 鏌ヨ琛ㄨ缁嗕俊鎭�
+export function getGenTable(tableId) {
+  return request({
+    url: '/tool/gen/' + tableId,
+    method: 'get'
+  })
+}
+
+// 淇敼浠g爜鐢熸垚淇℃伅
+export function updateGenTable(data) {
+  return request({
+    url: '/tool/gen',
+    method: 'put',
+    data: data
+  })
+}
+
+// 瀵煎叆琛�
+export function importTable(data) {
+  return request({
+    url: '/tool/gen/importTable',
+    method: 'post',
+    params: data
+  })
+}
+
+// 鍒涘缓琛�
+export function createTable(data) {
+  return request({
+    url: '/tool/gen/createTable',
+    method: 'post',
+    params: data
+  })
+}
+
+// 棰勮鐢熸垚浠g爜
+export function previewTable(tableId) {
+  return request({
+    url: '/tool/gen/preview/' + tableId,
+    method: 'get'
+  })
+}
+
+// 鍒犻櫎琛ㄦ暟鎹�
+export function delTable(tableId) {
+  return request({
+    url: '/tool/gen/' + tableId,
+    method: 'delete'
+  })
+}
+
+// 鐢熸垚浠g爜锛堣嚜瀹氫箟璺緞锛�
+export function genCode(tableName) {
+  return request({
+    url: '/tool/gen/genCode/' + tableName,
+    method: 'get'
+  })
+}
+
+// 鍚屾鏁版嵁搴�
+export function synchDb(tableName) {
+  return request({
+    url: '/tool/gen/synchDb/' + tableName,
+    method: 'get'
+  })
+}
diff --git a/ruoyi-ui/src/assets/401_images/401.gif b/ruoyi-ui/src/assets/401_images/401.gif
new file mode 100644
index 0000000..cd6e0d9
--- /dev/null
+++ b/ruoyi-ui/src/assets/401_images/401.gif
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404.png b/ruoyi-ui/src/assets/404_images/404.png
new file mode 100644
index 0000000..3d8e230
--- /dev/null
+++ b/ruoyi-ui/src/assets/404_images/404.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/404_images/404_cloud.png b/ruoyi-ui/src/assets/404_images/404_cloud.png
new file mode 100644
index 0000000..c6281d0
--- /dev/null
+++ b/ruoyi-ui/src/assets/404_images/404_cloud.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/icons/index.js b/ruoyi-ui/src/assets/icons/index.js
new file mode 100644
index 0000000..2c6b309
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/index.js
@@ -0,0 +1,9 @@
+import Vue from 'vue'
+import SvgIcon from '@/components/SvgIcon'// svg component
+
+// register globally
+Vue.component('svg-icon', SvgIcon)
+
+const req = require.context('./svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys().map(requireContext)
+requireAll(req)
diff --git a/ruoyi-ui/src/assets/icons/svg/404.svg b/ruoyi-ui/src/assets/icons/svg/404.svg
new file mode 100644
index 0000000..6df5019
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/404.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M121.718 73.272v9.953c3.957-7.584 6.199-16.05 6.199-24.995C127.917 26.079 99.273 0 63.958 0 28.644 0 0 26.079 0 58.23c0 .403.028.806.028 1.21l22.97-25.953h13.34l-19.76 27.187h6.42V53.77l13.728-19.477v49.361H22.998V73.272H2.158c5.951 20.284 23.608 36.208 45.998 41.399-1.44 3.3-5.618 11.263-12.565 12.674-8.607 1.764 23.358.428 46.163-13.178 17.519-4.611 31.938-15.849 39.77-30.513h-13.506V73.272H85.02V59.464l22.998-25.977h13.008l-19.429 27.187h6.421v-7.433l13.727-19.402v39.433h-.027zm-78.24 2.822a10.516 10.516 0 0 1-.996-4.535V44.548c0-1.613.332-3.124.996-4.535a11.66 11.66 0 0 1 2.713-3.68c1.134-1.032 2.49-1.864 4.04-2.468 1.55-.605 3.21-.908 4.982-.908h11.292c1.77 0 3.431.303 4.981.908 1.522.604 2.85 1.41 3.986 2.418l-12.26 16.303v-2.898a1.96 1.96 0 0 0-.665-1.512c-.443-.403-.996-.604-1.66-.604-.665 0-1.218.201-1.661.604a1.96 1.96 0 0 0-.664 1.512v9.071L44.364 77.606a10.556 10.556 0 0 1-.886-1.512zm35.73-4.535c0 1.613-.332 3.124-.997 4.535a11.66 11.66 0 0 1-2.712 3.68c-1.134 1.032-2.49 1.864-4.04 2.469-1.55.604-3.21.907-4.982.907H55.185c-1.77 0-3.431-.303-4.981-.907-1.55-.605-2.906-1.437-4.041-2.47a12.49 12.49 0 0 1-1.384-1.512l13.727-18.217v6.375c0 .605.222 1.109.665 1.512.442.403.996.604 1.66.604.664 0 1.218-.201 1.66-.604a1.96 1.96 0 0 0 .665-1.512V53.87L75.97 36.838c.913.932 1.66 1.99 2.214 3.175.664 1.41.996 2.922.996 4.535v27.011h.028z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/bug.svg b/ruoyi-ui/src/assets/icons/svg/bug.svg
new file mode 100644
index 0000000..05a150d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/bug.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M127.88 73.143c0 1.412-.506 2.635-1.518 3.669-1.011 1.033-2.209 1.55-3.592 1.55h-17.887c0 9.296-1.783 17.178-5.35 23.645l16.609 17.044c1.011 1.034 1.517 2.257 1.517 3.67 0 1.412-.506 2.635-1.517 3.668-.958 1.033-2.155 1.55-3.593 1.55-1.438 0-2.635-.517-3.593-1.55l-15.811-16.063a15.49 15.49 0 0 1-1.196 1.06c-.532.434-1.65 1.208-3.353 2.322a50.104 50.104 0 0 1-5.192 2.974c-1.758.87-3.94 1.658-6.546 2.364-2.607.706-5.189 1.06-7.748 1.06V47.044H58.89v73.062c-2.716 0-5.417-.367-8.106-1.102-2.688-.734-5.003-1.631-6.945-2.692a66.769 66.769 0 0 1-5.268-3.179c-1.571-1.057-2.73-1.94-3.476-2.65L33.9 109.34l-14.611 16.877c-1.066 1.14-2.344 1.711-3.833 1.711-1.277 0-2.422-.434-3.434-1.304-1.012-.978-1.557-2.187-1.635-3.627-.079-1.44.333-2.705 1.236-3.794l16.129-18.51c-3.087-6.197-4.63-13.644-4.63-22.342H5.235c-1.383 0-2.58-.517-3.592-1.55S.125 74.545.125 73.132c0-1.412.506-2.635 1.518-3.668 1.012-1.034 2.21-1.55 3.592-1.55h17.887V43.939L9.308 29.833c-1.012-1.033-1.517-2.256-1.517-3.669 0-1.412.505-2.635 1.517-3.668 1.012-1.034 2.21-1.55 3.593-1.55s2.58.516 3.593 1.55l13.813 14.106h67.396l13.814-14.106c1.012-1.034 2.21-1.55 3.592-1.55 1.384 0 2.581.516 3.593 1.55 1.012 1.033 1.518 2.256 1.518 3.668 0 1.413-.506 2.636-1.518 3.67l-13.814 14.105v23.975h17.887c1.383 0 2.58.516 3.593 1.55 1.011 1.033 1.517 2.256 1.517 3.668l-.005.01zM89.552 26.175H38.448c0-7.23 2.489-13.386 7.466-18.469C50.892 2.623 56.92.082 64 .082c7.08 0 13.108 2.541 18.086 7.624 4.977 5.083 7.466 11.24 7.466 18.469z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/build.svg b/ruoyi-ui/src/assets/icons/svg/build.svg
new file mode 100644
index 0000000..97c4688
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/build.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899741379" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2054" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M960 591.424V368.96c0-0.288 0.16-0.512 0.16-0.768S960 367.68 960 367.424V192a32 32 0 0 0-32-32H96a32 32 0 0 0-32 32v175.424c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768v222.464c0 0.288-0.16 0.512-0.16 0.768s0.16 0.48 0.16 0.768V864a32 32 0 0 0 32 32h832a32 32 0 0 0 32-32v-271.04c0-0.288 0.16-0.512 0.16-0.768S960 591.68 960 591.424z m-560-31.232v-160H608v160h-208z m208 64V832h-208v-207.808H608z m-480-224h208v160H128v-160z m544 0h224v160h-224v-160zM896 224v112.192H128V224h768zM128 624.192h208V832H128v-207.808zM672 832v-207.808h224V832h-224z" p-id="2055"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/button.svg b/ruoyi-ui/src/assets/icons/svg/button.svg
new file mode 100644
index 0000000..904fddc
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/button.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1588670460195" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1314" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M230.4 307.712c13.824 0 25.088-11.264 25.088-25.088 0-100.352 81.92-182.272 182.272-182.272s182.272 81.408 182.272 182.272c0 13.824 11.264 25.088 25.088 25.088s25.088-11.264 24.576-25.088c0-127.488-103.936-231.936-231.936-231.936S205.824 154.624 205.824 282.624c-0.512 14.336 10.752 25.088 24.576 25.088z m564.736 234.496c-11.264 0-21.504 2.048-31.232 6.144 0-44.544-40.448-81.92-88.064-81.92-14.848 0-28.16 3.584-39.936 10.24-13.824-28.16-44.544-48.128-78.848-48.128-12.288 0-24.576 2.56-35.328 7.68V284.16c0-45.568-37.888-81.92-84.48-81.92s-84.48 36.864-84.48 81.92v348.672l-69.12-112.64c-18.432-28.16-58.368-36.864-91.136-19.968-26.624 14.336-46.592 47.104-30.208 88.064 3.072 8.192 76.8 205.312 171.52 311.296 0 0 28.16 24.576 43.008 58.88 4.096 9.728 13.312 15.36 22.528 15.36 3.072 0 6.656-0.512 9.728-2.048 12.288-5.12 18.432-19.968 12.8-32.256-19.456-44.544-53.76-74.752-53.76-74.752C281.6 768 209.408 573.44 208.384 570.88c-5.12-12.8-2.56-20.992 7.168-26.112 9.216-4.608 21.504-4.608 26.112 2.56l113.152 184.32c4.096 8.704 12.8 14.336 22.528 14.336 13.824 0 25.088-10.752 25.088-25.088V284.16c0-17.92 15.36-32.256 34.816-32.256s34.816 14.336 34.816 32.256v284.16c0 13.824 10.24 25.088 24.576 25.088 13.824 0 25.088-11.264 25.088-25.088v-57.344c0-17.92 15.36-32.768 34.816-32.768 19.968 0 37.376 15.36 37.376 32.768v95.232c0 7.168 3.072 13.312 7.68 17.92 4.608 4.608 10.752 7.168 17.92 7.168 13.824 0 24.576-11.264 24.576-25.088V547.84c0-18.432 13.824-32.256 32.256-32.256 20.48 0 38.912 15.36 38.912 32.256v95.232c0 13.824 11.264 25.088 25.088 25.088s24.576-11.264 25.088-25.088v-18.944c0-18.944 12.8-32.256 30.72-32.256 18.432 0 22.528 18.944 22.528 31.744 0 1.024-11.776 99.84-50.688 173.056-30.72 58.368-45.056 112.128-51.2 146.944-2.56 13.312 6.656 26.112 19.968 28.672 1.536 0 3.072 0.512 4.608 0.512 11.776 0 22.016-8.192 24.064-20.48 5.632-31.232 18.432-79.36 46.08-132.608 43.52-81.92 55.808-186.88 56.32-193.536-0.512-50.688-29.696-83.968-72.704-83.968z"></path></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/cascader.svg b/ruoyi-ui/src/assets/icons/svg/cascader.svg
new file mode 100644
index 0000000..e256024
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/cascader.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576153230908" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="971" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M772.87036133 734.06115723c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714843H475.90991211c-56.60705567 0-102.66723633-46.06018067-102.66723633-102.66723633V600.82446289h305.859375c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012S827.9942627 467.50537109 772.87036133 467.50537109c-43.34106445 0-80.00793458 27.93273926-93.76831055 66.57714844H373.24267578V401.01062011h321.92687989c55.12390137 0 99.94812012-44.82421875 99.94812011-99.94812011V190.07312011C795.11767578 134.94921875 750.29345703 90.125 695.16955567 90.125H251.12963867C196.0057373 90.125 151.18151855 134.94921875 151.18151855 190.07312011V301.0625c0 55.12390137 44.82421875 99.94812012 99.94812012 99.94812012h55.53588867v296.96044921c0 93.35632325 75.97045898 169.32678223 169.32678224 169.32678223h203.19213866c13.76037598 38.64440918 50.42724609 66.57714844 93.76831055 66.57714844 55.12390137 0 99.94812012-44.82421875 99.94812012-99.94812012s-44.90661622-99.86572266-100.03051758-99.86572265z m0-199.89624024c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857423s-14.91394043 33.28857422-33.28857422 33.28857421-33.28857422-14.91394043-33.28857422-33.28857421 14.91394043-33.28857422 33.28857422-33.28857422zM217.75866699 301.0625V190.07312011c0-18.37463379 14.91394043-33.28857422 33.28857423-33.28857421h444.03991698c18.37463379 0 33.28857422 14.91394043 33.28857422 33.28857422V301.0625c0 18.37463379-14.91394043 33.28857422-33.28857422 33.28857422H251.12963867c-18.37463379 0-33.37097168-14.91394043-33.37097168-33.28857422z m555.11169434 566.23535156c-18.37463379 0-33.28857422-14.91394043-33.28857422-33.28857422 0-18.37463379 14.91394043-33.28857422 33.28857422-33.28857422s33.28857422 14.91394043 33.28857422 33.28857422c0.08239747 18.29223633-14.91394043 33.28857422-33.28857422 33.28857422z" p-id="972"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/chart.svg b/ruoyi-ui/src/assets/icons/svg/chart.svg
new file mode 100644
index 0000000..27728fb
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/chart.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h36.571V128H0V54.857zM91.429 27.43H128V128H91.429V27.429zM45.714 0h36.572v128H45.714V0z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/checkbox.svg b/ruoyi-ui/src/assets/icons/svg/checkbox.svg
new file mode 100644
index 0000000..013fd3a
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/checkbox.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575982282951" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="902" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M828.40625 90.125H195.59375C137.375 90.125 90.125 137.375 90.125 195.59375v632.8125c0 58.21875 47.25 105.46875 105.46875 105.46875h632.8125c58.21875 0 105.46875-47.25 105.46875-105.46875V195.59375c0-58.21875-47.25-105.46875-105.46875-105.46875z m52.734375 738.28125c0 29.16-23.57015625 52.734375-52.734375 52.734375H195.59375c-29.109375 0-52.734375-23.574375-52.734375-52.734375V195.59375c0-29.109375 23.625-52.734375 52.734375-52.734375h632.8125c29.16 0 52.734375 23.625 52.734375 52.734375v632.8125z" p-id="903"></path><path d="M421.52890625 709.55984375a36.28125 36.28125 0 0 1-27.55265625-12.66890625L205.17453125 476.613125a36.28546875 36.28546875 0 0 1 55.10109375-47.22890625l164.986875 192.4846875 342.16171875-298.48078125a36.2896875 36.2896875 0 0 1 47.70984375 54.68765625L445.3859375 700.6203125a36.3234375 36.3234375 0 0 1-23.85703125 8.93953125z" p-id="904"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/clipboard.svg b/ruoyi-ui/src/assets/icons/svg/clipboard.svg
new file mode 100644
index 0000000..90923ff
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/clipboard.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.857 118.857h64V73.143H89.143c-1.902 0-3.52-.668-4.855-2.002-1.335-1.335-2.002-2.954-2.002-4.855V36.57H54.857v82.286zM73.143 16v-4.571a2.2 2.2 0 0 0-.677-1.61 2.198 2.198 0 0 0-1.609-.676H20.571c-.621 0-1.158.225-1.609.676a2.198 2.198 0 0 0-.676 1.61V16a2.2 2.2 0 0 0 .676 1.61c.451.45.988.676 1.61.676h50.285c.622 0 1.158-.226 1.61-.677.45-.45.676-.987.676-1.609zm18.286 48h21.357L91.43 42.642V64zM128 73.143v48c0 1.902-.667 3.52-2.002 4.855-1.335 1.335-2.953 2.002-4.855 2.002H52.57c-1.901 0-3.52-.667-4.854-2.002-1.335-1.335-2.003-2.953-2.003-4.855v-11.429H6.857c-1.902 0-3.52-.667-4.855-2.002C.667 106.377 0 104.759 0 102.857v-96c0-1.902.667-3.52 2.002-4.855C3.337.667 4.955 0 6.857 0h77.714c1.902 0 3.52.667 4.855 2.002 1.335 1.335 2.003 2.953 2.003 4.855V30.29c1 .622 1.856 1.29 2.569 2.003l29.147 29.147c1.335 1.335 2.478 3.145 3.429 5.43.95 2.287 1.426 4.383 1.426 6.291v-.018z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/code.svg b/ruoyi-ui/src/assets/icons/svg/code.svg
new file mode 100644
index 0000000..5f9c5ab
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/code.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1546567861908" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2422" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M318.577778 819.2L17.066667 512l301.511111-307.2 45.511111 45.511111L96.711111 512l267.377778 261.688889zM705.422222 819.2l-45.511111-45.511111L927.288889 512l-267.377778-261.688889 45.511111-45.511111L1006.933333 512zM540.785778 221.866667l55.751111 11.150222L483.157333 802.133333l-55.751111-11.093333z" p-id="2423"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/color.svg b/ruoyi-ui/src/assets/icons/svg/color.svg
new file mode 100644
index 0000000..44a81aa
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/color.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577252187056" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2508" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M747.59340925 691.12859384c11.51396329 0.25305413 22.43746719-0.21087818 40.74171707-1.51832482 29.35428085-2.10878421 35.84933734-2.36183835 46.47761114-0.8856895 24.71495444 3.37405491 41.12129828 21.76265671 32.47528161 47.95376084-85.57447632 258.19957947-442.00123984 249.76444099-628.67084683 50.73735554-153.47733892-159.33976008-153.09775772-414.41833795 0.92786545-573.42069196 159.71934128-162.67163983 424.03439521-166.59397897 565.78689185 0.63263534 80.38686649 94.81095318 108.34934958 169.16669549 89.11723508 230.57450162-15.01454608 47.99593598-50.61082928 77.68762207-119.77896259 114.63352789-4.89237973 2.65706845-29.35428085 15.52065436-35.84933652 19.02123633-46.94154346 25.30541465-63.51659033 41.20565021-62.20914449 58.45550757 2.95229856 39.13904114 24.16667102 52.7196135 70.98168823 53.81618115z m44.41100207 50.10472101c-19.82257471 1.43397372-32.05352527 1.940082-45.63409763 1.6448519-70.34905207-1.60267593-115.98314969-30.91478165-121.38163769-101.64341492-3.45840683-46.05585397 24.7571304-73.13264758 89.24376132-107.96976837 6.7902866-3.66928501 31.37871396-16.57504688 36.06021551-19.06341229 57.69634516-30.83042972 85.15271997-53.73183005 94.76877722-84.47790866 12.77923398-40.78389304-9.10994898-98.94417051-79.24812286-181.6507002-121.17075953-142.97559219-350.14258521-139.60153647-489.2380134 2.06660824-134.49827774 138.84237405-134.79350784 362.12048163-0.42175717 501.637667 158.53842169 168.99799328 451.9968783 181.18676788 534.57688175-11.80919339-4.68150156 0.2952301-10.71262573 0.67481131-18.72600705 1.26527069z" p-id="2509"></path><path d="M346.03865637 637.18588562a78.82636652 78.82636652 0 0 0 78.32025825-79.29029883c0-43.69401562-35.005823-79.29029883-78.32025825-79.29029882a78.82636652 78.82636652 0 0 0-78.36243338 79.29029882c0 43.69401562 35.005823 79.29029883 78.36243338 79.29029883z m0-51.7495729a27.07679361 27.07679361 0 0 1-26.5706845-27.54072593c0-15.30977536 11.97789643-27.54072593 26.5706845-27.54072592 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072592a27.07679361 27.07679361 0 0 1-26.57068533 27.54072593zM475.7289063 807.11174353a78.82636652 78.82636652 0 0 0 78.3624334-79.29029882c0-43.69401562-34.96364785-79.29029883-78.32025825-79.29029883a78.82636652 78.82636652 0 0 0-78.32025742 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029882z m0-51.74957208a27.07679361 27.07679361 0 0 1-26.57068532-27.54072674c0-15.30977536 12.06224753-27.54072593 26.57068532-27.54072593 14.59278892 0 26.57068533 12.23095057 26.57068453 27.54072593a27.07679361 27.07679361 0 0 1-26.57068453 27.54072674zM601.24376214 377.21492718a78.82636652 78.82636652 0 0 0 78.32025742-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025742-79.29029882a78.82636652 78.82636652 0 0 0-78.32025823 79.29029883c0 43.69401562 34.96364785 79.29029883 78.32025824 79.29029883z m1e-8-51.74957208a27.07679361 27.07679361 0 0 1-26.57068534-27.54072675c0-15.30977536 11.97789643-27.54072593 26.57068534-27.54072591 14.55061295 0 26.57068533 12.23095057 26.57068451 27.54072592a27.07679361 27.07679361 0 0 1-26.57068451 27.54072674zM378.80916809 433.85687983a78.82636652 78.82636652 0 0 0 78.32025824-79.29029883c0-43.69401562-34.96364785-79.29029883-78.32025824-79.29029802a78.82636652 78.82636652 0 0 0-78.32025742 79.29029802c0 43.69401562 34.96364785 79.29029883 78.32025742 79.29029883z m0-51.74957209a27.07679361 27.07679361 0 0 1-26.57068451-27.54072674c0-15.30977536 11.97789643-27.54072593 26.57068451-27.54072593 14.55061295 0 26.57068533 12.23095057 26.57068533 27.54072593a27.07679361 27.07679361 0 0 1-26.57068533 27.54072674z" p-id="2510"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/component.svg b/ruoyi-ui/src/assets/icons/svg/component.svg
new file mode 100644
index 0000000..29c3458
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/component.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575804206892" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3145" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M826.56 470.016c-32.896 0-64.384 12.288-89.984 35.52l0-104.96c0-62.208-50.496-112.832-112.64-113.088L623.936 287.04 519.552 287.104C541.824 262.72 554.56 230.72 554.56 197.12c0-73.536-59.904-133.44-133.504-133.44-73.472 0-133.376 59.904-133.376 133.44 0 32.896 12.224 64.256 35.52 89.984L175.232 287.104l0 0.576C113.728 288.704 64 338.88 64 400.576l0.32 0 0.32 116.48C60.864 544.896 70.592 577.728 100.8 588.48c12.736 4.608 37.632 7.488 60.864-25.28 12.992-18.368 34.24-29.248 56.64-29.248 38.336 0 69.504 31.104 69.504 69.312 0 38.4-31.168 69.504-69.504 69.504-22.656 0-44.032-11.264-57.344-30.4C138.688 610.112 112.576 615.36 102.464 619.136c-29.824 10.752-39.104 43.776-38.144 67.392l0 160.384L64 846.912C64 909.248 114.752 960 177.216 960l446.272 0c62.4 0 113.152-50.752 113.152-113.152l0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.536 0 133.44-59.904 133.44-133.504C960 529.92 900.096 470.016 826.56 470.016zM826.56 672.896c-22.72 0-44.032-11.264-57.344-30.4-22.272-32.384-48.448-27.136-58.56-23.36-29.824 10.752-39.04 43.776-38.08 67.392l0 160.384c0 27.136-22.016 49.152-49.152 49.152L177.216 896.064C150.08 896 128 873.984 128 846.848l0.32 0 0-145.024c24.384 22.272 56.384 35.008 89.984 35.008 73.6 0 133.504-59.904 133.504-133.504 0-73.472-59.904-133.376-133.504-133.376-32.896 0-64.32 12.288-89.984 35.52l0-104.96L128 400.512c0-27.072 22.08-49.152 49.216-49.152L177.216 351.04 334.656 350.72c3.776 0.512 7.616 0.832 11.52 0.832 24.896 0 50.752-10.816 60.032-37.056 4.544-12.736 7.424-37.568-25.344-60.736C362.624 240.768 351.68 219.52 351.68 197.12c0-38.272 31.104-69.44 69.376-69.44 38.336 0 69.504 31.168 69.504 69.44 0 22.72-11.264 44.032-30.528 57.472C427.968 276.736 433.088 302.784 436.8 313.024c10.752 29.888 43.072 39.232 67.392 38.08l119.232 0 0 0.384c27.136 0 49.152 22.08 49.152 49.152l0.256 116.48c-3.776 27.84 6.016 60.736 36.224 71.488 12.736 4.608 37.632 7.488 60.8-25.28 13.056-18.368 34.24-29.248 56.704-29.248C864.832 534.016 896 565.12 896 603.392 896 641.728 864.832 672.896 826.56 672.896z" p-id="3146"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/dashboard.svg b/ruoyi-ui/src/assets/icons/svg/dashboard.svg
new file mode 100644
index 0000000..5317d37
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/dashboard.svg
@@ -0,0 +1 @@
+<svg width="128" height="100" xmlns="http://www.w3.org/2000/svg"><path d="M27.429 63.638c0-2.508-.893-4.65-2.679-6.424-1.786-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.465 2.662-1.785 1.774-2.678 3.916-2.678 6.424 0 2.508.893 4.65 2.678 6.424 1.786 1.775 3.94 2.662 6.465 2.662 2.524 0 4.678-.887 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm13.714-31.801c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM71.714 65.98l7.215-27.116c.285-1.23.107-2.378-.536-3.443-.643-1.064-1.56-1.762-2.75-2.094-1.19-.33-2.333-.177-3.429.462-1.095.639-1.81 1.573-2.143 2.804l-7.214 27.116c-2.857.237-5.405 1.266-7.643 3.088-2.238 1.822-3.738 4.152-4.5 6.992-.952 3.644-.476 7.098 1.429 10.364 1.905 3.265 4.69 5.37 8.357 6.317 3.667.947 7.143.474 10.429-1.42 3.285-1.892 5.404-4.66 6.357-8.305.762-2.84.619-5.607-.429-8.305-1.047-2.697-2.762-4.85-5.143-6.46zm47.143-2.342c0-2.508-.893-4.65-2.678-6.424-1.786-1.775-3.94-2.662-6.465-2.662-2.524 0-4.678.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.786 1.775 3.94 2.662 6.464 2.662 2.524 0 4.679-.887 6.465-2.662 1.785-1.775 2.678-3.916 2.678-6.424zm-45.714-45.43c0-2.509-.893-4.65-2.679-6.425C68.68 10.01 66.524 9.122 64 9.122c-2.524 0-4.679.887-6.464 2.661-1.786 1.775-2.679 3.916-2.679 6.425 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zm32 13.629c0-2.508-.893-4.65-2.679-6.424-1.785-1.775-3.94-2.662-6.464-2.662-2.524 0-4.679.887-6.464 2.662-1.786 1.774-2.679 3.916-2.679 6.424 0 2.508.893 4.65 2.679 6.424 1.785 1.774 3.94 2.662 6.464 2.662 2.524 0 4.679-.888 6.464-2.662 1.786-1.775 2.679-3.916 2.679-6.424zM128 63.638c0 12.351-3.357 23.78-10.071 34.286-.905 1.372-2.19 2.058-3.858 2.058H13.93c-1.667 0-2.953-.686-3.858-2.058C3.357 87.465 0 76.037 0 63.638c0-8.613 1.69-16.847 5.071-24.703C8.452 31.08 13 24.312 18.714 18.634c5.715-5.68 12.524-10.199 20.429-13.559C47.048 1.715 55.333.035 64 .035c8.667 0 16.952 1.68 24.857 5.04 7.905 3.36 14.714 7.88 20.429 13.559 5.714 5.678 10.262 12.446 13.643 20.301 3.38 7.856 5.071 16.09 5.071 24.703z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/date-range.svg b/ruoyi-ui/src/assets/icons/svg/date-range.svg
new file mode 100644
index 0000000..fda571e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/date-range.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774833889" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1376" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M887.466667 192.853333h-100.693334V119.466667c0-10.24-6.826667-17.066667-17.066666-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H303.786667V119.466667c0-10.24-6.826667-17.066667-17.066667-17.066667s-17.066667 6.826667-17.066667 17.066667v73.386666H168.96c-46.08 0-85.333333 37.546667-85.333333 85.333334V836.266667c0 46.08 37.546667 85.333333 85.333333 85.333333H887.466667c46.08 0 85.333333-37.546667 85.333333-85.333333V278.186667c0-47.786667-37.546667-85.333333-85.333333-85.333334z m-718.506667 34.133334h100.693333v66.56c0 10.24 6.826667 17.066667 17.066667 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56h450.56v66.56c0 10.24 6.826667 17.066667 17.066666 17.066666s17.066667-6.826667 17.066667-17.066666v-66.56H887.466667c27.306667 0 51.2 22.186667 51.2 51.2v88.746666H117.76v-88.746666c0-29.013333 22.186667-51.2 51.2-51.2zM887.466667 887.466667H168.96c-27.306667 0-51.2-22.186667-51.2-51.2V401.066667H938.666667V836.266667c0 27.306667-22.186667 51.2-51.2 51.2z" p-id="1377"></path><path d="M858.453333 493.226667H327.68c-10.24 0-17.066667 6.826667-17.066667 17.066666v114.346667h-116.053333c-10.24 0-17.066667 6.826667-17.066667 17.066667v133.12c0 10.24 6.826667 17.066667 17.066667 17.066666H460.8c10.24 0 17.066667-6.826667 17.066667-17.066666v-114.346667h380.586666c10.24 0 17.066667-6.826667 17.066667-17.066667v-133.12c0-10.24-6.826667-17.066667-17.066667-17.066666z m-413.013333 34.133333v97.28h-98.986667v-97.28h98.986667z m-230.4 131.413333h98.986667v98.986667h-98.986667v-98.986667z m131.413333 97.28v-97.28h98.986667v97.28h-98.986667z m133.12-228.693333h97.28v98.986667h-97.28v-98.986667z m131.413334 0h98.986666v98.986667h-98.986666v-98.986667z m230.4 97.28h-98.986667v-98.986667h98.986667v98.986667z" p-id="1378"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/date.svg b/ruoyi-ui/src/assets/icons/svg/date.svg
new file mode 100644
index 0000000..52dc73e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/date.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577186573535" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1068" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M479.85714249 608.42857168h64.28571502c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285751s-12.85714249-32.14285751-32.14285664-32.14285664h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285662s12.85714249 32.14285751 32.14285664 32.14285753z m-2e-8 122.14285665h64.28571504c19.28571417 0 32.14285751-12.85714249 32.14285664-32.14285665s-12.85714249-32.14285751-32.14285664-32.14285751h-64.28571504c-19.28571417 0-32.14285751 12.85714249-32.14285664 32.14285751s12.85714249 32.14285751 32.14285664 32.14285664z m353.57142921-559.28571416h-128.57142921v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285664-32.14285753s-32.14285751 12.85714249-32.14285751 32.14285753v32.14285664h-257.14285665v-32.14285664c0-19.28571417-12.85714249-32.14285751-32.14285752-32.14285753s-32.14285751 12.85714249-32.14285664 32.14285753v32.14285664h-128.57142919c-70.71428585 0-128.57142832 57.85714249-128.57142832 122.14285751v501.42857081c0 70.71428585 57.85714249 128.57142832 128.57142832 122.14285751h642.85714335c70.71428585 0 128.57142832-57.85714249 128.57142833-122.14285751v-501.42857081c0-70.71428585-57.85714249-122.14285753-128.57142833-122.14285751z m64.28571415 623.57142832c0 32.14285751-32.14285751 64.28571415-64.28571416 64.28571504h-642.85714335c-32.14285751 0-64.28571415-25.71428583-64.28571417-64.28571504v-372.85714249h771.42857168v372.85714249z m0-437.14285664h-771.42857168v-64.28571417c0-32.14285751 32.14285751-64.28571415 64.28571417-64.28571415h128.57142919v32.14285664c0 19.28571417 12.85714249 32.14285751 32.14285664 32.14285751s32.14285751-12.85714249 32.14285753-32.14285751v-32.14285664h257.14285665v32.14285664c0 19.28571417 12.85714249 32.14285751 32.1428575 32.14285751s32.14285751-12.85714249 32.14285664-32.14285751v-32.14285664h128.57142921c32.14285751 0 64.28571415 25.71428583 64.28571415 64.28571415v64.28571417z m-610.71428583 372.85714247h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285664s-12.85714249-32.14285751-32.14285753-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285751s12.85714249 32.14285751 32.14285751 32.14285665z m385.71428583-122.14285664h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285751s-12.85714249-32.14285751-32.14285751-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285664s12.85714249 32.14285751 32.14285753 32.14285751z m-385.71428583 0h64.28571415c19.28571417 0 32.14285751-12.85714249 32.14285753-32.14285751s-12.85714249-32.14285751-32.14285753-32.14285664h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285751 32.14285664s12.85714249 32.14285751 32.14285751 32.14285751z m385.71428583 122.14285665h64.28571417c19.28571417 0 32.14285751-12.85714249 32.14285751-32.14285665s-12.85714249-32.14285751-32.14285751-32.14285751h-64.28571415c-19.28571417 0-32.14285751 12.85714249-32.14285753 32.14285751s12.85714249 32.14285751 32.14285753 32.14285665z" p-id="1069"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/dict.svg b/ruoyi-ui/src/assets/icons/svg/dict.svg
new file mode 100644
index 0000000..4849377
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/dict.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035680909" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3601" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1002.0848 744.672l-33.568 10.368c0.96 7.264 2.144 14.304 2.144 21.76 0 7.328-1.184 14.432-2.368 21.568l33.792 10.56c7.936 2.24 14.496 7.616 18.336 14.752 3.84 7.328 4.672 15.808 1.952 23.552-5.376 16-23.168 24.672-39.936 19.68l-34.176-10.624c-7.136 12.8-15.776 24.672-26.208 35.2l20.8 27.488a28.96 28.96 0 0 1 5.824 22.816 29.696 29.696 0 0 1-12.704 19.616 32.544 32.544 0 0 1-44.416-6.752l-20.8-27.552c-13.696 6.56-28.192 11.2-43.008 13.888v33.632c0 16.736-14.112 30.432-31.648 30.432-17.6 0-31.872-13.696-31.872-30.432v-33.632a167.616 167.616 0 0 1-42.88-13.888l-20.928 27.552c-10.72 13.76-30.08 16.64-44.288 6.752a29.632 29.632 0 0 1-12.704-19.616 29.28 29.28 0 0 1 5.696-22.816l20.896-27.808a166.72 166.72 0 0 1-27.008-34.688l-33.376 10.432c-16.8 5.184-34.56-3.552-39.936-19.616a29.824 29.824 0 0 1 20.224-38.24l33.472-10.432c-0.8-7.264-2.016-14.304-2.016-21.824 0-7.36 1.184-14.496 2.304-21.632l-33.792-10.368c-16.672-5.376-25.632-22.496-20.224-38.432 5.376-16 23.136-24.672 39.936-19.68l34.016 10.752c7.328-12.672 15.84-24.8 26.336-35.328l-20.8-27.552a29.44 29.44 0 0 1 6.944-42.432 32.704 32.704 0 0 1 44.384 6.752l20.832 27.616c13.696-6.432 28.224-11.2 43.104-13.952v-33.568c0-16.736 14.048-30.432 31.648-30.432 17.536 0 31.808 13.568 31.808 30.432v33.504c15.072 2.688 29.344 7.808 42.848 14.016l20.992-27.616a32.48 32.48 0 0 1 44.224-6.752 29.568 29.568 0 0 1 7.136 42.432l-21.024 27.808c10.432 10.432 19.872 21.888 27.04 34.752l33.376-10.432c16.768-5.12 34.56 3.68 39.936 19.68 5.536 15.936-3.712 33.056-20.32 38.304z m-206.016-74.432c-61.344 0-111.136 47.808-111.136 106.56 0 58.88 49.792 106.496 111.136 106.496 61.312 0 111.104-47.616 111.104-106.496 0-58.752-49.792-106.56-111.104-106.56z" p-id="3602"></path><path d="M802.7888 57.152h-76.448c0-22.08-21.024-38.24-42.848-38.24H39.3968a39.68 39.68 0 0 0-39.36 40.032v795.616s41.888 120.192 110.752 120.192H673.2848a227.488 227.488 0 0 1-107.04-97.44H117.6368s-40.608-13.696-40.608-41.248l470.304-0.256 1.664 3.36a227.68 227.68 0 0 1-12.64-73.632c0-60.576 24-118.624 66.88-161.44a228.352 228.352 0 0 1 123.552-63.392l-3.2 0.288 2.144-424.672h38.208l0.576 421.024c27.04 0 52.672 4.8 76.64 13.344V101.536c0.032 0-6.304-44.384-38.368-44.384zM149.7648 514.336H72.3888v-77.408H149.7648v77.408z m0-144.32H72.3888v-77.44H149.7648v77.44z m0-137.248H72.3888v-77.44H149.7648v77.44z m501.856 281.568H206.0848v-77.408h445.536v77.408z m0-144.32H206.0848v-77.44h445.536v77.44z m0-137.248H206.0848v-77.44h445.536v77.44z" p-id="3603"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/documentation.svg b/ruoyi-ui/src/assets/icons/svg/documentation.svg
new file mode 100644
index 0000000..7043122
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/documentation.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M71.984 44.815H115.9L71.984 9.642v35.173zM16.094.05h63.875l47.906 38.37v76.74c0 3.392-1.682 6.645-4.677 9.044-2.995 2.399-7.056 3.746-11.292 3.746H16.094c-4.236 0-8.297-1.347-11.292-3.746-2.995-2.399-4.677-5.652-4.677-9.044V12.84C.125 5.742 7.23.05 16.094.05zm71.86 102.32V89.58h-71.86v12.79h71.86zm23.952-25.58V64H16.094v12.79h95.812z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/download.svg b/ruoyi-ui/src/assets/icons/svg/download.svg
new file mode 100644
index 0000000..c896951
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/download.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569915748289" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3062" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M768.35456 416a256 256 0 1 0-512 0 192 192 0 1 0 0 384v64a256 256 0 0 1-58.88-505.216 320.128 320.128 0 0 1 629.76 0A256.128 256.128 0 0 1 768.35456 864v-64a192 192 0 0 0 0-384z m-512 384h64v64H256.35456v-64z m448 0h64v64h-64v-64z" fill="#333333" p-id="3063"></path><path d="M539.04256 845.248V512.192a32.448 32.448 0 0 0-32-32.192c-17.664 0-32 14.912-32 32.192v333.056l-36.096-36.096a32.192 32.192 0 0 0-45.056 0.192 31.616 31.616 0 0 0-0.192 45.056l90.88 90.944a31.36 31.36 0 0 0 22.528 9.088 30.08 30.08 0 0 0 22.4-9.088l90.88-90.88a32.192 32.192 0 0 0-0.192-45.12 31.616 31.616 0 0 0-45.056-0.192l-36.096 36.096z" fill="#333333" p-id="3064"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/drag.svg b/ruoyi-ui/src/assets/icons/svg/drag.svg
new file mode 100644
index 0000000..4185d3c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/drag.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M73.137 29.08h-9.209 29.7L63.886.093 34.373 29.08h20.49v27.035H27.238v17.948h27.625v27.133h18.274V74.063h27.41V56.115h-27.41V29.08zm-9.245 98.827l27.518-26.711H36.59l27.302 26.71zM.042 64.982l27.196 27.029V38.167L.042 64.982zm100.505-26.815V92.01l27.41-27.029-27.41-26.815z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/druid.svg b/ruoyi-ui/src/assets/icons/svg/druid.svg
new file mode 100644
index 0000000..a2b4b4e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/druid.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036347051" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5853" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M832 128H192a64.19 64.19 0 0 0-64 64v640a64.19 64.19 0 0 0 64 64h640a64.19 64.19 0 0 0 64-64V192a64.19 64.19 0 0 0-64-64z m0 703.89l-0.11 0.11H192.11l-0.11-0.11V768h640zM832 544H720L605.6 696.54 442.18 435.07 333.25 544H192v-64h114.75l147.07-147.07L610.4 583.46 688 480h144z m0-288H192v-63.89l0.11-0.11h639.78l0.11 0.11z" p-id="5854"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/edit.svg b/ruoyi-ui/src/assets/icons/svg/edit.svg
new file mode 100644
index 0000000..d26101f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/edit.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M106.133 67.2a4.797 4.797 0 0 0-4.8 4.8c0 .187.014.36.027.533h-.027V118.4H9.6V26.667h50.133c2.654 0 4.8-2.147 4.8-4.8 0-2.654-2.146-4.8-4.8-4.8H9.6a9.594 9.594 0 0 0-9.6 9.6V118.4c0 5.307 4.293 9.6 9.6 9.6h91.733c5.307 0 9.6-4.293 9.6-9.6V72.533h-.026c.013-.173.026-.346.026-.533 0-2.653-2.146-4.8-4.8-4.8z"/><path d="M125.16 13.373L114.587 2.8c-3.747-3.747-9.854-3.72-13.6.027l-52.96 52.96a4.264 4.264 0 0 0-.907 1.36L33.813 88.533c-.746 1.76-.226 3.534.907 4.68 1.133 1.147 2.92 1.667 4.693.92l31.4-13.293c.507-.213.96-.52 1.36-.907l52.96-52.96c3.747-3.746 3.774-9.853.027-13.6zM66.107 72.4l-18.32 7.76 7.76-18.32L92.72 24.667l10.56 10.56L66.107 72.4zm52.226-52.227l-8.266 8.267-10.56-10.56 8.266-8.267.027-.026 10.56 10.56-.027.026z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/education.svg b/ruoyi-ui/src/assets/icons/svg/education.svg
new file mode 100644
index 0000000..7bfb01d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/education.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M88.883 119.565c-7.284 0-19.434 2.495-21.333 8.25v.127c-4.232.13-5.222 0-7.108 0-1.895-5.76-14.045-8.256-21.333-8.256H0V0h42.523c9.179 0 17.109 5.47 21.47 13.551C68.352 5.475 76.295 0 85.478 0H128v119.57l-39.113-.005h-.004zM60.442 24.763c0-9.651-8.978-16.507-17.777-16.507H7.108V111.43H39.11c7.054-.14 18.177.082 21.333 6.12v-4.628c-.134-5.722-.004-13.522 0-13.832V27.413l.004-2.655-.004.005zm60.442-16.517h-35.55c-8.802 0-17.78 6.856-17.78 16.493v74.259c.004.32.138 8.115 0 13.813v4.627c3.155-6.022 14.279-6.26 21.333-6.114h32V8.25l-.003-.005z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/email.svg b/ruoyi-ui/src/assets/icons/svg/email.svg
new file mode 100644
index 0000000..74d25e2
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/email.svg
@@ -0,0 +1 @@
+<svg width="128" height="96" xmlns="http://www.w3.org/2000/svg"><path d="M64.125 56.975L120.188.912A12.476 12.476 0 0 0 115.5 0h-103c-1.588 0-3.113.3-4.513.838l56.138 56.137z"/><path d="M64.125 68.287l-62.3-62.3A12.42 12.42 0 0 0 0 12.5v71C0 90.4 5.6 96 12.5 96h103c6.9 0 12.5-5.6 12.5-12.5v-71a12.47 12.47 0 0 0-1.737-6.35L64.125 68.287z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/example.svg b/ruoyi-ui/src/assets/icons/svg/example.svg
new file mode 100644
index 0000000..46f42b5
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/example.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M96.258 57.462h31.421C124.794 27.323 100.426 2.956 70.287.07v31.422a32.856 32.856 0 0 1 25.971 25.97zm-38.796-25.97V.07C27.323 2.956 2.956 27.323.07 57.462h31.422a32.856 32.856 0 0 1 25.97-25.97zm12.825 64.766v31.421c30.46-2.885 54.507-27.253 57.713-57.712H96.579c-2.886 13.466-13.146 23.726-26.292 26.291zM31.492 70.287H.07c2.886 30.46 27.253 54.507 57.713 57.713V96.579c-13.466-2.886-23.726-13.146-26.291-26.292z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/excel.svg b/ruoyi-ui/src/assets/icons/svg/excel.svg
new file mode 100644
index 0000000..74d97b8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/excel.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.208 16.576v8.384h38.72v5.376h-38.72v8.704h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.576h38.72v5.376h-38.72v8.512h38.72v5.376h-38.72v11.136H128v-94.72H78.208zM0 114.368L72.128 128V0L0 13.632v100.736z"/><path d="M28.672 82.56h-11.2l14.784-23.488-14.08-22.592h11.52l8.192 14.976 8.448-14.976h11.136l-14.08 22.208L58.368 82.56H46.656l-8.768-15.68z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg b/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg
new file mode 100644
index 0000000..485c128
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/exit-fullscreen.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M49.217 41.329l-.136-35.24c-.06-2.715-2.302-4.345-5.022-4.405h-3.65c-2.712-.06-4.866 2.303-4.806 5.016l.152 19.164-24.151-23.79a6.698 6.698 0 0 0-9.499 0 6.76 6.76 0 0 0 0 9.526l23.93 23.713-18.345.074c-2.712-.069-5.228 1.813-5.64 5.02v3.462c.069 2.721 2.31 4.97 5.022 5.03l35.028-.207c.052.005.087.025.133.025l2.457.054a4.626 4.626 0 0 0 3.436-1.38c.88-.874 1.205-2.096 1.169-3.462l-.262-2.465c0-.048.182-.081.182-.136h.002zm52.523 51.212l18.32-.073c2.713.06 5.224-1.609 5.64-4.815v-3.462c-.068-2.722-2.317-4.97-5.021-5.04l-34.58.21c-.053 0-.086-.021-.138-.021l-2.451-.06a4.64 4.64 0 0 0-3.445 1.381c-.885.868-1.201 2.094-1.174 3.46l.27 2.46c.005.06-.177.095-.177.141l.141 34.697c.069 2.713 2.31 4.338 5.022 4.397l3.45.006c2.705.062 4.867-2.31 4.8-5.026l-.153-18.752 24.151 23.946a6.69 6.69 0 0 0 9.494 0 6.747 6.747 0 0 0 0-9.523L101.74 92.54v.001zM48.125 80.662a4.636 4.636 0 0 0-3.437-1.382l-2.457.06c-.05 0-.082.022-.137.022l-35.025-.21c-2.712.07-4.957 2.318-5.022 5.04v3.462c.409 3.206 2.925 4.874 5.633 4.814l18.554.06-24.132 23.928c-2.62 2.626-2.62 6.89 0 9.524a6.694 6.694 0 0 0 9.496 0l24.155-23.79-.155 18.866c-.06 2.722 2.094 5.093 4.801 5.025h3.65c2.72-.069 4.962-1.685 5.022-4.406l.141-34.956c0-.05-.182-.082-.182-.136l.262-2.46c.03-1.366-.286-2.592-1.166-3.46h-.001zM80.08 47.397a4.62 4.62 0 0 0 3.443 1.374l2.45-.054c.055 0 .088-.02.143-.028l35.08.21c2.712-.062 4.953-2.312 5.021-5.033l.009-3.463c-.417-3.211-2.937-5.084-5.64-5.025l-18.615-.073 23.917-23.715c2.63-2.623 2.63-6.879.008-9.513a6.691 6.691 0 0 0-9.494 0L92.251 26.016l.155-19.312c.065-2.713-2.097-5.085-4.802-5.025h-3.45c-2.713.069-4.954 1.693-5.022 4.406l-.139 35.247c0 .054.18.088.18.136l-.267 2.465c-.028 1.366.288 2.588 1.174 3.463v.001z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/eye-open.svg b/ruoyi-ui/src/assets/icons/svg/eye-open.svg
new file mode 100644
index 0000000..88dcc98
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/eye-open.svg
@@ -0,0 +1 @@
+<svg class="icon" viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><defs><style/></defs><path d="M512 128q69.675 0 135.51 21.163t115.498 54.997 93.483 74.837 73.685 82.006 51.67 74.837 32.17 54.827L1024 512q-2.347 4.992-6.315 13.483T998.87 560.17t-31.658 51.669-44.331 59.99-56.832 64.34-69.504 60.16-82.347 51.5-94.848 34.687T512 896q-69.675 0-135.51-21.163t-115.498-54.826-93.483-74.326-73.685-81.493-51.67-74.496-32.17-54.997L0 513.707q2.347-4.992 6.315-13.483t18.816-34.816 31.658-51.84 44.331-60.33 56.832-64.683 69.504-60.331 82.347-51.84 94.848-34.816T512 128.085zm0 85.333q-46.677 0-91.648 12.331t-81.152 31.83-70.656 47.146-59.648 54.485-48.853 57.686-37.675 52.821-26.325 43.99q12.33 21.674 26.325 43.52t37.675 52.351 48.853 57.003 59.648 53.845T339.2 767.02t81.152 31.488T512 810.667t91.648-12.331 81.152-31.659 70.656-46.848 59.648-54.186 48.853-57.344 37.675-52.651T927.957 512q-12.33-21.675-26.325-43.648t-37.675-52.65-48.853-57.345-59.648-54.186-70.656-46.848-81.152-31.659T512 213.334zm0 128q70.656 0 120.661 50.006T682.667 512 632.66 632.661 512 682.667 391.339 632.66 341.333 512t50.006-120.661T512 341.333zm0 85.334q-35.328 0-60.33 25.002T426.666 512t25.002 60.33T512 597.334t60.33-25.002T597.334 512t-25.002-60.33T512 426.666z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/eye.svg b/ruoyi-ui/src/assets/icons/svg/eye.svg
new file mode 100644
index 0000000..16ed2d8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/eye.svg
@@ -0,0 +1 @@
+<svg width="128" height="64" xmlns="http://www.w3.org/2000/svg"><path d="M127.072 7.994c1.37-2.208.914-5.152-.914-6.87-2.056-1.717-4.797-1.226-6.396.982-.229.245-25.586 32.382-55.74 32.382-29.24 0-55.74-32.382-55.968-32.627-1.6-1.963-4.57-2.208-6.397-.49C-.17 3.086-.399 6.275 1.2 8.238c.457.736 5.94 7.36 14.62 14.72L4.17 35.96c-1.828 1.963-1.6 5.152.228 6.87.457.98 1.6 1.471 2.742 1.471s2.284-.49 3.198-1.472l12.564-13.983c5.94 4.416 13.021 8.587 20.788 11.53l-4.797 17.418c-.685 2.699.686 5.397 3.198 6.133h1.37c2.057 0 3.884-1.472 4.341-3.68L52.6 42.83c3.655.736 7.538 1.227 11.422 1.227 3.883 0 7.767-.49 11.422-1.227l4.797 17.173c.457 2.208 2.513 3.68 4.34 3.68.457 0 .914 0 1.143-.246 2.513-.736 3.883-3.434 3.198-6.133l-4.797-17.172c7.767-2.944 14.848-7.114 20.788-11.53l12.336 13.738c.913.981 2.056 1.472 3.198 1.472s2.284-.49 3.198-1.472c1.828-1.963 1.828-4.906.228-6.87l-11.65-13.001c9.366-7.36 14.849-14.474 14.849-14.474z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/form.svg b/ruoyi-ui/src/assets/icons/svg/form.svg
new file mode 100644
index 0000000..dcbaa18
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/form.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.068 23.784c-1.02 0-1.877-.32-2.572-.96a8.588 8.588 0 0 1-1.738-2.237 11.524 11.524 0 0 1-1.042-2.621c-.232-.895-.348-1.641-.348-2.238V0h.278c.834 0 1.622.085 2.363.256.742.17 1.645.575 2.711 1.214 1.066.64 2.363 1.535 3.892 2.686 1.53 1.15 3.453 2.664 5.77 4.54 2.502 2.045 4.494 3.771 5.977 5.178 1.483 1.406 2.618 2.6 3.406 3.58.787.98 1.274 1.812 1.46 2.494.185.682.277 1.278.277 1.79v2.046H84.068zM127.3 84.01c.278.682.464 1.535.556 2.558.093 1.023-.37 2.003-1.39 2.94-.463.427-.88.832-1.25 1.215-.372.384-.696.704-.974.96a6.69 6.69 0 0 1-.973.767l-11.816-10.741a44.331 44.331 0 0 0 1.877-1.535 31.028 31.028 0 0 1 1.737-1.406c1.112-.938 2.317-1.343 3.615-1.215 1.297.128 2.363.405 3.197.83.927.427 1.923 1.173 2.989 2.239 1.065 1.065 1.876 2.195 2.432 3.388zM78.23 95.902c2.038 0 3.752-.511 5.143-1.534l-26.969 25.83H18.037c-1.761 0-3.684-.47-5.77-1.407a24.549 24.549 0 0 1-5.838-3.709 21.373 21.373 0 0 1-4.518-5.306c-1.204-2.003-1.807-4.07-1.807-6.202V16.495c0-1.79.44-3.665 1.32-5.626A18.41 18.41 0 0 1 5.04 5.562a21.798 21.798 0 0 1 5.213-3.964C12.198.533 14.237 0 16.37 0h53.24v15.984c0 1.62.278 3.367.834 5.242a16.704 16.704 0 0 0 2.572 5.179c1.159 1.577 2.665 2.898 4.518 3.964 1.853 1.066 4.078 1.598 6.673 1.598h20.295v42.325L85.458 92.45c1.02-1.364 1.529-2.856 1.529-4.476 0-2.216-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1c-2.409 0-4.448.789-6.116 2.366-1.668 1.577-2.502 3.474-2.502 5.69 0 2.217.834 4.092 2.502 5.626 1.668 1.535 3.707 2.302 6.117 2.302h52.13zM26.1 47.951c-2.41 0-4.449.789-6.117 2.366-1.668 1.577-2.502 3.473-2.502 5.69 0 2.216.834 4.092 2.502 5.626 1.668 1.534 3.707 2.302 6.117 2.302h52.13c2.409 0 4.47-.768 6.185-2.302 1.715-1.534 2.572-3.41 2.572-5.626 0-2.217-.857-4.113-2.572-5.69-1.714-1.577-3.776-2.366-6.186-2.366H26.1zm52.407 64.063l1.807-1.663 3.476-3.196a479.75 479.75 0 0 0 4.587-4.284 500.757 500.757 0 0 1 5.004-4.667c3.985-3.666 8.48-7.758 13.485-12.276l11.677 10.741-13.485 12.404-5.004 4.603-4.587 4.22a179.46 179.46 0 0 0-3.267 3.068c-.88.853-1.367 1.322-1.46 1.407-.463.341-.973.703-1.529 1.087-.556.383-1.112.703-1.668.959-.556.256-1.413.575-2.572.959a83.5 83.5 0 0 1-3.545 1.087 72.2 72.2 0 0 1-3.475.895c-1.112.256-1.946.426-2.502.511-1.112.17-1.854.043-2.224-.383-.371-.426-.464-1.151-.278-2.174.092-.511.278-1.279.556-2.302.278-1.023.602-2.067.973-3.132l1.042-3.005c.325-.938.58-1.577.765-1.918a10.157 10.157 0 0 1 2.224-2.941z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/fullscreen.svg b/ruoyi-ui/src/assets/icons/svg/fullscreen.svg
new file mode 100644
index 0000000..0e86b6f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/fullscreen.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M38.47 52L52 38.462l-23.648-23.67L43.209 0H.035L0 43.137l14.757-14.865L38.47 52zm74.773 47.726L89.526 76 76 89.536l23.648 23.672L84.795 128h43.174L128 84.863l-14.757 14.863zM89.538 52l23.668-23.648L128 43.207V.038L84.866 0 99.73 14.76 76 38.472 89.538 52zM38.46 76L14.792 99.651 0 84.794v43.173l43.137.033-14.865-14.757L52 89.53 38.46 76z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/github.svg b/ruoyi-ui/src/assets/icons/svg/github.svg
new file mode 100644
index 0000000..db0a0d4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/github.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1581238998885" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4187" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M511.542857 14.057143C228.914286 13.942857 0 242.742857 0 525.142857 0 748.457143 143.2 938.285714 342.628571 1008c26.857143 6.742857 22.742857-12.342857 22.742858-25.371429v-88.571428c-155.085714 18.171429-161.371429-84.457143-171.771429-101.6C172.571429 756.571429 122.857143 747.428571 137.714286 730.285714c35.314286-18.171429 71.314286 4.571429 113.028571 66.171429 30.171429 44.685714 89.028571 37.142857 118.857143 29.714286 6.514286-26.857143 20.457143-50.857143 39.657143-69.485715-160.685714-28.8-227.657143-126.857143-227.657143-243.428571 0-56.571429 18.628571-108.571429 55.2-150.514286-23.314286-69.142857 2.171429-128.342857 5.6-137.142857 66.4-5.942857 135.428571 47.542857 140.8 51.771429 37.714286-10.171429 80.8-15.542857 129.028571-15.542858 48.457143 0 91.657143 5.6 129.714286 15.885715 12.914286-9.828571 76.914286-55.771429 138.628572-50.171429 3.314286 8.8 28.228571 66.628571 6.285714 134.857143 37.028571 42.057143 55.885714 94.514286 55.885714 151.2 0 116.8-67.428571 214.971429-228.571428 243.314286a145.714286 145.714286 0 0 1 43.542857 104v128.571428c0.914286 10.285714 0 20.457143 17.142857 20.457143 202.4-68.228571 348.114286-259.428571 348.114286-484.685714 0-282.514286-229.028571-511.2-511.428572-511.2z" p-id="4188"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/guide.svg b/ruoyi-ui/src/assets/icons/svg/guide.svg
new file mode 100644
index 0000000..b271001
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/guide.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.482 70.131l36.204 16.18 69.932-65.485-61.38 70.594 46.435 18.735c1.119.425 2.397-.17 2.797-1.363v-.085L127.998.047 1.322 65.874c-1.12.597-1.519 1.959-1.04 3.151.32.511.72.937 1.2 1.107zm44.676 57.821L64.22 107.26l-18.062-7.834v28.527z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/icon.svg b/ruoyi-ui/src/assets/icons/svg/icon.svg
new file mode 100644
index 0000000..82be8ee
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/icon.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.147.062a13 13 0 0 1 4.94.945c1.55.63 2.907 1.526 4.069 2.688a13.148 13.148 0 0 1 2.761 4.069c.678 1.55 1.017 3.245 1.017 5.086v102.3c0 3.681-1.187 6.733-3.56 9.155-2.373 2.422-5.352 3.633-8.937 3.633H12.992c-3.875 0-7-1.26-9.373-3.779-2.373-2.518-3.56-5.667-3.56-9.445V12.704c0-3.39 1.163-6.345 3.488-8.863C5.872 1.32 8.972.062 12.847.062h102.3zM81.434 109.047c1.744 0 3.003-.412 3.778-1.235.775-.824 1.163-1.914 1.163-3.27 0-1.26-.388-2.325-1.163-3.197-.775-.872-2.034-1.307-3.778-1.307H72.57c.097-.194.145-.485.145-.872V27.09h9.01c1.743 0 2.954-.436 3.633-1.308.678-.872 1.017-1.938 1.017-3.197 0-1.26-.34-2.325-1.017-3.197-.679-.872-1.89-1.308-3.633-1.308H46.268c-1.743 0-2.954.436-3.632 1.308-.678.872-1.018 1.938-1.018 3.197 0 1.26.34 2.325 1.018 3.197.678.872 1.889 1.308 3.632 1.308h8.138v72.075c0 .193.024.339.073.436.048.096.072.242.072.436H46.56c-1.744 0-3.003.435-3.778 1.307-.775.872-1.163 1.938-1.163 3.197 0 1.356.388 2.446 1.163 3.27.775.823 2.034 1.235 3.778 1.235h34.875z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/input.svg b/ruoyi-ui/src/assets/icons/svg/input.svg
new file mode 100644
index 0000000..ab91381
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/input.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802859706" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3102" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 224H128c-35.2 0-64 28.8-64 64v448c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V288c0-35.2-28.8-64-64-64z m0 480c0 19.2-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V320c0-19.2 12.8-32 32-32h704c19.2 0 32 12.8 32 32v384z" p-id="3103"></path><path d="M224 352c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32s32-12.8 32-32V384c0-16-12.8-32-32-32z" p-id="3104"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/international.svg b/ruoyi-ui/src/assets/icons/svg/international.svg
new file mode 100644
index 0000000..e9b56ee
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/international.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M83.287 103.01c-1.57-3.84-6.778-10.414-15.447-19.548-2.327-2.444-2.182-4.306-1.338-9.862v-.64c.553-3.81 1.513-6.05 14.313-8.087 6.516-1.018 8.203 1.57 10.589 5.178l.785 1.193a12.625 12.625 0 0 0 6.43 5.207c1.134.524 2.53 1.164 4.421 2.24 4.596 2.53 4.596 5.41 4.596 11.753v.727a26.91 26.91 0 0 1-5.178 17.454 59.055 59.055 0 0 1-19.025 11.026c3.49-6.546.814-14.313 0-16.553l-.146-.087zM64 5.12a58.502 58.502 0 0 1 25.484 5.818 54.313 54.313 0 0 0-12.859 10.327c-.93 1.28-1.716 2.473-2.472 3.579-2.444 3.694-3.637 5.352-5.818 5.614a25.105 25.105 0 0 1-4.219 0c-4.276-.29-10.094-.64-11.956 4.422-1.193 3.23-1.396 11.956 2.444 16.495.66 1.077.778 2.4.32 3.578a7.01 7.01 0 0 1-2.066 3.229 18.938 18.938 0 0 1-2.909-2.91 18.91 18.91 0 0 0-8.32-6.603c-1.25-.349-2.647-.64-3.985-.93-3.782-.786-8.03-1.688-9.019-3.812a14.895 14.895 0 0 1-.727-5.818 21.935 21.935 0 0 0-1.396-9.25 8.873 8.873 0 0 0-5.557-4.946A58.705 58.705 0 0 1 64 5.12zM0 64c0 35.346 28.654 64 64 64 35.346 0 64-28.654 64-64 0-35.346-28.654-64-64-64C28.654 0 0 28.654 0 64z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/job.svg b/ruoyi-ui/src/assets/icons/svg/job.svg
new file mode 100644
index 0000000..2a93a25
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/job.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036191400" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5472" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M934.912 1016.832H192c-14.336 0-25.6-11.264-25.6-25.6v-189.44c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v163.84h691.712V64H217.6v148.48c0 14.336-11.264 25.6-25.6 25.6s-25.6-11.264-25.6-25.6v-174.08c0-14.336 11.264-25.6 25.6-25.6h742.912c14.336 0 25.6 11.264 25.6 25.6v952.832c0 14.336-11.264 25.6-25.6 25.6z" p-id="5473"></path><path d="M232.96 371.2h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 540.16h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM232.96 698.88h-117.76c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h117.76c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6zM574.464 762.88c-134.144 0-243.2-109.056-243.2-243.2S440.32 276.48 574.464 276.48s243.2 109.056 243.2 243.2-109.056 243.2-243.2 243.2z m0-435.2c-105.984 0-192 86.016-192 192S468.48 711.68 574.464 711.68s192-86.016 192-192S680.448 327.68 574.464 327.68z" p-id="5474"></path><path d="M663.04 545.28h-87.04c-14.336 0-25.6-11.264-25.6-25.6s11.264-25.6 25.6-25.6h87.04c14.336 0 25.6 11.264 25.6 25.6s-11.264 25.6-25.6 25.6z" p-id="5475"></path><path d="M576 545.28c-14.336 0-25.6-11.264-25.6-25.6v-87.04c0-14.336 11.264-25.6 25.6-25.6s25.6 11.264 25.6 25.6v87.04c0 14.336-11.264 25.6-25.6 25.6z" p-id="5476"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/language.svg b/ruoyi-ui/src/assets/icons/svg/language.svg
new file mode 100644
index 0000000..0082b57
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/language.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M84.742 36.8c2.398 7.2 5.595 12.8 11.19 18.4 4.795-4.8 7.992-11.2 10.39-18.4h-21.58zm-52.748 40h20.78l-10.39-28-10.39 28z"/><path d="M111.916 0H16.009C7.218 0 .025 7.2.025 16v96c0 8.8 7.193 16 15.984 16h95.907c8.791 0 15.984-7.2 15.984-16V16c0-8.8-6.394-16-15.984-16zM72.754 103.2c-1.598 1.6-3.197 1.6-4.795 1.6-.8 0-2.398 0-3.197-.8-.8-.8-1.599 0-1.599-.8s-.799-1.6-1.598-3.2c-.8-1.6-.8-2.4-1.599-4l-3.196-8.8H28.797L25.6 96c-1.598 3.2-2.398 5.6-3.197 7.2-.8 1.6-2.398 1.6-4.795 1.6-1.599 0-3.197-.8-4.796-1.6-1.598-1.6-2.397-2.4-2.397-4 0-.8 0-1.6.799-3.2.8-1.6.8-2.4 1.598-4l17.583-44.8c.8-1.6.8-3.2 1.599-4.8.799-1.6 1.598-3.2 2.397-4 .8-.8 1.599-2.4 3.197-3.2 1.599-.8 3.197-.8 4.796-.8 1.598 0 3.196 0 4.795.8 1.598.8 2.398 1.6 3.197 3.2.799.8 1.598 2.4 2.397 4 .8 1.6 1.599 3.2 2.398 5.6l17.583 44c1.598 3.2 2.398 5.6 2.398 7.2-.8.8-1.599 2.4-2.398 4zM116.711 72c-8.791-3.2-15.185-7.2-20.78-12-5.594 5.6-12.787 9.6-21.579 12l-2.397-4c8.791-2.4 15.984-5.6 21.579-11.2C87.939 51.2 83.144 44 81.545 36h-7.992v-3.2h21.58c-1.6-2.4-3.198-5.6-4.796-8l2.397-.8c1.599 2.4 3.997 5.6 5.595 8.8h19.98v4h-7.992c-2.397 8-6.393 15.2-11.189 20 5.595 4.8 11.988 8.8 20.78 11.2l-3.197 4z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/link.svg b/ruoyi-ui/src/assets/icons/svg/link.svg
new file mode 100644
index 0000000..48197ba
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/link.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M115.625 127.937H.063V12.375h57.781v12.374H12.438v90.813h90.813V70.156h12.374z"/><path d="M116.426 2.821l8.753 8.753-56.734 56.734-8.753-8.745z"/><path d="M127.893 37.982h-12.375V12.375H88.706V0h39.187z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/list.svg b/ruoyi-ui/src/assets/icons/svg/list.svg
new file mode 100644
index 0000000..20259ed
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/list.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M1.585 12.087c0 6.616 3.974 11.98 8.877 11.98 4.902 0 8.877-5.364 8.877-11.98 0-6.616-3.975-11.98-8.877-11.98-4.903 0-8.877 5.364-8.877 11.98zM125.86.107H35.613c-1.268 0-2.114 1.426-2.114 2.852v18.255c0 1.712 1.057 2.853 2.114 2.853h90.247c1.268 0 2.114-1.426 2.114-2.853V2.96c0-1.711-1.057-2.852-2.114-2.852zM.106 62.86c0 6.615 3.974 11.979 8.876 11.979 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zM124.17 50.88H33.921c-1.268 0-2.114 1.425-2.114 2.851v18.256c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852V53.73c0-1.426-.846-2.852-2.114-2.852zM.106 115.913c0 6.616 3.974 11.98 8.876 11.98 4.903 0 8.877-5.364 8.877-11.98 0-6.616-3.974-11.98-8.877-11.98-4.902 0-8.876 5.364-8.876 11.98zm124.064-11.98H33.921c-1.268 0-2.114 1.426-2.114 2.853v18.255c0 1.711 1.057 2.852 2.114 2.852h90.247c1.268 0 2.114-1.426 2.114-2.852v-18.255c0-1.427-.846-2.853-2.114-2.853z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/lock.svg b/ruoyi-ui/src/assets/icons/svg/lock.svg
new file mode 100644
index 0000000..74fee54
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/lock.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M119.88 49.674h-7.987V39.52C111.893 17.738 90.45.08 63.996.08 37.543.08 16.1 17.738 16.1 39.52v10.154H8.113c-4.408 0-7.987 2.94-7.987 6.577v65.13c0 3.637 3.57 6.577 7.987 6.577H119.88c4.407 0 7.987-2.94 7.987-6.577v-65.13c-.008-3.636-3.58-6.577-7.987-6.577zm-23.953 0H32.065V39.52c0-14.524 14.301-26.295 31.931-26.295 17.63 0 31.932 11.777 31.932 26.295v10.153z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/log.svg b/ruoyi-ui/src/assets/icons/svg/log.svg
new file mode 100644
index 0000000..d879d33
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/log.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035943711" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4805" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M208.736 566.336H64.384v59.328h144.352v-59.328z m0-336.096H165.44V74.592c0-7.968 4.896-14.848 10.464-14.848h502.016V0.448H175.936c-38.72 1.248-69.248 34.368-68.192 74.144v155.648H64.384V289.6h144.352V230.24z m0 168.096H64.384v59.328h144.352v-59.328z m714.656 76.576h-57.76v474.496c0 7.936-4.896 14.848-10.464 14.848H175.936c-5.568 0-10.464-6.912-10.464-14.848v-155.68h43.296v-59.296H64.384v59.296h43.328v155.68c-1.024 39.776 29.472 72.896 68.192 74.144h679.232c38.72-1.184 69.248-34.368 68.256-74.144V474.912z m14.944-290.336l-83.072-85.312a71.264 71.264 0 0 0-52.544-21.728 71.52 71.52 0 0 0-51.616 23.872L386.528 507.264a30.496 30.496 0 0 0-6.176 10.72L308.16 740.512a30.016 30.016 0 0 0 6.976 30.24c7.712 7.968 19.2 10.752 29.568 7.2l216.544-74.112a28.736 28.736 0 0 0 12.128-7.936L940.448 287.456a75.552 75.552 0 0 0-2.112-102.88z m-557.12 518.272l39.104-120.64 78.336 80.416-117.44 40.224z m170.048-70.016l-103.552-106.016 200.16-222.4 103.52 106.304-200.128 222.112zM897.952 247.072l-0.256 0.224-107.136 119.168-103.52-106.528 106.432-118.624a14.144 14.144 0 0 1 10.304-4.736 13.44 13.44 0 0 1 10.464 4.288l83.264 85.696c5.472 5.6 5.664 14.72 0.448 20.512z" p-id="4806"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/logininfor.svg b/ruoyi-ui/src/assets/icons/svg/logininfor.svg
new file mode 100644
index 0000000..267f844
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/logininfor.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036016814" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5261" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 128h-85.333333a42.666667 42.666667 0 0 0 0 85.333333h42.666666v640H170.666667V213.333333h42.666666a42.666667 42.666667 0 0 0 0-85.333333H128a42.666667 42.666667 0 0 0-42.666667 42.666667v725.333333a42.666667 42.666667 0 0 0 42.666667 42.666667h768a42.666667 42.666667 0 0 0 42.666667-42.666667V170.666667a42.666667 42.666667 0 0 0-42.666667-42.666667z" p-id="5262"></path><path d="M341.333333 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666666 42.666667zM512 298.666667a42.666667 42.666667 0 0 0 42.666667-42.666667V128a42.666667 42.666667 0 0 0-85.333334 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM682.666667 298.666667a42.666667 42.666667 0 0 0 42.666666-42.666667V128a42.666667 42.666667 0 0 0-85.333333 0v128a42.666667 42.666667 0 0 0 42.666667 42.666667zM341.333333 768a42.666667 42.666667 0 0 0 42.666667-42.666667 128 128 0 0 1 256 0 42.666667 42.666667 0 0 0 85.333333 0 213.333333 213.333333 0 0 0-107.52-184.32A128 128 0 0 0 640 469.333333a128 128 0 0 0-256 0 128 128 0 0 0 22.186667 71.68A213.333333 213.333333 0 0 0 298.666667 725.333333a42.666667 42.666667 0 0 0 42.666666 42.666667z m128-298.666667a42.666667 42.666667 0 1 1 42.666667 42.666667 42.666667 42.666667 0 0 1-42.666667-42.666667z" p-id="5263"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/message.svg b/ruoyi-ui/src/assets/icons/svg/message.svg
new file mode 100644
index 0000000..14ca817
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/message.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 20.967v59.59c0 11.59 8.537 20.966 19.075 20.966h28.613l1 26.477L76.8 101.523h32.125c10.538 0 19.075-9.377 19.075-20.966v-59.59C128 9.377 119.463 0 108.925 0h-89.85C8.538 0 0 9.377 0 20.967zm82.325 33.1c0-5.524 4.013-9.935 9.037-9.935 5.026 0 9.038 4.41 9.038 9.934 0 5.524-4.025 9.934-9.038 9.934-5.024 0-9.037-4.41-9.037-9.934zm-27.613 0c0-5.524 4.013-9.935 9.038-9.935s9.037 4.41 9.037 9.934c0 5.524-4.025 9.934-9.037 9.934-5.025 0-9.038-4.41-9.038-9.934zm-27.1 0c0-5.524 4.013-9.935 9.038-9.935s9.038 4.41 9.038 9.934c0 5.524-4.026 9.934-9.05 9.934-5.013 0-9.025-4.41-9.025-9.934z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/money.svg b/ruoyi-ui/src/assets/icons/svg/money.svg
new file mode 100644
index 0000000..c1580de
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/money.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M54.122 127.892v-28.68H7.513V87.274h46.609v-12.4H7.513v-12.86h38.003L.099 0h22.6l32.556 45.07c3.617 5.144 6.44 9.611 8.487 13.385 1.788-3.05 4.89-7.779 9.301-14.186L103.93 0h24.01L82.385 62.013h38.34v12.862h-46.41v12.4h46.41v11.937h-46.41v28.68H54.123z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/monitor.svg b/ruoyi-ui/src/assets/icons/svg/monitor.svg
new file mode 100644
index 0000000..bc308cb
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/monitor.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827393750" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="4695" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M64 64V640H896V64H64zM0 0h960v704H0V0z" p-id="4696"></path><path d="M192 896H768v64H192zM448 640H512v256h-64z" p-id="4697"></path><path d="M479.232 561.604267l309.9904-348.330667-47.803733-42.5472-259.566934 291.669333L303.957333 240.008533 163.208533 438.6048l52.224 37.009067 91.6224-129.28z" p-id="4698"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/nested.svg b/ruoyi-ui/src/assets/icons/svg/nested.svg
new file mode 100644
index 0000000..06713a8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/nested.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.002 9.2c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-5.043-3.58-9.132-7.997-9.132S.002 4.157.002 9.2zM31.997.066h95.981V18.33H31.997V.066zm0 45.669c0 5.044 3.58 9.132 7.998 9.132 4.417 0 7.997-4.088 7.997-9.132 0-3.263-1.524-6.278-3.998-7.91-2.475-1.63-5.524-1.63-7.998 0-2.475 1.632-4 4.647-4 7.91zM63.992 36.6h63.986v18.265H63.992V36.6zm-31.995 82.2c0 5.043 3.58 9.132 7.998 9.132 4.417 0 7.997-4.089 7.997-9.132 0-5.044-3.58-9.133-7.997-9.133s-7.998 4.089-7.998 9.133zm31.995-9.131h63.986v18.265H63.992V109.67zm0-27.404c0 5.044 3.58 9.133 7.998 9.133 4.417 0 7.997-4.089 7.997-9.133 0-3.263-1.524-6.277-3.998-7.909-2.475-1.631-5.524-1.631-7.998 0-2.475 1.632-4 4.646-4 7.91zm31.995-9.13h31.991V91.4H95.987V73.135z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/number.svg b/ruoyi-ui/src/assets/icons/svg/number.svg
new file mode 100644
index 0000000..ad5ce9a
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/number.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802851180" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2867" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M279.272727 791.272727h512a46.545455 46.545455 0 0 1 0 93.090909H279.272727a46.545455 46.545455 0 0 1 0-93.090909z m33.838546-617.984V651.636364H193.722182V395.170909c0-37.003636-0.884364-59.298909-2.653091-66.746182a24.948364 24.948364 0 0 0-14.615273-16.989091c-8.005818-3.863273-25.786182-5.771636-53.341091-5.771636h-11.822545v-55.854545c57.716364-12.381091 101.562182-37.888 131.490909-76.520728h70.283636z m303.709091 396.8V651.636364H354.164364v-68.235637c77.777455-127.255273 124.043636-206.010182 138.705454-236.218182 14.661818-30.254545 22.016-53.853091 22.016-70.74909 0-13.032727-2.234182-22.714182-6.656-29.137455-4.421818-6.376727-11.170909-9.588364-20.247273-9.588364a22.248727 22.248727 0 0 0-20.200727 10.612364c-4.468364 7.121455-6.656 21.178182-6.656 42.263273v45.521454H354.164364v-17.454545c0-26.763636 1.396364-47.941818 4.142545-63.348364 2.746182-15.499636 9.541818-30.72 20.386909-45.661091 10.798545-14.987636 24.901818-26.298182 42.216727-33.978182 17.361455-7.68 38.167273-11.543273 62.37091-11.543272 47.476364 0 83.316364 11.776 107.706181 35.328 24.296727 23.552 36.445091 53.341091 36.445091 89.367272 0 27.368727-6.842182 56.32-20.48 86.853819-13.730909 30.533818-54.039273 95.325091-121.018182 194.420363h130.885819z m270.615272-189.393454c18.152727 6.097455 31.650909 16.104727 40.494546 29.975272 8.843636 13.917091 13.312 46.452364 13.312 97.652364 0 38.027636-4.328727 67.490909-13.032727 88.529455-8.657455 20.945455-23.598545 36.910545-44.869819 47.848727-21.271273 10.938182-48.593455 16.384-81.873454 16.384-37.794909 0-67.490909-6.330182-89.088-19.083636-21.550545-12.660364-35.746909-28.253091-42.542546-46.638546-6.795636-18.432-10.193455-50.362182-10.193454-95.883636v-37.841455h119.389091v77.730909c0 20.666182 1.210182 33.838545 3.723636 39.424 2.420364 5.585455 7.912727 8.424727 16.337455 8.424728 9.309091 0 15.36-3.537455 18.338909-10.612364 2.932364-7.121455 4.421818-25.6 4.421818-55.575273v-33.047273c0-18.338909-2.048-31.744-6.190546-40.215272a30.72 30.72 0 0 0-18.338909-16.709818c-8.052364-2.653091-23.738182-4.189091-46.964363-4.561455V357.050182c28.392727 0 45.893818-1.070545 52.596363-3.258182a22.946909 22.946909 0 0 0 14.475637-14.149818c2.932364-7.307636 4.421818-18.711273 4.421818-34.257455v-26.624c0-16.756364-1.722182-27.741091-5.12-33.047272-3.490909-5.352727-8.843636-8.005818-16.151273-8.005819-8.285091 0-13.963636 2.792727-16.989091 8.378182-3.025455 5.632-4.561455 17.640727-4.561454 35.933091v39.284364h-119.389091v-40.773818c0-45.661091 10.472727-76.567273 31.325091-92.625455 20.898909-16.058182 54.085818-24.064 99.607272-24.064 56.878545 0 95.511273 11.170909 115.805091 33.373091 20.293818 22.248727 30.394182 53.201455 30.394182 92.765091 0 26.810182-3.630545 46.173091-10.891636 58.088727-7.307636 11.915636-20.107636 22.807273-38.446546 32.628364z" p-id="2868"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/online.svg b/ruoyi-ui/src/assets/icons/svg/online.svg
new file mode 100644
index 0000000..330a202
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/online.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1568899557259" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="535" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M356.246145 681.56286c-68.156286-41.949414-107.246583-103.84102-107.246583-169.805384 0-65.966411 39.090297-127.860063 107.246583-169.809477 12.046361-7.414877 15.800871-23.190165 8.385994-35.236526-7.413853-12.046361-23.191188-15.801894-35.236526-8.387018-39.640836 24.399713-72.539106 56.044434-95.137801 91.515297-23.86657 37.461193-36.481889 79.620385-36.481889 121.917724 0 42.297338 12.615319 84.454484 36.481889 121.914654 22.598694 35.469839 55.496965 67.11456 95.137801 91.51325 4.185322 2.576685 8.821923 3.804652 13.400195 3.804652 8.598842 0 16.998139-4.329609 21.836331-12.190647C372.047016 704.752002 368.291482 688.976714 356.246145 681.56286zM263.943926 754.580874c-92.603071-61.111846-145.713686-149.623739-145.713686-242.840794 0-93.195565 53.094242-181.682899 145.667637-242.774279 11.805884-7.79043 15.061021-23.677259 7.269567-35.483142-7.79043-11.805884-23.677259-15.062044-35.483142-7.269567C128.487861 296.954249 67.006602 401.024489 67.006602 511.74008c0 110.73708 61.496609 214.830857 168.721703 285.593504 4.343935 2.867304 9.240455 4.238534 14.08274 4.238534 8.317433 0 16.476253-4.046153 21.400403-11.507078C279.003923 778.258133 275.748786 762.372328 263.943926 754.580874zM788.660552 226.213092c-11.80486-7.791453-27.692712-4.536316-35.483142 7.269567-7.79043 11.805884-4.536316 27.692712 7.269567 35.483142 92.575442 61.092403 145.670707 149.579737 145.670707 242.774279 0 93.216032-53.111638 181.727924-145.715733 242.840794-11.805884 7.79043-15.059997 23.678282-7.269567 35.484166 4.925173 7.461949 13.081946 11.507078 21.400403 11.507078 4.841262 0 9.739828-1.37123 14.083763-4.238534 107.22714-70.761624 168.724773-174.857447 168.724773-285.593504C957.341323 401.025513 895.860063 296.955272 788.660552 226.213092zM790.090111 633.67213c23.865547-37.459147 36.480866-79.617315 36.480866-121.914654 0-42.298362-12.615319-84.45653-36.480866-121.917724-22.598694-35.470863-55.496965-67.115584-95.139847-91.515297-12.047384-7.413853-27.821649-3.659343-35.236526 8.387018-7.414877 12.045337-3.659343 27.821649 8.385994 35.236526 68.156286 41.949414 107.247606 103.842043 107.247606 169.809477 0 65.964364-39.090297 127.85597-107.247606 169.804361-12.045337 7.414877-15.800871 23.190165-8.385994 35.237549 4.838192 7.861038 13.236466 12.190647 21.835308 12.190647 4.579295 0 9.215896-1.227967 13.400195-3.804652C734.591099 700.786691 767.490394 669.142993 790.090111 633.67213zM567.129086 518.274914c24.12342-17.150612 39.887452-45.305859 39.887452-77.07133 0-52.128241-42.452881-94.538143-94.634334-94.538143-52.18043 0-94.633311 42.408879-94.633311 94.538143 0 31.695886 15.696494 59.797921 39.730886 76.958766-49.875944 21.128203-84.917018 70.234621-84.917018 127.301338 0 2.366907 0.061398 4.762467 0.182149 7.119141l1.249457 24.296359 276.373515 0 1.238201-24.308639c0.119727-2.358721 0.181125-4.750187 0.181125-7.106862C651.786185 588.497255 616.865861 539.465538 567.129086 518.274914zM512.381182 397.889079c23.937179 0 43.411719 19.430538 43.411719 43.314505 0 23.882943-19.47454 43.313481-43.411719 43.313481-23.936155 0-43.409672-19.430538-43.409672-43.313481C468.971509 417.320641 488.445026 397.889079 512.381182 397.889079zM426.08884 625.656573c9.119705-38.542828 44.254923-67.337641 86.085634-67.337641s76.966952 28.794813 86.085634 67.337641L426.08884 625.656573z" p-id="536"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/password.svg b/ruoyi-ui/src/assets/icons/svg/password.svg
new file mode 100644
index 0000000..6c64def
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/password.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802846045" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2750" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M868.593046 403.832442c-30.081109-28.844955-70.037123-44.753273-112.624057-44.753273L265.949606 359.079168c-42.554188 0-82.510202 15.908318-112.469538 44.690852-30.236652 28.782533-46.857191 67.222007-46.857191 108.198258l0 294.079782c0 40.977273 16.619516 79.414701 46.702672 108.136859 29.959336 28.844955 70.069869 44.814672 112.624057 44.814672l490.019383 0c42.585911 0 82.696444-15.969717 112.624057-44.814672 30.082132-28.844955 46.579875-67.222007 46.579875-108.136859L915.172921 511.968278C915.171897 471.053426 898.675178 432.677397 868.593046 403.832442zM841.821309 806.049083c0 22.098297-8.882298 42.772152-25.099654 58.306964-16.154935 15.661701-37.81935 24.203238-60.752666 24.203238L265.949606 888.559285c-22.934339 0-44.567032-8.54256-60.877509-24.264637-16.186657-15.474436-25.067932-36.148291-25.067932-58.246589L180.004165 511.968278c0-22.035876 8.881274-42.772152 25.192775-58.307987 16.186657-15.536858 37.81935-24.139793 60.753689-24.139793l490.019383 0c22.933315 0 44.597731 8.602935 60.752666 24.139793 16.21838 15.535835 25.099654 36.272112 25.099654 58.307987L841.822332 806.049083zM510.974136 135.440715c114.914216 0 208.318536 89.75214 208.318536 200.055338l73.350588 0c0-149.113109-126.366036-270.496667-281.669124-270.496667-155.333788 0-281.699824 121.383558-281.699824 270.496667l73.350588 0C302.623877 225.193879 396.059919 135.440715 510.974136 135.440715zM474.299865 747.244792l73.350588 0L547.650453 629.576859l-73.350588 0L474.299865 747.244792z" p-id="2751"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/pdf.svg b/ruoyi-ui/src/assets/icons/svg/pdf.svg
new file mode 100644
index 0000000..957aa0c
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/pdf.svg
@@ -0,0 +1 @@
+<svg viewBox="0 0 1024 1024" xmlns="http://www.w3.org/2000/svg" width="128" height="128"><path d="M869.073 277.307H657.111V65.344l211.962 211.963zm-238.232 26.27V65.344l-476.498-.054v416.957h714.73v-178.67H630.841zm-335.836 360.57c-5.07-3.064-10.944-5.133-17.61-6.201-6.67-1.064-13.603-1.6-20.81-1.6h-48.821v85.641h48.822c7.206 0 14.14-.532 20.81-1.6 6.665-1.065 12.54-3.133 17.609-6.202 5.064-3.063 9.134-7.406 12.208-13.007 3.065-5.602 4.6-12.937 4.6-22.011 0-9.07-1.535-16.408-4.6-22.01-3.074-5.603-7.144-9.94-12.208-13.01zM35.82 541.805v416.904h952.358V541.805H35.821zm331.421 191.179c-3.6 11.071-9.343 20.879-17.209 29.413-7.874 8.542-18.078 15.408-30.617 20.61-12.544 5.206-27.747 7.807-45.621 7.807h-66.036v102.45h-62.831V607.517h128.867c17.874 0 33.077 2.6 45.62 7.802 12.541 5.207 22.745 12.076 30.618 20.615 7.866 8.538 13.604 18.277 17.21 29.212 3.6 10.943 5.401 22.278 5.401 34.018 0 11.477-1.8 22.752-5.402 33.819zM644.9 806.417c-5.343 17.61-13.408 32.818-24.212 45.627-10.807 12.803-24.283 22.879-40.423 30.213-16.146 7.343-35.155 11.007-57.03 11.007h-123.26V607.518h123.26c18.41 0 35.552 2.941 51.428 8.808 15.873 5.869 29.618 14.671 41.22 26.412 11.608 11.744 20.674 26.411 27.217 44.02 6.535 17.61 9.803 38.288 9.803 62.035 0 20.81-2.67 40.02-8.003 57.624zm245.362-146.07h-138.07v66.03h119.66v48.829h-119.66v118.058h-62.83V607.518h200.9v52.829h-.001zm-318.2 25.611c-6.402-8.266-14.877-14.604-25.412-19.01-10.544-4.402-23.551-6.602-39.019-6.602h-44.825v180.088h56.029c9.07 0 17.872-1.463 26.415-4.401 8.535-2.932 16.14-7.802 22.812-14.609 6.665-6.8 12.007-15.667 16.007-26.61 4.003-10.94 6.003-24.275 6.003-40.021 0-14.408-1.4-27.416-4.202-39.019-2.8-11.607-7.406-21.542-13.808-29.816zm0 0"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/people.svg b/ruoyi-ui/src/assets/icons/svg/people.svg
new file mode 100644
index 0000000..2bd54ae
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/people.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M104.185 95.254c8.161 7.574 13.145 17.441 13.145 28.28 0 1.508-.098 2.998-.285 4.466h-10.784c.238-1.465.403-2.948.403-4.465 0-8.983-4.36-17.115-11.419-23.216C86 104.66 75.355 107.162 64 107.162c-11.344 0-21.98-2.495-31.22-6.83-7.064 6.099-11.444 14.218-11.444 23.203 0 1.517.165 3 .403 4.465H10.955a35.444 35.444 0 0 1-.285-4.465c0-10.838 4.974-20.713 13.127-28.291C9.294 85.42.003 70.417.003 53.58.003 23.99 28.656.001 64 .001s63.997 23.988 63.997 53.58c0 16.842-9.299 31.85-23.812 41.673zM64 36.867c-29.454 0-53.33-10.077-53.33 15.342 0 25.418 23.876 46.023 53.33 46.023 29.454 0 53.33-20.605 53.33-46.023 0-25.419-23.876-15.342-53.33-15.342zm24.888 25.644c-3.927 0-7.111-2.665-7.111-5.953 0-3.288 3.184-5.954 7.11-5.954 3.928 0 7.111 2.666 7.111 5.954s-3.183 5.953-7.11 5.953zm-3.556 16.372c0 4.11-9.55 7.442-21.332 7.442-11.781 0-21.332-3.332-21.332-7.442 0-1.06.656-2.064 1.8-2.976 3.295 2.626 10.79 4.465 19.532 4.465 8.743 0 16.237-1.84 19.531-4.465 1.145.912 1.801 1.916 1.801 2.976zm-46.22-16.372c-3.927 0-7.11-2.665-7.11-5.953 0-3.288 3.183-5.954 7.11-5.954 3.927 0 7.111 2.666 7.111 5.954s-3.184 5.953-7.11 5.953z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/peoples.svg b/ruoyi-ui/src/assets/icons/svg/peoples.svg
new file mode 100644
index 0000000..aab852e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/peoples.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M95.648 118.762c0 5.035-3.563 9.121-7.979 9.121H7.98c-4.416 0-7.979-4.086-7.979-9.121C0 100.519 15.408 83.47 31.152 76.75c-9.099-6.43-15.216-17.863-15.216-30.987v-9.128c0-20.16 14.293-36.518 31.893-36.518s31.894 16.358 31.894 36.518v9.122c0 13.137-6.123 24.556-15.216 30.993 15.738 6.726 31.141 23.769 31.141 42.012z"/><path d="M106.032 118.252h15.867c3.376 0 6.101-3.125 6.101-6.972 0-13.957-11.787-26.984-23.819-32.123 6.955-4.919 11.638-13.66 11.638-23.704v-6.985c0-15.416-10.928-27.926-24.39-27.926-1.674 0-3.306.193-4.89.561 1.936 4.713 3.018 9.974 3.018 15.526v9.121c0 13.137-3.056 23.111-11.066 30.993 14.842 4.41 27.312 23.42 27.541 41.509z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/phone.svg b/ruoyi-ui/src/assets/icons/svg/phone.svg
new file mode 100644
index 0000000..ab8e8c4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/phone.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1567417214476" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2266" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M761.503029 2.90619 242.121921 2.90619c-32.405037 0-58.932204 26.060539-58.932204 58.527998l0 902.302287c0 32.156374 26.217105 58.216913 58.932204 58.216913l519.381108 0c32.344662 0 58.591443-26.060539 58.591443-58.216913L820.094472 61.123103C820.094472 28.966729 793.847691 2.90619 761.503029 2.90619M452.878996 61.123103l98.147344 0c6.780427 0 12.31549 5.536087 12.31549 12.253068 0 6.748704-5.535063 12.253068-12.31549 12.253068l-98.147344 0c-6.779404 0-12.345166-5.504364-12.345166-12.253068C440.532807 66.659189 446.099592 61.123103 452.878996 61.123103M501.641583 980.593398c-29.636994 0-53.987588-23.946388-53.987588-53.677527 0-29.356608 24.039509-53.614082 53.987588-53.614082 29.91738 0 53.987588 23.883967 53.987588 53.614082C555.629171 956.647009 531.559986 980.593398 501.641583 980.593398M766.35657 803.142893c0 16.23373-13.186324 29.107945-29.233811 29.107945l-470.618521 0c-16.35755 0-29.325909-13.186324-29.325909-29.107945L237.178329 163.500794c0-16.232706 13.279445-29.138644 29.325909-29.138644l470.246037 0c16.420995 0 29.357632 13.1853 29.357632 29.138644l0 639.642099L766.35657 803.142893zM766.35657 803.142893" p-id="2267"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/post.svg b/ruoyi-ui/src/assets/icons/svg/post.svg
new file mode 100644
index 0000000..2922c61
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/post.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566035724641" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3998" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M136.4 434.3h77.7c21.5 0 38.9-17.4 38.9-38.9s-17.4-38.9-38.9-38.9h-77.7c-21.5 0-38.9 17.4-38.9 38.9s17.4 38.9 38.9 38.9zM252.9 628.6c0-21.5-17.4-38.9-38.9-38.9h-77.7c-21.5 0-38.9 17.4-38.9 38.9s17.4 38.9 38.9 38.9H214c21.5-0.1 38.9-17.5 38.9-38.9z" p-id="3999"></path><path d="M874.7 97.5H227c-28.6 0-51.8 23.2-51.8 51.8v194.3h38.9c28.6 0 51.8 23.2 51.8 51.8 0 28.6-23.2 51.8-51.8 51.8h-38.9v129.5h38.9c28.6 0 51.8 23.2 51.8 51.8 0 28.6-23.2 51.8-51.8 51.8h-38.9v194.3c0 28.6 23.2 51.8 51.8 51.8h647.7c28.6 0 51.8-23.2 51.8-51.8V149.3c0-28.6-23.2-51.8-51.8-51.8z m-311.3 723c-15.6 0-146.7-71.6-146.7-91 0-19.4 102-368.6 102-368.6l-83.6-104s-12.3-23.1 24.6-23.1h208.9c36.9 0 18.4 23.1 18.4 23.1l-79 104s102 351.3 102 368.6c0.1 17.3-131 91-146.6 91z m169.2-253.6l-27.9 40.2-74.5-240 103.4 171.7c4.6 7.9 4.2 20.6-1 28.1z" p-id="4000"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/qq.svg b/ruoyi-ui/src/assets/icons/svg/qq.svg
new file mode 100644
index 0000000..ee13d4e
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/qq.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M18.448 57.545l-.244-.744-.198-.968-.132-.53v-2.181l.236-.859.24-.908.317-.953.428-1.06.561-1.103.794-1.104v-.773l.077-.724.123-.984.34-1.106.313-1.194.25-.548.289-.511.371-.569.405-.423v-2.73l.234-1.407.236-1.633.42-1.955.577-2.035.43-1.118.426-1.217.468-1.135.559-1.216.57-1.332.655-1.247.737-1.331.929-1.33.43-.762.457-.624.995-1.406 1.025-1.403 1.163-1.444 1.246-1.405 1.352-1.384 1.41-1.423 1.708-1.536 1.083-.934 1.322-1.008 1.34-.89 1.448-.855 1.392-.76 1.57-.63 1.667-.775 1.657-.532 1.653-.552 1.787-.548 1.785-.417 1.876-.347L59.128.68l1.879-.245 1.876-.252 2.002-.106h5.912l1.97.243 1.981.231 2.019.207 1.874.441 1.979.413 1.857.475 2.035.53 1.862.646 1.782.738 1.904.78 1.736.853 1.689.95 1.655 1.044 1.425.971.662.548.693.401 1.323 1.1 1.115 1.064 1.112 1.1 1.083 1.214.894 1.178 1.064 1.217.74 1.306.752 1.162.798 1.352.661 1.175 1.113 2.489.546 1.286.428 1.192.428 1.294.384 1.217.267 1.047.347 1.231.607 2.198.388 1.924.253 1.861.217 1.497.342 2.28.077.362.274.41.737 1.18.473.8.42.832.534.892.472 1.07.307 1.093.334 1.2.252 1.232.115.605.106.746v.648l-.106.643v.8l-.192.774-.35 1.5-.403.76-.299.852v.213l.142.264.4.623 1.746 2.53 1.377 1.9.66 1.267.889 1.389.774 1.52.893 1.627.894 1.828 1.006 2.069.567 1.268.518 1.239.447 1.307.44 1.175.336 1.235.342 1.16.432 2.261.343 2.31.235 2.05v2.891l-.158 1.025-.226 1.768-.308 1.59-.48 1.44-.18.588-.336.707-.28.493-.375.607-.33.383-.42.494-.375.4-.401.34-.48.207-.432.207-.355.114h-.543l-.346-.114-.66-.32-.302-.212-.317-.223-.347-.304-.35-.342-.579-.63-.684-.89-.539-.917-.538-.734-.526-.855-.741-1.517-.833-1.579-.098-.055h-.138l-.338.247-.196.415-.326.516-.567 1.533-.856 2.182-1.096 2.626-.824 1.308-.864 1.366-1.027 1.536-1.09 1.503-.557.68-.676.743-1.555 1.497.136.135.21.214.777.446 3.235 1.524 1.41.779 1.347.756 1.332.953 1.187.982.574.443.432.511.445.593.367.643.198.533.242.64.105.554.115.647-.115.433v.44l-.105.454-.242.415-.092.325-.22.394-.587.784-.543.627-.42.47-.35.348-.893.638-1.01.556-1.077.532-1.155.511-1.287.495-.693.207-.608.167-1.496.342-1.545.325-1.552.323-1.689.27-1.74.072-1.785.21h-5.539l-1.998-.114-1.86-.168-2.005-.27-1.99-.209-2.095-.286-2.03-.495-1.981-.374-1.968-.552-2.019-.707-1.98-.585-1.044-.342-.927-.323-.586-.223-.582-.12h-1.647l-1.904-.131-.962-.096-1.24-.135-.795.705-1.085.665-1.471.701-1.628.875-.99.475-1.033.376-2.281.914-1.24.305-1.3.343-1.803.344-1.13.086-1.193.1-1.246.135-1.45.053h-5.926l-3.346-.053-3.25-.321-1.644-.23-1.589-.23-1.546-.227-1.547-.305-1.442-.456-1.434-.325-1.294-.51-1.223-.474-1.142-.533-.99-.583-.984-.71-.336-.343-.44-.415-.334-.362-.3-.417-.278-.415-.215-.42-.311-.89-.109-.46-.138-.51v-.473l.138-.533v-.53l.109-.53v-1.069l.052-.564.259-.647.215-.646.39-.779.286-.3.236-.348.615-.738.49-.38.464-.266.428-.338.676-.21.543-.324.676-.341.77-.227.775-.231.897-.192.85-.11 1.008-.13 1.093-.081.284-.092h.063l.137-.115v-.13l-.2-.266-.58-.27-1.45-1.231-.975-.761-1.127-.967-1.136-1.082-1.181-1.382-1.36-1.558-.508-.843-.672-.87-.58-1.007-.522-1.1-.704-1.047-.459-1.194-.547-1.192-.546-1.33-.397-1.273-.378-1.575-.112-.057h-.115l-.059-.113h-.14l-.23.113-.114.057-.158.264-.057.321-.119.286-.206.477-.664 1.157-.345.701-.546.612-.58.736-.641.816-.677.724-.795.701-.734.658-.814.524-.89.546-.855.325-1.008.247-.99.095h-.233l-.228-.095-.18-.384-.29-.188-.38-.912-.237-.493-.255-.707-.21-.734-.113-.724-.313-1.648-.12-.972v-3.185l.12-2.379.196-1.214.23-1.252.21-1.347.374-1.254.42-1.443.431-1.407.578-1.448.545-1.38.754-1.4.699-1.52.855-1.425 1.006-1.538 1.023-1.382 1.069-1.538.891-1.071 1.142-1.227 1.202-1.237.56-.59.678-.662.985-.836 1.012-.853 1.647-1.446 1.242-.889z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/question.svg b/ruoyi-ui/src/assets/icons/svg/question.svg
new file mode 100644
index 0000000..cf75bd4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/question.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1581238842264" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1409" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M512 0C229.233778 0 0 229.233778 0 512s229.233778 512 512 512 512-229.233778 512-512A512 512 0 0 0 512 0z m0 938.666667C276.366222 938.666667 85.333333 747.633778 85.333333 512 85.333333 276.366222 276.366222 85.333333 512 85.333333c235.633778 0 426.666667 191.032889 426.666667 426.666667a426.666667 426.666667 0 0 1-426.666667 426.666667z m0-717.653334a170.666667 170.666667 0 0 0-170.666667 170.666667 42.666667 42.666667 0 0 0 85.333334 0 85.333333 85.333333 0 1 1 85.333333 85.333333 42.666667 42.666667 0 0 0-42.666667 42.666667v111.36a42.666667 42.666667 0 0 0 85.333334 0v-74.24A170.666667 170.666667 0 0 0 512 221.013333z m-42.666667 542.293334a42.666667 42.666667 0 1 0 85.333334 0 42.666667 42.666667 0 0 0-85.333334 0z" p-id="1410"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/radio.svg b/ruoyi-ui/src/assets/icons/svg/radio.svg
new file mode 100644
index 0000000..0cde345
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/radio.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575966775973" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="879" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M507.39346659 71.84873358c241.53533667 0 437.39770766 195.85422109 437.39770767 437.37442191 0 241.53766571-195.86237099 437.38955776-437.39770767 437.38955776-241.50040803 0-437.34997219-195.85189205-437.34997219-437.38955776C70.0434944 267.70295467 265.89189347 71.84873358 507.39346659 71.84873358L507.39346659 71.84873358zM507.39346659 282.81899805c-125.00686734 0-226.37039389 101.38914133-226.37039388 226.41813048 0 125.01268821 101.36352768 226.39717262 226.37039388 226.39717262 125.04295993 0 226.42395136-101.38448441 226.42395136-226.39717262C733.81625401 384.20813938 632.43642653 282.81899805 507.39346659 282.81899805L507.39346659 282.81899805zM507.39346659 120.78172615c-214.46664192 0-388.42047261 173.95150279-388.4204726 388.44026539 0 214.51204949 173.95499463 388.46122325 388.4204726 388.46122325 214.52369237 0 388.46005817-173.94800981 388.46005818-388.46122325C895.85236082 294.73322894 721.91715897 120.78172615 507.39346659 120.78172615z" p-id="880"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/rate.svg b/ruoyi-ui/src/assets/icons/svg/rate.svg
new file mode 100644
index 0000000..aa3b14d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/rate.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577246781606" class="icon" viewBox="0 0 1069 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1098" xmlns:xlink="http://www.w3.org/1999/xlink" width="84.5595703125" height="81"><defs><style type="text/css"></style></defs><path d="M633.72929961 378.02038203l9.49872568 18.68789795 20.78025469 2.79745225 206.61592412 27.33248408a11.46496817 11.46496817 0 0 1 6.6095543 19.47324902l-147.2675168 147.35350284-14.89299345 14.89299345 3.8006376 20.68280244 37.84585956 204.89044571a11.46496817 11.46496817 0 0 1-16.4808914 12.2961788L554.68980898 751.84713388l-18.68789794-9.49299345-18.48726123 9.99171915-183.23885392 99.34968163a11.46496817 11.46496817 0 0 1-16.78471347-11.8662416l32.5433127-205.79617881 3.29617793-20.78598692-15.19108243-14.49172002-151.03375839-143.48407587a11.46496817 11.46496817 0 0 1 6.09936328-19.63949062l205.79617881-32.63503185 20.78598691-3.2961788L428.87898125 380.72038203 518.59235674 192.64331182a11.46496817 11.46496817 0 0 1 20.56815264-0.26369385l94.56879023 185.63503183zM496.64840732 85.52038203l-121.75796162 254.98089229L95.76433145 384.76178369A34.3949045 34.3949045 0 0 0 77.46050938 443.66879023l204.87324901 194.66369385-44.16879023 279.1146498a34.3949045 34.3949045 0 0 0 50.36560489 35.61592325l248.4-134.67898038 251.84522285 128.27579591a34.3949045 34.3949045 0 0 0 49.43694287-36.89426777l-51.30573223-277.85350284 199.73120977-199.90891758a34.3949045 34.3949045 0 0 0-19.82866201-58.40827998l-280.11783428-37.03184736L558.32993633 84.71210205a34.3949045 34.3949045 0 0 0-61.68152901 0.80254775z" p-id="1099"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/redis-list.svg b/ruoyi-ui/src/assets/icons/svg/redis-list.svg
new file mode 100644
index 0000000..98a15b2
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/redis-list.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1656035183065" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="3395" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css">@font-face { font-family: feedback-iconfont; src: url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff2?t=1630033759944") format("woff2"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.woff?t=1630033759944") format("woff"), url("//at.alicdn.com/t/font_1031158_u69w8yhxdu.ttf?t=1630033759944") format("truetype"); }
+</style></defs><path d="M958.88 730.06H65.12c-18.28 0-33.12-14.82-33.12-33.12V68.91c0-18.29 14.83-33.12 33.12-33.12h893.77c18.28 0 33.12 14.82 33.12 33.12v628.03c-0.01 18.3-14.84 33.12-33.13 33.12zM98.23 663.83h827.53v-561.8H98.23v561.8z" p-id="3396"></path><path d="M512 954.55c-18.28 0-33.12-14.82-33.12-33.12V733.92c0-18.29 14.83-33.12 33.12-33.12s33.12 14.82 33.12 33.12v187.51c0 18.3-14.84 33.12-33.12 33.12z" p-id="3397"></path><path d="M762.01 988.21H261.99c-18.28 0-33.12-14.82-33.12-33.12 0-18.29 14.83-33.12 33.12-33.12h500.03c18.28 0 33.12 14.82 33.12 33.12-0.01 18.29-14.84 33.12-33.13 33.12zM514.74 578.55c-21.63 0-43.31-3.87-64.21-11.65-45.95-17.13-82.49-51.13-102.86-95.74-5.07-11.08-0.19-24.19 10.89-29.26 11.08-5.09 24.19-0.18 29.26 10.91 15.5 33.88 43.25 59.7 78.14 72.71 34.93 12.99 72.79 11.64 106.66-3.85 33.22-15.17 58.8-42.26 72.03-76.3 4.42-11.37 17.21-17.01 28.57-12.58 11.36 4.42 16.99 17.22 12.57 28.58-17.42 44.82-51.1 80.5-94.82 100.47-24.34 11.12-50.25 16.71-76.23 16.71z" p-id="3398"></path><path d="M325.27 528.78c-1.66 0-3.34-0.18-5.02-0.57-11.88-2.77-19.28-14.63-16.49-26.51l18.84-81c1.34-5.82 5-10.84 10.13-13.92 5.09-3.09 11.3-3.96 17.03-2.41l80.51 21.43c11.79 3.14 18.8 15.23 15.67 27.02-3.15 11.79-15.42 18.75-27.02 15.65l-58.49-15.57-13.69 58.81c-2.37 10.2-11.45 17.07-21.47 17.07zM360.8 351.01c-2.65 0-5.37-0.49-8-1.51-11.36-4.41-16.99-17.21-12.59-28.57 17.4-44.79 51.06-80.47 94.8-100.48 92.15-42.06 201.25-1.39 243.31 90.68 5.07 11.08 0.19 24.19-10.89 29.26-11.13 5.07-24.19 0.17-29.26-10.91-31.97-69.91-114.9-100.82-184.79-68.86-33.22 15.19-58.8 42.28-71.99 76.29-3.41 8.74-11.75 14.1-20.59 14.1z" p-id="3399"></path><path d="M684.68 376.74c-1.47 0-2.95-0.15-4.42-0.44l-81.61-16.68c-11.94-2.45-19.64-14.11-17.21-26.06 2.44-11.96 14.1-19.64 26.04-17.22l59.29 12.12 10.23-59.5c2.05-12 13.52-20.19 25.48-18.01 12.03 2.06 20.09 13.48 18.02 25.5l-14.08 81.96a22.089 22.089 0 0 1-9.29 14.49c-3.7 2.51-8.03 3.84-12.45 3.84z" p-id="3400"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/redis.svg b/ruoyi-ui/src/assets/icons/svg/redis.svg
new file mode 100644
index 0000000..2f1d62d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/redis.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1605865043777" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="856" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M1023.786667 611.84c-0.426667 9.770667-13.354667 20.693333-39.893334 34.56-54.613333 28.458667-337.749333 144.896-397.994666 176.298667-60.288 31.402667-93.738667 31.104-141.354667 8.32-47.616-22.741333-348.842667-144.469333-403.114667-170.368-27.093333-12.970667-40.917333-23.893333-41.386666-34.218667v103.509333c0 10.325333 14.250667 21.290667 41.386666 34.261334 54.272 25.941333 355.541333 147.626667 403.114667 170.368 47.616 22.784 81.066667 23.082667 141.354667-8.362667 60.245333-31.402667 343.338667-147.797333 397.994666-176.298667 27.776-14.464 40.106667-25.728 40.106667-35.925333v-102.058667l-0.213333-0.085333z m0-168.746667c-0.512 9.770667-13.397333 20.650667-39.893334 34.517334-54.613333 28.458667-337.749333 144.896-397.994666 176.298666-60.288 31.402667-93.738667 31.104-141.354667 8.362667-47.616-22.741333-348.842667-144.469333-403.114667-170.410667-27.093333-12.928-40.917333-23.893333-41.386666-34.176v103.509334c0 10.325333 14.250667 21.248 41.386666 34.218666 54.272 25.941333 355.498667 147.626667 403.114667 170.368 47.616 22.784 81.066667 23.082667 141.354667-8.32 60.245333-31.402667 343.338667-147.84 397.994666-176.298666 27.776-14.506667 40.106667-25.770667 40.106667-35.968v-102.058667l-0.256-0.042667z m0-175.018666c0.469333-10.410667-13.141333-19.541333-40.533334-29.610667-53.248-19.498667-334.634667-131.498667-388.522666-151.253333-53.888-19.712-75.818667-18.901333-139.093334 3.84C392.234667 113.706667 92.629333 231.253333 39.338667 252.074667c-26.666667 10.496-39.68 20.181333-39.253334 30.506666V386.133333c0 10.325333 14.250667 21.248 41.386667 34.218667 54.272 25.941333 355.498667 147.669333 403.114667 170.410667 47.616 22.741333 81.066667 23.04 141.354666-8.362667 60.245333-31.402667 343.338667-147.84 397.994667-176.298667 27.776-14.506667 40.106667-25.770667 40.106667-35.968V268.074667h-0.341334zM366.677333 366.08l237.269334-36.437333-71.68 105.088-165.546667-68.650667z m524.8-94.634667l-140.330666 55.466667-15.232 5.973333-140.245334-55.466666 155.392-61.44 140.373334 55.466666z m-411.989333-101.674666l-22.954667-42.325334 71.594667 27.989334 67.498667-22.101334-18.261334 43.733334 68.778667 25.770666-88.704 9.216-19.882667 47.786667-32.085333-53.290667-102.4-9.216 76.416-27.562666z m-176.768 59.733333c70.058667 0 126.805333 21.973333 126.805333 49.109333s-56.746667 49.152-126.805333 49.152-126.848-22.058667-126.848-49.152c0-27.136 56.789333-49.152 126.848-49.152z" p-id="857"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/row.svg b/ruoyi-ui/src/assets/icons/svg/row.svg
new file mode 100644
index 0000000..0780992
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/row.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579339929870" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1182" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M152 854.856875h325.7146875V237.715625H134.856875v600q0 6.99375 5.0746875 12.0684375T152 854.856875z m737.143125-17.1421875v-600H546.284375v617.1421875H872q6.99375 0 12.0684375-5.07375t5.0746875-12.0684375z m68.5715625-651.429375V837.715625q0 35.3821875-25.16625 60.5484375T872 923.4284375H152q-35.383125 0-60.5484375-25.1653125T66.284375 837.7146875V186.284375q0-35.3821875 25.16625-60.5484375T152 100.5715625h720q35.383125 0 60.5484375 25.1653125t25.16625 60.5484375z" p-id="1183"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/search.svg b/ruoyi-ui/src/assets/icons/svg/search.svg
new file mode 100644
index 0000000..84233dd
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/search.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M124.884 109.812L94.256 79.166c-.357-.357-.757-.629-1.129-.914a50.366 50.366 0 0 0 8.186-27.59C101.327 22.689 78.656 0 50.67 0 22.685 0 0 22.688 0 50.663c0 27.989 22.685 50.663 50.656 50.663 10.186 0 19.643-3.03 27.6-8.201.286.385.557.771.9 1.114l30.628 30.632a10.633 10.633 0 0 0 7.543 3.129c2.728 0 5.457-1.043 7.543-3.115 4.171-4.157 4.171-10.915.014-15.073M50.671 85.338C31.557 85.338 16 69.78 16 50.663c0-19.102 15.557-34.661 34.67-34.661 19.115 0 34.657 15.559 34.657 34.675 0 19.102-15.557 34.661-34.656 34.661"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/select.svg b/ruoyi-ui/src/assets/icons/svg/select.svg
new file mode 100644
index 0000000..d628382
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/select.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575803481213" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="804" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M62 511.97954521C62 263.86590869 263.90681826 62 511.97954521 62s449.97954521 201.825 449.97954521 449.97954521c0 248.19545479-201.90681826 449.97954521-449.97954521 449.97954521C263.90681826 962 62 760.175 62 511.97954521M901.98636348 511.97954521c0-215.24318174-175.00909131-390.41590869-390.00681827-390.41590869-215.03863652 0-389.96590869 175.17272695-389.96590868 390.41590869 0 215.28409131 175.00909131 390.45681826 389.96590868 390.45681826C727.01818174 902.47727305 901.98636348 727.30454521 901.98636348 511.97954521M264.17272695 430.28409131c0-5.76818174 2.12727305-11.51590869 6.64772696-15.87272696 8.71363652-8.75454521 22.88863652-8.75454521 31.725 0l209.4340913 208.22727305L721.45454521 414.53409131c8.75454521-8.71363652 22.97045479-8.71363652 31.90909132 0 8.71363652 8.75454521 8.71363652 22.88863652 0 31.60227304L511.97954521 685.74090869 270.71818174 446.01363653C266.27954521 441.77954521 264.17272695 436.05227305 264.17272695 430.28409131" p-id="805"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/server.svg b/ruoyi-ui/src/assets/icons/svg/server.svg
new file mode 100644
index 0000000..eb287e3
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/server.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1547360688278" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6717" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M890 120H134a70 70 0 0 0-70 70v500a70 70 0 0 0 70 70h756a70 70 0 0 0 70-70V190a70 70 0 0 0-70-70z m-10 520a40 40 0 0 1-40 40H712V448a40 40 0 0 0-80 0v232h-80V368a40 40 0 0 0-80 0v312h-80V512a40 40 0 0 0-80 0v168H184a40 40 0 0 1-40-40V240a40 40 0 0 1 40-40h656a40 40 0 0 1 40 40zM696 824H328a40 40 0 0 0 0 80h368a40 40 0 0 0 0-80z" p-id="6718"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/shopping.svg b/ruoyi-ui/src/assets/icons/svg/shopping.svg
new file mode 100644
index 0000000..87513e7
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/shopping.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M42.913 101.36c1.642 0 3.198.332 4.667.996a12.28 12.28 0 0 1 3.89 2.772c1.123 1.184 1.987 2.582 2.592 4.193.605 1.612.908 3.318.908 5.118 0 1.8-.303 3.507-.908 5.118-.605 1.611-1.469 3.01-2.593 4.194a13.3 13.3 0 0 1-3.889 2.843 10.582 10.582 0 0 1-4.667 1.066c-1.729 0-3.306-.355-4.732-1.066a13.604 13.604 0 0 1-3.825-2.843c-1.123-1.185-1.988-2.583-2.593-4.194a14.437 14.437 0 0 1-.907-5.118c0-1.8.302-3.506.907-5.118.605-1.61 1.47-3.009 2.593-4.193a12.515 12.515 0 0 1 3.825-2.772c1.426-.664 3.003-.996 4.732-.996zm53.932.285c1.643 0 3.22.331 4.733.995a11.386 11.386 0 0 1 3.889 2.772c1.08 1.185 1.945 2.583 2.593 4.194.648 1.61.972 3.317.972 5.118 0 1.8-.324 3.506-.972 5.117-.648 1.611-1.513 3.01-2.593 4.194a12.253 12.253 0 0 1-3.89 2.843 11 11 0 0 1-4.732 1.066 10.58 10.58 0 0 1-4.667-1.066 12.478 12.478 0 0 1-3.824-2.843c-1.08-1.185-1.945-2.583-2.593-4.194a13.581 13.581 0 0 1-.973-5.117c0-1.801.325-3.507.973-5.118.648-1.611 1.512-3.01 2.593-4.194a11.559 11.559 0 0 1 3.824-2.772 11.212 11.212 0 0 1 4.667-.995zm21.781-80.747c2.42 0 4.3.355 5.64 1.066 1.34.71 2.29 1.587 2.852 2.63a6.427 6.427 0 0 1 .778 3.34c-.044 1.185-.195 2.204-.454 3.057-.26.853-.8 2.606-1.62 5.26a589.268 589.268 0 0 1-2.788 8.743 1236.373 1236.373 0 0 0-3.047 9.453c-.994 3.128-1.75 5.592-2.269 7.393-1.123 3.79-2.55 6.42-4.278 7.89-1.728 1.469-3.846 2.203-6.352 2.203H39.023l1.945 12.795h65.342c4.148 0 6.223 1.943 6.223 5.828 0 1.896-.41 3.53-1.232 4.905-.821 1.374-2.442 2.061-4.862 2.061H38.505c-1.729 0-3.176-.426-4.343-1.28-1.167-.852-2.14-1.966-2.917-3.34a21.277 21.277 0 0 1-1.88-4.478 44.128 44.128 0 0 1-1.102-4.55c-.087-.568-.324-1.942-.713-4.122-.39-2.18-.865-4.904-1.426-8.174l-1.88-10.947c-.692-4.027-1.383-8.079-2.075-12.154-1.642-9.572-3.5-20.234-5.574-31.986H6.87c-1.296 0-2.377-.356-3.24-1.067a9.024 9.024 0 0 1-2.14-2.558 10.416 10.416 0 0 1-1.167-3.2C.108 8.53 0 7.488 0 6.54c0-1.896.583-3.46 1.75-4.69C2.917.615 4.494 0 6.482 0h13.095c1.728 0 3.111.284 4.148.853 1.037.569 1.858 1.28 2.463 2.132a8.548 8.548 0 0 1 1.297 2.701c.26.948.475 1.754.648 2.417.173.758.346 1.825.519 3.199.173 1.374.345 2.772.518 4.193.26 1.706.519 3.507.778 5.403h88.678z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/size.svg b/ruoyi-ui/src/assets/icons/svg/size.svg
new file mode 100644
index 0000000..ddb25b8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/size.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M0 54.857h54.796v18.286H36.531V128H18.265V73.143H0V54.857zm127.857-36.571H91.935V128H72.456V18.286H36.534V0h91.326l-.003 18.286z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/skill.svg b/ruoyi-ui/src/assets/icons/svg/skill.svg
new file mode 100644
index 0000000..a3b7312
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/skill.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M31.652 93.206h33.401c1.44 2.418 3.077 4.663 4.93 6.692h-38.33v-6.692zm0-10.586h28.914a44.8 44.8 0 0 1-1.264-6.688h-27.65v6.688zm0-17.27H59.39c.288-2.286.714-4.532 1.34-6.687H31.65v6.687h.003zm53.913 44.84v5.85c0 2.798-2.095 5.075-4.667 5.075h-70.07c-2.576 0-4.663-2.277-4.663-5.075V31.26l23.22-20.96v22.25H17.16v6.688h18.39V6.688h45.348c2.576 0 4.667 2.277 4.667 5.066v20.009c1.987-.675 4.053-1.128 6.17-1.445v-18.56C91.738 5.28 86.874 0 80.902 0H31.15L0 28.118v87.917c0 6.48 4.859 11.759 10.832 11.759h70.07c5.974 0 10.837-5.27 10.837-11.759v-4.41c-2.117-.312-4.183-.765-6.17-1.435h-.004zM23.279 58.667h-7.96v6.688h7.96v-6.688zm-7.956 41.23h7.96v-6.691h-7.96v6.692zm7.956-23.96h-7.96v6.687h7.96v-6.688zm89.718-15.042l-4.896-4.07-12.447 17.613-11.19-9.305-3.762 5.311 16.091 13.38 16.204-22.929zM128 70.978c0-18.632-13.97-33.782-31.147-33.782-17.168 0-31.135 15.155-31.135 33.782 0 18.628 13.97 33.783 31.135 33.783 17.172 0 31.143-15.15 31.143-33.783H128zm-6.17 0c0 14.933-11.203 27.1-24.981 27.1-13.77 0-24.987-12.158-24.987-27.1 0-14.941 11.195-27.099 24.987-27.099 13.778 0 24.982 12.158 24.982 27.1z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/slider.svg b/ruoyi-ui/src/assets/icons/svg/slider.svg
new file mode 100644
index 0000000..fbe4f39
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/slider.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577185310368" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1238" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M951.453125 476.84375H523.671875a131.8359375 131.8359375 0 0 0-254.1796875 0H72.546875v70.3125h196.9453125a131.8359375 131.8359375 0 0 0 254.1796875 0H951.453125z" p-id="1239"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/star.svg b/ruoyi-ui/src/assets/icons/svg/star.svg
new file mode 100644
index 0000000..6cf86e6
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/star.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M70.66 4.328l14.01 29.693c1.088 2.29 3.177 3.882 5.603 4.25l31.347 4.76c6.087.926 8.528 8.756 4.117 13.247L103.05 79.395c-1.75 1.78-2.544 4.352-2.132 6.867l5.352 32.641c1.043 6.337-5.33 11.182-10.778 8.19l-28.039-15.409a7.13 7.13 0 0 0-6.91 0l-28.039 15.41c-5.448 2.99-11.821-1.854-10.777-8.19l5.352-32.642c.415-2.515-.387-5.088-2.136-6.867L2.264 56.278C-2.146 51.787.286 43.957 6.38 43.031l31.343-4.76c2.419-.368 4.51-1.96 5.595-4.25L57.334 4.328c2.728-5.77 10.605-5.77 13.325 0z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/swagger.svg b/ruoyi-ui/src/assets/icons/svg/swagger.svg
new file mode 100644
index 0000000..05d4e7b
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/swagger.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1566036776944" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="6463" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M64 223.995345h168.001164v47.997673c0 26.428509 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.569164 41.984-47.997673v-47.997673h504.003491a32.004655 32.004655 0 0 0 0-64.009309H455.996509V111.988364c0-26.428509-18.878836-47.997673-41.984-47.997673H273.985164c-23.095855 0-41.984 21.569164-41.984 47.997673v47.997672H64a32.004655 32.004655 0 0 0 0 64.009309zM288.004655 128h111.997672V256H288.004655V128zM960 479.995345H791.998836v-47.997672c0-26.372655-18.878836-47.997673-41.984-47.997673H609.978182c-23.095855 0-41.984 21.634327-41.984 47.997673v47.997672H64a32.004655 32.004655 0 0 0 0 64.00931h504.003491v47.997672c0 26.363345 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.634327 41.984-47.997673v-47.997672h168.001164a32.004655 32.004655 0 1 0-0.009309-64.00931zM735.995345 576H623.997673v-128h111.997672v128zM960 800.293236v-0.288581H455.996509v-47.997673c0-26.363345-18.878836-47.997673-41.984-47.997673H274.050327c-23.105164 0-41.984 21.634327-41.984 47.997673v47.997673H64v0.288581a32.004655 32.004655 0 0 0 0 64.009309c0.986764 0 1.917673-0.195491 2.885818-0.288581h165.115346v47.997672c0 26.363345 18.878836 47.997673 41.984 47.997673h140.036654c23.095855 0 41.984-21.634327 41.984-47.997673v-47.997672h501.108364c0.968145 0.093091 1.899055 0.288582 2.895127 0.288581a32.004655 32.004655 0 1 0-0.009309-64.009309zM400.002327 896H288.004655V768h111.997672v128z" fill="" p-id="6464"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/switch.svg b/ruoyi-ui/src/assets/icons/svg/switch.svg
new file mode 100644
index 0000000..0ba61e3
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/switch.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1576042673958" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1110" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M692 792H332c-150 0-270-120-270-270s120-270 270-270h360c150 0 270 120 270 270 0 147-120 270-270 270zM332 312c-117 0-210 93-210 210s93 210 210 210h360c117 0 210-93 210-210s-93-210-210-210H332z" p-id="1111"></path><path d="M341 522m-150 0a150 150 0 1 0 300 0 150 150 0 1 0-300 0Z" p-id="1112"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/system.svg b/ruoyi-ui/src/assets/icons/svg/system.svg
new file mode 100644
index 0000000..5992593
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/system.svg
@@ -0,0 +1,2 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1543827724451" class="icon" style="" viewBox="0 0 1084 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="10233" xmlns:xlink="http://www.w3.org/1999/xlink" width="211.71875" height="200"><defs><style type="text/css">@font-face { font-family: rbicon; src: url("chrome-extension://dipiagiiohfljcicegpgffpbnjmgjcnf/fonts/rbicon.woff2") format("woff2"); font-weight: normal; font-style: normal; }
+</style></defs><path d="M1080.09609 434.500756c-4.216302-23.731757-26.9241-47.945376-50.595623-53.185637l-17.648235-4.095836a175.940257 175.940257 0 0 1-101.612877-80.832531 177.807476 177.807476 0 0 1-18.732427-129.801867l5.541425-16.684509c7.10748-23.129428-2.108151-54.992624-20.599646-70.833873 0 0-16.624276-14.094495-63.244529-41.199293-46.800951-26.984332-66.858502-34.513443-66.858502-34.513443-22.76803-8.372371-54.631227-0.361397-71.255503 17.407304l-12.287509 13.251234a173.470708 173.470708 0 0 1-120.465769 48.065842A174.13327 174.13327 0 0 1 421.329029 33.590675L409.583617 20.761071C393.140039 2.99237 361.096144-4.898138 338.267881 3.353767c0 0-20.358715 7.529111-67.099434 34.513443-46.800951 27.34573-63.244529 41.440225-63.244529 41.440225-18.431263 15.66055-27.646894 47.222582-20.539413 70.592941l5.059562 16.865207a178.048407 178.048407 0 0 1-18.672194 129.621169 174.916297 174.916297 0 0 1-102.275439 81.073463l-17.045906 3.854904c-23.310126 5.42096-46.258856 29.333415-50.595623 53.185637 0 0-3.854905 21.382674-3.854905 75.712737 0 54.330062 3.854905 75.712736 3.854905 75.712736 4.216302 23.972688 26.9241 47.945376 50.595623 53.185637l16.624276 3.854905a174.253736 174.253736 0 0 1 102.395904 81.314394c23.310126 40.837896 28.911785 87.337683 18.732427 129.801867l-4.81863 16.443578c-7.10748 23.129428 2.108151 54.992624 20.599646 70.833872 0 0 16.624276 14.094495 63.244529 41.199293 46.800951 27.104798 66.918735 34.513443 66.918735 34.513443 22.707798 8.372371 54.631227 0.361397 71.255503-17.407303l11.624947-12.588673a175.096996 175.096996 0 0 1 242.256662 0.120465l11.624947 12.648906c16.383345 17.708468 48.427239 25.598976 71.255503 17.347071 0 0 20.358715-7.529111 67.159666-34.513443 46.740719-27.104798 63.124063-41.199293 63.124064-41.199293 18.491496-15.600317 27.707127-47.463513 20.599646-70.833873l-5.059562-17.106139a176.723284 176.723284 0 0 1 18.672194-129.139305 176.060722 176.060722 0 0 1 102.395904-81.314394l16.68451-3.854905c23.310126-5.42096 46.258856-29.333415 50.595623-53.185637 0 0 3.854905-21.382674 3.854904-75.712737-0.240932-54.330062-4.095836-75.833202-4.095836-75.833202z m-537.819428 293.334149c-119.261112 0-216.175824-97.336342-216.175824-217.621412a216.657687 216.657687 0 0 1 216.236057-217.320249c119.200879 0 216.115591 97.276109 216.11559 217.56118-0.240932 120.044139-96.974945 217.320248-216.175823 217.320249z" p-id="10234"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tab.svg b/ruoyi-ui/src/assets/icons/svg/tab.svg
new file mode 100644
index 0000000..b4b48e4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tab.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.921.052H49.08c-1.865 0-3.198 1.599-3.198 3.464v6.661c0 1.865 1.6 3.464 3.198 3.464h29.84c1.865 0 3.198-1.599 3.198-3.464V3.516C82.385 1.65 80.786.052 78.92.052zm45.563 0H94.642c-1.865 0-3.464 1.599-3.464 3.464v6.661c0 1.865 1.599 3.464 3.464 3.464h29.842c1.865-.266 3.464-1.599 3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464zm0 22.382H40.02c-1.866 0-3.464-1.599-3.464-3.464V3.516c0-1.865-1.599-3.464-3.464-3.464H3.516C1.65.052.052 1.651.052 3.516V124.75c0 1.598 1.599 3.197 3.464 3.197h120.968c1.865 0 3.464-1.599 3.464-3.464V25.898c0-1.865-1.599-3.464-3.464-3.464z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/table.svg b/ruoyi-ui/src/assets/icons/svg/table.svg
new file mode 100644
index 0000000..0e3dc9d
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/table.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/><path d="M.006.064h127.988v31.104H.006V.064zm0 38.016h38.396v41.472H.006V38.08zm0 48.384h38.396v41.472H.006V86.464zM44.802 38.08h38.396v41.472H44.802V38.08zm0 48.384h38.396v41.472H44.802V86.464zM89.598 38.08h38.396v41.472H89.598zm0 48.384h38.396v41.472H89.598z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/textarea.svg b/ruoyi-ui/src/assets/icons/svg/textarea.svg
new file mode 100644
index 0000000..2709f29
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/textarea.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1575802855098" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="2984" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M896 160H128c-35.2 0-64 28.8-64 64v576c0 35.2 28.8 64 64 64h768c35.2 0 64-28.8 64-64V224c0-35.2-28.8-64-64-64z m0 608c0 16-12.8 32-32 32H160c-19.2 0-32-12.8-32-32V256c0-16 12.8-32 32-32h704c19.2 0 32 12.8 32 32v512z" p-id="2985"></path><path d="M224 288c-19.2 0-32 12.8-32 32v256c0 16 12.8 32 32 32s32-12.8 32-32V320c0-16-12.8-32-32-32z m608 480c19.2 0 32-12.8 32-32V608L704 768h128z" p-id="2986"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/theme.svg b/ruoyi-ui/src/assets/icons/svg/theme.svg
new file mode 100644
index 0000000..5982a2f
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/theme.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M125.5 36.984L95.336 2.83C93.735 1.018 91.565 0 89.3 0c-2.263 0-4.433 1.018-6.033 2.83l-3.786 4.286c-1.6 1.812-3.77 2.83-6.032 2.831H54.553c-2.263 0-4.434-1.018-6.033-2.83L44.734 2.83C43.134 1.018 40.964 0 38.701 0c-2.263 0-4.434 1.018-6.034 2.83L2.5 36.984C.9 38.796 0 41.254 0 43.815c0 2.562.899 5.02 2.5 6.831L14.565 64.31c2.178 2.468 5.367 3.403 8.33 2.444 1.35-.435 2.709.592 2.709 2.18v49.407c0 5.313 3.84 9.66 8.532 9.66h59.726c4.693 0 8.532-4.347 8.532-9.66V68.934c0-1.59 1.36-2.616 2.71-2.181 2.962.96 6.15.024 8.329-2.444L125.5 50.646c1.6-1.811 2.499-4.269 2.499-6.83 0-2.563-.899-5.02-2.5-6.832z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/time-range.svg b/ruoyi-ui/src/assets/icons/svg/time-range.svg
new file mode 100644
index 0000000..13c1202
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/time-range.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1579774825624" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1248" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M498.595712 482.290351 345.420077 482.290351l0 57.307194 210.477712 0L555.897789 274.196942l-57.301054 0L498.596735 482.290351zM498.595712 482.290351" p-id="1249"></path><path d="M577.685002 644.98478l379.879913 0 0 57.302077L577.685002 702.286858 577.685002 644.98478 577.685002 644.98478zM577.685002 644.98478" p-id="1250"></path><path d="M577.685002 773.764795l379.879913 0 0 57.307194L577.685002 831.071989 577.685002 773.764795 577.685002 773.764795zM577.685002 773.764795" p-id="1251"></path><path d="M577.685002 902.549927l379.879913 0 0 57.307194L577.685002 959.857121 577.685002 902.549927 577.685002 902.549927zM577.685002 902.549927" p-id="1252"></path><path d="M102.523001 382.290823c4.450359 2.615571 9.470699 3.954055 14.530948 3.954055 2.969635 0 5.952572-0.461511 8.836249-1.394766l190.809767-61.886489c15.052834-4.882194 23.297612-21.040199 18.415418-36.08894-4.882194-15.052834-21.040199-23.297612-36.093033-18.415418L175.676092 308.458257c15.994276-26.115797 35.170011-50.537 57.370639-72.743768 73.767074-73.767074 171.845857-114.388237 276.16783-114.388237 104.32095 0 202.39564 40.622186 276.16169 114.388237s114.393353 171.845857 114.393353 276.16783c0 26.427906-2.615571 52.449559-7.709589 77.780481l58.302871 0c4.464685-25.499767 6.708795-51.470255 6.708795-77.780481 0-60.449767-11.845793-119.102608-35.204803-174.336584-22.559808-53.334719-54.850236-101.226472-95.968725-142.349055-41.122583-41.122583-89.017406-73.408917-142.348032-95.968725C628.317169 75.866898 569.659211 64.021106 509.215584 64.021106c-60.448744 0-119.106702 11.845793-174.336584 35.207873-53.334719 22.559808-101.230566 54.846142-142.349055 95.968725-23.980157 23.980157-44.934398 50.278103-62.727647 78.601172l-20.738323-105.655342c-3.043313-15.527648-18.105357-25.642007-33.631982-22.599717-15.527648 3.048429-25.64303 18.105357-22.599717 33.637098l36.102243 183.932126C90.51348 371.153158 95.460142 378.13313 102.523001 382.290823L102.523001 382.290823zM102.523001 382.290823" p-id="1253"></path><path d="M126.020158 587.9416 67.768453 587.9416c5.759167 33.679054 15.368012 66.544579 28.789697 98.278327 22.559808 53.333696 54.850236 101.225449 95.971795 142.348032 41.122583 41.122583 89.014336 73.408917 142.349055 95.968725 54.112432 22.88829 111.517863 34.71157 170.668031 35.18229L505.547031 902.395408c-102.94972-0.941442-199.594851-41.445948-272.499277-114.349351C177.545672 732.543975 140.810003 663.275355 126.020158 587.9416L126.020158 587.9416zM126.020158 587.9416" p-id="1254"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/time.svg b/ruoyi-ui/src/assets/icons/svg/time.svg
new file mode 100644
index 0000000..b376e32
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/time.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577099827399" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1008" xmlns:xlink="http://www.w3.org/1999/xlink" width="81" height="81"><defs><style type="text/css"></style></defs><path d="M520 559h204c17.673 0 32 14.327 32 32 0 17.673-14.327 32-32 32H488c-17.673 0-32-14.327-32-32 0-0.167 0.001-0.334 0.004-0.5a32.65 32.65 0 0 1-0.004-0.5V277c0-17.673 14.327-32 32-32 17.673 0 32 14.327 32 32v282z m-8 401C264.576 960 64 759.424 64 512S264.576 64 512 64s448 200.576 448 448-200.576 448-448 448z m0-64c212.077 0 384-171.923 384-384S724.077 128 512 128 128 299.923 128 512s171.923 384 384 384z" p-id="1009"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tool.svg b/ruoyi-ui/src/assets/icons/svg/tool.svg
new file mode 100644
index 0000000..48e0e35
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tool.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1553828490559" class="icon" style="" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1684" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M898.831744 900.517641 103.816972 900.517641c-36.002982 0-65.363683-29.286-65.363683-65.313541l0-554.949184c0-36.041868 29.361725-65.326844 65.363683-65.326844l795.015795 0c36.002982 0 65.198931 29.284977 65.198931 65.326844l0 554.949184C964.030675 871.231641 934.834726 900.517641 898.831744 900.517641L898.831744 900.517641zM103.816972 255.593236c-13.576203 0-24.711821 11.085476-24.711821 24.662703l0 554.949184c0 13.576203 11.136641 24.662703 24.711821 24.662703l795.015795 0c13.577227 0 24.547069-11.086499 24.547069-24.662703l0-554.949184c0-13.577227-10.970866-24.662703-24.547069-24.662703L103.816972 255.593236 103.816972 255.593236zM664.346245 251.774257c-11.161201 0-20.332071-9.080819-20.332071-20.332071l0-101.278661c0-13.576203-11.047614-24.623817-24.699542-24.623817L383.181611 105.539708c-13.576203 0-24.712845 11.04659-24.712845 24.623817l0 101.278661c0 11.252275-9.041934 20.332071-20.332071 20.332071-11.20111 0-20.319791-9.080819-20.319791-20.332071l0-101.278661c0-35.989679 29.323862-65.275679 65.364707-65.275679l236.133022 0c36.06745 0 65.402569 29.284977 65.402569 65.275679l0 101.278661C684.717202 242.694461 675.636383 251.774257 664.346245 251.774257L664.346245 251.774257zM413.233044 521.725502 75.694471 521.725502c-11.163247 0-20.333094-9.117658-20.333094-20.35663 0-11.252275 9.169847-20.332071 20.333094-20.332071l337.538573 0c11.277858 0 20.319791 9.080819 20.319791 20.332071C433.552835 512.607844 424.510902 521.725502 413.233044 521.725502L413.233044 521.725502zM912.894018 521.725502 575.367725 521.725502c-11.213389 0-20.332071-9.117658-20.332071-20.35663 0-11.252275 9.118682-20.332071 20.332071-20.332071l337.526293 0c11.290137 0 20.332071 9.080819 20.332071 20.332071C933.226089 512.607844 924.184155 521.725502 912.894018 521.725502L912.894018 521.725502zM557.56322 634.217552 445.085496 634.217552c-11.213389 0-20.332071-9.079796-20.332071-20.331048l0-168.763658c0-11.251252 9.118682-20.332071 20.332071-20.332071l112.478747 0c11.290137 0 20.370956 9.080819 20.370956 20.332071l0 168.763658C577.934177 625.137757 568.853357 634.217552 557.56322 634.217552L557.56322 634.217552zM465.417567 593.514525l71.827909 0L537.245476 465.454918l-71.827909 0L465.417567 593.514525 465.417567 593.514525z" p-id="1685"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tree-table.svg b/ruoyi-ui/src/assets/icons/svg/tree-table.svg
new file mode 100644
index 0000000..8aafdb8
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tree-table.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M44.8 0h79.543C126.78 0 128 1.422 128 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H44.8c-2.438 0-3.657-1.422-3.657-4.267V4.267C41.143 1.422 42.362 0 44.8 0zm22.857 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 80 64 78.578 64 75.733V52.267C64 49.422 65.219 48 67.657 48zm0 48h56.686c2.438 0 3.657 1.422 3.657 4.267v23.466c0 2.845-1.219 4.267-3.657 4.267H67.657C65.22 128 64 126.578 64 123.733v-23.466C64 97.422 65.219 96 67.657 96zM50.286 68.267c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V32h6.4c2.02 0 3.658-1.91 3.658-4.267V4.267C27.429 1.91 25.79 0 23.77 0H3.657C1.637 0 0 1.91 0 4.267v23.466C0 30.09 1.637 32 3.657 32h6.4v80c0 2.356 1.638 4.267 3.657 4.267h36.572c2.02 0 3.657-1.91 3.657-4.267 0-2.356-1.638-4.267-3.657-4.267H17.37V68.267h32.915z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/tree.svg b/ruoyi-ui/src/assets/icons/svg/tree.svg
new file mode 100644
index 0000000..dd4b7dd
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/tree.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M126.713 90.023c.858.985 1.287 2.134 1.287 3.447v29.553c0 1.423-.429 2.6-1.287 3.53-.858.93-1.907 1.395-3.146 1.395H97.824c-1.145 0-2.146-.465-3.004-1.395-.858-.93-1.287-2.107-1.287-3.53V93.47c0-.875.19-1.696.572-2.462.382-.766.906-1.368 1.573-1.806a3.84 3.84 0 0 1 2.146-.657h9.725V69.007a3.84 3.84 0 0 0-.43-1.806 3.569 3.569 0 0 0-1.143-1.313 2.714 2.714 0 0 0-1.573-.492h-36.47v23.149h9.725c1.144 0 2.145.492 3.004 1.478.858.985 1.287 2.134 1.287 3.447v29.553c0 .876-.191 1.696-.573 2.463-.38.766-.905 1.368-1.573 1.806a3.84 3.84 0 0 1-2.145.656H51.915a3.84 3.84 0 0 1-2.145-.656c-.668-.438-1.216-1.04-1.645-1.806a4.96 4.96 0 0 1-.644-2.463V93.47c0-1.313.43-2.462 1.288-3.447.858-.986 1.907-1.478 3.146-1.478h9.582v-23.15h-37.9c-.953 0-1.74.356-2.359 1.068-.62.711-.93 1.56-.93 2.544v19.538h9.726c1.239 0 2.264.492 3.074 1.478.81.985 1.216 2.134 1.216 3.447v29.553c0 1.423-.405 2.6-1.216 3.53-.81.93-1.835 1.395-3.074 1.395H4.29c-.476 0-.93-.082-1.358-.246a4.1 4.1 0 0 1-1.144-.657 4.658 4.658 0 0 1-.93-1.067 5.186 5.186 0 0 1-.643-1.395 5.566 5.566 0 0 1-.215-1.56V93.47c0-.437.048-.875.143-1.313a3.95 3.95 0 0 1 .429-1.15c.19-.328.429-.656.715-.984.286-.329.572-.602.858-.821.286-.22.62-.383 1.001-.493.382-.11.763-.164 1.144-.164h9.726V61.619c0-.985.31-1.833.93-2.544.619-.712 1.358-1.068 2.216-1.068h44.335V39.62h-9.582c-1.24 0-2.288-.492-3.146-1.477a5.09 5.09 0 0 1-1.287-3.448V5.14c0-1.423.429-2.627 1.287-3.612.858-.985 1.907-1.477 3.146-1.477h25.743c.763 0 1.478.246 2.145.739a5.17 5.17 0 0 1 1.573 1.888c.382.766.573 1.587.573 2.462v29.553c0 1.313-.43 2.463-1.287 3.448-.859.985-1.86 1.477-3.004 1.477h-9.725v18.389h42.762c.954 0 1.74.355 2.36 1.067.62.711.93 1.56.93 2.545v26.925h9.582c1.239 0 2.288.492 3.146 1.478z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/upload.svg b/ruoyi-ui/src/assets/icons/svg/upload.svg
new file mode 100644
index 0000000..bae49c0
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/upload.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1577540289643" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="7922" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M530.944 458.24l4.8 3.456 122.176 106.816a32 32 0 0 1-37.44 51.584l-4.672-3.392L546.56 556.16v280.704a32 32 0 0 1-26.24 31.488l-5.76 0.512a32 32 0 0 1-31.424-26.24l-0.512-5.76-0.064-280.704-69.12 60.48a32 32 0 0 1-40.96 0.896l-4.16-3.968a32 32 0 0 1-0.96-40.96l4.032-4.16 122.176-106.816a32 32 0 0 1 37.312-3.456zM497.92 128c128.128 0 239.168 82.304 275.52 199.04 123.968 11.264 221.312 113.088 221.312 237.44 0 128.128-103.68 232.96-234.88 238.272h-5.888l-35.52 0.192a32 32 0 0 1-0.192-64l35.264-0.128 4.672-0.064c96.384-3.84 172.544-80.896 172.544-174.272 0-96.128-80.512-174.464-179.584-174.464h-1.984a32 32 0 0 1-32-25.28C695.872 264.96 604.736 192 497.92 192 381.824 192 285.44 277.76 274.816 388.48a32 32 0 0 1-28.352 28.8c-83.968 9.152-147.84 78.208-147.84 159.552l0.192 7.936c3.84 85.76 77.056 154.112 166.592 154.112h45.632a32 32 0 0 1 0 64h-45.632C142.016 802.944 40.32 708.032 34.88 586.88l-0.192-9.28c0-106.88 76.352-197.184 179.968-219.904C239.488 226.112 357.76 128 497.856 128z" p-id="7923"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/user.svg b/ruoyi-ui/src/assets/icons/svg/user.svg
new file mode 100644
index 0000000..0ba0716
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/user.svg
@@ -0,0 +1 @@
+<svg width="130" height="130" xmlns="http://www.w3.org/2000/svg"><path d="M63.444 64.996c20.633 0 37.359-14.308 37.359-31.953 0-17.649-16.726-31.952-37.359-31.952-20.631 0-37.36 14.303-37.358 31.952 0 17.645 16.727 31.953 37.359 31.953zM80.57 75.65H49.434c-26.652 0-48.26 18.477-48.26 41.27v2.664c0 9.316 21.608 9.325 48.26 9.325H80.57c26.649 0 48.256-.344 48.256-9.325v-2.663c0-22.794-21.605-41.271-48.256-41.271z" stroke="#979797"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/validCode.svg b/ruoyi-ui/src/assets/icons/svg/validCode.svg
new file mode 100644
index 0000000..cfb1021
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/validCode.svg
@@ -0,0 +1 @@
+<?xml version="1.0" standalone="no"?><!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"><svg t="1569580729849" class="icon" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="1939" xmlns:xlink="http://www.w3.org/1999/xlink" width="200" height="200"><defs><style type="text/css"></style></defs><path d="M513.3 958.5c-142.2 0-397.9-222.1-401.6-440.5V268c1.7-39.6 31.7-72.3 71.1-77.3 49-4.6 97.1-16.5 142.7-35.3 47.8-14 91.9-38.3 129.4-71.1 30.3-24.4 72.9-26.3 105.3-4.6 39.9 30.7 83.8 55.9 130.5 74.6 48.6 14.7 98.2 25.9 148.4 33.7 38.5 7.6 67.1 40.3 69.5 79.5 3.3 84.9 2.5 169.9-2.6 254.7-33.7 281.6-253.7 436.4-392.7 436.3z m-0.1-813.7c-7.2-0.2-14.3 2-20 6.4-39.7 35.2-86.8 61.1-137.7 75.7-46.8 19.2-96.2 31-146.6 35.2-11 3.2-18.8 13-19.5 24.4v230.1c3.5 180.3 223.3 361 323.9 361s287.3-120.2 317.6-360.5c7.3-142.7 0-228.6 0-229.6-1.3-13.3-11-24.3-24-27.3-49.6-7.7-98.6-19-146.5-33.7-46.3-19.5-89.7-45.3-129-76.7-5.8-3.8-12.7-5.5-19.5-4.9l1.3-0.1z" fill="#C6CCDA" p-id="1940"></path><path d="M750.1 428L490.7 673.2c-11.7 11.1-29.5 12.9-43.1 4.2l-6.8-5.8-141.2-149.4c-9.3-9.3-12.7-22.9-9-35.5 3.8-12.6 14.1-22.1 27-24.8 12.9-2.7 26.1 1.9 34.6 11.9L469 597.5l233.7-221c14.6-12.8 36.8-11.6 49.9 2.7 13.2 14.2 11.5 35.3-2.5 48.8" fill="#C6CCDA" p-id="1941"></path></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/wechat.svg b/ruoyi-ui/src/assets/icons/svg/wechat.svg
new file mode 100644
index 0000000..c586e55
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/wechat.svg
@@ -0,0 +1 @@
+<svg width="128" height="110" xmlns="http://www.w3.org/2000/svg"><path d="M86.635 33.334c1.467 0 2.917.113 4.358.283C87.078 14.392 67.58.111 45.321.111 20.44.111.055 17.987.055 40.687c0 13.104 6.781 23.863 18.115 32.209l-4.527 14.352 15.82-8.364c5.666 1.182 10.207 2.395 15.858 2.395 1.42 0 2.829-.073 4.227-.189-.886-3.19-1.398-6.53-1.398-9.996 0-20.845 16.98-37.76 38.485-37.76zm-24.34-12.936c3.407 0 5.665 2.363 5.665 5.954 0 3.576-2.258 5.97-5.666 5.97-3.392 0-6.795-2.395-6.795-5.97 0-3.591 3.403-5.954 6.795-5.954zM30.616 32.323c-3.393 0-6.818-2.395-6.818-5.971 0-3.591 3.425-5.954 6.818-5.954 3.392 0 5.65 2.363 5.65 5.954 0 3.576-2.258 5.97-5.65 5.97z"/><path d="M127.945 70.52c0-19.075-18.108-34.623-38.448-34.623-21.537 0-38.5 15.548-38.5 34.623 0 19.108 16.963 34.622 38.5 34.622 4.508 0 9.058-1.2 13.584-2.395l12.414 7.167-3.404-11.923c9.087-7.184 15.854-16.712 15.854-27.471zm-50.928-5.97c-2.254 0-4.53-2.362-4.53-4.773 0-2.378 2.276-4.771 4.53-4.771 3.422 0 5.665 2.393 5.665 4.771 0 2.41-2.243 4.773-5.665 4.773zm24.897 0c-2.24 0-4.498-2.362-4.498-4.773 0-2.378 2.258-4.771 4.498-4.771 3.392 0 5.665 2.393 5.665 4.771 0 2.41-2.273 4.773-5.665 4.773z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svg/zip.svg b/ruoyi-ui/src/assets/icons/svg/zip.svg
new file mode 100644
index 0000000..f806fc4
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svg/zip.svg
@@ -0,0 +1 @@
+<svg width="128" height="128" xmlns="http://www.w3.org/2000/svg"><path d="M78.527 116.793c.178.008.348.024.527.024h40.233c4.711-.005 8.53-3.677 8.534-8.21V18.895c-.004-4.532-3.823-8.204-8.534-8.209H79.054c-.179 0-.353.016-.527.024V0L0 10.082v107.406l78.527 10.342v-11.037zm0-101.362c.174-.024.348-.052.527-.052h40.233c2.018 0 3.659 1.578 3.659 3.52v89.713c-.003 1.942-1.64 3.517-3.659 3.519H79.054c-.179 0-.353-.028-.527-.052V15.431zM30.262 75.757l-18.721-.46V72.37l11.3-16.673v-.148l-10.266.164v-4.51l17.504-.44v3.264L18.696 70.76v.144l11.566.176v4.678zm9.419.231l-5.823-.144V50.671l5.823-.144v25.461zm22.255-11.632c-2.168 1.922-5.353 2.76-9.02 2.736-.702.004-1.402-.04-2.097-.131v9.303l-5.997-.148V50.743c1.852-.352 4.473-.647 8.218-.743 3.838-.096 6.608.539 8.48 1.913 1.807 1.306 3.032 3.5 3.032 6.112s-.926 4.833-2.612 6.331h-.004zM53.36 54.45c-.856-.01-1.71.083-2.541.275v7.682c.523.116 1.167.152 2.06.152 3.301-.004 5.36-1.614 5.36-4.314 0-2.425-1.772-3.843-4.875-3.791l-.004-.004zm39.847-37.066h9.564v3.795h-9.564v-3.795zm-9.568 5.68h9.564v3.8h-9.564v-3.8zm9.568 6.216h9.564v3.799h-9.564V29.28zm0 12h9.564v3.794h-9.564V41.28zm-9.568-6.096h9.564v3.795h-9.564v-3.795zm9.472 47.064c2.512 0 4.921-.96 6.697-2.67 1.776-1.708 2.773-4.026 2.772-6.442l-1.748-15.263c0-5.033-2.492-9.112-7.725-9.112-5.232 0-7.72 4.079-7.72 9.112l-1.752 15.263c-.001 2.417.996 4.735 2.773 6.444 1.777 1.71 4.187 2.669 6.7 2.668h.003zm-3.135-16.75h6.27v12.743h-6.27V65.5z"/></svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/icons/svgo.yml b/ruoyi-ui/src/assets/icons/svgo.yml
new file mode 100644
index 0000000..d11906a
--- /dev/null
+++ b/ruoyi-ui/src/assets/icons/svgo.yml
@@ -0,0 +1,22 @@
+# replace default config
+
+# multipass: true
+# full: true
+
+plugins:
+
+  # - name
+  #
+  # or:
+  # - name: false
+  # - name: true
+  #
+  # or:
+  # - name:
+  #     param1: 1
+  #     param2: 2
+
+- removeAttrs:
+    attrs:
+      - 'fill'
+      - 'fill-rule'
diff --git a/ruoyi-ui/src/assets/images/dark.svg b/ruoyi-ui/src/assets/images/dark.svg
new file mode 100644
index 0000000..f646bd7
--- /dev/null
+++ b/ruoyi-ui/src/assets/images/dark.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="閰嶇疆闈㈡澘" width="48" height="40" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" width="48" height="40" transform="translate(-1190.000000, -136.000000)">
+            <g id="Group-8" width="48" height="40" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5-Copy-5" filter="url(#filter-1)" transform="translate(25.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                    <rect id="Rectangle-18" fill="#303648" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/images/light.svg b/ruoyi-ui/src/assets/images/light.svg
new file mode 100644
index 0000000..ab7cc08
--- /dev/null
+++ b/ruoyi-ui/src/assets/images/light.svg
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<svg width="52px" height="45px" viewBox="0 0 52 45" version="1.1" 
+    xmlns="http://www.w3.org/2000/svg" 
+    xmlns:xlink="http://www.w3.org/1999/xlink">
+    <defs>
+        <filter x="-9.4%" y="-6.2%" width="118.8%" height="122.5%" filterUnits="objectBoundingBox" id="filter-1">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="1" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.15 0" type="matrix" in="shadowBlurOuter1" result="shadowMatrixOuter1"></feColorMatrix>
+            <feMerge>
+                <feMergeNode in="shadowMatrixOuter1"></feMergeNode>
+                <feMergeNode in="SourceGraphic"></feMergeNode>
+            </feMerge>
+        </filter>
+        <rect id="path-2" x="0" y="0" width="48" height="40" rx="4"></rect>
+        <filter x="-4.2%" y="-2.5%" width="108.3%" height="110.0%" filterUnits="objectBoundingBox" id="filter-4">
+            <feOffset dx="0" dy="1" in="SourceAlpha" result="shadowOffsetOuter1"></feOffset>
+            <feGaussianBlur stdDeviation="0.5" in="shadowOffsetOuter1" result="shadowBlurOuter1"></feGaussianBlur>
+            <feColorMatrix values="0 0 0 0 0   0 0 0 0 0   0 0 0 0 0  0 0 0 0.1 0" type="matrix" in="shadowBlurOuter1"></feColorMatrix>
+        </filter>
+    </defs>
+    <g id="閰嶇疆闈㈡澘" stroke="none" stroke-width="1" fill="none" fill-rule="evenodd">
+        <g id="setting-copy-2" transform="translate(-1254.000000, -136.000000)">
+            <g id="Group-8" transform="translate(1167.000000, 0.000000)">
+                <g id="Group-5" filter="url(#filter-1)" transform="translate(89.000000, 137.000000)">
+                    <mask id="mask-3" fill="white">
+                        <use xlink:href="#path-2"></use>
+                    </mask>
+                    <g id="Rectangle-18">
+                        <use fill="black" fill-opacity="1" filter="url(#filter-4)" xlink:href="#path-2"></use>
+                        <use fill="#F0F2F5" fill-rule="evenodd" xlink:href="#path-2"></use>
+                    </g>
+                    <rect id="Rectangle-18" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="16" height="40"></rect>
+                    <rect id="Rectangle-11" fill="#FFFFFF" mask="url(#mask-3)" x="0" y="0" width="48" height="10"></rect>
+                </g>
+            </g>
+        </g>
+    </g>
+</svg>
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/images/login-background.jpg b/ruoyi-ui/src/assets/images/login-background.jpg
new file mode 100644
index 0000000..8a89eb8
--- /dev/null
+++ b/ruoyi-ui/src/assets/images/login-background.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/images/pay.png b/ruoyi-ui/src/assets/images/pay.png
new file mode 100644
index 0000000..bb8b967
--- /dev/null
+++ b/ruoyi-ui/src/assets/images/pay.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/images/profile.jpg b/ruoyi-ui/src/assets/images/profile.jpg
new file mode 100644
index 0000000..b3a940b
--- /dev/null
+++ b/ruoyi-ui/src/assets/images/profile.jpg
Binary files differ
diff --git a/ruoyi-ui/src/assets/logo/logo.png b/ruoyi-ui/src/assets/logo/logo.png
new file mode 100644
index 0000000..e263760
--- /dev/null
+++ b/ruoyi-ui/src/assets/logo/logo.png
Binary files differ
diff --git a/ruoyi-ui/src/assets/styles/btn.scss b/ruoyi-ui/src/assets/styles/btn.scss
new file mode 100644
index 0000000..e6ba1a8
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/btn.scss
@@ -0,0 +1,99 @@
+@import './variables.scss';
+
+@mixin colorBtn($color) {
+  background: $color;
+
+  &:hover {
+    color: $color;
+
+    &:before,
+    &:after {
+      background: $color;
+    }
+  }
+}
+
+.blue-btn {
+  @include colorBtn($blue)
+}
+
+.light-blue-btn {
+  @include colorBtn($light-blue)
+}
+
+.red-btn {
+  @include colorBtn($red)
+}
+
+.pink-btn {
+  @include colorBtn($pink)
+}
+
+.green-btn {
+  @include colorBtn($green)
+}
+
+.tiffany-btn {
+  @include colorBtn($tiffany)
+}
+
+.yellow-btn {
+  @include colorBtn($yellow)
+}
+
+.pan-btn {
+  font-size: 14px;
+  color: #fff;
+  padding: 14px 36px;
+  border-radius: 8px;
+  border: none;
+  outline: none;
+  transition: 600ms ease all;
+  position: relative;
+  display: inline-block;
+
+  &:hover {
+    background: #fff;
+
+    &:before,
+    &:after {
+      width: 100%;
+      transition: 600ms ease all;
+    }
+  }
+
+  &:before,
+  &:after {
+    content: '';
+    position: absolute;
+    top: 0;
+    right: 0;
+    height: 2px;
+    width: 0;
+    transition: 400ms ease all;
+  }
+
+  &::after {
+    right: inherit;
+    top: inherit;
+    left: 0;
+    bottom: 0;
+  }
+}
+
+.custom-button {
+  display: inline-block;
+  line-height: 1;
+  white-space: nowrap;
+  cursor: pointer;
+  background: #fff;
+  color: #fff;
+  -webkit-appearance: none;
+  text-align: center;
+  box-sizing: border-box;
+  outline: 0;
+  margin: 0;
+  padding: 10px 15px;
+  font-size: 14px;
+  border-radius: 4px;
+}
diff --git a/ruoyi-ui/src/assets/styles/element-ui.scss b/ruoyi-ui/src/assets/styles/element-ui.scss
new file mode 100644
index 0000000..363092a
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/element-ui.scss
@@ -0,0 +1,92 @@
+// cover some element-ui styles
+
+.el-breadcrumb__inner,
+.el-breadcrumb__inner a {
+  font-weight: 400 !important;
+}
+
+.el-upload {
+  input[type="file"] {
+    display: none !important;
+  }
+}
+
+.el-upload__input {
+  display: none;
+}
+
+.cell {
+  .el-tag {
+    margin-right: 0px;
+  }
+}
+
+.small-padding {
+  .cell {
+    padding-left: 5px;
+    padding-right: 5px;
+  }
+}
+
+.fixed-width {
+  .el-button--mini {
+    padding: 7px 10px;
+    width: 60px;
+  }
+}
+
+.status-col {
+  .cell {
+    padding: 0 10px;
+    text-align: center;
+
+    .el-tag {
+      margin-right: 0px;
+    }
+  }
+}
+
+// to fixed https://github.com/ElemeFE/element/issues/2461
+.el-dialog {
+  transform: none;
+  left: 0;
+  position: relative;
+  margin: 0 auto;
+}
+
+// refine element ui upload
+.upload-container {
+  .el-upload {
+    width: 100%;
+
+    .el-upload-dragger {
+      width: 100%;
+      height: 200px;
+    }
+  }
+}
+
+// dropdown
+.el-dropdown-menu {
+  a {
+    display: block
+  }
+}
+
+// fix date-picker ui bug in filter-item
+.el-range-editor.el-input__inner {
+  display: inline-flex !important;
+}
+
+// to fix el-date-picker css style
+.el-range-separator {
+  box-sizing: content-box;
+}
+
+.el-menu--collapse
+  > div
+  > .el-submenu
+  > .el-submenu__title
+  .el-submenu__icon-arrow {
+  display: none;
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/assets/styles/element-variables.scss b/ruoyi-ui/src/assets/styles/element-variables.scss
new file mode 100644
index 0000000..1615ff2
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/element-variables.scss
@@ -0,0 +1,31 @@
+/**
+* I think element-ui's default theme color is too light for long-term use.
+* So I modified the default color and you can modify it to your liking.
+**/
+
+/* theme color */
+$--color-primary: #1890ff;
+$--color-success: #13ce66;
+$--color-warning: #ffba00;
+$--color-danger: #ff4949;
+// $--color-info: #1E1E1E;
+
+$--button-font-weight: 400;
+
+// $--color-text-regular: #1f2d3d;
+
+$--border-color-light: #dfe4ed;
+$--border-color-lighter: #e6ebf5;
+
+$--table-border: 1px solid #dfe6ec;
+
+/* icon font path, required */
+$--font-path: '~element-ui/lib/theme-chalk/fonts';
+
+@import "~element-ui/packages/theme-chalk/src/index";
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  theme: $--color-primary;
+}
diff --git a/ruoyi-ui/src/assets/styles/index.scss b/ruoyi-ui/src/assets/styles/index.scss
new file mode 100644
index 0000000..2f3b9ef
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/index.scss
@@ -0,0 +1,182 @@
+@import './variables.scss';
+@import './mixin.scss';
+@import './transition.scss';
+@import './element-ui.scss';
+@import './sidebar.scss';
+@import './btn.scss';
+
+body {
+  height: 100%;
+  -moz-osx-font-smoothing: grayscale;
+  -webkit-font-smoothing: antialiased;
+  text-rendering: optimizeLegibility;
+  font-family: Helvetica Neue, Helvetica, PingFang SC, Hiragino Sans GB, Microsoft YaHei, Arial, sans-serif;
+}
+
+label {
+  font-weight: 700;
+}
+
+html {
+  height: 100%;
+  box-sizing: border-box;
+}
+
+#app {
+  height: 100%;
+}
+
+*,
+*:before,
+*:after {
+  box-sizing: inherit;
+}
+
+.no-padding {
+  padding: 0px !important;
+}
+
+.padding-content {
+  padding: 4px 0;
+}
+
+a:focus,
+a:active {
+  outline: none;
+}
+
+a,
+a:focus,
+a:hover {
+  cursor: pointer;
+  color: inherit;
+  text-decoration: none;
+}
+
+div:focus {
+  outline: none;
+}
+
+.fr {
+  float: right;
+}
+
+.fl {
+  float: left;
+}
+
+.pr-5 {
+  padding-right: 5px;
+}
+
+.pl-5 {
+  padding-left: 5px;
+}
+
+.block {
+  display: block;
+}
+
+.pointer {
+  cursor: pointer;
+}
+
+.inlineBlock {
+  display: block;
+}
+
+.clearfix {
+  &:after {
+    visibility: hidden;
+    display: block;
+    font-size: 0;
+    content: " ";
+    clear: both;
+    height: 0;
+  }
+}
+
+aside {
+  background: #eef1f6;
+  padding: 8px 24px;
+  margin-bottom: 20px;
+  border-radius: 2px;
+  display: block;
+  line-height: 32px;
+  font-size: 16px;
+  font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
+  color: #2c3e50;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+
+  a {
+    color: #337ab7;
+    cursor: pointer;
+
+    &:hover {
+      color: rgb(32, 160, 255);
+    }
+  }
+}
+
+//main-container鍏ㄥ眬鏍峰紡
+.app-container {
+  padding: 20px;
+}
+
+.components-container {
+  margin: 30px 50px;
+  position: relative;
+}
+
+.pagination-container {
+  margin-top: 30px;
+}
+
+.text-center {
+  text-align: center
+}
+
+.sub-navbar {
+  height: 50px;
+  line-height: 50px;
+  position: relative;
+  width: 100%;
+  text-align: right;
+  padding-right: 20px;
+  transition: 600ms ease position;
+  background: linear-gradient(90deg, rgba(32, 182, 249, 1) 0%, rgba(32, 182, 249, 1) 0%, rgba(33, 120, 241, 1) 100%, rgba(33, 120, 241, 1) 100%);
+
+  .subtitle {
+    font-size: 20px;
+    color: #fff;
+  }
+
+  &.draft {
+    background: #d0d0d0;
+  }
+
+  &.deleted {
+    background: #d0d0d0;
+  }
+}
+
+.link-type,
+.link-type:focus {
+  color: #337ab7;
+  cursor: pointer;
+
+  &:hover {
+    color: rgb(32, 160, 255);
+  }
+}
+
+.filter-container {
+  padding-bottom: 10px;
+
+  .filter-item {
+    display: inline-block;
+    vertical-align: middle;
+    margin-bottom: 10px;
+  }
+}
diff --git a/ruoyi-ui/src/assets/styles/mixin.scss b/ruoyi-ui/src/assets/styles/mixin.scss
new file mode 100644
index 0000000..06fa061
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/mixin.scss
@@ -0,0 +1,66 @@
+@mixin clearfix {
+  &:after {
+    content: "";
+    display: table;
+    clear: both;
+  }
+}
+
+@mixin scrollBar {
+  &::-webkit-scrollbar-track-piece {
+    background: #d3dce6;
+  }
+
+  &::-webkit-scrollbar {
+    width: 6px;
+  }
+
+  &::-webkit-scrollbar-thumb {
+    background: #99a9bf;
+    border-radius: 20px;
+  }
+}
+
+@mixin relative {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+@mixin pct($pct) {
+  width: #{$pct};
+  position: relative;
+  margin: 0 auto;
+}
+
+@mixin triangle($width, $height, $color, $direction) {
+  $width: $width/2;
+  $color-border-style: $height solid $color;
+  $transparent-border-style: $width solid transparent;
+  height: 0;
+  width: 0;
+
+  @if $direction==up {
+    border-bottom: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==right {
+    border-left: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+
+  @else if $direction==down {
+    border-top: $color-border-style;
+    border-left: $transparent-border-style;
+    border-right: $transparent-border-style;
+  }
+
+  @else if $direction==left {
+    border-right: $color-border-style;
+    border-top: $transparent-border-style;
+    border-bottom: $transparent-border-style;
+  }
+}
diff --git a/ruoyi-ui/src/assets/styles/ruoyi.scss b/ruoyi-ui/src/assets/styles/ruoyi.scss
new file mode 100644
index 0000000..7e44513
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/ruoyi.scss
@@ -0,0 +1,296 @@
+/**
+* 閫氱敤css鏍峰紡甯冨眬澶勭悊
+* Copyright (c) 2019 ruoyi
+*/
+
+/** 鍩虹閫氱敤 **/
+.pt5 {
+  padding-top: 5px;
+}
+
+.pr5 {
+  padding-right: 5px;
+}
+
+.pb5 {
+  padding-bottom: 5px;
+}
+
+.mt5 {
+  margin-top: 5px;
+}
+
+.mr5 {
+  margin-right: 5px;
+}
+
+.mb5 {
+  margin-bottom: 5px;
+}
+
+.mb8 {
+  margin-bottom: 8px;
+}
+
+.ml5 {
+  margin-left: 5px;
+}
+
+.mt10 {
+  margin-top: 10px;
+}
+
+.mr10 {
+  margin-right: 10px;
+}
+
+.mb10 {
+  margin-bottom: 10px;
+}
+.ml10 {
+	margin-left: 10px;
+}
+
+.mt20 {
+  margin-top: 20px;
+}
+
+.mr20 {
+  margin-right: 20px;
+}
+
+.mb20 {
+  margin-bottom: 20px;
+}
+.ml20 {
+	margin-left: 20px;
+}
+
+.h1, .h2, .h3, .h4, .h5, .h6, h1, h2, h3, h4, h5, h6 {
+  font-family: inherit;
+  font-weight: 500;
+  line-height: 1.1;
+  color: inherit;
+}
+
+.el-message-box__status + .el-message-box__message{
+  word-break: break-word;
+}
+
+.el-dialog:not(.is-fullscreen) {
+  margin-top: 6vh !important;
+}
+
+.el-dialog__wrapper.scrollbar .el-dialog .el-dialog__body {
+  overflow: auto;
+  overflow-x: hidden;
+  max-height: 70vh;
+  padding: 10px 20px 0;
+}
+
+.el-table {
+  .el-table__header-wrapper, .el-table__fixed-header-wrapper {
+    th {
+      word-break: break-word;
+      background-color: #f8f8f9;
+      color: #515a6e;
+      height: 40px;
+      font-size: 13px;
+    }
+  }
+
+  .el-table__body-wrapper {
+    .el-button [class*="el-icon-"] + span {
+      margin-left: 1px;
+    }
+  }
+}
+
+/** 琛ㄥ崟甯冨眬 **/
+.form-header {
+  font-size: 15px;
+  color: #6379bb;
+  border-bottom: 1px solid #ddd;
+  margin: 8px 10px 25px 10px;
+  padding-bottom: 5px
+}
+
+/** 琛ㄦ牸甯冨眬 **/
+.pagination-container {
+  position: relative;
+  height: 32px;
+  margin-bottom: 10px;
+  margin-top: 15px;
+  padding: 10px 20px !important;
+}
+
+/* tree border */
+.tree-border {
+  margin-top: 5px;
+  border: 1px solid #e5e6e7;
+  background: #FFFFFF none;
+  border-radius: 4px;
+}
+
+.pagination-container .el-pagination {
+  right: 0;
+  position: absolute;
+}
+
+@media (max-width: 768px) {
+  .pagination-container .el-pagination > .el-pagination__jump {
+    display: none !important;
+  }
+  .pagination-container .el-pagination > .el-pagination__sizes {
+    display: none !important;
+  }
+}
+
+.el-table .fixed-width .el-button--mini {
+  padding-left: 0;
+  padding-right: 0;
+  width: inherit;
+}
+
+/** 琛ㄦ牸鏇村鎿嶄綔涓嬫媺鏍峰紡 */
+.el-table .el-dropdown-link,.el-table .el-dropdown-selfdefine {
+	cursor: pointer;
+	margin-left: 5px;
+}
+
+.el-table .el-dropdown, .el-icon-arrow-down {
+  font-size: 12px;
+}
+
+.el-tree-node__content > .el-checkbox {
+  margin-right: 8px;
+}
+
+.list-group-striped > .list-group-item {
+  border-left: 0;
+  border-right: 0;
+  border-radius: 0;
+  padding-left: 0;
+  padding-right: 0;
+}
+
+.list-group {
+  padding-left: 0px;
+  list-style: none;
+}
+
+.list-group-item {
+  border-bottom: 1px solid #e7eaec;
+  border-top: 1px solid #e7eaec;
+  margin-bottom: -1px;
+  padding: 11px 0px;
+  font-size: 13px;
+}
+
+.pull-right {
+  float: right !important;
+}
+
+.el-card__header {
+  padding: 14px 15px 7px;
+  min-height: 40px;
+}
+
+.el-card__body {
+  padding: 15px 20px 20px 20px;
+}
+
+.card-box {
+  padding-right: 15px;
+  padding-left: 15px;
+  margin-bottom: 10px;
+}
+
+/* button color */
+.el-button--cyan.is-active,
+.el-button--cyan:active {
+  background: #20B2AA;
+  border-color: #20B2AA;
+  color: #FFFFFF;
+}
+
+.el-button--cyan:focus,
+.el-button--cyan:hover {
+  background: #48D1CC;
+  border-color: #48D1CC;
+  color: #FFFFFF;
+}
+
+.el-button--cyan {
+  background-color: #20B2AA;
+  border-color: #20B2AA;
+  color: #FFFFFF;
+}
+
+/* text color */
+.text-navy {
+  color: #1ab394;
+}
+
+.text-primary {
+  color: inherit;
+}
+
+.text-success {
+  color: #1c84c6;
+}
+
+.text-info {
+  color: #23c6c8;
+}
+
+.text-warning {
+  color: #f8ac59;
+}
+
+.text-danger {
+  color: #ed5565;
+}
+
+.text-muted {
+  color: #888888;
+}
+
+/* image */
+.img-circle {
+  border-radius: 50%;
+}
+
+.img-lg {
+  width: 120px;
+  height: 120px;
+}
+
+.avatar-upload-preview {
+  position: relative;
+  top: 50%;
+  left: 50%;
+  transform: translate(-50%, -50%);
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  box-shadow: 0 0 4px #ccc;
+  overflow: hidden;
+}
+
+/* 鎷栨嫿鍒楁牱寮� */
+.sortable-ghost {
+  opacity: .8;
+  color: #fff !important;
+  background: #42b983 !important;
+}
+
+.top-right-btn {
+  position: relative;
+  float: right;
+}
+
+/* 鍒嗗壊闈㈡澘鏍峰紡 */
+.splitpanes.default-theme .splitpanes__pane {
+  background-color: #fff!important;
+}
diff --git a/ruoyi-ui/src/assets/styles/sidebar.scss b/ruoyi-ui/src/assets/styles/sidebar.scss
new file mode 100644
index 0000000..abe5b63
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/sidebar.scss
@@ -0,0 +1,227 @@
+#app {
+
+  .main-container {
+    height: 100%;
+    transition: margin-left .28s;
+    margin-left: $base-sidebar-width;
+    position: relative;
+  }
+
+  .sidebarHide {
+    margin-left: 0!important;
+  }
+
+  .sidebar-container {
+    -webkit-transition: width .28s;
+    transition: width 0.28s;
+    width: $base-sidebar-width !important;
+    background-color: $base-menu-background;
+    height: 100%;
+    position: fixed;
+    font-size: 0px;
+    top: 0;
+    bottom: 0;
+    left: 0;
+    z-index: 1001;
+    overflow: hidden;
+    -webkit-box-shadow: 2px 0 6px rgba(0,21,41,.35);
+    box-shadow: 2px 0 6px rgba(0,21,41,.35);
+
+    // reset element-ui css
+    .horizontal-collapse-transition {
+      transition: 0s width ease-in-out, 0s padding-left ease-in-out, 0s padding-right ease-in-out;
+    }
+
+    .scrollbar-wrapper {
+      overflow-x: hidden !important;
+    }
+
+    .el-scrollbar__bar.is-vertical {
+      right: 0px;
+    }
+
+    .el-scrollbar {
+      height: 100%;
+    }
+
+    &.has-logo {
+      .el-scrollbar {
+        height: calc(100% - 50px);
+      }
+    }
+
+    .is-horizontal {
+      display: none;
+    }
+
+    a {
+      display: inline-block;
+      width: 100%;
+      overflow: hidden;
+    }
+
+    .svg-icon {
+      margin-right: 16px;
+    }
+
+    .el-menu {
+      border: none;
+      height: 100%;
+      width: 100% !important;
+    }
+
+    .el-menu-item, .el-submenu__title {
+      overflow: hidden !important;
+      text-overflow: ellipsis !important;
+      white-space: nowrap !important;
+    }
+
+    // menu hover
+    .submenu-title-noDropdown,
+    .el-submenu__title {
+      &:hover {
+        background-color: rgba(0, 0, 0, 0.06) !important;
+      }
+    }
+
+    & .theme-dark .is-active > .el-submenu__title {
+      color: $base-menu-color-active !important;
+    }
+
+    & .nest-menu .el-submenu>.el-submenu__title,
+    & .el-submenu .el-menu-item {
+      min-width: $base-sidebar-width !important;
+
+      &:hover {
+        background-color: rgba(0, 0, 0, 0.06) !important;
+      }
+    }
+
+    & .theme-dark .nest-menu .el-submenu>.el-submenu__title,
+    & .theme-dark .el-submenu .el-menu-item {
+      background-color: $base-sub-menu-background !important;
+
+      &:hover {
+        background-color: $base-sub-menu-hover !important;
+      }
+    }
+  }
+
+  .hideSidebar {
+    .sidebar-container {
+      width: 54px !important;
+    }
+
+    .main-container {
+      margin-left: 54px;
+    }
+
+    .submenu-title-noDropdown {
+      padding: 0 !important;
+      position: relative;
+
+      .el-tooltip {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+      }
+    }
+
+    .el-submenu {
+      overflow: hidden;
+
+      &>.el-submenu__title {
+        padding: 0 !important;
+
+        .svg-icon {
+          margin-left: 20px;
+        }
+
+      }
+    }
+
+    .el-menu--collapse {
+      .el-submenu {
+        &>.el-submenu__title {
+          &>span {
+            height: 0;
+            width: 0;
+            overflow: hidden;
+            visibility: hidden;
+            display: inline-block;
+          }
+        }
+      }
+    }
+  }
+
+  .el-menu--collapse .el-menu .el-submenu {
+    min-width: $base-sidebar-width !important;
+  }
+
+  // mobile responsive
+  .mobile {
+    .main-container {
+      margin-left: 0px;
+    }
+
+    .sidebar-container {
+      transition: transform .28s;
+      width: $base-sidebar-width !important;
+    }
+
+    &.hideSidebar {
+      .sidebar-container {
+        pointer-events: none;
+        transition-duration: 0.3s;
+        transform: translate3d(-$base-sidebar-width, 0, 0);
+      }
+    }
+  }
+
+  .withoutAnimation {
+
+    .main-container,
+    .sidebar-container {
+      transition: none;
+    }
+  }
+}
+
+// when menu collapsed
+.el-menu--vertical {
+  &>.el-menu {
+    .svg-icon {
+      margin-right: 16px;
+    }
+  }
+
+  .nest-menu .el-submenu>.el-submenu__title,
+  .el-menu-item {
+    &:hover {
+      // you can use $subMenuHover
+      background-color: rgba(0, 0, 0, 0.06) !important;
+    }
+  }
+
+  // the scroll bar appears when the subMenu is too long
+  >.el-menu--popup {
+    max-height: 100vh;
+    overflow-y: auto;
+
+    &::-webkit-scrollbar-track-piece {
+      background: #d3dce6;
+    }
+
+    &::-webkit-scrollbar {
+      width: 6px;
+    }
+
+    &::-webkit-scrollbar-thumb {
+      background: #99a9bf;
+      border-radius: 20px;
+    }
+  }
+}
diff --git a/ruoyi-ui/src/assets/styles/transition.scss b/ruoyi-ui/src/assets/styles/transition.scss
new file mode 100644
index 0000000..073f8c6
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/transition.scss
@@ -0,0 +1,49 @@
+// global transition css
+
+/* fade */
+.fade-enter-active,
+.fade-leave-active {
+  transition: opacity 0.28s;
+}
+
+.fade-enter,
+.fade-leave-active {
+  opacity: 0;
+}
+
+/* fade-transform */
+.fade-transform--move,
+.fade-transform-leave-active,
+.fade-transform-enter-active {
+  transition: all .5s;
+}
+
+.fade-transform-enter {
+  opacity: 0;
+  transform: translateX(-30px);
+}
+
+.fade-transform-leave-to {
+  opacity: 0;
+  transform: translateX(30px);
+}
+
+/* breadcrumb transition */
+.breadcrumb-enter-active,
+.breadcrumb-leave-active {
+  transition: all .5s;
+}
+
+.breadcrumb-enter,
+.breadcrumb-leave-active {
+  opacity: 0;
+  transform: translateX(20px);
+}
+
+.breadcrumb-move {
+  transition: all .5s;
+}
+
+.breadcrumb-leave-active {
+  position: absolute;
+}
diff --git a/ruoyi-ui/src/assets/styles/variables.scss b/ruoyi-ui/src/assets/styles/variables.scss
new file mode 100644
index 0000000..34484d4
--- /dev/null
+++ b/ruoyi-ui/src/assets/styles/variables.scss
@@ -0,0 +1,54 @@
+// base color
+$blue:#324157;
+$light-blue:#3A71A8;
+$red:#C03639;
+$pink: #E65D6E;
+$green: #30B08F;
+$tiffany: #4AB7BD;
+$yellow:#FEC171;
+$panGreen: #30B08F;
+
+// 榛樿鑿滃崟涓婚椋庢牸
+$base-menu-color:#bfcbd9;
+$base-menu-color-active:#f4f4f5;
+$base-menu-background:#304156;
+$base-logo-title-color: #ffffff;
+
+$base-menu-light-color:rgba(0,0,0,.70);
+$base-menu-light-background:#ffffff;
+$base-logo-light-title-color: #001529;
+
+$base-sub-menu-background:#1f2d3d;
+$base-sub-menu-hover:#001528;
+
+// 鑷畾涔夋殫鑹茶彍鍗曢鏍�
+/**
+$base-menu-color:hsla(0,0%,100%,.65);
+$base-menu-color-active:#fff;
+$base-menu-background:#001529;
+$base-logo-title-color: #ffffff;
+
+$base-menu-light-color:rgba(0,0,0,.70);
+$base-menu-light-background:#ffffff;
+$base-logo-light-title-color: #001529;
+
+$base-sub-menu-background:#000c17;
+$base-sub-menu-hover:#001528;
+*/
+
+$base-sidebar-width: 200px;
+
+// the :export directive is the magic sauce for webpack
+// https://www.bluematador.com/blog/how-to-share-variables-between-js-and-sass
+:export {
+  menuColor: $base-menu-color;
+  menuLightColor: $base-menu-light-color;
+  menuColorActive: $base-menu-color-active;
+  menuBackground: $base-menu-background;
+  menuLightBackground: $base-menu-light-background;
+  subMenuBackground: $base-sub-menu-background;
+  subMenuHover: $base-sub-menu-hover;
+  sideBarWidth: $base-sidebar-width;
+  logoTitleColor: $base-logo-title-color;
+  logoLightTitleColor: $base-logo-light-title-color
+}
diff --git a/ruoyi-ui/src/components/Breadcrumb/index.vue b/ruoyi-ui/src/components/Breadcrumb/index.vue
new file mode 100644
index 0000000..080595a
--- /dev/null
+++ b/ruoyi-ui/src/components/Breadcrumb/index.vue
@@ -0,0 +1,103 @@
+<template>
+  <el-breadcrumb class="app-breadcrumb" separator="/">
+    <transition-group name="breadcrumb">
+      <el-breadcrumb-item v-for="(item, index) in levelList" :key="item.path">
+        <span v-if="item.redirect === 'noRedirect' || index == levelList.length - 1" class="no-redirect">{{ item.meta.title }}</span>
+        <a v-else @click.prevent="handleLink(item)">{{ item.meta.title }}</a>
+      </el-breadcrumb-item>
+    </transition-group>
+  </el-breadcrumb>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      levelList: null
+    }
+  },
+  watch: {
+    $route(route) {
+      // if you go to the redirect page, do not update the breadcrumbs
+      if (route.path.startsWith('/redirect/')) {
+        return
+      }
+      this.getBreadcrumb()
+    }
+  },
+  created() {
+    this.getBreadcrumb()
+  },
+  methods: {
+    getBreadcrumb() {
+      // only show routes with meta.title
+      let matched = []
+      const router = this.$route
+      const pathNum = this.findPathNum(router.path)
+      // multi-level menu
+      if (pathNum > 2) {
+        const reg = /\/\w+/gi
+        const pathList = router.path.match(reg).map((item, index) => {
+          if (index !== 0) item = item.slice(1)
+          return item
+        })
+        this.getMatched(pathList, this.$store.getters.defaultRoutes, matched)
+      } else {
+        matched = router.matched.filter(item => item.meta && item.meta.title)
+      }
+      // 鍒ゆ柇鏄惁涓洪椤�
+      if (!this.isDashboard(matched[0])) {
+        matched = [{ path: "/index", meta: { title: "棣栭〉" } }].concat(matched)
+      }
+      this.levelList = matched.filter(item => item.meta && item.meta.title && item.meta.breadcrumb !== false)
+    },
+    findPathNum(str, char = "/") {
+      let index = str.indexOf(char)
+      let num = 0
+      while (index !== -1) {
+        num++
+        index = str.indexOf(char, index + 1)
+      }
+      return num
+    },
+    getMatched(pathList, routeList, matched) {
+      let data = routeList.find(item => item.path == pathList[0] || (item.name += '').toLowerCase() == pathList[0])
+      if (data) {
+        matched.push(data)
+        if (data.children && pathList.length) {
+          pathList.shift()
+          this.getMatched(pathList, data.children, matched)
+        }
+      }
+    },
+    isDashboard(route) {
+      const name = route && route.name
+      if (!name) {
+        return false
+      }
+      return name.trim() === 'Index'
+    },
+    handleLink(item) {
+      const { redirect, path } = item
+      if (redirect) {
+        this.$router.push(redirect)
+        return
+      }
+      this.$router.push(path)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-breadcrumb.el-breadcrumb {
+  display: inline-block;
+  font-size: 14px;
+  line-height: 50px;
+  margin-left: 8px;
+  .no-redirect {
+    color: #97a8be;
+    cursor: text;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/Crontab/day.vue b/ruoyi-ui/src/components/Crontab/day.vue
new file mode 100644
index 0000000..fe3eaf0
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/day.vue
@@ -0,0 +1,161 @@
+<template>
+	<el-form size="small">
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				鏃ワ紝鍏佽鐨勯�氶厤绗, - * ? / L W]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				涓嶆寚瀹�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min="1" :max="30" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="31" /> 鏃�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				浠�
+				<el-input-number v-model='average01' :min="1" :max="30" /> 鍙峰紑濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="31 - average01 || 1" /> 鏃ユ墽琛屼竴娆�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="5">
+				姣忔湀
+				<el-input-number v-model='workday' :min="1" :max="31" /> 鍙锋渶杩戠殑閭d釜宸ヤ綔鏃�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="6">
+				鏈湀鏈�鍚庝竴澶�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="7">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="item in 31" :key="item" :value="item">{{item}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 1,
+			workday: 1,
+			cycle01: 1,
+			cycle02: 2,
+			average01: 1,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-day',
+	props: ['check', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			('day rachange');
+			if (this.radioValue !== 2 && this.cron.week !== '?') {
+				this.$emit('update', 'week', '?', 'day')
+			}
+
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'day', '*');
+					break;
+				case 2:
+					this.$emit('update', 'day', '?');
+					break;
+				case 3:
+					this.$emit('update', 'day', this.cycleTotal);
+					break;
+				case 4:
+					this.$emit('update', 'day', this.averageTotal);
+					break;
+				case 5:
+					this.$emit('update', 'day', this.workday + 'W');
+					break;
+				case 6:
+					this.$emit('update', 'day', 'L');
+					break;
+				case 7:
+					this.$emit('update', 'day', this.checkboxString);
+					break;
+			}
+			('day rachange end');
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'day', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'day', this.averageTotal);
+			}
+		},
+		// 鏈�杩戝伐浣滄棩鍊煎彉鍖栨椂
+		workdayChange() {
+			if (this.radioValue == '5') {
+				this.$emit('update', 'day', this.workdayCheck + 'W');
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '7') {
+				this.$emit('update', 'day', this.checkboxString);
+			}
+		}
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'workdayCheck': 'workdayChange',
+		'checkboxString': 'checkboxChange',
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, 1, 30)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 31, 31)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, 1, 30)
+			const average02 = this.checkNum(this.average02, 1, 31 - average01 || 0)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻宸ヤ綔鏃ユ牸寮�
+		workdayCheck: function () {
+			const workday = this.checkNum(this.workday, 1, 31)
+			return workday;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/hour.vue b/ruoyi-ui/src/components/Crontab/hour.vue
new file mode 100644
index 0000000..3216c33
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/hour.vue
@@ -0,0 +1,120 @@
+<template>
+	<el-form size="small">
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				灏忔椂锛屽厑璁哥殑閫氶厤绗, - * /]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min="0" :max="22" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="23" /> 灏忔椂
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				浠�
+				<el-input-number v-model='average01' :min="0" :max="22" /> 灏忔椂寮�濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="23 - average01 || 0" /> 灏忔椂鎵ц涓�娆�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="item in 24" :key="item" :value="item-1">{{item-1}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 1,
+			cycle01: 0,
+			cycle02: 1,
+			average01: 0,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-hour',
+	props: ['check', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			if (this.cron.min === '*') {
+			    this.$emit('update', 'min', '0', 'hour');
+			}
+			if (this.cron.second === '*') {
+			    this.$emit('update', 'second', '0', 'hour');
+			}
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'hour', '*')
+					break;
+				case 2:
+					this.$emit('update', 'hour', this.cycleTotal);
+					break;
+				case 3:
+					this.$emit('update', 'hour', this.averageTotal);
+					break;
+				case 4:
+					this.$emit('update', 'hour', this.checkboxString);
+					break;
+			}
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '2') {
+				this.$emit('update', 'hour', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'hour', this.averageTotal);
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'hour', this.checkboxString);
+			}
+		}
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'checkboxString': 'checkboxChange'
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, 0, 22)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 23)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, 0, 22)
+			const average02 = this.checkNum(this.average02, 1, 23 - average01 || 0)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/index.vue b/ruoyi-ui/src/components/Crontab/index.vue
new file mode 100644
index 0000000..3963df2
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/index.vue
@@ -0,0 +1,430 @@
+<template>
+  <div>
+    <el-tabs type="border-card">
+      <el-tab-pane label="绉�" v-if="shouldHide('second')">
+        <CrontabSecond
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronsecond"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="鍒嗛挓" v-if="shouldHide('min')">
+        <CrontabMin
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronmin"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="灏忔椂" v-if="shouldHide('hour')">
+        <CrontabHour
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronhour"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="鏃�" v-if="shouldHide('day')">
+        <CrontabDay
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronday"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="鏈�" v-if="shouldHide('month')">
+        <CrontabMonth
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronmonth"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="鍛�" v-if="shouldHide('week')">
+        <CrontabWeek
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronweek"
+        />
+      </el-tab-pane>
+
+      <el-tab-pane label="骞�" v-if="shouldHide('year')">
+        <CrontabYear
+          @update="updateCrontabValue"
+          :check="checkNumber"
+          :cron="crontabValueObj"
+          ref="cronyear"
+        />
+      </el-tab-pane>
+    </el-tabs>
+
+    <div class="popup-main">
+      <div class="popup-result">
+        <p class="title">鏃堕棿琛ㄨ揪寮�</p>
+        <table>
+          <thead>
+            <th v-for="item of tabTitles" width="40" :key="item">{{item}}</th>
+            <th>Cron 琛ㄨ揪寮�</th>
+          </thead>
+          <tbody>
+            <td>
+              <span>{{crontabValueObj.second}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.min}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.hour}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.day}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.month}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.week}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueObj.year}}</span>
+            </td>
+            <td>
+              <span>{{crontabValueString}}</span>
+            </td>
+          </tbody>
+        </table>
+      </div>
+      <CrontabResult :ex="crontabValueString"></CrontabResult>
+
+      <div class="pop_btn">
+        <el-button size="small" type="primary" @click="submitFill">纭畾</el-button>
+        <el-button size="small" type="warning" @click="clearCron">閲嶇疆</el-button>
+        <el-button size="small" @click="hidePopup">鍙栨秷</el-button>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import CrontabSecond from "./second.vue";
+import CrontabMin from "./min.vue";
+import CrontabHour from "./hour.vue";
+import CrontabDay from "./day.vue";
+import CrontabMonth from "./month.vue";
+import CrontabWeek from "./week.vue";
+import CrontabYear from "./year.vue";
+import CrontabResult from "./result.vue";
+
+export default {
+  data() {
+    return {
+      tabTitles: ["绉�", "鍒嗛挓", "灏忔椂", "鏃�", "鏈�", "鍛�", "骞�"],
+      tabActive: 0,
+      myindex: 0,
+      crontabValueObj: {
+        second: "*",
+        min: "*",
+        hour: "*",
+        day: "*",
+        month: "*",
+        week: "?",
+        year: "",
+      },
+    };
+  },
+  name: "vcrontab",
+  props: ["expression", "hideComponent"],
+  methods: {
+    shouldHide(key) {
+      if (this.hideComponent && this.hideComponent.includes(key)) return false;
+      return true;
+    },
+    resolveExp() {
+      // 鍙嶈В鏋� 琛ㄨ揪寮�
+      if (this.expression) {
+        let arr = this.expression.split(" ");
+        if (arr.length >= 6) {
+          //6 浣嶄互涓婃槸鍚堟硶琛ㄨ揪寮�
+          let obj = {
+            second: arr[0],
+            min: arr[1],
+            hour: arr[2],
+            day: arr[3],
+            month: arr[4],
+            week: arr[5],
+            year: arr[6] ? arr[6] : "",
+          };
+          this.crontabValueObj = {
+            ...obj,
+          };
+          for (let i in obj) {
+            if (obj[i]) this.changeRadio(i, obj[i]);
+          }
+        }
+      } else {
+        // 娌℃湁浼犲叆鐨勮〃杈惧紡 鍒欒繕鍘�
+        this.clearCron();
+      }
+    },
+    // tab鍒囨崲鍊�
+    tabCheck(index) {
+      this.tabActive = index;
+    },
+    // 鐢卞瓙缁勪欢瑙﹀彂锛屾洿鏀硅〃杈惧紡缁勬垚鐨勫瓧娈靛��
+    updateCrontabValue(name, value, from) {
+      "updateCrontabValue", name, value, from;
+      this.crontabValueObj[name] = value;
+      if (from && from !== name) {
+        console.log(`鏉ヨ嚜缁勪欢 ${from} 鏀瑰彉浜� ${name} ${value}`);
+        this.changeRadio(name, value);
+      }
+    },
+    // 璧嬪�煎埌缁勪欢
+    changeRadio(name, value) {
+      let arr = ["second", "min", "hour", "month"],
+        refName = "cron" + name,
+        insValue;
+
+      if (!this.$refs[refName]) return;
+
+      if (arr.includes(name)) {
+        if (value === "*") {
+          insValue = 1;
+        } else if (value.indexOf("-") > -1) {
+          let indexArr = value.split("-");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].cycle01 = 0)
+            : (this.$refs[refName].cycle01 = indexArr[0]);
+          this.$refs[refName].cycle02 = indexArr[1];
+          insValue = 2;
+        } else if (value.indexOf("/") > -1) {
+          let indexArr = value.split("/");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].average01 = 0)
+            : (this.$refs[refName].average01 = indexArr[0]);
+          this.$refs[refName].average02 = indexArr[1];
+          insValue = 3;
+        } else {
+          insValue = 4;
+          this.$refs[refName].checkboxList = value.split(",");
+        }
+      } else if (name == "day") {
+        if (value === "*") {
+          insValue = 1;
+        } else if (value == "?") {
+          insValue = 2;
+        } else if (value.indexOf("-") > -1) {
+          let indexArr = value.split("-");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].cycle01 = 0)
+            : (this.$refs[refName].cycle01 = indexArr[0]);
+          this.$refs[refName].cycle02 = indexArr[1];
+          insValue = 3;
+        } else if (value.indexOf("/") > -1) {
+          let indexArr = value.split("/");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].average01 = 0)
+            : (this.$refs[refName].average01 = indexArr[0]);
+          this.$refs[refName].average02 = indexArr[1];
+          insValue = 4;
+        } else if (value.indexOf("W") > -1) {
+          let indexArr = value.split("W");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].workday = 0)
+            : (this.$refs[refName].workday = indexArr[0]);
+          insValue = 5;
+        } else if (value === "L") {
+          insValue = 6;
+        } else {
+          this.$refs[refName].checkboxList = value.split(",");
+          insValue = 7;
+        }
+      } else if (name == "week") {
+        if (value === "*") {
+          insValue = 1;
+        } else if (value == "?") {
+          insValue = 2;
+        } else if (value.indexOf("-") > -1) {
+          let indexArr = value.split("-");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].cycle01 = 0)
+            : (this.$refs[refName].cycle01 = indexArr[0]);
+          this.$refs[refName].cycle02 = indexArr[1];
+          insValue = 3;
+        } else if (value.indexOf("#") > -1) {
+          let indexArr = value.split("#");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].average01 = 1)
+            : (this.$refs[refName].average01 = indexArr[0]);
+          this.$refs[refName].average02 = indexArr[1];
+          insValue = 4;
+        } else if (value.indexOf("L") > -1) {
+          let indexArr = value.split("L");
+          isNaN(indexArr[0])
+            ? (this.$refs[refName].weekday = 1)
+            : (this.$refs[refName].weekday = indexArr[0]);
+          insValue = 5;
+        } else {
+          this.$refs[refName].checkboxList = value.split(",");
+          insValue = 6;
+        }
+      } else if (name == "year") {
+        if (value == "") {
+          insValue = 1;
+        } else if (value == "*") {
+          insValue = 2;
+        } else if (value.indexOf("-") > -1) {
+          insValue = 3;
+        } else if (value.indexOf("/") > -1) {
+          insValue = 4;
+        } else {
+          this.$refs[refName].checkboxList = value.split(",");
+          insValue = 5;
+        }
+      }
+      this.$refs[refName].radioValue = insValue;
+    },
+    // 琛ㄥ崟閫夐」鐨勫瓙缁勪欢鏍¢獙鏁板瓧鏍煎紡锛堥�氳繃-props浼犻�掞級
+    checkNumber(value, minLimit, maxLimit) {
+      // 妫�鏌ュ繀椤讳负鏁存暟
+      value = Math.floor(value);
+      if (value < minLimit) {
+        value = minLimit;
+      } else if (value > maxLimit) {
+        value = maxLimit;
+      }
+      return value;
+    },
+    // 闅愯棌寮圭獥
+    hidePopup() {
+      this.$emit("hide");
+    },
+    // 濉厖琛ㄨ揪寮�
+    submitFill() {
+      this.$emit("fill", this.crontabValueString);
+      this.hidePopup();
+    },
+    clearCron() {
+      // 杩樺師閫夋嫨椤�
+      ("鍑嗗杩樺師");
+      this.crontabValueObj = {
+        second: "*",
+        min: "*",
+        hour: "*",
+        day: "*",
+        month: "*",
+        week: "?",
+        year: "",
+      };
+      for (let j in this.crontabValueObj) {
+        this.changeRadio(j, this.crontabValueObj[j]);
+      }
+    },
+  },
+  computed: {
+    crontabValueString: function() {
+      let obj = this.crontabValueObj;
+      let str =
+        obj.second +
+        " " +
+        obj.min +
+        " " +
+        obj.hour +
+        " " +
+        obj.day +
+        " " +
+        obj.month +
+        " " +
+        obj.week +
+        (obj.year == "" ? "" : " " + obj.year);
+      return str;
+    },
+  },
+  components: {
+    CrontabSecond,
+    CrontabMin,
+    CrontabHour,
+    CrontabDay,
+    CrontabMonth,
+    CrontabWeek,
+    CrontabYear,
+    CrontabResult,
+  },
+  watch: {
+    expression: "resolveExp",
+    hideComponent(value) {
+      // 闅愯棌閮ㄥ垎缁勪欢
+    },
+  },
+  mounted: function() {
+    this.resolveExp();
+  },
+};
+</script>
+<style scoped>
+.pop_btn {
+  text-align: center;
+  margin-top: 20px;
+}
+.popup-main {
+  position: relative;
+  margin: 10px auto;
+  background: #fff;
+  border-radius: 5px;
+  font-size: 12px;
+  overflow: hidden;
+}
+.popup-title {
+  overflow: hidden;
+  line-height: 34px;
+  padding-top: 6px;
+  background: #f2f2f2;
+}
+.popup-result {
+  box-sizing: border-box;
+  line-height: 24px;
+  margin: 25px auto;
+  padding: 15px 10px 10px;
+  border: 1px solid #ccc;
+  position: relative;
+}
+.popup-result .title {
+  position: absolute;
+  top: -28px;
+  left: 50%;
+  width: 140px;
+  font-size: 14px;
+  margin-left: -70px;
+  text-align: center;
+  line-height: 30px;
+  background: #fff;
+}
+.popup-result table {
+  text-align: center;
+  width: 100%;
+  margin: 0 auto;
+}
+.popup-result table span {
+  display: block;
+  width: 100%;
+  font-family: arial;
+  line-height: 30px;
+  height: 30px;
+  white-space: nowrap;
+  overflow: hidden;
+  border: 1px solid #e8e8e8;
+}
+.popup-result-scroll {
+  font-size: 12px;
+  line-height: 24px;
+  height: 10em;
+  overflow-y: auto;
+}
+</style>
diff --git a/ruoyi-ui/src/components/Crontab/min.vue b/ruoyi-ui/src/components/Crontab/min.vue
new file mode 100644
index 0000000..43cab90
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/min.vue
@@ -0,0 +1,116 @@
+<template>
+	<el-form size="small">
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				鍒嗛挓锛屽厑璁哥殑閫氶厤绗, - * /]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min="0" :max="58" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> 鍒嗛挓
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				浠�
+				<el-input-number v-model='average01' :min="0" :max="58" /> 鍒嗛挓寮�濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 鍒嗛挓鎵ц涓�娆�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 1,
+			cycle01: 1,
+			cycle02: 2,
+			average01: 0,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-min',
+	props: ['check', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'min', '*', 'min');
+					break;
+				case 2:
+					this.$emit('update', 'min', this.cycleTotal, 'min');
+					break;
+				case 3:
+					this.$emit('update', 'min', this.averageTotal, 'min');
+					break;
+				case 4:
+					this.$emit('update', 'min', this.checkboxString, 'min');
+					break;
+			}
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '2') {
+				this.$emit('update', 'min', this.cycleTotal, 'min');
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'min', this.averageTotal, 'min');
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'min', this.checkboxString, 'min');
+			}
+		},
+
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'checkboxString': 'checkboxChange',
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, 0, 58)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, 0, 58)
+			const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/Crontab/month.vue b/ruoyi-ui/src/components/Crontab/month.vue
new file mode 100644
index 0000000..fd0ac38
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/month.vue
@@ -0,0 +1,114 @@
+<template>
+	<el-form size='small'>
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				鏈堬紝鍏佽鐨勯�氶厤绗, - * /]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min="1" :max="11" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 2" :max="12" /> 鏈�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				浠�
+				<el-input-number v-model='average01' :min="1" :max="11" /> 鏈堝紑濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="12 - average01 || 0" /> 鏈堟湀鎵ц涓�娆�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="item in 12" :key="item" :value="item">{{item}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 1,
+			cycle01: 1,
+			cycle02: 2,
+			average01: 1,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.check
+		}
+	},
+	name: 'crontab-month',
+	props: ['check', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'month', '*');
+					break;
+				case 2:
+					this.$emit('update', 'month', this.cycleTotal);
+					break;
+				case 3:
+					this.$emit('update', 'month', this.averageTotal);
+					break;
+				case 4:
+					this.$emit('update', 'month', this.checkboxString);
+					break;
+			}
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '2') {
+				this.$emit('update', 'month', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'month', this.averageTotal);
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'month', this.checkboxString);
+			}
+		}
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'checkboxString': 'checkboxChange'
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, 1, 11)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 2, 12)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, 1, 11)
+			const average02 = this.checkNum(this.average02, 1, 12 - average01 || 0)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/result.vue b/ruoyi-ui/src/components/Crontab/result.vue
new file mode 100644
index 0000000..aea6e0e
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/result.vue
@@ -0,0 +1,559 @@
+<template>
+	<div class="popup-result">
+		<p class="title">鏈�杩�5娆¤繍琛屾椂闂�</p>
+		<ul class="popup-result-scroll">
+			<template v-if='isShow'>
+				<li v-for='item in resultList' :key="item">{{item}}</li>
+			</template>
+			<li v-else>璁$畻缁撴灉涓�...</li>
+		</ul>
+	</div>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			dayRule: '',
+			dayRuleSup: '',
+			dateArr: [],
+			resultList: [],
+			isShow: false
+		}
+	},
+	name: 'crontab-result',
+	methods: {
+		// 琛ㄨ揪寮忓�煎彉鍖栨椂锛屽紑濮嬪幓璁$畻缁撴灉
+		expressionChange() {
+
+			// 璁$畻寮�濮�-闅愯棌缁撴灉
+			this.isShow = false;
+			// 鑾峰彇瑙勫垯鏁扮粍[0绉掋��1鍒嗐��2鏃躲��3鏃ャ��4鏈堛��5鏄熸湡銆�6骞碷
+			let ruleArr = this.$options.propsData.ex.split(' ');
+			// 鐢ㄤ簬璁板綍杩涘叆寰幆鐨勬鏁�
+			let nums = 0;
+			// 鐢ㄤ簬鏆傛椂瀛樼鍙锋椂闂磋鍒欑粨鏋滅殑鏁扮粍
+			let resultArr = [];
+			// 鑾峰彇褰撳墠鏃堕棿绮剧‘鑷砙骞淬�佹湀銆佹棩銆佹椂銆佸垎銆佺]
+			let nTime = new Date();
+			let nYear = nTime.getFullYear();
+			let nMonth = nTime.getMonth() + 1;
+			let nDay = nTime.getDate();
+			let nHour = nTime.getHours();
+			let nMin = nTime.getMinutes();
+			let nSecond = nTime.getSeconds();
+			// 鏍规嵁瑙勫垯鑾峰彇鍒拌繎100骞村彲鑳藉勾鏁扮粍銆佹湀鏁扮粍绛夌瓑
+			this.getSecondArr(ruleArr[0]);
+			this.getMinArr(ruleArr[1]);
+			this.getHourArr(ruleArr[2]);
+			this.getDayArr(ruleArr[3]);
+			this.getMonthArr(ruleArr[4]);
+			this.getWeekArr(ruleArr[5]);
+			this.getYearArr(ruleArr[6], nYear);
+			// 灏嗚幏鍙栧埌鐨勬暟缁勮祴鍊�-鏂逛究浣跨敤
+			let sDate = this.dateArr[0];
+			let mDate = this.dateArr[1];
+			let hDate = this.dateArr[2];
+			let DDate = this.dateArr[3];
+			let MDate = this.dateArr[4];
+			let YDate = this.dateArr[5];
+			// 鑾峰彇褰撳墠鏃堕棿鍦ㄦ暟缁勪腑鐨勭储寮�
+			let sIdx = this.getIndex(sDate, nSecond);
+			let mIdx = this.getIndex(mDate, nMin);
+			let hIdx = this.getIndex(hDate, nHour);
+			let DIdx = this.getIndex(DDate, nDay);
+			let MIdx = this.getIndex(MDate, nMonth);
+			let YIdx = this.getIndex(YDate, nYear);
+			// 閲嶇疆鏈堟棩鏃跺垎绉掔殑鍑芥暟(鍚庨潰鐢ㄧ殑姣旇緝澶�)
+			const resetSecond = function () {
+				sIdx = 0;
+				nSecond = sDate[sIdx]
+			}
+			const resetMin = function () {
+				mIdx = 0;
+				nMin = mDate[mIdx]
+				resetSecond();
+			}
+			const resetHour = function () {
+				hIdx = 0;
+				nHour = hDate[hIdx]
+				resetMin();
+			}
+			const resetDay = function () {
+				DIdx = 0;
+				nDay = DDate[DIdx]
+				resetHour();
+			}
+			const resetMonth = function () {
+				MIdx = 0;
+				nMonth = MDate[MIdx]
+				resetDay();
+			}
+			// 濡傛灉褰撳墠骞翠唤涓嶄负鏁扮粍涓綋鍓嶅��
+			if (nYear !== YDate[YIdx]) {
+				resetMonth();
+			}
+			// 濡傛灉褰撳墠鏈堜唤涓嶄负鏁扮粍涓綋鍓嶅��
+			if (nMonth !== MDate[MIdx]) {
+				resetDay();
+			}
+			// 濡傛灉褰撳墠鈥滄棩鈥濅笉涓烘暟缁勪腑褰撳墠鍊�
+			if (nDay !== DDate[DIdx]) {
+				resetHour();
+			}
+			// 濡傛灉褰撳墠鈥滄椂鈥濅笉涓烘暟缁勪腑褰撳墠鍊�
+			if (nHour !== hDate[hIdx]) {
+				resetMin();
+			}
+			// 濡傛灉褰撳墠鈥滃垎鈥濅笉涓烘暟缁勪腑褰撳墠鍊�
+			if (nMin !== mDate[mIdx]) {
+				resetSecond();
+			}
+
+			// 寰幆骞翠唤鏁扮粍
+			goYear: for (let Yi = YIdx; Yi < YDate.length; Yi++) {
+				let YY = YDate[Yi];
+				// 濡傛灉鍒拌揪鏈�澶у�兼椂
+				if (nMonth > MDate[MDate.length - 1]) {
+					resetMonth();
+					continue;
+				}
+				// 寰幆鏈堜唤鏁扮粍
+				goMonth: for (let Mi = MIdx; Mi < MDate.length; Mi++) {
+					// 璧嬪�笺�佹柟渚垮悗闈㈣繍绠�
+					let MM = MDate[Mi];
+					MM = MM < 10 ? '0' + MM : MM;
+					// 濡傛灉鍒拌揪鏈�澶у�兼椂
+					if (nDay > DDate[DDate.length - 1]) {
+						resetDay();
+						if (Mi == MDate.length - 1) {
+							resetMonth();
+							continue goYear;
+						}
+						continue;
+					}
+					// 寰幆鏃ユ湡鏁扮粍
+					goDay: for (let Di = DIdx; Di < DDate.length; Di++) {
+						// 璧嬪�笺�佹柟渚垮悗闈㈣繍绠�
+						let DD = DDate[Di];
+						let thisDD = DD < 10 ? '0' + DD : DD;
+
+						// 濡傛灉鍒拌揪鏈�澶у�兼椂
+						if (nHour > hDate[hDate.length - 1]) {
+							resetHour();
+							if (Di == DDate.length - 1) {
+								resetDay();
+								if (Mi == MDate.length - 1) {
+									resetMonth();
+									continue goYear;
+								}
+								continue goMonth;
+							}
+							continue;
+						}
+
+						// 鍒ゆ柇鏃ユ湡鐨勫悎娉曟�э紝涓嶅悎娉曠殑璇濅篃鏄烦鍑哄綋鍓嶅惊鐜�
+						if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true && this.dayRule !== 'workDay' && this.dayRule !== 'lastWeek' && this.dayRule !== 'lastDay') {
+							resetDay();
+							continue goMonth;
+						}
+						// 濡傛灉鏃ユ湡瑙勫垯涓湁鍊兼椂
+						if (this.dayRule == 'lastDay') {
+							// 濡傛灉涓嶆槸鍚堟硶鏃ユ湡鍒欓渶瑕佸皢鍓嶅皢鏃ユ湡璋冨埌鍚堟硶鏃ユ湡鍗虫湀鏈渶鍚庝竴澶�
+
+							if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+								while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+									DD--;
+
+									thisDD = DD < 10 ? '0' + DD : DD;
+								}
+							}
+						} else if (this.dayRule == 'workDay') {
+							// 鏍¢獙骞惰皟鏁村鏋滄槸2鏈�30鍙疯繖绉嶆棩鏈熶紶杩涙潵鏃堕渶璋冩暣鑷虫甯告湀搴�
+							if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+								while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+									DD--;
+									thisDD = DD < 10 ? '0' + DD : DD;
+								}
+							}
+							// 鑾峰彇杈惧埌鏉′欢鐨勬棩鏈熸槸鏄熸湡X
+							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
+							// 褰撴槦鏈熸棩鏃�
+							if (thisWeek == 1) {
+								// 鍏堟壘涓嬩竴涓棩锛屽苟鍒ゆ柇鏄惁涓烘湀搴�
+								DD++;
+								thisDD = DD < 10 ? '0' + DD : DD;
+								// 鍒ゆ柇涓嬩竴鏃ュ凡缁忎笉鏄悎娉曟棩鏈�
+								if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+									DD -= 3;
+								}
+							} else if (thisWeek == 7) {
+								// 褰撴槦鏈�6鏃跺彧闇�鍒ゆ柇涓嶆槸1鍙峰氨鍙繘琛屾搷浣�
+								if (this.dayRuleSup !== 1) {
+									DD--;
+								} else {
+									DD += 2;
+								}
+							}
+						} else if (this.dayRule == 'weekDay') {
+							// 濡傛灉鎸囧畾浜嗘槸鏄熸湡鍑�
+							// 鑾峰彇褰撳墠鏃ユ湡鏄睘浜庢槦鏈熷嚑
+							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
+							// 鏍¢獙褰撳墠鏄熸湡鏄惁鍦ㄦ槦鏈熸睜锛坉ayRuleSup锛変腑
+							if (this.dayRuleSup.indexOf(thisWeek) < 0) {
+								// 濡傛灉鍒拌揪鏈�澶у�兼椂
+								if (Di == DDate.length - 1) {
+									resetDay();
+									if (Mi == MDate.length - 1) {
+										resetMonth();
+										continue goYear;
+									}
+									continue goMonth;
+								}
+								continue;
+							}
+						} else if (this.dayRule == 'assWeek') {
+							// 濡傛灉鎸囧畾浜嗘槸绗嚑鍛ㄧ殑鏄熸湡鍑�
+							// 鑾峰彇姣忔湀1鍙锋槸灞炰簬鏄熸湡鍑�
+							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + DD + ' 00:00:00'), 'week');
+							if (this.dayRuleSup[1] >= thisWeek) {
+								DD = (this.dayRuleSup[0] - 1) * 7 + this.dayRuleSup[1] - thisWeek + 1;
+							} else {
+								DD = this.dayRuleSup[0] * 7 + this.dayRuleSup[1] - thisWeek + 1;
+							}
+						} else if (this.dayRule == 'lastWeek') {
+							// 濡傛灉鎸囧畾浜嗘瘡鏈堟渶鍚庝竴涓槦鏈熷嚑
+							// 鏍¢獙骞惰皟鏁村鏋滄槸2鏈�30鍙疯繖绉嶆棩鏈熶紶杩涙潵鏃堕渶璋冩暣鑷虫甯告湀搴�
+							if (this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+								while (DD > 0 && this.checkDate(YY + '-' + MM + '-' + thisDD + ' 00:00:00') !== true) {
+									DD--;
+									thisDD = DD < 10 ? '0' + DD : DD;
+								}
+							}
+							// 鑾峰彇鏈堟湯鏈�鍚庝竴澶╂槸鏄熸湡鍑�
+							let thisWeek = this.formatDate(new Date(YY + '-' + MM + '-' + thisDD + ' 00:00:00'), 'week');
+							// 鎵惧埌瑕佹眰涓渶杩戠殑閭d釜鏄熸湡鍑�
+							if (this.dayRuleSup < thisWeek) {
+								DD -= thisWeek - this.dayRuleSup;
+							} else if (this.dayRuleSup > thisWeek) {
+								DD -= 7 - (this.dayRuleSup - thisWeek)
+							}
+						}
+						// 鍒ゆ柇鏃堕棿鍊兼槸鍚﹀皬浜�10缃崲鎴愨��05鈥濊繖绉嶆牸寮�
+						DD = DD < 10 ? '0' + DD : DD;
+
+						// 寰幆鈥滄椂鈥濇暟缁�
+						goHour: for (let hi = hIdx; hi < hDate.length; hi++) {
+							let hh = hDate[hi] < 10 ? '0' + hDate[hi] : hDate[hi]
+
+							// 濡傛灉鍒拌揪鏈�澶у�兼椂
+							if (nMin > mDate[mDate.length - 1]) {
+								resetMin();
+								if (hi == hDate.length - 1) {
+									resetHour();
+									if (Di == DDate.length - 1) {
+										resetDay();
+										if (Mi == MDate.length - 1) {
+											resetMonth();
+											continue goYear;
+										}
+										continue goMonth;
+									}
+									continue goDay;
+								}
+								continue;
+							}
+							// 寰幆"鍒�"鏁扮粍
+							goMin: for (let mi = mIdx; mi < mDate.length; mi++) {
+								let mm = mDate[mi] < 10 ? '0' + mDate[mi] : mDate[mi];
+
+								// 濡傛灉鍒拌揪鏈�澶у�兼椂
+								if (nSecond > sDate[sDate.length - 1]) {
+									resetSecond();
+									if (mi == mDate.length - 1) {
+										resetMin();
+										if (hi == hDate.length - 1) {
+											resetHour();
+											if (Di == DDate.length - 1) {
+												resetDay();
+												if (Mi == MDate.length - 1) {
+													resetMonth();
+													continue goYear;
+												}
+												continue goMonth;
+											}
+											continue goDay;
+										}
+										continue goHour;
+									}
+									continue;
+								}
+								// 寰幆"绉�"鏁扮粍
+								goSecond: for (let si = sIdx; si <= sDate.length - 1; si++) {
+									let ss = sDate[si] < 10 ? '0' + sDate[si] : sDate[si];
+									// 娣诲姞褰撳墠鏃堕棿锛堟椂闂村悎娉曟�у湪鏃ユ湡寰幆鏃跺凡缁忓垽鏂級
+									if (MM !== '00' && DD !== '00') {
+										resultArr.push(YY + '-' + MM + '-' + DD + ' ' + hh + ':' + mm + ':' + ss)
+										nums++;
+									}
+									// 濡傛灉鏉℃暟婊′簡灏遍��鍑哄惊鐜�
+									if (nums == 5) break goYear;
+									// 濡傛灉鍒拌揪鏈�澶у�兼椂
+									if (si == sDate.length - 1) {
+										resetSecond();
+										if (mi == mDate.length - 1) {
+											resetMin();
+											if (hi == hDate.length - 1) {
+												resetHour();
+												if (Di == DDate.length - 1) {
+													resetDay();
+													if (Mi == MDate.length - 1) {
+														resetMonth();
+														continue goYear;
+													}
+													continue goMonth;
+												}
+												continue goDay;
+											}
+											continue goHour;
+										}
+										continue goMin;
+									}
+								} //goSecond
+							} //goMin
+						}//goHour
+					}//goDay
+				}//goMonth
+			}
+			// 鍒ゆ柇100骞村唴鐨勭粨鏋滄潯鏁�
+			if (resultArr.length == 0) {
+				this.resultList = ['娌℃湁杈惧埌鏉′欢鐨勭粨鏋滐紒'];
+			} else {
+				this.resultList = resultArr;
+				if (resultArr.length !== 5) {
+					this.resultList.push('鏈�杩�100骞村唴鍙湁涓婇潰' + resultArr.length + '鏉$粨鏋滐紒')
+				}
+			}
+			// 璁$畻瀹屾垚-鏄剧ず缁撴灉
+			this.isShow = true;
+
+
+		},
+		// 鐢ㄤ簬璁$畻鏌愪綅鏁板瓧鍦ㄦ暟缁勪腑鐨勭储寮�
+		getIndex(arr, value) {
+			if (value <= arr[0] || value > arr[arr.length - 1]) {
+				return 0;
+			} else {
+				for (let i = 0; i < arr.length - 1; i++) {
+					if (value > arr[i] && value <= arr[i + 1]) {
+						return i + 1;
+					}
+				}
+			}
+		},
+		// 鑾峰彇"骞�"鏁扮粍
+		getYearArr(rule, year) {
+			this.dateArr[5] = this.getOrderArr(year, year + 100);
+			if (rule !== undefined) {
+				if (rule.indexOf('-') >= 0) {
+					this.dateArr[5] = this.getCycleArr(rule, year + 100, false)
+				} else if (rule.indexOf('/') >= 0) {
+					this.dateArr[5] = this.getAverageArr(rule, year + 100)
+				} else if (rule !== '*') {
+					this.dateArr[5] = this.getAssignArr(rule)
+				}
+			}
+		},
+		// 鑾峰彇"鏈�"鏁扮粍
+		getMonthArr(rule) {
+			this.dateArr[4] = this.getOrderArr(1, 12);
+			if (rule.indexOf('-') >= 0) {
+				this.dateArr[4] = this.getCycleArr(rule, 12, false)
+			} else if (rule.indexOf('/') >= 0) {
+				this.dateArr[4] = this.getAverageArr(rule, 12)
+			} else if (rule !== '*') {
+				this.dateArr[4] = this.getAssignArr(rule)
+			}
+		},
+		// 鑾峰彇"鏃�"鏁扮粍-涓昏涓烘棩鏈熻鍒�
+		getWeekArr(rule) {
+			// 鍙湁褰撴棩鏈熻鍒欑殑涓や釜鍊煎潎涓衡�溾�濇椂鍒欒〃杈炬棩鏈熸槸鏈夐�夐」鐨�
+			if (this.dayRule == '' && this.dayRuleSup == '') {
+				if (rule.indexOf('-') >= 0) {
+					this.dayRule = 'weekDay';
+					this.dayRuleSup = this.getCycleArr(rule, 7, false)
+				} else if (rule.indexOf('#') >= 0) {
+					this.dayRule = 'assWeek';
+					let matchRule = rule.match(/[0-9]{1}/g);
+					this.dayRuleSup = [Number(matchRule[1]), Number(matchRule[0])];
+					this.dateArr[3] = [1];
+					if (this.dayRuleSup[1] == 7) {
+						this.dayRuleSup[1] = 0;
+					}
+				} else if (rule.indexOf('L') >= 0) {
+					this.dayRule = 'lastWeek';
+					this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
+					this.dateArr[3] = [31];
+					if (this.dayRuleSup == 7) {
+						this.dayRuleSup = 0;
+					}
+				} else if (rule !== '*' && rule !== '?') {
+					this.dayRule = 'weekDay';
+					this.dayRuleSup = this.getAssignArr(rule)
+				}
+			}
+		},
+		// 鑾峰彇"鏃�"鏁扮粍-灏戦噺涓烘棩鏈熻鍒�
+		getDayArr(rule) {
+			this.dateArr[3] = this.getOrderArr(1, 31);
+			this.dayRule = '';
+			this.dayRuleSup = '';
+			if (rule.indexOf('-') >= 0) {
+				this.dateArr[3] = this.getCycleArr(rule, 31, false)
+				this.dayRuleSup = 'null';
+			} else if (rule.indexOf('/') >= 0) {
+				this.dateArr[3] = this.getAverageArr(rule, 31)
+				this.dayRuleSup = 'null';
+			} else if (rule.indexOf('W') >= 0) {
+				this.dayRule = 'workDay';
+				this.dayRuleSup = Number(rule.match(/[0-9]{1,2}/g)[0]);
+				this.dateArr[3] = [this.dayRuleSup];
+			} else if (rule.indexOf('L') >= 0) {
+				this.dayRule = 'lastDay';
+				this.dayRuleSup = 'null';
+				this.dateArr[3] = [31];
+			} else if (rule !== '*' && rule !== '?') {
+				this.dateArr[3] = this.getAssignArr(rule)
+				this.dayRuleSup = 'null';
+			} else if (rule == '*') {
+				this.dayRuleSup = 'null';
+			}
+		},
+		// 鑾峰彇"鏃�"鏁扮粍
+		getHourArr(rule) {
+			this.dateArr[2] = this.getOrderArr(0, 23);
+			if (rule.indexOf('-') >= 0) {
+				this.dateArr[2] = this.getCycleArr(rule, 24, true)
+			} else if (rule.indexOf('/') >= 0) {
+				this.dateArr[2] = this.getAverageArr(rule, 23)
+			} else if (rule !== '*') {
+				this.dateArr[2] = this.getAssignArr(rule)
+			}
+		},
+		// 鑾峰彇"鍒�"鏁扮粍
+		getMinArr(rule) {
+			this.dateArr[1] = this.getOrderArr(0, 59);
+			if (rule.indexOf('-') >= 0) {
+				this.dateArr[1] = this.getCycleArr(rule, 60, true)
+			} else if (rule.indexOf('/') >= 0) {
+				this.dateArr[1] = this.getAverageArr(rule, 59)
+			} else if (rule !== '*') {
+				this.dateArr[1] = this.getAssignArr(rule)
+			}
+		},
+		// 鑾峰彇"绉�"鏁扮粍
+		getSecondArr(rule) {
+			this.dateArr[0] = this.getOrderArr(0, 59);
+			if (rule.indexOf('-') >= 0) {
+				this.dateArr[0] = this.getCycleArr(rule, 60, true)
+			} else if (rule.indexOf('/') >= 0) {
+				this.dateArr[0] = this.getAverageArr(rule, 59)
+			} else if (rule !== '*') {
+				this.dateArr[0] = this.getAssignArr(rule)
+			}
+		},
+		// 鏍规嵁浼犺繘鏉ョ殑min-max杩斿洖涓�涓『搴忕殑鏁扮粍
+		getOrderArr(min, max) {
+			let arr = [];
+			for (let i = min; i <= max; i++) {
+				arr.push(i);
+			}
+			return arr;
+		},
+		// 鏍规嵁瑙勫垯涓寚瀹氱殑闆舵暎鍊艰繑鍥炰竴涓暟缁�
+		getAssignArr(rule) {
+			let arr = [];
+			let assiginArr = rule.split(',');
+			for (let i = 0; i < assiginArr.length; i++) {
+				arr[i] = Number(assiginArr[i])
+			}
+			arr.sort(this.compare)
+			return arr;
+		},
+		// 鏍规嵁涓�瀹氱畻鏈鍒欒绠楄繑鍥炰竴涓暟缁�
+		getAverageArr(rule, limit) {
+			let arr = [];
+			let agArr = rule.split('/');
+			let min = Number(agArr[0]);
+			let step = Number(agArr[1]);
+			while (min <= limit) {
+				arr.push(min);
+				min += step;
+			}
+			return arr;
+		},
+		// 鏍规嵁瑙勫垯杩斿洖涓�涓叿鏈夊懆鏈熸�х殑鏁扮粍
+		getCycleArr(rule, limit, status) {
+			// status--琛ㄧず鏄惁浠�0寮�濮嬶紙鍒欎粠1寮�濮嬶級
+			let arr = [];
+			let cycleArr = rule.split('-');
+			let min = Number(cycleArr[0]);
+			let max = Number(cycleArr[1]);
+			if (min > max) {
+				max += limit;
+			}
+			for (let i = min; i <= max; i++) {
+				let add = 0;
+				if (status == false && i % limit == 0) {
+					add = limit;
+				}
+				arr.push(Math.round(i % limit + add))
+			}
+			arr.sort(this.compare)
+			return arr;
+		},
+		// 姣旇緝鏁板瓧澶у皬锛堢敤浜嶢rray.sort锛�
+		compare(value1, value2) {
+			if (value2 - value1 > 0) {
+				return -1;
+			} else {
+				return 1;
+			}
+		},
+		// 鏍煎紡鍖栨棩鏈熸牸寮忓锛�2017-9-19 18:04:33
+		formatDate(value, type) {
+			// 璁$畻鏃ユ湡鐩稿叧鍊�
+			let time = typeof value == 'number' ? new Date(value) : value;
+			let Y = time.getFullYear();
+			let M = time.getMonth() + 1;
+			let D = time.getDate();
+			let h = time.getHours();
+			let m = time.getMinutes();
+			let s = time.getSeconds();
+			let week = time.getDay();
+			// 濡傛灉浼犻�掍簡type鐨勮瘽
+			if (type == undefined) {
+				return Y + '-' + (M < 10 ? '0' + M : M) + '-' + (D < 10 ? '0' + D : D) + ' ' + (h < 10 ? '0' + h : h) + ':' + (m < 10 ? '0' + m : m) + ':' + (s < 10 ? '0' + s : s);
+			} else if (type == 'week') {
+				// 鍦╭uartz涓� 1涓烘槦鏈熸棩
+				return week + 1;
+			}
+		},
+		// 妫�鏌ユ棩鏈熸槸鍚﹀瓨鍦�
+		checkDate(value) {
+			let time = new Date(value);
+			let format = this.formatDate(time)
+			return value === format;
+		}
+	},
+	watch: {
+		'ex': 'expressionChange'
+	},
+	props: ['ex'],
+	mounted: function () {
+		// 鍒濆鍖� 鑾峰彇涓�娆$粨鏋�
+		this.expressionChange();
+	}
+}
+
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/second.vue b/ruoyi-ui/src/components/Crontab/second.vue
new file mode 100644
index 0000000..e7b7761
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/second.vue
@@ -0,0 +1,117 @@
+<template>
+	<el-form size="small">
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				绉掞紝鍏佽鐨勯�氶厤绗, - * /]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min="0" :max="58" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : 1" :max="59" /> 绉�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				浠�
+				<el-input-number v-model='average01' :min="0" :max="58" /> 绉掑紑濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="59 - average01 || 0" /> 绉掓墽琛屼竴娆�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="item in 60" :key="item" :value="item-1">{{item-1}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 1,
+			cycle01: 1,
+			cycle02: 2,
+			average01: 0,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-second',
+	props: ['check', 'radioParent'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'second', '*', 'second');
+					break;
+				case 2:
+					this.$emit('update', 'second', this.cycleTotal);
+					break;
+				case 3:
+					this.$emit('update', 'second', this.averageTotal);
+					break;
+				case 4:
+					this.$emit('update', 'second', this.checkboxString);
+					break;
+			}
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '2') {
+				this.$emit('update', 'second', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'second', this.averageTotal);
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'second', this.checkboxString);
+			}
+		}
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'checkboxString': 'checkboxChange',
+		radioParent() {
+			this.radioValue = this.radioParent
+		}
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, 0, 58)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : 1, 59)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, 0, 58)
+			const average02 = this.checkNum(this.average02, 1, 59 - average01 || 0)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/week.vue b/ruoyi-ui/src/components/Crontab/week.vue
new file mode 100644
index 0000000..1cec700
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/week.vue
@@ -0,0 +1,202 @@
+<template>
+	<el-form size='small'>
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="1">
+				鍛紝鍏佽鐨勯�氶厤绗, - * ? / L #]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="2">
+				涓嶆寚瀹�
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="3">
+				鍛ㄦ湡浠庢槦鏈�
+				<el-select clearable v-model="cycle01">
+					<el-option
+						v-for="(item,index) of weekList"
+						:key="index"
+						:label="item.value"
+						:value="item.key"
+						:disabled="item.key === 1"
+					>{{item.value}}</el-option>
+				</el-select>
+				-
+				<el-select clearable v-model="cycle02">
+					<el-option
+						v-for="(item,index) of weekList"
+						:key="index"
+						:label="item.value"
+						:value="item.key"
+						:disabled="item.key < cycle01 && item.key !== 1"
+					>{{item.value}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="4">
+				绗�
+				<el-input-number v-model='average01' :min="1" :max="4" /> 鍛ㄧ殑鏄熸湡
+				<el-select clearable v-model="average02">
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="5">
+				鏈湀鏈�鍚庝竴涓槦鏈�
+				<el-select clearable v-model="weekday">
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="item.key">{{item.value}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio v-model='radioValue' :label="6">
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple style="width:100%">
+					<el-option v-for="(item,index) of weekList" :key="index" :label="item.value" :value="String(item.key)">{{item.value}}</el-option>
+				</el-select>
+			</el-radio>
+		</el-form-item>
+
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			radioValue: 2,
+			weekday: 2,
+			cycle01: 2,
+			cycle02: 3,
+			average01: 1,
+			average02: 2,
+			checkboxList: [],
+			weekList: [
+				{
+					key: 2,
+					value: '鏄熸湡涓�'
+				},
+				{
+					key: 3,
+					value: '鏄熸湡浜�'
+				},
+				{
+					key: 4,
+					value: '鏄熸湡涓�'
+				},
+				{
+					key: 5,
+					value: '鏄熸湡鍥�'
+				},
+				{
+					key: 6,
+					value: '鏄熸湡浜�'
+				},
+				{
+					key: 7,
+					value: '鏄熸湡鍏�'
+				},
+				{
+					key: 1,
+					value: '鏄熸湡鏃�'
+				}
+			],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-week',
+	props: ['check', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			if (this.radioValue !== 2 && this.cron.day !== '?') {
+				this.$emit('update', 'day', '?', 'week');
+			}
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'week', '*');
+					break;
+				case 2:
+					this.$emit('update', 'week', '?');
+					break;
+				case 3:
+					this.$emit('update', 'week', this.cycleTotal);
+					break;
+				case 4:
+					this.$emit('update', 'week', this.averageTotal);
+					break;
+				case 5:
+					this.$emit('update', 'week', this.weekdayCheck + 'L');
+					break;
+				case 6:
+					this.$emit('update', 'week', this.checkboxString);
+					break;
+			}
+		},
+
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'week', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'week', this.averageTotal);
+			}
+		},
+		// 鏈�杩戝伐浣滄棩鍊煎彉鍖栨椂
+		weekdayChange() {
+			if (this.radioValue == '5') {
+				this.$emit('update', 'week', this.weekday + 'L');
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '6') {
+				this.$emit('update', 'week', this.checkboxString);
+			}
+		},
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'weekdayCheck': 'weekdayChange',
+		'checkboxString': 'checkboxChange',
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			this.cycle01 = this.checkNum(this.cycle01, 1, 7)
+			this.cycle02 = this.checkNum(this.cycle02, 1, 7)
+			return this.cycle01 + '-' + this.cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			this.average01 = this.checkNum(this.average01, 1, 4)
+			this.average02 = this.checkNum(this.average02, 1, 7)
+			return this.average02 + '#' + this.average01;
+		},
+		// 鏈�杩戠殑宸ヤ綔鏃ワ紙鏍煎紡锛�
+		weekdayCheck: function () {
+			this.weekday = this.checkNum(this.weekday, 1, 7)
+			return this.weekday;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str == '' ? '*' : str;
+		}
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/Crontab/year.vue b/ruoyi-ui/src/components/Crontab/year.vue
new file mode 100644
index 0000000..5487a6c
--- /dev/null
+++ b/ruoyi-ui/src/components/Crontab/year.vue
@@ -0,0 +1,131 @@
+<template>
+	<el-form size="small">
+		<el-form-item>
+			<el-radio :label="1" v-model='radioValue'>
+				涓嶅~锛屽厑璁哥殑閫氶厤绗, - * /]
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio :label="2" v-model='radioValue'>
+				姣忓勾
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio :label="3" v-model='radioValue'>
+				鍛ㄦ湡浠�
+				<el-input-number v-model='cycle01' :min='fullYear' :max="2098" /> -
+				<el-input-number v-model='cycle02' :min="cycle01 ? cycle01 + 1 : fullYear + 1" :max="2099" />
+			</el-radio>
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio :label="4" v-model='radioValue'>
+				浠�
+				<el-input-number v-model='average01' :min='fullYear' :max="2098"/> 骞村紑濮嬶紝姣�
+				<el-input-number v-model='average02' :min="1" :max="2099 - average01 || fullYear" /> 骞存墽琛屼竴娆�
+			</el-radio>
+
+		</el-form-item>
+
+		<el-form-item>
+			<el-radio :label="5" v-model='radioValue'>
+				鎸囧畾
+				<el-select clearable v-model="checkboxList" placeholder="鍙閫�" multiple>
+					<el-option v-for="item in 9" :key="item" :value="item - 1 + fullYear" :label="item -1 + fullYear" />
+				</el-select>
+			</el-radio>
+		</el-form-item>
+	</el-form>
+</template>
+
+<script>
+export default {
+	data() {
+		return {
+			fullYear: 0,
+			radioValue: 1,
+			cycle01: 0,
+			cycle02: 0,
+			average01: 0,
+			average02: 1,
+			checkboxList: [],
+			checkNum: this.$options.propsData.check
+		}
+	},
+	name: 'crontab-year',
+	props: ['check', 'month', 'cron'],
+	methods: {
+		// 鍗曢�夋寜閽�煎彉鍖栨椂
+		radioChange() {
+			switch (this.radioValue) {
+				case 1:
+					this.$emit('update', 'year', '');
+					break;
+				case 2:
+					this.$emit('update', 'year', '*');
+					break;
+				case 3:
+					this.$emit('update', 'year', this.cycleTotal);
+					break;
+				case 4:
+					this.$emit('update', 'year', this.averageTotal);
+					break;
+				case 5:
+					this.$emit('update', 'year', this.checkboxString);
+					break;
+			}
+		},
+		// 鍛ㄦ湡涓や釜鍊煎彉鍖栨椂
+		cycleChange() {
+			if (this.radioValue == '3') {
+				this.$emit('update', 'year', this.cycleTotal);
+			}
+		},
+		// 骞冲潎涓や釜鍊煎彉鍖栨椂
+		averageChange() {
+			if (this.radioValue == '4') {
+				this.$emit('update', 'year', this.averageTotal);
+			}
+		},
+		// checkbox鍊煎彉鍖栨椂
+		checkboxChange() {
+			if (this.radioValue == '5') {
+				this.$emit('update', 'year', this.checkboxString);
+			}
+		}
+	},
+	watch: {
+		'radioValue': 'radioChange',
+		'cycleTotal': 'cycleChange',
+		'averageTotal': 'averageChange',
+		'checkboxString': 'checkboxChange'
+	},
+	computed: {
+		// 璁$畻涓や釜鍛ㄦ湡鍊�
+		cycleTotal: function () {
+			const cycle01 = this.checkNum(this.cycle01, this.fullYear, 2098)
+			const cycle02 = this.checkNum(this.cycle02, cycle01 ? cycle01 + 1 : this.fullYear + 1, 2099)
+			return cycle01 + '-' + cycle02;
+		},
+		// 璁$畻骞冲潎鐢ㄥ埌鐨勫��
+		averageTotal: function () {
+			const average01 = this.checkNum(this.average01, this.fullYear, 2098)
+			const average02 = this.checkNum(this.average02, 1, 2099 - average01 || this.fullYear)
+			return average01 + '/' + average02;
+		},
+		// 璁$畻鍕鹃�夌殑checkbox鍊煎悎闆�
+		checkboxString: function () {
+			let str = this.checkboxList.join();
+			return str;
+		}
+	},
+	mounted: function () {
+		// 浠呰幏鍙栧綋鍓嶅勾浠�
+		this.fullYear = Number(new Date().getFullYear());
+		this.cycle01 = this.fullYear
+		this.average01 = this.fullYear
+	}
+}
+</script>
diff --git a/ruoyi-ui/src/components/DictData/index.js b/ruoyi-ui/src/components/DictData/index.js
new file mode 100644
index 0000000..7b85d4a
--- /dev/null
+++ b/ruoyi-ui/src/components/DictData/index.js
@@ -0,0 +1,49 @@
+import Vue from 'vue'
+import store from '@/store'
+import DataDict from '@/utils/dict'
+import { getDicts as getDicts } from '@/api/system/dict/data'
+
+function searchDictByKey(dict, key) {
+  if (key == null && key == "") {
+    return null
+  }
+  try {
+    for (let i = 0; i < dict.length; i++) {
+      if (dict[i].key == key) {
+        return dict[i].value
+      }
+    }
+  } catch (e) {
+    return null
+  }
+}
+
+function install() {
+  Vue.use(DataDict, {
+    metas: {
+      '*': {
+        labelField: 'dictLabel',
+        valueField: 'dictValue',
+        request(dictMeta) {
+          const storeDict = searchDictByKey(store.getters.dict, dictMeta.type)
+          if (storeDict) {
+            return new Promise(resolve => { resolve(storeDict) })
+          } else {
+            return new Promise((resolve, reject) => {
+              getDicts(dictMeta.type).then(res => {
+                store.dispatch('dict/setDict', { key: dictMeta.type, value: res.data })
+                resolve(res.data)
+              }).catch(error => {
+                reject(error)
+              })
+            })
+          }
+        },
+      },
+    },
+  })
+}
+
+export default {
+  install,
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/components/DictTag/index.vue b/ruoyi-ui/src/components/DictTag/index.vue
new file mode 100644
index 0000000..6b5b230
--- /dev/null
+++ b/ruoyi-ui/src/components/DictTag/index.vue
@@ -0,0 +1,89 @@
+<template>
+  <div>
+    <template v-for="(item, index) in options">
+      <template v-if="values.includes(item.value)">
+        <span
+          v-if="(item.raw.listClass == 'default' || item.raw.listClass == '') && (item.raw.cssClass == '' || item.raw.cssClass == null)"
+          :key="item.value"
+          :index="index"
+          :class="item.raw.cssClass"
+          >{{ item.label + ' ' }}</span
+        >
+        <el-tag
+          v-else
+          :disable-transitions="true"
+          :key="item.value"
+          :index="index"
+          :type="item.raw.listClass == 'primary' ? '' : item.raw.listClass"
+          :class="item.raw.cssClass"
+        >
+          {{ item.label + ' ' }}
+        </el-tag>
+      </template>
+    </template>
+    <template v-if="unmatch && showValue">
+      {{ unmatchArray | handleArray }}
+    </template>
+  </div>
+</template>
+
+<script>
+export default {
+  name: "DictTag",
+  props: {
+    options: {
+      type: Array,
+      default: null,
+    },
+    value: [Number, String, Array],
+    // 褰撴湭鎵惧埌鍖归厤鐨勬暟鎹椂锛屾樉绀簐alue
+    showValue: {
+      type: Boolean,
+      default: true,
+    },
+    separator: {
+      type: String,
+      default: ","
+    }
+  },
+  data() {
+    return {
+      unmatchArray: [], // 璁板綍鏈尮閰嶇殑椤�
+    }
+  },
+  computed: {
+    values() {
+      if (this.value === null || typeof this.value === 'undefined' || this.value === '') return []
+      return Array.isArray(this.value) ? this.value.map(item => '' + item) : String(this.value).split(this.separator)
+    },
+    unmatch() {
+      this.unmatchArray = []
+      // 娌℃湁value涓嶆樉绀�
+      if (this.value === null || typeof this.value === 'undefined' || this.value === '' || this.options.length === 0) return false
+      // 浼犲叆鍊间负鏁扮粍
+      let unmatch = false // 娣诲姞涓�涓爣蹇楁潵鍒ゆ柇鏄惁鏈夋湭鍖归厤椤�
+      this.values.forEach(item => {
+        if (!this.options.some(v => v.value === item)) {
+          this.unmatchArray.push(item)
+          unmatch = true // 濡傛灉鏈夋湭鍖归厤椤癸紝灏嗘爣蹇楄缃负true
+        }
+      })
+      return unmatch // 杩斿洖鏍囧織鐨勫��
+    },
+
+  },
+  filters: {
+    handleArray(array) {
+      if (array.length === 0) return '';
+      return array.reduce((pre, cur) => {
+        return pre + ' ' + cur;
+      })
+    },
+  }
+};
+</script>
+<style scoped>
+.el-tag + .el-tag {
+  margin-left: 10px;
+}
+</style>
diff --git a/ruoyi-ui/src/components/Editor/index.vue b/ruoyi-ui/src/components/Editor/index.vue
new file mode 100644
index 0000000..9323e53
--- /dev/null
+++ b/ruoyi-ui/src/components/Editor/index.vue
@@ -0,0 +1,274 @@
+<template>
+  <div>
+    <el-upload
+      :action="uploadUrl"
+      :before-upload="handleBeforeUpload"
+      :on-success="handleUploadSuccess"
+      :on-error="handleUploadError"
+      name="file"
+      :show-file-list="false"
+      :headers="headers"
+      style="display: none"
+      ref="upload"
+      v-if="this.type == 'url'"
+    >
+    </el-upload>
+    <div class="editor" ref="editor" :style="styles"></div>
+  </div>
+</template>
+
+<script>
+import Quill from "quill";
+import "quill/dist/quill.core.css";
+import "quill/dist/quill.snow.css";
+import "quill/dist/quill.bubble.css";
+import { getToken } from "@/utils/auth";
+
+export default {
+  name: "Editor",
+  props: {
+    /* 缂栬緫鍣ㄧ殑鍐呭 */
+    value: {
+      type: String,
+      default: "",
+    },
+    /* 楂樺害 */
+    height: {
+      type: Number,
+      default: null,
+    },
+    /* 鏈�灏忛珮搴� */
+    minHeight: {
+      type: Number,
+      default: null,
+    },
+    /* 鍙 */
+    readOnly: {
+      type: Boolean,
+      default: false,
+    },
+    /* 涓婁紶鏂囦欢澶у皬闄愬埗(MB) */
+    fileSize: {
+      type: Number,
+      default: 5,
+    },
+    /* 绫诲瀷锛坆ase64鏍煎紡銆乽rl鏍煎紡锛� */
+    type: {
+      type: String,
+      default: "url",
+    }
+  },
+  data() {
+    return {
+      uploadUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+      headers: {
+        Authorization: "Bearer " + getToken()
+      },
+      Quill: null,
+      currentValue: "",
+      options: {
+        theme: "snow",
+        bounds: document.body,
+        debug: "warn",
+        modules: {
+          // 宸ュ叿鏍忛厤缃�
+          toolbar: [
+            ["bold", "italic", "underline", "strike"],       // 鍔犵矖 鏂滀綋 涓嬪垝绾� 鍒犻櫎绾�
+            ["blockquote", "code-block"],                    // 寮曠敤  浠g爜鍧�
+            [{ list: "ordered" }, { list: "bullet" }],       // 鏈夊簭銆佹棤搴忓垪琛�
+            [{ indent: "-1" }, { indent: "+1" }],            // 缂╄繘
+            [{ size: ["small", false, "large", "huge"] }],   // 瀛椾綋澶у皬
+            [{ header: [1, 2, 3, 4, 5, 6, false] }],         // 鏍囬
+            [{ color: [] }, { background: [] }],             // 瀛椾綋棰滆壊銆佸瓧浣撹儗鏅鑹�
+            [{ align: [] }],                                 // 瀵归綈鏂瑰紡
+            ["clean"],                                       // 娓呴櫎鏂囨湰鏍煎紡
+            ["link", "image", "video"]                       // 閾炬帴銆佸浘鐗囥�佽棰�
+          ],
+        },
+        placeholder: "璇疯緭鍏ュ唴瀹�",
+        readOnly: this.readOnly,
+      },
+    };
+  },
+  computed: {
+    styles() {
+      let style = {};
+      if (this.minHeight) {
+        style.minHeight = `${this.minHeight}px`;
+      }
+      if (this.height) {
+        style.height = `${this.height}px`;
+      }
+      return style;
+    },
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val !== this.currentValue) {
+          this.currentValue = val === null ? "" : val;
+          if (this.Quill) {
+            this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue);
+          }
+        }
+      },
+      immediate: true,
+    },
+  },
+  mounted() {
+    this.init();
+  },
+  beforeDestroy() {
+    this.Quill = null;
+  },
+  methods: {
+    init() {
+      const editor = this.$refs.editor;
+      this.Quill = new Quill(editor, this.options);
+      // 濡傛灉璁剧疆浜嗕笂浼犲湴鍧�鍒欒嚜瀹氫箟鍥剧墖涓婁紶浜嬩欢
+      if (this.type == 'url') {
+        let toolbar = this.Quill.getModule("toolbar");
+        toolbar.addHandler("image", (value) => {
+          if (value) {
+            this.$refs.upload.$children[0].$refs.input.click();
+          } else {
+            this.quill.format("image", false);
+          }
+        });
+      }
+      this.Quill.clipboard.dangerouslyPasteHTML(this.currentValue);
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        const html = this.$refs.editor.children[0].innerHTML;
+        const text = this.Quill.getText();
+        const quill = this.Quill;
+        this.currentValue = html;
+        this.$emit("input", html);
+        this.$emit("on-change", { html, text, quill });
+      });
+      this.Quill.on("text-change", (delta, oldDelta, source) => {
+        this.$emit("on-text-change", delta, oldDelta, source);
+      });
+      this.Quill.on("selection-change", (range, oldRange, source) => {
+        this.$emit("on-selection-change", range, oldRange, source);
+      });
+      this.Quill.on("editor-change", (eventName, ...args) => {
+        this.$emit("on-editor-change", eventName, ...args);
+      });
+    },
+    // 涓婁紶鍓嶆牎妫�鏍煎紡鍜屽ぇ灏�
+    handleBeforeUpload(file) {
+      const type = ["image/jpeg", "image/jpg", "image/png", "image/svg"];
+      const isJPG = type.includes(file.type);
+      // 妫�楠屾枃浠舵牸寮�
+      if (!isJPG) {
+        this.$message.error(`鍥剧墖鏍煎紡閿欒!`);
+        return false;
+      }
+      // 鏍℃鏂囦欢澶у皬
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$message.error(`涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      return true;
+    },
+    handleUploadSuccess(res, file) {
+      // 濡傛灉涓婁紶鎴愬姛
+      if (res.code == 200) {
+        // 鑾峰彇瀵屾枃鏈粍浠跺疄渚�
+        let quill = this.Quill;
+        // 鑾峰彇鍏夋爣鎵�鍦ㄤ綅缃�
+        let length = quill.getSelection().index;
+        // 鎻掑叆鍥剧墖  res.url涓烘湇鍔″櫒杩斿洖鐨勫浘鐗囧湴鍧�
+        quill.insertEmbed(length, "image", process.env.VUE_APP_BASE_API + res.fileName);
+        // 璋冩暣鍏夋爣鍒版渶鍚�
+        quill.setSelection(length + 1);
+      } else {
+        this.$message.error("鍥剧墖鎻掑叆澶辫触");
+      }
+    },
+    handleUploadError() {
+      this.$message.error("鍥剧墖鎻掑叆澶辫触");
+    },
+  },
+};
+</script>
+
+<style>
+.editor, .ql-toolbar {
+  white-space: pre-wrap !important;
+  line-height: normal !important;
+}
+.quill-img {
+  display: none;
+}
+.ql-snow .ql-tooltip[data-mode="link"]::before {
+  content: "璇疯緭鍏ラ摼鎺ュ湴鍧�:";
+}
+.ql-snow .ql-tooltip.ql-editing a.ql-action::after {
+  border-right: 0px;
+  content: "淇濆瓨";
+  padding-right: 0px;
+}
+.ql-snow .ql-tooltip[data-mode="video"]::before {
+  content: "璇疯緭鍏ヨ棰戝湴鍧�:";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item::before {
+  content: "14px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="small"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="small"]::before {
+  content: "10px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="large"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="large"]::before {
+  content: "18px";
+}
+.ql-snow .ql-picker.ql-size .ql-picker-label[data-value="huge"]::before,
+.ql-snow .ql-picker.ql-size .ql-picker-item[data-value="huge"]::before {
+  content: "32px";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item::before {
+  content: "鏂囨湰";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="1"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="1"]::before {
+  content: "鏍囬1";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="2"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="2"]::before {
+  content: "鏍囬2";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="3"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="3"]::before {
+  content: "鏍囬3";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="4"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="4"]::before {
+  content: "鏍囬4";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="5"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="5"]::before {
+  content: "鏍囬5";
+}
+.ql-snow .ql-picker.ql-header .ql-picker-label[data-value="6"]::before,
+.ql-snow .ql-picker.ql-header .ql-picker-item[data-value="6"]::before {
+  content: "鏍囬6";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item::before {
+  content: "鏍囧噯瀛椾綋";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="serif"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="serif"]::before {
+  content: "琛嚎瀛椾綋";
+}
+.ql-snow .ql-picker.ql-font .ql-picker-label[data-value="monospace"]::before,
+.ql-snow .ql-picker.ql-font .ql-picker-item[data-value="monospace"]::before {
+  content: "绛夊瀛椾綋";
+}
+</style>
diff --git a/ruoyi-ui/src/components/FileUpload/index.vue b/ruoyi-ui/src/components/FileUpload/index.vue
new file mode 100644
index 0000000..12ad4ea
--- /dev/null
+++ b/ruoyi-ui/src/components/FileUpload/index.vue
@@ -0,0 +1,221 @@
+<template>
+  <div class="upload-file">
+    <el-upload
+      multiple
+      :action="uploadFileUrl"
+      :before-upload="handleBeforeUpload"
+      :file-list="fileList"
+      :limit="limit"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      :on-success="handleUploadSuccess"
+      :show-file-list="false"
+      :headers="headers"
+      class="upload-file-uploader"
+      ref="fileUpload"
+    >
+      <!-- 涓婁紶鎸夐挳 -->
+      <el-button size="mini" type="primary">閫夊彇鏂囦欢</el-button>
+      <!-- 涓婁紶鎻愮ず -->
+      <div class="el-upload__tip" slot="tip" v-if="showTip">
+        璇蜂笂浼�
+        <template v-if="fileSize"> 澶у皬涓嶈秴杩� <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+        <template v-if="fileType"> 鏍煎紡涓� <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+        鐨勬枃浠�
+      </div>
+    </el-upload>
+
+    <!-- 鏂囦欢鍒楄〃 -->
+    <transition-group class="upload-file-list el-upload-list el-upload-list--text" name="el-fade-in-linear" tag="ul">
+      <li :key="file.url" class="el-upload-list__item ele-upload-list__item-content" v-for="(file, index) in fileList">
+        <el-link :href="`${baseUrl}${file.url}`" :underline="false" target="_blank">
+          <span class="el-icon-document"> {{ getFileName(file.name) }} </span>
+        </el-link>
+        <div class="ele-upload-list__item-content-action">
+          <el-link :underline="false" @click="handleDelete(index)" type="danger">鍒犻櫎</el-link>
+        </div>
+      </li>
+    </transition-group>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+
+export default {
+  name: "FileUpload",
+  props: {
+    // 鍊�
+    value: [String, Object, Array],
+    // 鏁伴噺闄愬埗
+    limit: {
+      type: Number,
+      default: 5,
+    },
+    // 澶у皬闄愬埗(MB)
+    fileSize: {
+      type: Number,
+      default: 5,
+    },
+    // 鏂囦欢绫诲瀷, 渚嬪['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["doc", "xls", "ppt", "txt", "pdf"],
+    },
+    // 鏄惁鏄剧ず鎻愮ず
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      number: 0,
+      uploadList: [],
+      baseUrl: process.env.VUE_APP_BASE_API,
+      uploadFileUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鏂囦欢鏈嶅姟鍣ㄥ湴鍧�
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: [],
+    };
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          let temp = 1;
+          // 棣栧厛灏嗗�艰浆涓烘暟缁�
+          const list = Array.isArray(val) ? val : this.value.split(',');
+          // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁�
+          this.fileList = list.map(item => {
+            if (typeof item === "string") {
+              item = { name: item, url: item };
+            }
+            item.uid = item.uid || new Date().getTime() + temp++;
+            return item;
+          });
+        } else {
+          this.fileList = [];
+          return [];
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  computed: {
+    // 鏄惁鏄剧ず鎻愮ず
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+  },
+  methods: {
+    // 涓婁紶鍓嶆牎妫�鏍煎紡鍜屽ぇ灏�
+    handleBeforeUpload(file) {
+      // 鏍℃鏂囦欢绫诲瀷
+      if (this.fileType) {
+        const fileName = file.name.split('.');
+        const fileExt = fileName[fileName.length - 1];
+        const isTypeOk = this.fileType.indexOf(fileExt) >= 0;
+        if (!isTypeOk) {
+          this.$modal.msgError(`鏂囦欢鏍煎紡涓嶆纭紝璇蜂笂浼�${this.fileType.join("/")}鏍煎紡鏂囦欢!`);
+          return false;
+        }
+      }
+      // 鏍℃鏂囦欢鍚嶆槸鍚﹀寘鍚壒娈婂瓧绗�
+      if (file.name.includes(',')) {
+        this.$modal.msgError('鏂囦欢鍚嶄笉姝g‘锛屼笉鑳藉寘鍚嫳鏂囬�楀彿!');
+        return false;
+      }
+      // 鏍℃鏂囦欢澶у皬
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$modal.msgError(`涓婁紶鏂囦欢澶у皬涓嶈兘瓒呰繃 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      this.$modal.loading("姝e湪涓婁紶鏂囦欢锛岃绋嶅��...");
+      this.number++;
+      return true;
+    },
+    // 鏂囦欢涓暟瓒呭嚭
+    handleExceed() {
+      this.$modal.msgError(`涓婁紶鏂囦欢鏁伴噺涓嶈兘瓒呰繃 ${this.limit} 涓�!`);
+    },
+    // 涓婁紶澶辫触
+    handleUploadError(err) {
+      this.$modal.msgError("涓婁紶鏂囦欢澶辫触锛岃閲嶈瘯");
+      this.$modal.closeLoading();
+    },
+    // 涓婁紶鎴愬姛鍥炶皟
+    handleUploadSuccess(res, file) {
+      if (res.code === 200) {
+        this.uploadList.push({ name: res.fileName, url: res.fileName });
+        this.uploadedSuccessfully();
+      } else {
+        this.number--;
+        this.$modal.closeLoading();
+        this.$modal.msgError(res.msg);
+        this.$refs.fileUpload.handleRemove(file);
+        this.uploadedSuccessfully();
+      }
+    },
+    // 鍒犻櫎鏂囦欢
+    handleDelete(index) {
+      this.fileList.splice(index, 1);
+      this.$emit("input", this.listToString(this.fileList));
+    },
+    // 涓婁紶缁撴潫澶勭悊
+    uploadedSuccessfully() {
+      if (this.number > 0 && this.uploadList.length === this.number) {
+        this.fileList = this.fileList.concat(this.uploadList);
+        this.uploadList = [];
+        this.number = 0;
+        this.$emit("input", this.listToString(this.fileList));
+        this.$modal.closeLoading();
+      }
+    },
+    // 鑾峰彇鏂囦欢鍚嶇О
+    getFileName(name) {
+      // 濡傛灉鏄痷rl閭d箞鍙栨渶鍚庣殑鍚嶅瓧 濡傛灉涓嶆槸鐩存帴杩斿洖
+      if (name.lastIndexOf("/") > -1) {
+        return name.slice(name.lastIndexOf("/") + 1);
+      } else {
+        return name;
+      }
+    },
+    // 瀵硅薄杞垚鎸囧畾瀛楃涓插垎闅�
+    listToString(list, separator) {
+      let strs = "";
+      separator = separator || ",";
+      for (let i in list) {
+        strs += list[i].url + separator;
+      }
+      return strs != '' ? strs.substr(0, strs.length - 1) : '';
+    }
+  }
+};
+</script>
+
+<style scoped lang="scss">
+.upload-file-uploader {
+  margin-bottom: 5px;
+}
+.upload-file-list .el-upload-list__item {
+  border: 1px solid #e4e7ed;
+  line-height: 2;
+  margin-bottom: 10px;
+  position: relative;
+}
+.upload-file-list .ele-upload-list__item-content {
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+  color: inherit;
+}
+.ele-upload-list__item-content-action .el-link {
+  margin-right: 10px;
+}
+</style>
diff --git a/ruoyi-ui/src/components/Hamburger/index.vue b/ruoyi-ui/src/components/Hamburger/index.vue
new file mode 100644
index 0000000..368b002
--- /dev/null
+++ b/ruoyi-ui/src/components/Hamburger/index.vue
@@ -0,0 +1,44 @@
+<template>
+  <div style="padding: 0 15px;" @click="toggleClick">
+    <svg
+      :class="{'is-active':isActive}"
+      class="hamburger"
+      viewBox="0 0 1024 1024"
+      xmlns="http://www.w3.org/2000/svg"
+      width="64"
+      height="64"
+    >
+      <path d="M408 442h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8zm-8 204c0 4.4 3.6 8 8 8h480c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8H408c-4.4 0-8 3.6-8 8v56zm504-486H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zm0 632H120c-4.4 0-8 3.6-8 8v56c0 4.4 3.6 8 8 8h784c4.4 0 8-3.6 8-8v-56c0-4.4-3.6-8-8-8zM142.4 642.1L298.7 519a8.84 8.84 0 0 0 0-13.9L142.4 381.9c-5.8-4.6-14.4-.5-14.4 6.9v246.3a8.9 8.9 0 0 0 14.4 7z" />
+    </svg>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'Hamburger',
+  props: {
+    isActive: {
+      type: Boolean,
+      default: false
+    }
+  },
+  methods: {
+    toggleClick() {
+      this.$emit('toggleClick')
+    }
+  }
+}
+</script>
+
+<style scoped>
+.hamburger {
+  display: inline-block;
+  vertical-align: middle;
+  width: 20px;
+  height: 20px;
+}
+
+.hamburger.is-active {
+  transform: rotate(180deg);
+}
+</style>
diff --git a/ruoyi-ui/src/components/HeaderSearch/index.vue b/ruoyi-ui/src/components/HeaderSearch/index.vue
new file mode 100644
index 0000000..339a688
--- /dev/null
+++ b/ruoyi-ui/src/components/HeaderSearch/index.vue
@@ -0,0 +1,196 @@
+<template>
+  <div :class="{'show':show}" class="header-search">
+    <svg-icon class-name="search-icon" icon-class="search" @click.stop="click" />
+    <el-select
+      ref="headerSearchSelect"
+      v-model="search"
+      :remote-method="querySearch"
+      filterable
+      default-first-option
+      remote
+      placeholder="Search"
+      class="header-search-select"
+      @change="change"
+    >
+      <el-option v-for="option in options" :key="option.item.path" :value="option.item" :label="option.item.title.join(' > ')" />
+    </el-select>
+  </div>
+</template>
+
+<script>
+// fuse is a lightweight fuzzy-search module
+// make search results more in line with expectations
+import Fuse from 'fuse.js/dist/fuse.min.js'
+import path from 'path'
+import { isHttp } from '@/utils/validate'
+
+export default {
+  name: 'HeaderSearch',
+  data() {
+    return {
+      search: '',
+      options: [],
+      searchPool: [],
+      show: false,
+      fuse: undefined
+    }
+  },
+  computed: {
+    routes() {
+      return this.$store.getters.permission_routes
+    }
+  },
+  watch: {
+    routes() {
+      this.searchPool = this.generateRoutes(this.routes)
+    },
+    searchPool(list) {
+      this.initFuse(list)
+    },
+    show(value) {
+      if (value) {
+        document.body.addEventListener('click', this.close)
+      } else {
+        document.body.removeEventListener('click', this.close)
+      }
+    }
+  },
+  mounted() {
+    this.searchPool = this.generateRoutes(this.routes)
+  },
+  methods: {
+    click() {
+      this.show = !this.show
+      if (this.show) {
+        this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.focus()
+      }
+    },
+    close() {
+      this.$refs.headerSearchSelect && this.$refs.headerSearchSelect.blur()
+      this.options = []
+      this.show = false
+    },
+    change(val) {
+      const path = val.path;
+      const query = val.query;
+      if(isHttp(val.path)) {
+        // http(s):// 璺緞鏂扮獥鍙f墦寮�
+        const pindex = path.indexOf("http");
+        window.open(path.substr(pindex, path.length), "_blank");
+      } else {
+        if (query) {
+          this.$router.push({ path: path, query: JSON.parse(query) });
+        } else {
+          this.$router.push(path)
+        }
+      }
+      this.search = ''
+      this.options = []
+      this.$nextTick(() => {
+        this.show = false
+      })
+    },
+    initFuse(list) {
+      this.fuse = new Fuse(list, {
+        shouldSort: true,
+        threshold: 0.4,
+        location: 0,
+        distance: 100,
+        minMatchCharLength: 1,
+        keys: [{
+          name: 'title',
+          weight: 0.7
+        }, {
+          name: 'path',
+          weight: 0.3
+        }]
+      })
+    },
+    // Filter out the routes that can be displayed in the sidebar
+    // And generate the internationalized title
+    generateRoutes(routes, basePath = '/', prefixTitle = []) {
+      let res = []
+
+      for (const router of routes) {
+        // skip hidden router
+        if (router.hidden) { continue }
+
+        const data = {
+          path: !isHttp(router.path) ? path.resolve(basePath, router.path) : router.path,
+          title: [...prefixTitle]
+        }
+
+        if (router.meta && router.meta.title) {
+          data.title = [...data.title, router.meta.title]
+
+          if (router.redirect !== 'noRedirect') {
+            // only push the routes with title
+            // special case: need to exclude parent router without redirect
+            res.push(data)
+          }
+        }
+
+        if (router.query) {
+          data.query = router.query
+        }
+
+        // recursive child routes
+        if (router.children) {
+          const tempRoutes = this.generateRoutes(router.children, data.path, data.title)
+          if (tempRoutes.length >= 1) {
+            res = [...res, ...tempRoutes]
+          }
+        }
+      }
+      return res
+    },
+    querySearch(query) {
+      if (query !== '') {
+        this.options = this.fuse.search(query)
+      } else {
+        this.options = []
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.header-search {
+  font-size: 0 !important;
+
+  .search-icon {
+    cursor: pointer;
+    font-size: 18px;
+    vertical-align: middle;
+  }
+
+  .header-search-select {
+    font-size: 18px;
+    transition: width 0.2s;
+    width: 0;
+    overflow: hidden;
+    background: transparent;
+    border-radius: 0;
+    display: inline-block;
+    vertical-align: middle;
+
+    ::v-deep .el-input__inner {
+      border-radius: 0;
+      border: 0;
+      padding-left: 0;
+      padding-right: 0;
+      box-shadow: none !important;
+      border-bottom: 1px solid #d9d9d9;
+      vertical-align: middle;
+    }
+  }
+
+  &.show {
+    .header-search-select {
+      width: 210px;
+      margin-left: 10px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/IconSelect/index.vue b/ruoyi-ui/src/components/IconSelect/index.vue
new file mode 100644
index 0000000..8dadc02
--- /dev/null
+++ b/ruoyi-ui/src/components/IconSelect/index.vue
@@ -0,0 +1,104 @@
+<!-- @author zhengjie -->
+<template>
+  <div class="icon-body">
+    <el-input v-model="name" class="icon-search" clearable placeholder="璇疯緭鍏ュ浘鏍囧悕绉�" @clear="filterIcons" @input="filterIcons">
+      <i slot="suffix" class="el-icon-search el-input__icon" />
+    </el-input>
+    <div class="icon-list">
+      <div class="list-container">
+        <div v-for="(item, index) in iconList" class="icon-item-wrapper" :key="index" @click="selectedIcon(item)">
+          <div :class="['icon-item', { active: activeIcon === item }]">
+            <svg-icon :icon-class="item" class-name="icon" style="height: 25px;width: 16px;"/>
+            <span>{{ item }}</span>
+          </div>
+        </div>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+import icons from './requireIcons'
+export default {
+  name: 'IconSelect',
+  props: {
+    activeIcon: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      name: '',
+      iconList: icons
+    }
+  },
+  methods: {
+    filterIcons() {
+      this.iconList = icons
+      if (this.name) {
+        this.iconList = this.iconList.filter(item => item.includes(this.name))
+      }
+    },
+    selectedIcon(name) {
+      this.$emit('selected', name)
+      document.body.click()
+    },
+    reset() {
+      this.name = ''
+      this.iconList = icons
+    }
+  }
+}
+</script>
+
+<style rel="stylesheet/scss" lang="scss" scoped>
+  .icon-body {
+    width: 100%;
+    padding: 10px;
+    .icon-search {
+      position: relative;
+      margin-bottom: 5px;
+    }
+    .icon-list {
+      height: 200px;
+      overflow: auto;
+      .list-container {
+        display: flex;
+        flex-wrap: wrap;
+        .icon-item-wrapper {
+          width: calc(100% / 3);
+          height: 25px;
+          line-height: 25px;
+          cursor: pointer;
+          display: flex;
+          .icon-item {
+            display: flex;
+            max-width: 100%;
+            height: 100%;
+            padding: 0 5px;
+            &:hover {
+              background: #ececec;
+              border-radius: 5px;
+            }
+            .icon {
+              flex-shrink: 0;
+            }
+            span {
+              display: inline-block;
+              vertical-align: -0.15em;
+              fill: currentColor;
+              padding-left: 2px;
+              overflow: hidden;
+              text-overflow: ellipsis;
+              white-space: nowrap;
+            }
+          }
+          .icon-item.active {
+            background: #ececec;
+            border-radius: 5px;
+          }
+        }
+      }
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/components/IconSelect/requireIcons.js b/ruoyi-ui/src/components/IconSelect/requireIcons.js
new file mode 100644
index 0000000..99e5c54
--- /dev/null
+++ b/ruoyi-ui/src/components/IconSelect/requireIcons.js
@@ -0,0 +1,11 @@
+
+const req = require.context('../../assets/icons/svg', false, /\.svg$/)
+const requireAll = requireContext => requireContext.keys()
+
+const re = /\.\/(.*)\.svg/
+
+const icons = requireAll(req).map(i => {
+  return i.match(re)[1]
+})
+
+export default icons
diff --git a/ruoyi-ui/src/components/ImagePreview/index.vue b/ruoyi-ui/src/components/ImagePreview/index.vue
new file mode 100644
index 0000000..3c770c7
--- /dev/null
+++ b/ruoyi-ui/src/components/ImagePreview/index.vue
@@ -0,0 +1,90 @@
+<template>
+  <el-image
+    :src="`${realSrc}`"
+    fit="cover"
+    :style="`width:${realWidth};height:${realHeight};`"
+    :preview-src-list="realSrcList"
+  >
+    <div slot="error" class="image-slot">
+      <i class="el-icon-picture-outline"></i>
+    </div>
+  </el-image>
+</template>
+
+<script>
+import { isExternal } from "@/utils/validate";
+
+export default {
+  name: "ImagePreview",
+  props: {
+    src: {
+      type: String,
+      default: ""
+    },
+    width: {
+      type: [Number, String],
+      default: ""
+    },
+    height: {
+      type: [Number, String],
+      default: ""
+    }
+  },
+  computed: {
+    realSrc() {
+      if (!this.src) {
+        return;
+      }
+      let real_src = this.src.split(",")[0];
+      if (isExternal(real_src)) {
+        return real_src;
+      }
+      return process.env.VUE_APP_BASE_API + real_src;
+    },
+    realSrcList() {
+      if (!this.src) {
+        return;
+      }
+      let real_src_list = this.src.split(",");
+      let srcList = [];
+      real_src_list.forEach(item => {
+        if (isExternal(item)) {
+          return srcList.push(item);
+        }
+        return srcList.push(process.env.VUE_APP_BASE_API + item);
+      });
+      return srcList;
+    },
+    realWidth() {
+      return typeof this.width == "string" ? this.width : `${this.width}px`;
+    },
+    realHeight() {
+      return typeof this.height == "string" ? this.height : `${this.height}px`;
+    }
+  },
+};
+</script>
+
+<style lang="scss" scoped>
+.el-image {
+  border-radius: 5px;
+  background-color: #ebeef5;
+  box-shadow: 0 0 5px 1px #ccc;
+  ::v-deep .el-image__inner {
+    transition: all 0.3s;
+    cursor: pointer;
+    &:hover {
+      transform: scale(1.2);
+    }
+  }
+  ::v-deep .image-slot {
+    display: flex;
+    justify-content: center;
+    align-items: center;
+    width: 100%;
+    height: 100%;
+    color: #909399;
+    font-size: 30px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/ImageUpload/index.vue b/ruoyi-ui/src/components/ImageUpload/index.vue
new file mode 100644
index 0000000..bf7e381
--- /dev/null
+++ b/ruoyi-ui/src/components/ImageUpload/index.vue
@@ -0,0 +1,231 @@
+<template>
+  <div class="component-upload-image">
+    <el-upload
+      multiple
+      :action="uploadImgUrl"
+      list-type="picture-card"
+      :on-success="handleUploadSuccess"
+      :before-upload="handleBeforeUpload"
+      :limit="limit"
+      :on-error="handleUploadError"
+      :on-exceed="handleExceed"
+      ref="imageUpload"
+      :on-remove="handleDelete"
+      :show-file-list="true"
+      :headers="headers"
+      :file-list="fileList"
+      :on-preview="handlePictureCardPreview"
+      :class="{hide: this.fileList.length >= this.limit}"
+    >
+      <i class="el-icon-plus"></i>
+    </el-upload>
+
+    <!-- 涓婁紶鎻愮ず -->
+    <div class="el-upload__tip" slot="tip" v-if="showTip">
+      璇蜂笂浼�
+      <template v-if="fileSize"> 澶у皬涓嶈秴杩� <b style="color: #f56c6c">{{ fileSize }}MB</b> </template>
+      <template v-if="fileType"> 鏍煎紡涓� <b style="color: #f56c6c">{{ fileType.join("/") }}</b> </template>
+      鐨勬枃浠�
+    </div>
+
+    <el-dialog
+      :visible.sync="dialogVisible"
+      title="棰勮"
+      width="800"
+      append-to-body
+    >
+      <img
+        :src="dialogImageUrl"
+        style="display: block; max-width: 100%; margin: 0 auto"
+      />
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getToken } from "@/utils/auth";
+import { isExternal } from "@/utils/validate";
+
+export default {
+  props: {
+    value: [String, Object, Array],
+    // 鍥剧墖鏁伴噺闄愬埗
+    limit: {
+      type: Number,
+      default: 5,
+    },
+    // 澶у皬闄愬埗(MB)
+    fileSize: {
+       type: Number,
+      default: 5,
+    },
+    // 鏂囦欢绫诲瀷, 渚嬪['png', 'jpg', 'jpeg']
+    fileType: {
+      type: Array,
+      default: () => ["png", "jpg", "jpeg"],
+    },
+    // 鏄惁鏄剧ず鎻愮ず
+    isShowTip: {
+      type: Boolean,
+      default: true
+    }
+  },
+  data() {
+    return {
+      number: 0,
+      uploadList: [],
+      dialogImageUrl: "",
+      dialogVisible: false,
+      hideUpload: false,
+      baseUrl: process.env.VUE_APP_BASE_API,
+      uploadImgUrl: process.env.VUE_APP_BASE_API + "/common/upload", // 涓婁紶鐨勫浘鐗囨湇鍔″櫒鍦板潃
+      headers: {
+        Authorization: "Bearer " + getToken(),
+      },
+      fileList: []
+    };
+  },
+  watch: {
+    value: {
+      handler(val) {
+        if (val) {
+          // 棣栧厛灏嗗�艰浆涓烘暟缁�
+          const list = Array.isArray(val) ? val : this.value.split(',');
+          // 鐒跺悗灏嗘暟缁勮浆涓哄璞℃暟缁�
+          this.fileList = list.map(item => {
+            if (typeof item === "string") {
+              if (item.indexOf(this.baseUrl) === -1 && !isExternal(item)) {
+                  item = { name: this.baseUrl + item, url: this.baseUrl + item };
+              } else {
+                  item = { name: item, url: item };
+              }
+            }
+            return item;
+          });
+        } else {
+          this.fileList = [];
+          return [];
+        }
+      },
+      deep: true,
+      immediate: true
+    }
+  },
+  computed: {
+    // 鏄惁鏄剧ず鎻愮ず
+    showTip() {
+      return this.isShowTip && (this.fileType || this.fileSize);
+    },
+  },
+  methods: {
+    // 涓婁紶鍓峫oading鍔犺浇
+    handleBeforeUpload(file) {
+      let isImg = false;
+      if (this.fileType.length) {
+        let fileExtension = "";
+        if (file.name.lastIndexOf(".") > -1) {
+          fileExtension = file.name.slice(file.name.lastIndexOf(".") + 1);
+        }
+        isImg = this.fileType.some(type => {
+          if (file.type.indexOf(type) > -1) return true;
+          if (fileExtension && fileExtension.indexOf(type) > -1) return true;
+          return false;
+        });
+      } else {
+        isImg = file.type.indexOf("image") > -1;
+      }
+
+      if (!isImg) {
+        this.$modal.msgError(`鏂囦欢鏍煎紡涓嶆纭紝璇蜂笂浼�${this.fileType.join("/")}鍥剧墖鏍煎紡鏂囦欢!`);
+        return false;
+      }
+      if (file.name.includes(',')) {
+        this.$modal.msgError('鏂囦欢鍚嶄笉姝g‘锛屼笉鑳藉寘鍚嫳鏂囬�楀彿!');
+        return false;
+      }
+      if (this.fileSize) {
+        const isLt = file.size / 1024 / 1024 < this.fileSize;
+        if (!isLt) {
+          this.$modal.msgError(`涓婁紶澶村儚鍥剧墖澶у皬涓嶈兘瓒呰繃 ${this.fileSize} MB!`);
+          return false;
+        }
+      }
+      this.$modal.loading("姝e湪涓婁紶鍥剧墖锛岃绋嶅��...");
+      this.number++;
+    },
+    // 鏂囦欢涓暟瓒呭嚭
+    handleExceed() {
+      this.$modal.msgError(`涓婁紶鏂囦欢鏁伴噺涓嶈兘瓒呰繃 ${this.limit} 涓�!`);
+    },
+    // 涓婁紶鎴愬姛鍥炶皟
+    handleUploadSuccess(res, file) {
+      if (res.code === 200) {
+        this.uploadList.push({ name: res.fileName, url: res.fileName });
+        this.uploadedSuccessfully();
+      } else {
+        this.number--;
+        this.$modal.closeLoading();
+        this.$modal.msgError(res.msg);
+        this.$refs.imageUpload.handleRemove(file);
+        this.uploadedSuccessfully();
+      }
+    },
+    // 鍒犻櫎鍥剧墖
+    handleDelete(file) {
+      const findex = this.fileList.map(f => f.name).indexOf(file.name);
+      if (findex > -1) {
+        this.fileList.splice(findex, 1);
+        this.$emit("input", this.listToString(this.fileList));
+      }
+    },
+    // 涓婁紶澶辫触
+    handleUploadError() {
+      this.$modal.msgError("涓婁紶鍥剧墖澶辫触锛岃閲嶈瘯");
+      this.$modal.closeLoading();
+    },
+    // 涓婁紶缁撴潫澶勭悊
+    uploadedSuccessfully() {
+      if (this.number > 0 && this.uploadList.length === this.number) {
+        this.fileList = this.fileList.concat(this.uploadList);
+        this.uploadList = [];
+        this.number = 0;
+        this.$emit("input", this.listToString(this.fileList));
+        this.$modal.closeLoading();
+      }
+    },
+    // 棰勮
+    handlePictureCardPreview(file) {
+      this.dialogImageUrl = file.url;
+      this.dialogVisible = true;
+    },
+    // 瀵硅薄杞垚鎸囧畾瀛楃涓插垎闅�
+    listToString(list, separator) {
+      let strs = "";
+      separator = separator || ",";
+      for (let i in list) {
+        if (list[i].url) {
+          strs += list[i].url.replace(this.baseUrl, "") + separator;
+        }
+      }
+      return strs != '' ? strs.substr(0, strs.length - 1) : '';
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+// .el-upload--picture-card 鎺у埗鍔犲彿閮ㄥ垎
+::v-deep.hide .el-upload--picture-card {
+    display: none;
+}
+// 鍘绘帀鍔ㄧ敾鏁堟灉
+::v-deep .el-list-enter-active,
+::v-deep .el-list-leave-active {
+    transition: all 0s;
+}
+
+::v-deep .el-list-enter, .el-list-leave-active {
+  opacity: 0;
+  transform: translateY(0);
+}
+</style>
+
diff --git a/ruoyi-ui/src/components/Pagination/index.vue b/ruoyi-ui/src/components/Pagination/index.vue
new file mode 100644
index 0000000..56f5a6b
--- /dev/null
+++ b/ruoyi-ui/src/components/Pagination/index.vue
@@ -0,0 +1,114 @@
+<template>
+  <div :class="{'hidden':hidden}" class="pagination-container">
+    <el-pagination
+      :background="background"
+      :current-page.sync="currentPage"
+      :page-size.sync="pageSize"
+      :layout="layout"
+      :page-sizes="pageSizes"
+      :pager-count="pagerCount"
+      :total="total"
+      v-bind="$attrs"
+      @size-change="handleSizeChange"
+      @current-change="handleCurrentChange"
+    />
+  </div>
+</template>
+
+<script>
+import { scrollTo } from '@/utils/scroll-to'
+
+export default {
+  name: 'Pagination',
+  props: {
+    total: {
+      required: true,
+      type: Number
+    },
+    page: {
+      type: Number,
+      default: 1
+    },
+    limit: {
+      type: Number,
+      default: 20
+    },
+    pageSizes: {
+      type: Array,
+      default() {
+        return [10, 20, 30, 50]
+      }
+    },
+    // 绉诲姩绔〉鐮佹寜閽殑鏁伴噺绔粯璁ゅ��5
+    pagerCount: {
+      type: Number,
+      default: document.body.clientWidth < 992 ? 5 : 7
+    },
+    layout: {
+      type: String,
+      default: 'total, sizes, prev, pager, next, jumper'
+    },
+    background: {
+      type: Boolean,
+      default: true
+    },
+    autoScroll: {
+      type: Boolean,
+      default: true
+    },
+    hidden: {
+      type: Boolean,
+      default: false
+    }
+  },
+  data() {
+    return {
+    };
+  },
+  computed: {
+    currentPage: {
+      get() {
+        return this.page
+      },
+      set(val) {
+        this.$emit('update:page', val)
+      }
+    },
+    pageSize: {
+      get() {
+        return this.limit
+      },
+      set(val) {
+        this.$emit('update:limit', val)
+      }
+    }
+  },
+  methods: {
+    handleSizeChange(val) {
+      if (this.currentPage * val > this.total) {
+        this.currentPage = 1
+      }
+      this.$emit('pagination', { page: this.currentPage, limit: val })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    },
+    handleCurrentChange(val) {
+      this.$emit('pagination', { page: val, limit: this.pageSize })
+      if (this.autoScroll) {
+        scrollTo(0, 800)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pagination-container {
+  background: #fff;
+  padding: 32px 16px;
+}
+.pagination-container.hidden {
+  display: none;
+}
+</style>
diff --git a/ruoyi-ui/src/components/PanThumb/index.vue b/ruoyi-ui/src/components/PanThumb/index.vue
new file mode 100644
index 0000000..1bcf417
--- /dev/null
+++ b/ruoyi-ui/src/components/PanThumb/index.vue
@@ -0,0 +1,142 @@
+<template>
+  <div :style="{zIndex:zIndex,height:height,width:width}" class="pan-item">
+    <div class="pan-info">
+      <div class="pan-info-roles-container">
+        <slot />
+      </div>
+    </div>
+    <!-- eslint-disable-next-line -->
+    <div :style="{backgroundImage: `url(${image})`}" class="pan-thumb"></div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'PanThumb',
+  props: {
+    image: {
+      type: String,
+      required: true
+    },
+    zIndex: {
+      type: Number,
+      default: 1
+    },
+    width: {
+      type: String,
+      default: '150px'
+    },
+    height: {
+      type: String,
+      default: '150px'
+    }
+  }
+}
+</script>
+
+<style scoped>
+.pan-item {
+  width: 200px;
+  height: 200px;
+  border-radius: 50%;
+  display: inline-block;
+  position: relative;
+  cursor: default;
+  box-shadow: 0 1px 3px rgba(0, 0, 0, 0.2);
+}
+
+.pan-info-roles-container {
+  padding: 20px;
+  text-align: center;
+}
+
+.pan-thumb {
+  width: 100%;
+  height: 100%;
+  background-position: center center;
+  background-size: cover;
+  border-radius: 50%;
+  overflow: hidden;
+  position: absolute;
+  transform-origin: 95% 40%;
+  transition: all 0.3s ease-in-out;
+}
+
+/* .pan-thumb:after {
+  content: '';
+  width: 8px;
+  height: 8px;
+  position: absolute;
+  border-radius: 50%;
+  top: 40%;
+  left: 95%;
+  margin: -4px 0 0 -4px;
+  background: radial-gradient(ellipse at center, rgba(14, 14, 14, 1) 0%, rgba(125, 126, 125, 1) 100%);
+  box-shadow: 0 0 1px rgba(255, 255, 255, 0.9);
+} */
+
+.pan-info {
+  position: absolute;
+  width: inherit;
+  height: inherit;
+  border-radius: 50%;
+  overflow: hidden;
+  box-shadow: inset 0 0 0 5px rgba(0, 0, 0, 0.05);
+}
+
+.pan-info h3 {
+  color: #fff;
+  text-transform: uppercase;
+  position: relative;
+  letter-spacing: 2px;
+  font-size: 18px;
+  margin: 0 60px;
+  padding: 22px 0 0 0;
+  height: 85px;
+  font-family: 'Open Sans', Arial, sans-serif;
+  text-shadow: 0 0 1px #fff, 0 1px 2px rgba(0, 0, 0, 0.3);
+}
+
+.pan-info p {
+  color: #fff;
+  padding: 10px 5px;
+  font-style: italic;
+  margin: 0 30px;
+  font-size: 12px;
+  border-top: 1px solid rgba(255, 255, 255, 0.5);
+}
+
+.pan-info p a {
+  display: block;
+  color: #333;
+  width: 80px;
+  height: 80px;
+  background: rgba(255, 255, 255, 0.3);
+  border-radius: 50%;
+  color: #fff;
+  font-style: normal;
+  font-weight: 700;
+  text-transform: uppercase;
+  font-size: 9px;
+  letter-spacing: 1px;
+  padding-top: 24px;
+  margin: 7px auto 0;
+  font-family: 'Open Sans', Arial, sans-serif;
+  opacity: 0;
+  transition: transform 0.3s ease-in-out 0.2s, opacity 0.3s ease-in-out 0.2s, background 0.2s linear 0s;
+  transform: translateX(60px) rotate(90deg);
+}
+
+.pan-info p a:hover {
+  background: rgba(255, 255, 255, 0.5);
+}
+
+.pan-item:hover .pan-thumb {
+  transform: rotate(-110deg);
+}
+
+.pan-item:hover .pan-info p a {
+  opacity: 1;
+  transform: translateX(0px) rotate(0deg);
+}
+</style>
diff --git a/ruoyi-ui/src/components/ParentView/index.vue b/ruoyi-ui/src/components/ParentView/index.vue
new file mode 100644
index 0000000..7bf6148
--- /dev/null
+++ b/ruoyi-ui/src/components/ParentView/index.vue
@@ -0,0 +1,3 @@
+<template >
+  <router-view />
+</template>
diff --git a/ruoyi-ui/src/components/RightPanel/index.vue b/ruoyi-ui/src/components/RightPanel/index.vue
new file mode 100644
index 0000000..5abeecb
--- /dev/null
+++ b/ruoyi-ui/src/components/RightPanel/index.vue
@@ -0,0 +1,106 @@
+<template>
+  <div ref="rightPanel" class="rightPanel-container">
+    <div class="rightPanel-background" />
+    <div class="rightPanel">
+      <div class="rightPanel-items">
+        <slot />
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+export default {
+  name: 'RightPanel',
+  props: {
+    clickNotClose: {
+      default: false,
+      type: Boolean
+    }
+  },
+  computed: {
+    show: {
+      get() {
+        return this.$store.state.settings.showSettings
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'showSettings',
+          value: val
+        })
+      }
+    }
+  },
+  watch: {
+    show(value) {
+      if (value && !this.clickNotClose) {
+        this.addEventClick()
+      }
+    }
+  },
+  mounted() {
+    this.addEventClick()
+  },
+  beforeDestroy() {
+    const elx = this.$refs.rightPanel
+    elx.remove()
+  },
+  methods: {
+    addEventClick() {
+      window.addEventListener('click', this.closeSidebar)
+    },
+    closeSidebar(evt) {
+      const parent = evt.target.closest('.el-drawer__body')
+      if (!parent) {
+        this.show = false
+        window.removeEventListener('click', this.closeSidebar)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.rightPanel-background {
+  position: fixed;
+  top: 0;
+  left: 0;
+  opacity: 0;
+  transition: opacity .3s cubic-bezier(.7, .3, .1, 1);
+  background: rgba(0, 0, 0, .2);
+  z-index: -1;
+}
+
+.rightPanel {
+  width: 100%;
+  max-width: 260px;
+  height: 100vh;
+  position: fixed;
+  top: 0;
+  right: 0;
+  box-shadow: 0px 0px 15px 0px rgba(0, 0, 0, .05);
+  transition: all .25s cubic-bezier(.7, .3, .1, 1);
+  transform: translate(100%);
+  background: #fff;
+  z-index: 40000;
+}
+
+.handle-button {
+  width: 48px;
+  height: 48px;
+  position: absolute;
+  left: -48px;
+  text-align: center;
+  font-size: 24px;
+  border-radius: 6px 0 0 6px !important;
+  z-index: 0;
+  pointer-events: auto;
+  cursor: pointer;
+  color: #fff;
+  line-height: 48px;
+  i {
+    font-size: 24px;
+    line-height: 48px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/components/RightToolbar/index.vue b/ruoyi-ui/src/components/RightToolbar/index.vue
new file mode 100644
index 0000000..67da293
--- /dev/null
+++ b/ruoyi-ui/src/components/RightToolbar/index.vue
@@ -0,0 +1,129 @@
+<template>
+  <div class="top-right-btn" :style="style">
+    <el-row>
+      <el-tooltip class="item" effect="dark" :content="showSearch ? '闅愯棌鎼滅储' : '鏄剧ず鎼滅储'" placement="top" v-if="search">
+        <el-button size="mini" circle icon="el-icon-search" @click="toggleSearch()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="鍒锋柊" placement="top">
+        <el-button size="mini" circle icon="el-icon-refresh" @click="refresh()" />
+      </el-tooltip>
+      <el-tooltip class="item" effect="dark" content="鏄鹃殣鍒�" placement="top" v-if="columns">
+        <el-button size="mini" circle icon="el-icon-menu" @click="showColumn()" v-if="showColumnsType == 'transfer'"/>
+        <el-dropdown trigger="click" :hide-on-click="false" style="padding-left: 12px" v-if="showColumnsType == 'checkbox'">
+          <el-button size="mini" circle icon="el-icon-menu" />
+          <el-dropdown-menu slot="dropdown">
+            <template v-for="item in columns">
+              <el-dropdown-item :key="item.key">
+                <el-checkbox :checked="item.visible" @change="checkboxChange($event, item.label)" :label="item.label" />
+              </el-dropdown-item>
+            </template>
+          </el-dropdown-menu>
+        </el-dropdown>
+      </el-tooltip>
+    </el-row>
+    <el-dialog :title="title" :visible.sync="open" append-to-body>
+      <el-transfer
+        :titles="['鏄剧ず', '闅愯棌']"
+        v-model="value"
+        :data="columns"
+        @change="dataChange"
+      ></el-transfer>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  name: "RightToolbar",
+  data() {
+    return {
+      // 鏄鹃殣鏁版嵁
+      value: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "鏄剧ず/闅愯棌",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+    };
+  },
+  props: {
+    /* 鏄惁鏄剧ず妫�绱㈡潯浠� */
+    showSearch: {
+      type: Boolean,
+      default: true,
+    },
+    /* 鏄鹃殣鍒椾俊鎭� */
+    columns: {
+      type: Array,
+    },
+    /* 鏄惁鏄剧ず妫�绱㈠浘鏍� */
+    search: {
+      type: Boolean,
+      default: true,
+    },
+    /* 鏄鹃殣鍒楃被鍨嬶紙transfer绌挎妗嗐�乧heckbox澶嶉�夋锛� */
+    showColumnsType: {
+      type: String,
+      default: "checkbox",
+    },
+    /* 鍙冲杈硅窛 */
+    gutter: {
+      type: Number,
+      default: 10,
+    },
+  },
+  computed: {
+    style() {
+      const ret = {};
+      if (this.gutter) {
+        ret.marginRight = `${this.gutter / 2}px`;
+      }
+      return ret;
+    }
+  },
+  created() {
+    if (this.showColumnsType == 'transfer') {
+      // 鏄鹃殣鍒楀垵濮嬮粯璁ら殣钘忓垪
+      for (let item in this.columns) {
+        if (this.columns[item].visible === false) {
+          this.value.push(parseInt(item));
+        }
+      }
+    }
+  },
+  methods: {
+    // 鎼滅储
+    toggleSearch() {
+      this.$emit("update:showSearch", !this.showSearch);
+    },
+    // 鍒锋柊
+    refresh() {
+      this.$emit("queryTable");
+    },
+    // 鍙充晶鍒楄〃鍏冪礌鍙樺寲
+    dataChange(data) {
+      for (let item in this.columns) {
+        const key = this.columns[item].key;
+        this.columns[item].visible = !data.includes(key);
+      }
+    },
+    // 鎵撳紑鏄鹃殣鍒梔ialog
+    showColumn() {
+      this.open = true;
+    },
+    // 鍕鹃��
+    checkboxChange(event, label) {
+      this.columns.filter(item => item.label == label)[0].visible = event;
+    }
+  },
+};
+</script>
+<style lang="scss" scoped>
+::v-deep .el-transfer__button {
+  border-radius: 50%;
+  padding: 12px;
+  display: block;
+  margin-left: 0px;
+}
+::v-deep .el-transfer__button:first-child {
+  margin-bottom: 10px;
+}
+</style>
diff --git a/ruoyi-ui/src/components/RuoYi/Doc/index.vue b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
new file mode 100644
index 0000000..75fa864
--- /dev/null
+++ b/ruoyi-ui/src/components/RuoYi/Doc/index.vue
@@ -0,0 +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
diff --git a/ruoyi-ui/src/components/RuoYi/Git/index.vue b/ruoyi-ui/src/components/RuoYi/Git/index.vue
new file mode 100644
index 0000000..bdafbae
--- /dev/null
+++ b/ruoyi-ui/src/components/RuoYi/Git/index.vue
@@ -0,0 +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
diff --git a/ruoyi-ui/src/components/Screenfull/index.vue b/ruoyi-ui/src/components/Screenfull/index.vue
new file mode 100644
index 0000000..d4e539c
--- /dev/null
+++ b/ruoyi-ui/src/components/Screenfull/index.vue
@@ -0,0 +1,57 @@
+<template>
+  <div>
+    <svg-icon :icon-class="isFullscreen?'exit-fullscreen':'fullscreen'" @click="click" />
+  </div>
+</template>
+
+<script>
+import screenfull from 'screenfull'
+
+export default {
+  name: 'Screenfull',
+  data() {
+    return {
+      isFullscreen: false
+    }
+  },
+  mounted() {
+    this.init()
+  },
+  beforeDestroy() {
+    this.destroy()
+  },
+  methods: {
+    click() {
+      if (!screenfull.isEnabled) {
+        this.$message({ message: '浣犵殑娴忚鍣ㄤ笉鏀寔鍏ㄥ睆', type: 'warning' })
+        return false
+      }
+      screenfull.toggle()
+    },
+    change() {
+      this.isFullscreen = screenfull.isFullscreen
+    },
+    init() {
+      if (screenfull.isEnabled) {
+        screenfull.on('change', this.change)
+      }
+    },
+    destroy() {
+      if (screenfull.isEnabled) {
+        screenfull.off('change', this.change)
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.screenfull-svg {
+  display: inline-block;
+  cursor: pointer;
+  fill: #5a5e66;;
+  width: 20px;
+  height: 20px;
+  vertical-align: 10px;
+}
+</style>
diff --git a/ruoyi-ui/src/components/SizeSelect/index.vue b/ruoyi-ui/src/components/SizeSelect/index.vue
new file mode 100644
index 0000000..069b5de
--- /dev/null
+++ b/ruoyi-ui/src/components/SizeSelect/index.vue
@@ -0,0 +1,56 @@
+<template>
+  <el-dropdown trigger="click" @command="handleSetSize">
+    <div>
+      <svg-icon class-name="size-icon" icon-class="size" />
+    </div>
+    <el-dropdown-menu slot="dropdown">
+      <el-dropdown-item v-for="item of sizeOptions" :key="item.value" :disabled="size===item.value" :command="item.value">
+        {{ item.label }}
+      </el-dropdown-item>
+    </el-dropdown-menu>
+  </el-dropdown>
+</template>
+
+<script>
+export default {
+  data() {
+    return {
+      sizeOptions: [
+        { label: 'Default', value: 'default' },
+        { label: 'Medium', value: 'medium' },
+        { label: 'Small', value: 'small' },
+        { label: 'Mini', value: 'mini' }
+      ]
+    }
+  },
+  computed: {
+    size() {
+      return this.$store.getters.size
+    }
+  },
+  methods: {
+    handleSetSize(size) {
+      this.$ELEMENT.size = size
+      this.$store.dispatch('app/setSize', size)
+      this.refreshView()
+      this.$message({
+        message: 'Switch Size Success',
+        type: 'success'
+      })
+    },
+    refreshView() {
+      // In order to make the cached page re-rendered
+      this.$store.dispatch('tagsView/delAllCachedViews', this.$route)
+
+      const { fullPath } = this.$route
+
+      this.$nextTick(() => {
+        this.$router.replace({
+          path: '/redirect' + fullPath
+        })
+      })
+    }
+  }
+
+}
+</script>
diff --git a/ruoyi-ui/src/components/SvgIcon/index.vue b/ruoyi-ui/src/components/SvgIcon/index.vue
new file mode 100644
index 0000000..e4bf5ad
--- /dev/null
+++ b/ruoyi-ui/src/components/SvgIcon/index.vue
@@ -0,0 +1,61 @@
+<template>
+  <div v-if="isExternal" :style="styleExternalIcon" class="svg-external-icon svg-icon" v-on="$listeners" />
+  <svg v-else :class="svgClass" aria-hidden="true" v-on="$listeners">
+    <use :xlink:href="iconName" />
+  </svg>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  name: 'SvgIcon',
+  props: {
+    iconClass: {
+      type: String,
+      required: true
+    },
+    className: {
+      type: String,
+      default: ''
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.iconClass)
+    },
+    iconName() {
+      return `#icon-${this.iconClass}`
+    },
+    svgClass() {
+      if (this.className) {
+        return 'svg-icon ' + this.className
+      } else {
+        return 'svg-icon'
+      }
+    },
+    styleExternalIcon() {
+      return {
+        mask: `url(${this.iconClass}) no-repeat 50% 50%`,
+        '-webkit-mask': `url(${this.iconClass}) no-repeat 50% 50%`
+      }
+    }
+  }
+}
+</script>
+
+<style scoped>
+.svg-icon {
+  width: 1em;
+  height: 1em;
+  vertical-align: -0.15em;
+  fill: currentColor;
+  overflow: hidden;
+}
+
+.svg-external-icon {
+  background-color: currentColor;
+  mask-size: cover!important;
+  display: inline-block;
+}
+</style>
diff --git a/ruoyi-ui/src/components/ThemePicker/index.vue b/ruoyi-ui/src/components/ThemePicker/index.vue
new file mode 100644
index 0000000..a69ee45
--- /dev/null
+++ b/ruoyi-ui/src/components/ThemePicker/index.vue
@@ -0,0 +1,170 @@
+<template>
+  <el-color-picker
+    v-model="theme"
+    :predefine="['#409EFF', '#1890ff', '#304156','#212121','#11a983', '#13c2c2', '#6959CD', '#f5222d', ]"
+    class="theme-picker"
+    popper-class="theme-picker-dropdown"
+  />
+</template>
+
+<script>
+const ORIGINAL_THEME = '#409EFF' // default color
+
+export default {
+  data() {
+    return {
+      chalk: '', // content of theme-chalk css
+      theme: ''
+    }
+  },
+  computed: {
+    defaultTheme() {
+      return this.$store.state.settings.theme
+    }
+  },
+  watch: {
+    defaultTheme: {
+      handler: function(val, oldVal) {
+        this.theme = val
+      },
+      immediate: true
+    },
+    async theme(val) {
+      await this.setTheme(val)
+    }
+  },
+  created() {
+    if(this.defaultTheme !== ORIGINAL_THEME) {
+      this.setTheme(this.defaultTheme)
+    }
+  },
+  methods: {
+    async setTheme(val) {
+      const oldVal = this.chalk ? this.theme : ORIGINAL_THEME
+      if (typeof val !== 'string') return
+      const themeCluster = this.getThemeCluster(val.replace('#', ''))
+      const originalCluster = this.getThemeCluster(oldVal.replace('#', ''))
+
+      const getHandler = (variable, id) => {
+        return () => {
+          const originalCluster = this.getThemeCluster(ORIGINAL_THEME.replace('#', ''))
+          const newStyle = this.updateStyle(this[variable], originalCluster, themeCluster)
+
+          let styleTag = document.getElementById(id)
+          if (!styleTag) {
+            styleTag = document.createElement('style')
+            styleTag.setAttribute('id', id)
+            document.head.appendChild(styleTag)
+          }
+          styleTag.innerText = newStyle
+        }
+      }
+
+      if (!this.chalk) {
+        const url = `/styles/theme-chalk/index.css`
+        await this.getCSSString(url, 'chalk')
+      }
+
+      const chalkHandler = getHandler('chalk', 'chalk-style')
+      chalkHandler()
+
+      const styles = [].slice.call(document.querySelectorAll('style'))
+        .filter(style => {
+          const text = style.innerText
+          return new RegExp(oldVal, 'i').test(text) && !/Chalk Variables/.test(text)
+        })
+      styles.forEach(style => {
+        const { innerText } = style
+        if (typeof innerText !== 'string') return
+        style.innerText = this.updateStyle(innerText, originalCluster, themeCluster)
+      })
+
+      this.$emit('change', val)
+    },
+
+    updateStyle(style, oldCluster, newCluster) {
+      let newStyle = style
+      oldCluster.forEach((color, index) => {
+        newStyle = newStyle.replace(new RegExp(color, 'ig'), newCluster[index])
+      })
+      return newStyle
+    },
+
+    getCSSString(url, variable) {
+      return new Promise(resolve => {
+        const xhr = new XMLHttpRequest()
+        xhr.onreadystatechange = () => {
+          if (xhr.readyState === 4 && xhr.status === 200) {
+            this[variable] = xhr.responseText.replace(/@font-face{[^}]+}/, '')
+            resolve()
+          }
+        }
+        xhr.open('GET', url)
+        xhr.send()
+      })
+    },
+
+    getThemeCluster(theme) {
+      const tintColor = (color, tint) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        if (tint === 0) { // when primary color is in its rgb space
+          return [red, green, blue].join(',')
+        } else {
+          red += Math.round(tint * (255 - red))
+          green += Math.round(tint * (255 - green))
+          blue += Math.round(tint * (255 - blue))
+
+          red = red.toString(16)
+          green = green.toString(16)
+          blue = blue.toString(16)
+
+          return `#${red}${green}${blue}`
+        }
+      }
+
+      const shadeColor = (color, shade) => {
+        let red = parseInt(color.slice(0, 2), 16)
+        let green = parseInt(color.slice(2, 4), 16)
+        let blue = parseInt(color.slice(4, 6), 16)
+
+        red = Math.round((1 - shade) * red)
+        green = Math.round((1 - shade) * green)
+        blue = Math.round((1 - shade) * blue)
+
+        red = red.toString(16)
+        green = green.toString(16)
+        blue = blue.toString(16)
+
+        return `#${red}${green}${blue}`
+      }
+
+      const clusters = [theme]
+      for (let i = 0; i <= 9; i++) {
+        clusters.push(tintColor(theme, Number((i / 10).toFixed(2))))
+      }
+      clusters.push(shadeColor(theme, 0.1))
+      return clusters
+    }
+  }
+}
+</script>
+
+<style>
+.theme-message,
+.theme-picker-dropdown {
+  z-index: 99999 !important;
+}
+
+.theme-picker .el-color-picker__trigger {
+  height: 26px !important;
+  width: 26px !important;
+  padding: 2px;
+}
+
+.theme-picker-dropdown .el-color-dropdown__link-btn {
+  display: none;
+}
+</style>
diff --git a/ruoyi-ui/src/components/TopNav/index.vue b/ruoyi-ui/src/components/TopNav/index.vue
new file mode 100644
index 0000000..e27a12f
--- /dev/null
+++ b/ruoyi-ui/src/components/TopNav/index.vue
@@ -0,0 +1,193 @@
+<template>
+  <el-menu
+    :default-active="activeMenu"
+    mode="horizontal"
+    @select="handleSelect"
+  >
+    <template v-for="(item, index) in topMenus">
+      <el-menu-item :style="{'--theme': theme}" :index="item.path" :key="index" v-if="index < visibleNumber">
+        <svg-icon
+        v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+        :icon-class="item.meta.icon"/>
+        {{ item.meta.title }}
+      </el-menu-item>
+    </template>
+
+    <!-- 椤堕儴鑿滃崟瓒呭嚭鏁伴噺鎶樺彔 -->
+    <el-submenu :style="{'--theme': theme}" index="more" :key="visibleNumber" v-if="topMenus.length > visibleNumber">
+      <template slot="title">鏇村鑿滃崟</template>
+      <template v-for="(item, index) in topMenus">
+        <el-menu-item
+          :index="item.path"
+          :key="index"
+          v-if="index >= visibleNumber">
+          <svg-icon
+            v-if="item.meta && item.meta.icon && item.meta.icon !== '#'"
+            :icon-class="item.meta.icon"/>
+          {{ item.meta.title }}
+        </el-menu-item>
+      </template>
+    </el-submenu>
+  </el-menu>
+</template>
+
+<script>
+import { constantRoutes } from "@/router";
+import { isHttp } from "@/utils/validate";
+
+// 闅愯棌渚ц竟鏍忚矾鐢�
+const hideList = ['/index', '/user/profile'];
+
+export default {
+  data() {
+    return {
+      // 椤堕儴鏍忓垵濮嬫暟
+      visibleNumber: 5,
+      // 褰撳墠婵�娲昏彍鍗曠殑 index
+      currentIndex: undefined
+    };
+  },
+  computed: {
+    theme() {
+      return this.$store.state.settings.theme;
+    },
+    // 椤堕儴鏄剧ず鑿滃崟
+    topMenus() {
+      let topMenus = [];
+      this.routers.map((menu) => {
+        if (menu.hidden !== true) {
+          // 鍏煎椤堕儴鏍忎竴绾ц彍鍗曞唴閮ㄨ烦杞�
+          if (menu.path === "/") {
+            topMenus.push(menu.children[0]);
+          } else {
+            topMenus.push(menu);
+          }
+        }
+      });
+      return topMenus;
+    },
+    // 鎵�鏈夌殑璺敱淇℃伅
+    routers() {
+      return this.$store.state.permission.topbarRouters;
+    },
+    // 璁剧疆瀛愯矾鐢�
+    childrenMenus() {
+      var childrenMenus = [];
+      this.routers.map((router) => {
+        for (var item in router.children) {
+          if (router.children[item].parentPath === undefined) {
+            if(router.path === "/") {
+              router.children[item].path = "/" + router.children[item].path;
+            } else {
+              if(!isHttp(router.children[item].path)) {
+                router.children[item].path = router.path + "/" + router.children[item].path;
+              }
+            }
+            router.children[item].parentPath = router.path;
+          }
+          childrenMenus.push(router.children[item]);
+        }
+      });
+      return constantRoutes.concat(childrenMenus);
+    },
+    // 榛樿婵�娲荤殑鑿滃崟
+    activeMenu() {
+      const path = this.$route.path;
+      let activePath = path;
+      if (path !== undefined && path.lastIndexOf("/") > 0 && hideList.indexOf(path) === -1) {
+        const tmpPath = path.substring(1, path.length);
+        if (!this.$route.meta.link) {
+          activePath = "/" + tmpPath.substring(0, tmpPath.indexOf("/"));
+          this.$store.dispatch('app/toggleSideBarHide', false);
+        }
+      } else if(!this.$route.children) {
+        activePath = path;
+        this.$store.dispatch('app/toggleSideBarHide', true);
+      }
+      this.activeRoutes(activePath);
+      return activePath;
+    },
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.setVisibleNumber)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.setVisibleNumber)
+  },
+  mounted() {
+    this.setVisibleNumber();
+  },
+  methods: {
+    // 鏍规嵁瀹藉害璁$畻璁剧疆鏄剧ず鏍忔暟
+    setVisibleNumber() {
+      const width = document.body.getBoundingClientRect().width / 3;
+      this.visibleNumber = parseInt(width / 85);
+    },
+    // 鑿滃崟閫夋嫨浜嬩欢
+    handleSelect(key, keyPath) {
+      this.currentIndex = key;
+      const route = this.routers.find(item => item.path === key);
+      if (isHttp(key)) {
+        // http(s):// 璺緞鏂扮獥鍙f墦寮�
+        window.open(key, "_blank");
+      } else if (!route || !route.children) {
+        // 娌℃湁瀛愯矾鐢辫矾寰勫唴閮ㄦ墦寮�
+        const routeMenu = this.childrenMenus.find(item => item.path === key);
+        if (routeMenu && routeMenu.query) {
+          let query = JSON.parse(routeMenu.query);
+          this.$router.push({ path: key, query: query });
+        } else {
+          this.$router.push({ path: key });
+        }
+        this.$store.dispatch('app/toggleSideBarHide', true);
+      } else {
+        // 鏄剧ず宸︿晶鑱斿姩鑿滃崟
+        this.activeRoutes(key);
+        this.$store.dispatch('app/toggleSideBarHide', false);
+      }
+    },
+    // 褰撳墠婵�娲荤殑璺敱
+    activeRoutes(key) {
+      var routes = [];
+      if (this.childrenMenus && this.childrenMenus.length > 0) {
+        this.childrenMenus.map((item) => {
+          if (key == item.parentPath || (key == "index" && "" == item.path)) {
+            routes.push(item);
+          }
+        });
+      }
+      if(routes.length > 0) {
+        this.$store.commit("SET_SIDEBAR_ROUTERS", routes);
+      } else {
+        this.$store.dispatch('app/toggleSideBarHide', true);
+      }
+    }
+  },
+};
+</script>
+
+<style lang="scss">
+.topmenu-container.el-menu--horizontal > .el-menu-item {
+  float: left;
+  height: 50px !important;
+  line-height: 50px !important;
+  color: #999093 !important;
+  padding: 0 5px !important;
+  margin: 0 10px !important;
+}
+
+.topmenu-container.el-menu--horizontal > .el-menu-item.is-active, .el-menu--horizontal > .el-submenu.is-active .el-submenu__title {
+  border-bottom: 2px solid #{'var(--theme)'} !important;
+  color: #303133;
+}
+
+/* submenu item */
+.topmenu-container.el-menu--horizontal > .el-submenu .el-submenu__title {
+  float: left;
+  height: 50px !important;
+  line-height: 50px !important;
+  color: #999093 !important;
+  padding: 0 5px !important;
+  margin: 0 10px !important;
+}
+</style>
diff --git a/ruoyi-ui/src/components/iFrame/index.vue b/ruoyi-ui/src/components/iFrame/index.vue
new file mode 100644
index 0000000..426857f
--- /dev/null
+++ b/ruoyi-ui/src/components/iFrame/index.vue
@@ -0,0 +1,36 @@
+<template>
+  <div v-loading="loading" :style="'height:' + height">
+    <iframe
+      :src="src"
+      frameborder="no"
+      style="width: 100%; height: 100%"
+      scrolling="auto"
+    />
+  </div>
+</template>
+<script>
+export default {
+  props: {
+    src: {
+      type: String,
+      required: true
+    },
+  },
+  data() {
+    return {
+      height: document.documentElement.clientHeight - 94.5 + "px;",
+      loading: true,
+      url: this.src
+    };
+  },
+  mounted: function () {
+    setTimeout(() => {
+      this.loading = false;
+    }, 300);
+    const that = this;
+    window.onresize = function temp() {
+      that.height = document.documentElement.clientHeight - 94.5 + "px;";
+    };
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/directive/dialog/drag.js b/ruoyi-ui/src/directive/dialog/drag.js
new file mode 100644
index 0000000..2e82346
--- /dev/null
+++ b/ruoyi-ui/src/directive/dialog/drag.js
@@ -0,0 +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 姝e垯鍖归厤鏇挎崲
+      let styL, styT;
+
+      // 娉ㄦ剰鍦╥e涓� 绗竴娆¤幏鍙栧埌鐨勫�间负缁勪欢鑷甫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
diff --git a/ruoyi-ui/src/directive/dialog/dragHeight.js b/ruoyi-ui/src/directive/dialog/dragHeight.js
new file mode 100644
index 0000000..97e5305
--- /dev/null
+++ b/ruoyi-ui/src/directive/dialog/dragHeight.js
@@ -0,0 +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);
+  }
+}
diff --git a/ruoyi-ui/src/directive/dialog/dragWidth.js b/ruoyi-ui/src/directive/dialog/dragWidth.js
new file mode 100644
index 0000000..2df0867
--- /dev/null
+++ b/ruoyi-ui/src/directive/dialog/dragWidth.js
@@ -0,0 +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);
+  }
+}
diff --git a/ruoyi-ui/src/directive/index.js b/ruoyi-ui/src/directive/index.js
new file mode 100644
index 0000000..b9b07da
--- /dev/null
+++ b/ruoyi-ui/src/directive/index.js
@@ -0,0 +1,23 @@
+import hasRole from './permission/hasRole'
+import hasPermi from './permission/hasPermi'
+import dialogDrag from './dialog/drag'
+import dialogDragWidth from './dialog/dragWidth'
+import dialogDragHeight from './dialog/dragHeight'
+import clipboard from './module/clipboard'
+
+const install = function(Vue) {
+  Vue.directive('hasRole', hasRole)
+  Vue.directive('hasPermi', hasPermi)
+  Vue.directive('clipboard', clipboard)
+  Vue.directive('dialogDrag', dialogDrag)
+  Vue.directive('dialogDragWidth', dialogDragWidth)
+  Vue.directive('dialogDragHeight', dialogDragHeight)
+}
+
+if (window.Vue) {
+  window['hasRole'] = hasRole
+  window['hasPermi'] = hasPermi
+  Vue.use(install); // eslint-disable-line
+}
+
+export default install
diff --git a/ruoyi-ui/src/directive/module/clipboard.js b/ruoyi-ui/src/directive/module/clipboard.js
new file mode 100644
index 0000000..635315a
--- /dev/null
+++ b/ruoyi-ui/src/directive/module/clipboard.js
@@ -0,0 +1,54 @@
+/**
+* v-clipboard 鏂囧瓧澶嶅埗鍓创
+* Copyright (c) 2021 ruoyi
+*/
+
+import Clipboard from 'clipboard'
+export default {
+  bind(el, binding, vnode) {
+    switch (binding.arg) {
+      case 'success':
+        el._vClipBoard_success = binding.value;
+        break;
+      case 'error':
+        el._vClipBoard_error = binding.value;
+        break;
+      default: {
+        const clipboard = new Clipboard(el, {
+          text: () => binding.value,
+          action: () => binding.arg === 'cut' ? 'cut' : 'copy'
+        });
+        clipboard.on('success', e => {
+          const callback = el._vClipBoard_success;
+          callback && callback(e);
+        });
+        clipboard.on('error', e => {
+          const callback = el._vClipBoard_error;
+          callback && callback(e);
+        });
+        el._vClipBoard = clipboard;
+      }
+    }
+  },
+  update(el, binding) {
+    if (binding.arg === 'success') {
+      el._vClipBoard_success = binding.value;
+    } else if (binding.arg === 'error') {
+      el._vClipBoard_error = binding.value;
+    } else {
+      el._vClipBoard.text = function () { return binding.value; };
+      el._vClipBoard.action = () => binding.arg === 'cut' ? 'cut' : 'copy';
+    }
+  },
+  unbind(el, binding) {
+    if (!el._vClipboard) return
+    if (binding.arg === 'success') {
+      delete el._vClipBoard_success;
+    } else if (binding.arg === 'error') {
+      delete el._vClipBoard_error;
+    } else {
+      el._vClipBoard.destroy();
+      delete el._vClipBoard;
+    }
+  }
+}
diff --git a/ruoyi-ui/src/directive/permission/hasPermi.js b/ruoyi-ui/src/directive/permission/hasPermi.js
new file mode 100644
index 0000000..7101e3e
--- /dev/null
+++ b/ruoyi-ui/src/directive/permission/hasPermi.js
@@ -0,0 +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(`璇疯缃搷浣滄潈闄愭爣绛惧�糮)
+    }
+  }
+}
diff --git a/ruoyi-ui/src/directive/permission/hasRole.js b/ruoyi-ui/src/directive/permission/hasRole.js
new file mode 100644
index 0000000..ad9d4d7
--- /dev/null
+++ b/ruoyi-ui/src/directive/permission/hasRole.js
@@ -0,0 +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(`璇疯缃鑹叉潈闄愭爣绛惧��"`)
+    }
+  }
+}
diff --git a/ruoyi-ui/src/layout/components/AppMain.vue b/ruoyi-ui/src/layout/components/AppMain.vue
new file mode 100644
index 0000000..66b33bf
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/AppMain.vue
@@ -0,0 +1,91 @@
+<template>
+  <section class="app-main">
+    <transition name="fade-transform" mode="out-in">
+      <keep-alive :include="cachedViews">
+        <router-view v-if="!$route.meta.link" :key="key" />
+      </keep-alive>
+    </transition>
+    <iframe-toggle />
+  </section>
+</template>
+
+<script>
+import iframeToggle from "./IframeToggle/index"
+
+export default {
+  name: 'AppMain',
+  components: { iframeToggle },
+  computed: {
+    cachedViews() {
+      return this.$store.state.tagsView.cachedViews
+    },
+    key() {
+      return this.$route.path
+    }
+  },
+  watch: {
+    $route() {
+      this.addIframe()
+    }
+  },
+  mounted() {
+    this.addIframe()
+  },
+  methods: {
+    addIframe() {
+      const {name} = this.$route
+      if (name && this.$route.meta.link) {
+        this.$store.dispatch('tagsView/addIframeView', this.$route)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.app-main {
+  /* 50= navbar  50  */
+  min-height: calc(100vh - 50px);
+  width: 100%;
+  position: relative;
+  overflow: hidden;
+}
+
+.fixed-header + .app-main {
+  padding-top: 50px;
+}
+
+.hasTagsView {
+  .app-main {
+    /* 84 = navbar + tags-view = 50 + 34 */
+    min-height: calc(100vh - 84px);
+  }
+
+  .fixed-header + .app-main {
+    padding-top: 84px;
+  }
+}
+</style>
+
+<style lang="scss">
+// fix css style bug in open el-dialog
+.el-popup-parent--hidden {
+  .fixed-header {
+    padding-right: 6px;
+  }
+}
+
+::-webkit-scrollbar {
+  width: 6px;
+  height: 6px;
+}
+
+::-webkit-scrollbar-track {
+  background-color: #f1f1f1;
+}
+
+::-webkit-scrollbar-thumb {
+  background-color: #c0c0c0;
+  border-radius: 3px;
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/IframeToggle/index.vue b/ruoyi-ui/src/layout/components/IframeToggle/index.vue
new file mode 100644
index 0000000..39ad15b
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/IframeToggle/index.vue
@@ -0,0 +1,33 @@
+<template>
+  <transition-group name="fade-transform" mode="out-in">
+    <inner-link
+      v-for="(item, index) in iframeViews"
+      :key="item.path"
+      :iframeId="'iframe' + index"
+      v-show="$route.path === item.path"
+      :src="iframeUrl(item.meta.link, item.query)"
+    ></inner-link>
+  </transition-group>
+</template>
+
+<script>
+import InnerLink from "../InnerLink/index";
+
+export default {
+  components: { InnerLink },
+  computed: {
+    iframeViews() {
+      return this.$store.state.tagsView.iframeViews;
+    }
+  },
+  methods: {
+    iframeUrl(url, query) {
+      if (Object.keys(query).length > 0) {
+        let params = Object.keys(query).map((key) => key + "=" + query[key]).join("&");
+        return url + "?" + params;
+      }
+      return url;
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/InnerLink/index.vue b/ruoyi-ui/src/layout/components/InnerLink/index.vue
new file mode 100644
index 0000000..badefc5
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/InnerLink/index.vue
@@ -0,0 +1,47 @@
+<template>
+  <div :style="'height:' + height" v-loading="loading" element-loading-text="姝e湪鍔犺浇椤甸潰锛岃绋嶅�欙紒">
+    <iframe
+      :id="iframeId"
+      style="width: 100%; height: 100%"
+      :src="src"
+      frameborder="no"
+    ></iframe>
+  </div>
+</template>
+
+<script>
+export default {
+  props: {
+    src: {
+      type: String,
+      default: "/"
+    },
+    iframeId: {
+      type: String
+    }
+  },
+  data() {
+    return {
+      loading: false,
+      height: document.documentElement.clientHeight - 94.5 + "px;"
+    };
+  },
+  mounted() {
+    var _this = this;
+    const iframeId = ("#" + this.iframeId).replace(/\//g, "\\/");
+    const iframe = document.querySelector(iframeId);
+    // iframe椤甸潰loading鎺у埗
+    if (iframe.attachEvent) {
+      this.loading = true;
+      iframe.attachEvent("onload", function () {
+        _this.loading = false;
+      });
+    } else {
+      this.loading = true;
+      iframe.onload = function () {
+        _this.loading = false;
+      };
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/layout/components/Navbar.vue b/ruoyi-ui/src/layout/components/Navbar.vue
new file mode 100644
index 0000000..466cd98
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Navbar.vue
@@ -0,0 +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>
diff --git a/ruoyi-ui/src/layout/components/Settings/index.vue b/ruoyi-ui/src/layout/components/Settings/index.vue
new file mode 100644
index 0000000..bb3c9ce
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Settings/index.vue
@@ -0,0 +1,260 @@
+<template>
+  <el-drawer size="280px" :visible="visible" :with-header="false" :append-to-body="true" :show-close="false">
+    <div class="drawer-container">
+      <div>
+        <div class="setting-drawer-content">
+          <div class="setting-drawer-title">
+            <h3 class="drawer-title">涓婚椋庢牸璁剧疆</h3>
+          </div>
+          <div class="setting-drawer-block-checbox">
+            <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-dark')">
+              <img src="@/assets/images/dark.svg" alt="dark">
+              <div v-if="sideTheme === 'theme-dark'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+                <i aria-label="鍥炬爣: check" class="anticon anticon-check">
+                  <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
+                    <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+                  </svg>
+                </i>
+              </div>
+            </div>
+            <div class="setting-drawer-block-checbox-item" @click="handleTheme('theme-light')">
+              <img src="@/assets/images/light.svg" alt="light">
+              <div v-if="sideTheme === 'theme-light'" class="setting-drawer-block-checbox-selectIcon" style="display: block;">
+                <i aria-label="鍥炬爣: check" class="anticon anticon-check">
+                  <svg viewBox="64 64 896 896" data-icon="check" width="1em" height="1em" :fill="theme" aria-hidden="true" focusable="false" class="">
+                    <path d="M912 190h-69.9c-9.8 0-19.1 4.5-25.1 12.2L404.7 724.5 207 474a32 32 0 0 0-25.1-12.2H112c-6.7 0-10.4 7.7-6.3 12.9l273.9 347c12.8 16.2 37.4 16.2 50.3 0l488.4-618.9c4.1-5.1.4-12.8-6.3-12.8z"/>
+                  </svg>
+                </i>
+              </div>
+            </div>
+          </div>
+
+          <div class="drawer-item">
+            <span>涓婚棰滆壊</span>
+            <theme-picker style="float: right;height: 26px;margin: -3px 8px 0 0;" @change="themeChange" />
+          </div>
+        </div>
+
+        <el-divider/>
+
+        <h3 class="drawer-title">绯荤粺甯冨眬閰嶇疆</h3>
+
+        <div class="drawer-item">
+          <span>寮�鍚� TopNav</span>
+          <el-switch v-model="topNav" class="drawer-switch" />
+        </div>
+
+        <div class="drawer-item">
+          <span>寮�鍚� Tags-Views</span>
+          <el-switch v-model="tagsView" class="drawer-switch" />
+        </div>
+
+        <div class="drawer-item">
+          <span>鍥哄畾 Header</span>
+          <el-switch v-model="fixedHeader" class="drawer-switch" />
+        </div>
+
+        <div class="drawer-item">
+          <span>鏄剧ず Logo</span>
+          <el-switch v-model="sidebarLogo" class="drawer-switch" />
+        </div>
+
+        <div class="drawer-item">
+          <span>鍔ㄦ�佹爣棰�</span>
+          <el-switch v-model="dynamicTitle" class="drawer-switch" />
+        </div>
+
+        <el-divider/>
+
+        <el-button size="small" type="primary" plain icon="el-icon-document-add" @click="saveSetting">淇濆瓨閰嶇疆</el-button>
+        <el-button size="small" plain icon="el-icon-refresh" @click="resetSetting">閲嶇疆閰嶇疆</el-button>
+      </div>
+    </div>
+  </el-drawer>
+</template>
+
+<script>
+import ThemePicker from '@/components/ThemePicker'
+
+export default {
+  components: { ThemePicker },
+  data() {
+    return {
+      theme: this.$store.state.settings.theme,
+      sideTheme: this.$store.state.settings.sideTheme
+    };
+  },
+  computed: {
+    visible: {
+      get() {
+        return this.$store.state.settings.showSettings
+      }
+    },
+    fixedHeader: {
+      get() {
+        return this.$store.state.settings.fixedHeader
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'fixedHeader',
+          value: val
+        })
+      }
+    },
+    topNav: {
+      get() {
+        return this.$store.state.settings.topNav
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'topNav',
+          value: val
+        })
+        if (!val) {
+          this.$store.dispatch('app/toggleSideBarHide', false);
+          this.$store.commit("SET_SIDEBAR_ROUTERS", this.$store.state.permission.defaultRoutes);
+        }
+      }
+    },
+    tagsView: {
+      get() {
+        return this.$store.state.settings.tagsView
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'tagsView',
+          value: val
+        })
+      }
+    },
+    sidebarLogo: {
+      get() {
+        return this.$store.state.settings.sidebarLogo
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'sidebarLogo',
+          value: val
+        })
+      }
+    },
+    dynamicTitle: {
+      get() {
+        return this.$store.state.settings.dynamicTitle
+      },
+      set(val) {
+        this.$store.dispatch('settings/changeSetting', {
+          key: 'dynamicTitle',
+          value: val
+        })
+      }
+    },
+  },
+  methods: {
+    themeChange(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'theme',
+        value: val
+      })
+      this.theme = val;
+    },
+    handleTheme(val) {
+      this.$store.dispatch('settings/changeSetting', {
+        key: 'sideTheme',
+        value: val
+      })
+      this.sideTheme = val;
+    },
+    saveSetting() {
+      this.$modal.loading("姝e湪淇濆瓨鍒版湰鍦帮紝璇风◢鍊�...");
+      this.$cache.local.set(
+        "layout-setting",
+        `{
+            "topNav":${this.topNav},
+            "tagsView":${this.tagsView},
+            "fixedHeader":${this.fixedHeader},
+            "sidebarLogo":${this.sidebarLogo},
+            "dynamicTitle":${this.dynamicTitle},
+            "sideTheme":"${this.sideTheme}",
+            "theme":"${this.theme}"
+          }`
+      );
+      setTimeout(this.$modal.closeLoading(), 1000)
+    },
+    resetSetting() {
+      this.$modal.loading("姝e湪娓呴櫎璁剧疆缂撳瓨骞跺埛鏂帮紝璇风◢鍊�...");
+      this.$cache.local.remove("layout-setting")
+      setTimeout("window.location.reload()", 1000)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .setting-drawer-content {
+    .setting-drawer-title {
+      margin-bottom: 12px;
+      color: rgba(0, 0, 0, .85);
+      font-size: 14px;
+      line-height: 22px;
+      font-weight: bold;
+    }
+
+    .setting-drawer-block-checbox {
+      display: flex;
+      justify-content: flex-start;
+      align-items: center;
+      margin-top: 10px;
+      margin-bottom: 20px;
+
+      .setting-drawer-block-checbox-item {
+        position: relative;
+        margin-right: 16px;
+        border-radius: 2px;
+        cursor: pointer;
+
+        img {
+          width: 48px;
+          height: 48px;
+        }
+
+        .setting-drawer-block-checbox-selectIcon {
+          position: absolute;
+          top: 0;
+          right: 0;
+          width: 100%;
+          height: 100%;
+          padding-top: 15px;
+          padding-left: 24px;
+          color: #1890ff;
+          font-weight: 700;
+          font-size: 14px;
+        }
+      }
+    }
+  }
+
+  .drawer-container {
+    padding: 20px;
+    font-size: 14px;
+    line-height: 1.5;
+    word-wrap: break-word;
+
+    .drawer-title {
+      margin-bottom: 12px;
+      color: rgba(0, 0, 0, .85);
+      font-size: 14px;
+      line-height: 22px;
+    }
+
+    .drawer-item {
+      color: rgba(0, 0, 0, .65);
+      font-size: 14px;
+      padding: 12px 0;
+    }
+
+    .drawer-switch {
+      float: right
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js b/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
new file mode 100644
index 0000000..6823726
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/FixiOSBug.js
@@ -0,0 +1,25 @@
+export default {
+  computed: {
+    device() {
+      return this.$store.state.app.device
+    }
+  },
+  mounted() {
+    // In order to fix the click on menu on the ios device will trigger the mouseleave bug
+    this.fixBugIniOS()
+  },
+  methods: {
+    fixBugIniOS() {
+      const $subMenu = this.$refs.subMenu
+      if ($subMenu) {
+        const handleMouseleave = $subMenu.handleMouseleave
+        $subMenu.handleMouseleave = (e) => {
+          if (this.device === 'mobile') {
+            return
+          }
+          handleMouseleave(e)
+        }
+      }
+    }
+  }
+}
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Item.vue b/ruoyi-ui/src/layout/components/Sidebar/Item.vue
new file mode 100644
index 0000000..be3285d
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Item.vue
@@ -0,0 +1,33 @@
+<script>
+export default {
+  name: 'MenuItem',
+  functional: true,
+  props: {
+    icon: {
+      type: String,
+      default: ''
+    },
+    title: {
+      type: String,
+      default: ''
+    }
+  },
+  render(h, context) {
+    const { icon, title } = context.props
+    const vnodes = []
+
+    if (icon) {
+      vnodes.push(<svg-icon icon-class={icon}/>)
+    }
+
+    if (title) {
+      if (title.length > 5) {
+        vnodes.push(<span slot='title' title={(title)}>{(title)}</span>)
+      } else {
+        vnodes.push(<span slot='title'>{(title)}</span>)
+      }
+    }
+    return vnodes
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Link.vue b/ruoyi-ui/src/layout/components/Sidebar/Link.vue
new file mode 100644
index 0000000..8b0bc93
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Link.vue
@@ -0,0 +1,43 @@
+<template>
+  <component :is="type" v-bind="linkProps(to)">
+    <slot />
+  </component>
+</template>
+
+<script>
+import { isExternal } from '@/utils/validate'
+
+export default {
+  props: {
+    to: {
+      type: [String, Object],
+      required: true
+    }
+  },
+  computed: {
+    isExternal() {
+      return isExternal(this.to)
+    },
+    type() {
+      if (this.isExternal) {
+        return 'a'
+      }
+      return 'router-link'
+    }
+  },
+  methods: {
+    linkProps(to) {
+      if (this.isExternal) {
+        return {
+          href: to,
+          target: '_blank',
+          rel: 'noopener'
+        }
+      }
+      return {
+        to: to
+      }
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/Logo.vue b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
new file mode 100644
index 0000000..2774cc8
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/Logo.vue
@@ -0,0 +1,93 @@
+<template>
+  <div class="sidebar-logo-container" :class="{'collapse':collapse}" :style="{ backgroundColor: sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
+    <transition name="sidebarLogoFade">
+      <router-link v-if="collapse" key="collapse" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo" />
+        <h1 v-else class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+      </router-link>
+      <router-link v-else key="expand" class="sidebar-logo-link" to="/">
+        <img v-if="logo" :src="logo" class="sidebar-logo" />
+        <h1 class="sidebar-title" :style="{ color: sideTheme === 'theme-dark' ? variables.logoTitleColor : variables.logoLightTitleColor }">{{ title }} </h1>
+      </router-link>
+    </transition>
+  </div>
+</template>
+
+<script>
+import logoImg from '@/assets/logo/logo.png'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+  name: 'SidebarLogo',
+  props: {
+    collapse: {
+      type: Boolean,
+      required: true
+    }
+  },
+  computed: {
+    variables() {
+      return variables;
+    },
+    sideTheme() {
+      return this.$store.state.settings.sideTheme
+    }
+  },
+  data() {
+    return {
+      title: process.env.VUE_APP_TITLE,
+      logo: logoImg
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.sidebarLogoFade-enter-active {
+  transition: opacity 1.5s;
+}
+
+.sidebarLogoFade-enter,
+.sidebarLogoFade-leave-to {
+  opacity: 0;
+}
+
+.sidebar-logo-container {
+  position: relative;
+  width: 100%;
+  height: 50px;
+  line-height: 50px;
+  background: #2b2f3a;
+  text-align: center;
+  overflow: hidden;
+
+  & .sidebar-logo-link {
+    height: 100%;
+    width: 100%;
+
+    & .sidebar-logo {
+      width: 32px;
+      height: 32px;
+      vertical-align: middle;
+      margin-right: 12px;
+    }
+
+    & .sidebar-title {
+      display: inline-block;
+      margin: 0;
+      color: #fff;
+      font-weight: 600;
+      line-height: 50px;
+      font-size: 14px;
+      font-family: Avenir, Helvetica Neue, Arial, Helvetica, sans-serif;
+      vertical-align: middle;
+    }
+  }
+
+  &.collapse {
+    .sidebar-logo {
+      margin-right: 0px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue b/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
new file mode 100644
index 0000000..fabc61e
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/SidebarItem.vue
@@ -0,0 +1,99 @@
+<template>
+  <div v-if="!item.hidden">
+    <template v-if="hasOneShowingChild(item.children,item) && (!onlyOneChild.children||onlyOneChild.noShowingChildren)&&!item.alwaysShow">
+      <app-link v-if="onlyOneChild.meta" :to="resolvePath(onlyOneChild.path, onlyOneChild.query)">
+        <el-menu-item :index="resolvePath(onlyOneChild.path)" :class="{'submenu-title-noDropdown':!isNest}">
+          <item :icon="onlyOneChild.meta.icon||(item.meta&&item.meta.icon)" :title="onlyOneChild.meta.title" />
+        </el-menu-item>
+      </app-link>
+    </template>
+
+    <el-submenu v-else ref="subMenu" :index="resolvePath(item.path)" popper-append-to-body>
+      <template slot="title">
+        <item v-if="item.meta" :icon="item.meta && item.meta.icon" :title="item.meta.title" />
+      </template>
+      <sidebar-item
+        v-for="(child, index) in item.children"
+        :key="child.path + index"
+        :is-nest="true"
+        :item="child"
+        :base-path="resolvePath(child.path)"
+        class="nest-menu"
+      />
+    </el-submenu>
+  </div>
+</template>
+
+<script>
+import path from 'path'
+import { isExternal } from '@/utils/validate'
+import Item from './Item'
+import AppLink from './Link'
+import FixiOSBug from './FixiOSBug'
+
+export default {
+  name: 'SidebarItem',
+  components: { Item, AppLink },
+  mixins: [FixiOSBug],
+  props: {
+    // route object
+    item: {
+      type: Object,
+      required: true
+    },
+    isNest: {
+      type: Boolean,
+      default: false
+    },
+    basePath: {
+      type: String,
+      default: ''
+    }
+  },
+  data() {
+    this.onlyOneChild = null
+    return {}
+  },
+  methods: {
+    hasOneShowingChild(children = [], parent) {
+      if (!children) {
+        children = [];
+      }
+      const showingChildren = children.filter(item => {
+        if (item.hidden) {
+          return false
+        }
+        // Temp set(will be used if only has one showing child)
+        this.onlyOneChild = item
+        return true
+      })
+
+      // When there is only one child router, the child router is displayed by default
+      if (showingChildren.length === 1) {
+        return true
+      }
+
+      // Show parent if there are no child router to display
+      if (showingChildren.length === 0) {
+        this.onlyOneChild = { ... parent, path: '', noShowingChildren: true }
+        return true
+      }
+
+      return false
+    },
+    resolvePath(routePath, routeQuery) {
+      if (isExternal(routePath)) {
+        return routePath
+      }
+      if (isExternal(this.basePath)) {
+        return this.basePath
+      }
+      if (routeQuery) {
+        let query = JSON.parse(routeQuery);
+        return { path: path.resolve(this.basePath, routePath), query: query }
+      }
+      return path.resolve(this.basePath, routePath)
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/layout/components/Sidebar/index.vue b/ruoyi-ui/src/layout/components/Sidebar/index.vue
new file mode 100644
index 0000000..51d0839
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/Sidebar/index.vue
@@ -0,0 +1,57 @@
+<template>
+    <div :class="{'has-logo':showLogo}" :style="{ backgroundColor: settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground }">
+        <logo v-if="showLogo" :collapse="isCollapse" />
+        <el-scrollbar :class="settings.sideTheme" wrap-class="scrollbar-wrapper">
+            <el-menu
+                :default-active="activeMenu"
+                :collapse="isCollapse"
+                :background-color="settings.sideTheme === 'theme-dark' ? variables.menuBackground : variables.menuLightBackground"
+                :text-color="settings.sideTheme === 'theme-dark' ? variables.menuColor : variables.menuLightColor"
+                :unique-opened="true"
+                :active-text-color="settings.theme"
+                :collapse-transition="false"
+                mode="vertical"
+            >
+                <sidebar-item
+                    v-for="(route, index) in sidebarRouters"
+                    :key="route.path  + index"
+                    :item="route"
+                    :base-path="route.path"
+                />
+            </el-menu>
+        </el-scrollbar>
+    </div>
+</template>
+
+<script>
+import { mapGetters, mapState } from "vuex";
+import Logo from "./Logo";
+import SidebarItem from "./SidebarItem";
+import variables from "@/assets/styles/variables.scss";
+
+export default {
+    components: { SidebarItem, Logo },
+    computed: {
+        ...mapState(["settings"]),
+        ...mapGetters(["sidebarRouters", "sidebar"]),
+        activeMenu() {
+            const route = this.$route;
+            const { meta, path } = route;
+            // if set path, the sidebar will highlight the path you set
+            if (meta.activeMenu) {
+                return meta.activeMenu;
+            }
+            return path;
+        },
+        showLogo() {
+            return this.$store.state.settings.sidebarLogo;
+        },
+        variables() {
+            return variables;
+        },
+        isCollapse() {
+            return !this.sidebar.opened;
+        }
+    }
+};
+</script>
diff --git a/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
new file mode 100644
index 0000000..bb753a1
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/TagsView/ScrollPane.vue
@@ -0,0 +1,94 @@
+<template>
+  <el-scrollbar ref="scrollContainer" :vertical="false" class="scroll-container" @wheel.native.prevent="handleScroll">
+    <slot />
+  </el-scrollbar>
+</template>
+
+<script>
+const tagAndTagSpacing = 4 // tagAndTagSpacing
+
+export default {
+  name: 'ScrollPane',
+  data() {
+    return {
+      left: 0
+    }
+  },
+  computed: {
+    scrollWrapper() {
+      return this.$refs.scrollContainer.$refs.wrap
+    }
+  },
+  mounted() {
+    this.scrollWrapper.addEventListener('scroll', this.emitScroll, true)
+  },
+  beforeDestroy() {
+    this.scrollWrapper.removeEventListener('scroll', this.emitScroll)
+  },
+  methods: {
+    handleScroll(e) {
+      const eventDelta = e.wheelDelta || -e.deltaY * 40
+      const $scrollWrapper = this.scrollWrapper
+      $scrollWrapper.scrollLeft = $scrollWrapper.scrollLeft + eventDelta / 4
+    },
+    emitScroll() {
+      this.$emit('scroll')
+    },
+    moveToTarget(currentTag) {
+      const $container = this.$refs.scrollContainer.$el
+      const $containerWidth = $container.offsetWidth
+      const $scrollWrapper = this.scrollWrapper
+      const tagList = this.$parent.$refs.tag
+
+      let firstTag = null
+      let lastTag = null
+
+      // find first tag and last tag
+      if (tagList.length > 0) {
+        firstTag = tagList[0]
+        lastTag = tagList[tagList.length - 1]
+      }
+
+      if (firstTag === currentTag) {
+        $scrollWrapper.scrollLeft = 0
+      } else if (lastTag === currentTag) {
+        $scrollWrapper.scrollLeft = $scrollWrapper.scrollWidth - $containerWidth
+      } else {
+        // find preTag and nextTag
+        const currentIndex = tagList.findIndex(item => item === currentTag)
+        const prevTag = tagList[currentIndex - 1]
+        const nextTag = tagList[currentIndex + 1]
+
+        // the tag's offsetLeft after of nextTag
+        const afterNextTagOffsetLeft = nextTag.$el.offsetLeft + nextTag.$el.offsetWidth + tagAndTagSpacing
+
+        // the tag's offsetLeft before of prevTag
+        const beforePrevTagOffsetLeft = prevTag.$el.offsetLeft - tagAndTagSpacing
+
+        if (afterNextTagOffsetLeft > $scrollWrapper.scrollLeft + $containerWidth) {
+          $scrollWrapper.scrollLeft = afterNextTagOffsetLeft - $containerWidth
+        } else if (beforePrevTagOffsetLeft < $scrollWrapper.scrollLeft) {
+          $scrollWrapper.scrollLeft = beforePrevTagOffsetLeft
+        }
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.scroll-container {
+  white-space: nowrap;
+  position: relative;
+  overflow: hidden;
+  width: 100%;
+  ::v-deep {
+    .el-scrollbar__bar {
+      bottom: 0px;
+    }
+    .el-scrollbar__wrap {
+      height: 49px;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/TagsView/index.vue b/ruoyi-ui/src/layout/components/TagsView/index.vue
new file mode 100644
index 0000000..39ded08
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/TagsView/index.vue
@@ -0,0 +1,328 @@
+<template>
+  <div id="tags-view-container" class="tags-view-container">
+    <scroll-pane ref="scrollPane" class="tags-view-wrapper" @scroll="handleScroll">
+      <router-link
+        v-for="tag in visitedViews"
+        ref="tag"
+        :key="tag.path"
+        :class="isActive(tag)?'active':''"
+        :to="{ path: tag.path, query: tag.query, fullPath: tag.fullPath }"
+        tag="span"
+        class="tags-view-item"
+        :style="activeStyle(tag)"
+        @click.middle.native="!isAffix(tag)?closeSelectedTag(tag):''"
+        @contextmenu.prevent.native="openMenu(tag,$event)"
+      >
+        {{ tag.title }}
+        <span v-if="!isAffix(tag)" class="el-icon-close" @click.prevent.stop="closeSelectedTag(tag)" />
+      </router-link>
+    </scroll-pane>
+    <ul v-show="visible" :style="{left:left+'px',top:top+'px'}" class="contextmenu">
+      <li @click="refreshSelectedTag(selectedTag)"><i class="el-icon-refresh-right"></i> 鍒锋柊椤甸潰</li>
+      <li v-if="!isAffix(selectedTag)" @click="closeSelectedTag(selectedTag)"><i class="el-icon-close"></i> 鍏抽棴褰撳墠</li>
+      <li @click="closeOthersTags"><i class="el-icon-circle-close"></i> 鍏抽棴鍏朵粬</li>
+      <li v-if="!isFirstView()" @click="closeLeftTags"><i class="el-icon-back"></i> 鍏抽棴宸︿晶</li>
+      <li v-if="!isLastView()" @click="closeRightTags"><i class="el-icon-right"></i> 鍏抽棴鍙充晶</li>
+      <li @click="closeAllTags(selectedTag)"><i class="el-icon-circle-close"></i> 鍏ㄩ儴鍏抽棴</li>
+    </ul>
+  </div>
+</template>
+
+<script>
+import ScrollPane from './ScrollPane'
+import path from 'path'
+
+export default {
+  components: { ScrollPane },
+  data() {
+    return {
+      visible: false,
+      top: 0,
+      left: 0,
+      selectedTag: {},
+      affixTags: []
+    }
+  },
+  computed: {
+    visitedViews() {
+      return this.$store.state.tagsView.visitedViews
+    },
+    routes() {
+      return this.$store.state.permission.routes
+    },
+    theme() {
+      return this.$store.state.settings.theme;
+    }
+  },
+  watch: {
+    $route() {
+      this.addTags()
+      this.moveToCurrentTag()
+    },
+    visible(value) {
+      if (value) {
+        document.body.addEventListener('click', this.closeMenu)
+      } else {
+        document.body.removeEventListener('click', this.closeMenu)
+      }
+    }
+  },
+  mounted() {
+    this.initTags()
+    this.addTags()
+  },
+  methods: {
+    isActive(route) {
+      return route.path === this.$route.path
+    },
+    activeStyle(tag) {
+      if (!this.isActive(tag)) return {};
+      return {
+        "background-color": this.theme,
+        "border-color": this.theme
+      };
+    },
+    isAffix(tag) {
+      return tag.meta && tag.meta.affix
+    },
+    isFirstView() {
+      try {
+        return this.selectedTag.fullPath === '/index' || this.selectedTag.fullPath === this.visitedViews[1].fullPath
+      } catch (err) {
+        return false
+      }
+    },
+    isLastView() {
+      try {
+        return this.selectedTag.fullPath === this.visitedViews[this.visitedViews.length - 1].fullPath
+      } catch (err) {
+        return false
+      }
+    },
+    filterAffixTags(routes, basePath = '/') {
+      let tags = []
+      routes.forEach(route => {
+        if (route.meta && route.meta.affix) {
+          const tagPath = path.resolve(basePath, route.path)
+          tags.push({
+            fullPath: tagPath,
+            path: tagPath,
+            name: route.name,
+            meta: { ...route.meta }
+          })
+        }
+        if (route.children) {
+          const tempTags = this.filterAffixTags(route.children, route.path)
+          if (tempTags.length >= 1) {
+            tags = [...tags, ...tempTags]
+          }
+        }
+      })
+      return tags
+    },
+    initTags() {
+      const affixTags = this.affixTags = this.filterAffixTags(this.routes)
+      for (const tag of affixTags) {
+        // Must have tag name
+        if (tag.name) {
+          this.$store.dispatch('tagsView/addVisitedView', tag)
+        }
+      }
+    },
+    addTags() {
+      const { name } = this.$route
+      if (name) {
+        this.$store.dispatch('tagsView/addView', this.$route)
+      }
+    },
+    moveToCurrentTag() {
+      const tags = this.$refs.tag
+      this.$nextTick(() => {
+        for (const tag of tags) {
+          if (tag.to.path === this.$route.path) {
+            this.$refs.scrollPane.moveToTarget(tag)
+            // when query is different then update
+            if (tag.to.fullPath !== this.$route.fullPath) {
+              this.$store.dispatch('tagsView/updateVisitedView', this.$route)
+            }
+            break
+          }
+        }
+      })
+    },
+    refreshSelectedTag(view) {
+      this.$tab.refreshPage(view);
+      if (this.$route.meta.link) {
+        this.$store.dispatch('tagsView/delIframeView', this.$route)
+      }
+    },
+    closeSelectedTag(view) {
+      this.$tab.closePage(view).then(({ visitedViews }) => {
+        if (this.isActive(view)) {
+          this.toLastView(visitedViews, view)
+        }
+      })
+    },
+    closeRightTags() {
+      this.$tab.closeRightPage(this.selectedTag).then(visitedViews => {
+        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
+          this.toLastView(visitedViews)
+        }
+      })
+    },
+    closeLeftTags() {
+      this.$tab.closeLeftPage(this.selectedTag).then(visitedViews => {
+        if (!visitedViews.find(i => i.fullPath === this.$route.fullPath)) {
+          this.toLastView(visitedViews)
+        }
+      })
+    },
+    closeOthersTags() {
+      this.$router.push(this.selectedTag.fullPath).catch(()=>{});
+      this.$tab.closeOtherPage(this.selectedTag).then(() => {
+        this.moveToCurrentTag()
+      })
+    },
+    closeAllTags(view) {
+      this.$tab.closeAllPage().then(({ visitedViews }) => {
+        if (this.affixTags.some(tag => tag.path === this.$route.path)) {
+          return
+        }
+        this.toLastView(visitedViews, view)
+      })
+    },
+    toLastView(visitedViews, view) {
+      const latestView = visitedViews.slice(-1)[0]
+      if (latestView) {
+        this.$router.push(latestView.fullPath)
+      } else {
+        // now the default is to redirect to the home page if there is no tags-view,
+        // you can adjust it according to your needs.
+        if (view.name === 'Dashboard') {
+          // to reload home page
+          this.$router.replace({ path: '/redirect' + view.fullPath })
+        } else {
+          this.$router.push('/')
+        }
+      }
+    },
+    openMenu(tag, e) {
+      const menuMinWidth = 105
+      const offsetLeft = this.$el.getBoundingClientRect().left // container margin left
+      const offsetWidth = this.$el.offsetWidth // container width
+      const maxLeft = offsetWidth - menuMinWidth // left boundary
+      const left = e.clientX - offsetLeft + 15 // 15: margin right
+
+      if (left > maxLeft) {
+        this.left = maxLeft
+      } else {
+        this.left = left
+      }
+
+      this.top = e.clientY
+      this.visible = true
+      this.selectedTag = tag
+    },
+    closeMenu() {
+      this.visible = false
+    },
+    handleScroll() {
+      this.closeMenu()
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.tags-view-container {
+  height: 34px;
+  width: 100%;
+  background: #fff;
+  border-bottom: 1px solid #d8dce5;
+  box-shadow: 0 1px 3px 0 rgba(0, 0, 0, .12), 0 0 3px 0 rgba(0, 0, 0, .04);
+  .tags-view-wrapper {
+    .tags-view-item {
+      display: inline-block;
+      position: relative;
+      cursor: pointer;
+      height: 26px;
+      line-height: 26px;
+      border: 1px solid #d8dce5;
+      color: #495060;
+      background: #fff;
+      padding: 0 8px;
+      font-size: 12px;
+      margin-left: 5px;
+      margin-top: 4px;
+      &:first-of-type {
+        margin-left: 15px;
+      }
+      &:last-of-type {
+        margin-right: 15px;
+      }
+      &.active {
+        background-color: #42b983;
+        color: #fff;
+        border-color: #42b983;
+        &::before {
+          content: '';
+          background: #fff;
+          display: inline-block;
+          width: 8px;
+          height: 8px;
+          border-radius: 50%;
+          position: relative;
+          margin-right: 2px;
+        }
+      }
+    }
+  }
+  .contextmenu {
+    margin: 0;
+    background: #fff;
+    z-index: 3000;
+    position: absolute;
+    list-style-type: none;
+    padding: 5px 0;
+    border-radius: 4px;
+    font-size: 12px;
+    font-weight: 400;
+    color: #333;
+    box-shadow: 2px 2px 3px 0 rgba(0, 0, 0, .3);
+    li {
+      margin: 0;
+      padding: 7px 16px;
+      cursor: pointer;
+      &:hover {
+        background: #eee;
+      }
+    }
+  }
+}
+</style>
+
+<style lang="scss">
+//reset element css of el-icon-close
+.tags-view-wrapper {
+  .tags-view-item {
+    .el-icon-close {
+      width: 16px;
+      height: 16px;
+      vertical-align: 2px;
+      border-radius: 50%;
+      text-align: center;
+      transition: all .3s cubic-bezier(.645, .045, .355, 1);
+      transform-origin: 100% 50%;
+      &:before {
+        transform: scale(.6);
+        display: inline-block;
+        vertical-align: -3px;
+      }
+      &:hover {
+        background-color: #b4bccc;
+        color: #fff;
+      }
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/layout/components/index.js b/ruoyi-ui/src/layout/components/index.js
new file mode 100644
index 0000000..104bd3a
--- /dev/null
+++ b/ruoyi-ui/src/layout/components/index.js
@@ -0,0 +1,5 @@
+export { default as AppMain } from './AppMain'
+export { default as Navbar } from './Navbar'
+export { default as Settings } from './Settings'
+export { default as Sidebar } from './Sidebar/index.vue'
+export { default as TagsView } from './TagsView/index.vue'
diff --git a/ruoyi-ui/src/layout/index.vue b/ruoyi-ui/src/layout/index.vue
new file mode 100644
index 0000000..dba4393
--- /dev/null
+++ b/ruoyi-ui/src/layout/index.vue
@@ -0,0 +1,111 @@
+<template>
+  <div :class="classObj" class="app-wrapper" :style="{'--current-color': theme}">
+    <div v-if="device==='mobile'&&sidebar.opened" class="drawer-bg" @click="handleClickOutside"/>
+    <sidebar v-if="!sidebar.hide" class="sidebar-container"/>
+    <div :class="{hasTagsView:needTagsView,sidebarHide:sidebar.hide}" class="main-container">
+      <div :class="{'fixed-header':fixedHeader}">
+        <navbar/>
+        <tags-view v-if="needTagsView"/>
+      </div>
+      <app-main/>
+      <right-panel>
+        <settings/>
+      </right-panel>
+    </div>
+  </div>
+</template>
+
+<script>
+import RightPanel from '@/components/RightPanel'
+import { AppMain, Navbar, Settings, Sidebar, TagsView } from './components'
+import ResizeMixin from './mixin/ResizeHandler'
+import { mapState } from 'vuex'
+import variables from '@/assets/styles/variables.scss'
+
+export default {
+  name: 'Layout',
+  components: {
+    AppMain,
+    Navbar,
+    RightPanel,
+    Settings,
+    Sidebar,
+    TagsView
+  },
+  mixins: [ResizeMixin],
+  computed: {
+    ...mapState({
+      theme: state => state.settings.theme,
+      sideTheme: state => state.settings.sideTheme,
+      sidebar: state => state.app.sidebar,
+      device: state => state.app.device,
+      needTagsView: state => state.settings.tagsView,
+      fixedHeader: state => state.settings.fixedHeader
+    }),
+    classObj() {
+      return {
+        hideSidebar: !this.sidebar.opened,
+        openSidebar: this.sidebar.opened,
+        withoutAnimation: this.sidebar.withoutAnimation,
+        mobile: this.device === 'mobile'
+      }
+    },
+    variables() {
+      return variables;
+    }
+  },
+  methods: {
+    handleClickOutside() {
+      this.$store.dispatch('app/closeSideBar', { withoutAnimation: false })
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  @import "~@/assets/styles/mixin.scss";
+  @import "~@/assets/styles/variables.scss";
+
+  .app-wrapper {
+    @include clearfix;
+    position: relative;
+    height: 100%;
+    width: 100%;
+
+    &.mobile.openSidebar {
+      position: fixed;
+      top: 0;
+    }
+  }
+
+  .drawer-bg {
+    background: #000;
+    opacity: 0.3;
+    width: 100%;
+    top: 0;
+    height: 100%;
+    position: absolute;
+    z-index: 999;
+  }
+
+  .fixed-header {
+    position: fixed;
+    top: 0;
+    right: 0;
+    z-index: 9;
+    width: calc(100% - #{$base-sidebar-width});
+    transition: width 0.28s;
+  }
+
+  .hideSidebar .fixed-header {
+    width: calc(100% - 54px);
+  }
+
+  .sidebarHide .fixed-header {
+    width: 100%;
+  }
+
+  .mobile .fixed-header {
+    width: 100%;
+  }
+</style>
diff --git a/ruoyi-ui/src/layout/mixin/ResizeHandler.js b/ruoyi-ui/src/layout/mixin/ResizeHandler.js
new file mode 100644
index 0000000..e8d0df8
--- /dev/null
+++ b/ruoyi-ui/src/layout/mixin/ResizeHandler.js
@@ -0,0 +1,45 @@
+import store from '@/store'
+
+const { body } = document
+const WIDTH = 992 // refer to Bootstrap's responsive design
+
+export default {
+  watch: {
+    $route(route) {
+      if (this.device === 'mobile' && this.sidebar.opened) {
+        store.dispatch('app/closeSideBar', { withoutAnimation: false })
+      }
+    }
+  },
+  beforeMount() {
+    window.addEventListener('resize', this.$_resizeHandler)
+  },
+  beforeDestroy() {
+    window.removeEventListener('resize', this.$_resizeHandler)
+  },
+  mounted() {
+    const isMobile = this.$_isMobile()
+    if (isMobile) {
+      store.dispatch('app/toggleDevice', 'mobile')
+      store.dispatch('app/closeSideBar', { withoutAnimation: true })
+    }
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_isMobile() {
+      const rect = body.getBoundingClientRect()
+      return rect.width - 1 < WIDTH
+    },
+    $_resizeHandler() {
+      if (!document.hidden) {
+        const isMobile = this.$_isMobile()
+        store.dispatch('app/toggleDevice', isMobile ? 'mobile' : 'desktop')
+
+        if (isMobile) {
+          store.dispatch('app/closeSideBar', { withoutAnimation: true })
+        }
+      }
+    }
+  }
+}
diff --git a/ruoyi-ui/src/main.js b/ruoyi-ui/src/main.js
new file mode 100644
index 0000000..13c6cf2
--- /dev/null
+++ b/ruoyi-ui/src/main.js
@@ -0,0 +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)
+})
diff --git a/ruoyi-ui/src/permission.js b/ruoyi-ui/src/permission.js
new file mode 100644
index 0000000..b66190b
--- /dev/null
+++ b/ruoyi-ui/src/permission.js
@@ -0,0 +1,63 @@
+import router from './router'
+import store from './store'
+import { Message } from 'element-ui'
+import NProgress from 'nprogress'
+import 'nprogress/nprogress.css'
+import { getToken } from '@/utils/auth'
+import { isPathMatch } from '@/utils/validate'
+import { isRelogin } from '@/utils/request'
+
+NProgress.configure({ showSpinner: false })
+
+const whiteList = ['/login', '/register']
+
+const isWhiteList = (path) => {
+  return whiteList.some(pattern => isPathMatch(pattern, path))
+}
+
+router.beforeEach((to, from, next) => {
+  NProgress.start()
+  if (getToken()) {
+    to.meta.title && store.dispatch('settings/setTitle', to.meta.title)
+    /* has token*/
+    if (to.path === '/login') {
+      next({ path: '/' })
+      NProgress.done()
+    } else if (isWhiteList(to.path)) {
+      next()
+    } else {
+      if (store.getters.roles.length === 0) {
+        isRelogin.show = true
+        // 鍒ゆ柇褰撳墠鐢ㄦ埛鏄惁宸叉媺鍙栧畬user_info淇℃伅
+        store.dispatch('GetInfo').then(() => {
+          isRelogin.show = false
+          store.dispatch('GenerateRoutes').then(accessRoutes => {
+            // 鏍规嵁roles鏉冮檺鐢熸垚鍙闂殑璺敱琛�
+            router.addRoutes(accessRoutes) // 鍔ㄦ�佹坊鍔犲彲璁块棶璺敱琛�
+            next({ ...to, replace: true }) // hack鏂规硶 纭繚addRoutes宸插畬鎴�
+          })
+        }).catch(err => {
+            store.dispatch('LogOut').then(() => {
+              Message.error(err)
+              next({ path: '/' })
+            })
+          })
+      } else {
+        next()
+      }
+    }
+  } else {
+    // 娌℃湁token
+    if (isWhiteList(to.path)) {
+      // 鍦ㄥ厤鐧诲綍鐧藉悕鍗曪紝鐩存帴杩涘叆
+      next()
+    } else {
+      next(`/login?redirect=${encodeURIComponent(to.fullPath)}`) // 鍚﹀垯鍏ㄩ儴閲嶅畾鍚戝埌鐧诲綍椤�
+      NProgress.done()
+    }
+  }
+})
+
+router.afterEach(() => {
+  NProgress.done()
+})
diff --git a/ruoyi-ui/src/plugins/auth.js b/ruoyi-ui/src/plugins/auth.js
new file mode 100644
index 0000000..6c6bc24
--- /dev/null
+++ b/ruoyi-ui/src/plugins/auth.js
@@ -0,0 +1,60 @@
+import store from '@/store'
+
+function authPermission(permission) {
+  const all_permission = "*:*:*";
+  const permissions = store.getters && store.getters.permissions
+  if (permission && permission.length > 0) {
+    return permissions.some(v => {
+      return all_permission === v || v === permission
+    })
+  } else {
+    return false
+  }
+}
+
+function authRole(role) {
+  const super_admin = "admin";
+  const roles = store.getters && store.getters.roles
+  if (role && role.length > 0) {
+    return roles.some(v => {
+      return super_admin === v || v === role
+    })
+  } else {
+    return false
+  }
+}
+
+export default {
+  // 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愭潈闄�
+  hasPermi(permission) {
+    return authPermission(permission);
+  },
+  // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾鏉冮檺锛屽彧闇�鍖呭惈鍏朵腑涓�涓�
+  hasPermiOr(permissions) {
+    return permissions.some(item => {
+      return authPermission(item)
+    })
+  },
+  // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾鏉冮檺锛屽繀椤诲叏閮ㄦ嫢鏈�
+  hasPermiAnd(permissions) {
+    return permissions.every(item => {
+      return authPermission(item)
+    })
+  },
+  // 楠岃瘉鐢ㄦ埛鏄惁鍏峰鏌愯鑹�
+  hasRole(role) {
+    return authRole(role);
+  },
+  // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾瑙掕壊锛屽彧闇�鍖呭惈鍏朵腑涓�涓�
+  hasRoleOr(roles) {
+    return roles.some(item => {
+      return authRole(item)
+    })
+  },
+  // 楠岃瘉鐢ㄦ埛鏄惁鍚湁鎸囧畾瑙掕壊锛屽繀椤诲叏閮ㄦ嫢鏈�
+  hasRoleAnd(roles) {
+    return roles.every(item => {
+      return authRole(item)
+    })
+  }
+}
diff --git a/ruoyi-ui/src/plugins/cache.js b/ruoyi-ui/src/plugins/cache.js
new file mode 100644
index 0000000..b67d453
--- /dev/null
+++ b/ruoyi-ui/src/plugins/cache.js
@@ -0,0 +1,79 @@
+const sessionCache = {
+  set (key, value) {
+    if (!sessionStorage) {
+      return
+    }
+    if (key != null && value != null) {
+      sessionStorage.setItem(key, value)
+    }
+  },
+  get (key) {
+    if (!sessionStorage) {
+      return null
+    }
+    if (key == null) {
+      return null
+    }
+    return sessionStorage.getItem(key)
+  },
+  setJSON (key, jsonValue) {
+    if (jsonValue != null) {
+      this.set(key, JSON.stringify(jsonValue))
+    }
+  },
+  getJSON (key) {
+    const value = this.get(key)
+    if (value != null) {
+      return JSON.parse(value)
+    }
+    return null
+  },
+  remove (key) {
+    sessionStorage.removeItem(key);
+  }
+}
+const localCache = {
+  set (key, value) {
+    if (!localStorage) {
+      return
+    }
+    if (key != null && value != null) {
+      localStorage.setItem(key, value)
+    }
+  },
+  get (key) {
+    if (!localStorage) {
+      return null
+    }
+    if (key == null) {
+      return null
+    }
+    return localStorage.getItem(key)
+  },
+  setJSON (key, jsonValue) {
+    if (jsonValue != null) {
+      this.set(key, JSON.stringify(jsonValue))
+    }
+  },
+  getJSON (key) {
+    const value = this.get(key)
+    if (value != null) {
+      return JSON.parse(value)
+    }
+    return null
+  },
+  remove (key) {
+    localStorage.removeItem(key);
+  }
+}
+
+export default {
+  /**
+   * 浼氳瘽绾х紦瀛�
+   */
+  session: sessionCache,
+  /**
+   * 鏈湴缂撳瓨
+   */
+  local: localCache
+}
diff --git a/ruoyi-ui/src/plugins/download.js b/ruoyi-ui/src/plugins/download.js
new file mode 100644
index 0000000..42acd00
--- /dev/null
+++ b/ruoyi-ui/src/plugins/download.js
@@ -0,0 +1,79 @@
+import axios from 'axios'
+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";
+
+const baseURL = process.env.VUE_APP_BASE_API
+let downloadLoadingInstance;
+
+export default {
+  name(name, isDelete = true) {
+    var url = baseURL + "/common/download?fileName=" + encodeURIComponent(name) + "&delete=" + isDelete
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then((res) => {
+      const isBlob = blobValidate(res.data);
+      if (isBlob) {
+        const blob = new Blob([res.data])
+        this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data);
+      }
+    })
+  },
+  resource(resource) {
+    var url = baseURL + "/common/download/resource?resource=" + encodeURIComponent(resource);
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then((res) => {
+      const isBlob = blobValidate(res.data);
+      if (isBlob) {
+        const blob = new Blob([res.data])
+        this.saveAs(blob, decodeURIComponent(res.headers['download-filename']))
+      } else {
+        this.printErrMsg(res.data);
+      }
+    })
+  },
+  zip(url, name) {
+    var url = baseURL + url
+    downloadLoadingInstance = Loading.service({ text: "姝e湪涓嬭浇鏁版嵁锛岃绋嶅��", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
+    axios({
+      method: 'get',
+      url: url,
+      responseType: 'blob',
+      headers: { 'Authorization': 'Bearer ' + getToken() }
+    }).then((res) => {
+      const isBlob = blobValidate(res.data);
+      if (isBlob) {
+        const blob = new Blob([res.data], { type: 'application/zip' })
+        this.saveAs(blob, name)
+      } else {
+        this.printErrMsg(res.data);
+      }
+      downloadLoadingInstance.close();
+    }).catch((r) => {
+      console.error(r)
+      Message.error('涓嬭浇鏂囦欢鍑虹幇閿欒锛岃鑱旂郴绠$悊鍛橈紒')
+      downloadLoadingInstance.close();
+    })
+  },
+  saveAs(text, name, opts) {
+    saveAs(text, name, opts);
+  },
+  async printErrMsg(data) {
+    const resText = await data.text();
+    const rspObj = JSON.parse(resText);
+    const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+    Message.error(errMsg);
+  }
+}
+
diff --git a/ruoyi-ui/src/plugins/index.js b/ruoyi-ui/src/plugins/index.js
new file mode 100644
index 0000000..d000f2d
--- /dev/null
+++ b/ruoyi-ui/src/plugins/index.js
@@ -0,0 +1,20 @@
+import tab from './tab'
+import auth from './auth'
+import cache from './cache'
+import modal from './modal'
+import download from './download'
+
+export default {
+  install(Vue) {
+    // 椤电鎿嶄綔
+    Vue.prototype.$tab = tab
+    // 璁よ瘉瀵硅薄
+    Vue.prototype.$auth = auth
+    // 缂撳瓨瀵硅薄
+    Vue.prototype.$cache = cache
+    // 妯℃�佹瀵硅薄
+    Vue.prototype.$modal = modal
+    // 涓嬭浇鏂囦欢
+    Vue.prototype.$download = download
+  }
+}
diff --git a/ruoyi-ui/src/plugins/modal.js b/ruoyi-ui/src/plugins/modal.js
new file mode 100644
index 0000000..b37ca14
--- /dev/null
+++ b/ruoyi-ui/src/plugins/modal.js
@@ -0,0 +1,83 @@
+import { Message, MessageBox, Notification, Loading } from 'element-ui'
+
+let loadingInstance;
+
+export default {
+  // 娑堟伅鎻愮ず
+  msg(content) {
+    Message.info(content)
+  },
+  // 閿欒娑堟伅
+  msgError(content) {
+    Message.error(content)
+  },
+  // 鎴愬姛娑堟伅
+  msgSuccess(content) {
+    Message.success(content)
+  },
+  // 璀﹀憡娑堟伅
+  msgWarning(content) {
+    Message.warning(content)
+  },
+  // 寮瑰嚭鎻愮ず
+  alert(content) {
+    MessageBox.alert(content, "绯荤粺鎻愮ず")
+  },
+  // 閿欒鎻愮ず
+  alertError(content) {
+    MessageBox.alert(content, "绯荤粺鎻愮ず", { type: 'error' })
+  },
+  // 鎴愬姛鎻愮ず
+  alertSuccess(content) {
+    MessageBox.alert(content, "绯荤粺鎻愮ず", { type: 'success' })
+  },
+  // 璀﹀憡鎻愮ず
+  alertWarning(content) {
+    MessageBox.alert(content, "绯荤粺鎻愮ず", { type: 'warning' })
+  },
+  // 閫氱煡鎻愮ず
+  notify(content) {
+    Notification.info(content)
+  },
+  // 閿欒閫氱煡
+  notifyError(content) {
+    Notification.error(content);
+  },
+  // 鎴愬姛閫氱煡
+  notifySuccess(content) {
+    Notification.success(content)
+  },
+  // 璀﹀憡閫氱煡
+  notifyWarning(content) {
+    Notification.warning(content)
+  },
+  // 纭绐椾綋
+  confirm(content) {
+    return MessageBox.confirm(content, "绯荤粺鎻愮ず", {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: "warning",
+    })
+  },
+  // 鎻愪氦鍐呭
+  prompt(content) {
+    return MessageBox.prompt(content, "绯荤粺鎻愮ず", {
+      confirmButtonText: '纭畾',
+      cancelButtonText: '鍙栨秷',
+      type: "warning",
+    })
+  },
+  // 鎵撳紑閬僵灞�
+  loading(content) {
+    loadingInstance = Loading.service({
+      lock: true,
+      text: content,
+      spinner: "el-icon-loading",
+      background: "rgba(0, 0, 0, 0.7)",
+    })
+  },
+  // 鍏抽棴閬僵灞�
+  closeLoading() {
+    loadingInstance.close();
+  }
+}
diff --git a/ruoyi-ui/src/plugins/tab.js b/ruoyi-ui/src/plugins/tab.js
new file mode 100644
index 0000000..fcde419
--- /dev/null
+++ b/ruoyi-ui/src/plugins/tab.js
@@ -0,0 +1,71 @@
+import store from '@/store'
+import router from '@/router';
+
+export default {
+  // 鍒锋柊褰撳墠tab椤电
+  refreshPage(obj) {
+    const { path, query, matched } = router.currentRoute;
+    if (obj === undefined) {
+      matched.forEach((m) => {
+        if (m.components && m.components.default && m.components.default.name) {
+          if (!['Layout', 'ParentView'].includes(m.components.default.name)) {
+            obj = { name: m.components.default.name, path: path, query: query };
+          }
+        }
+      });
+    }
+    return store.dispatch('tagsView/delCachedView', obj).then(() => {
+      const { path, query } = obj
+      router.replace({
+        path: '/redirect' + path,
+        query: query
+      })
+    })
+  },
+  // 鍏抽棴褰撳墠tab椤电锛屾墦寮�鏂伴〉绛�
+  closeOpenPage(obj) {
+    store.dispatch("tagsView/delView", router.currentRoute);
+    if (obj !== undefined) {
+      return router.push(obj);
+    }
+  },
+  // 鍏抽棴鎸囧畾tab椤电
+  closePage(obj) {
+    if (obj === undefined) {
+      return store.dispatch('tagsView/delView', router.currentRoute).then(({ visitedViews }) => {
+        const latestView = visitedViews.slice(-1)[0]
+        if (latestView) {
+          return router.push(latestView.fullPath)
+        }
+        return router.push('/');
+      });
+    }
+    return store.dispatch('tagsView/delView', obj);
+  },
+  // 鍏抽棴鎵�鏈塼ab椤电
+  closeAllPage() {
+    return store.dispatch('tagsView/delAllViews');
+  },
+  // 鍏抽棴宸︿晶tab椤电
+  closeLeftPage(obj) {
+    return store.dispatch('tagsView/delLeftTags', obj || router.currentRoute);
+  },
+  // 鍏抽棴鍙充晶tab椤电
+  closeRightPage(obj) {
+    return store.dispatch('tagsView/delRightTags', obj || router.currentRoute);
+  },
+  // 鍏抽棴鍏朵粬tab椤电
+  closeOtherPage(obj) {
+    return store.dispatch('tagsView/delOthersViews', obj || router.currentRoute);
+  },
+  // 娣诲姞tab椤电
+  openPage(title, url, params) {
+    const obj = { path: url, meta: { title: title } }
+    store.dispatch('tagsView/addView', obj);
+    return router.push({ path: url, query: params });
+  },
+  // 淇敼tab椤电
+  updatePage(obj) {
+    return store.dispatch('tagsView/updateVisitedView', obj);
+  }
+}
diff --git a/ruoyi-ui/src/router/index.js b/ruoyi-ui/src/router/index.js
new file mode 100644
index 0000000..71907b6
--- /dev/null
+++ b/ruoyi-ui/src/router/index.js
@@ -0,0 +1,183 @@
+import Vue from 'vue'
+import Router from 'vue-router'
+
+Vue.use(Router)
+
+/* Layout */
+import Layout from '@/layout'
+
+/**
+ * Note: 璺敱閰嶇疆椤�
+ *
+ * hidden: true                     // 褰撹缃� true 鐨勬椂鍊欒璺敱涓嶄細鍐嶄晶杈规爮鍑虹幇 濡�401锛宭ogin绛夐〉闈紝鎴栬�呭涓�浜涚紪杈戦〉闈�/edit/1
+ * alwaysShow: true                 // 褰撲綘涓�涓矾鐢变笅闈㈢殑 children 澹版槑鐨勮矾鐢卞ぇ浜�1涓椂锛岃嚜鍔ㄤ細鍙樻垚宓屽鐨勬ā寮�--濡傜粍浠堕〉闈�
+ *                                  // 鍙湁涓�涓椂锛屼細灏嗛偅涓瓙璺敱褰撳仛鏍硅矾鐢辨樉绀哄湪渚ц竟鏍�--濡傚紩瀵奸〉闈�
+ *                                  // 鑻ヤ綘鎯充笉绠¤矾鐢变笅闈㈢殑 children 澹版槑鐨勪釜鏁伴兘鏄剧ず浣犵殑鏍硅矾鐢�
+ *                                  // 浣犲彲浠ヨ缃� alwaysShow: true锛岃繖鏍峰畠灏变細蹇界暐涔嬪墠瀹氫箟鐨勮鍒欙紝涓�鐩存樉绀烘牴璺敱
+ * redirect: noRedirect             // 褰撹缃� noRedirect 鐨勬椂鍊欒璺敱鍦ㄩ潰鍖呭睉瀵艰埅涓笉鍙鐐瑰嚮
+ * name:'router-name'               // 璁惧畾璺敱鐨勫悕瀛楋紝涓�瀹氳濉啓涓嶇劧浣跨敤<keep-alive>鏃朵細鍑虹幇鍚勭闂
+ * query: '{"id": 1, "name": "ry"}' // 璁块棶璺敱鐨勯粯璁や紶閫掑弬鏁�
+ * roles: ['admin', 'common']       // 璁块棶璺敱鐨勮鑹叉潈闄�
+ * permissions: ['a:a:a', 'b:b:b']  // 璁块棶璺敱鐨勮彍鍗曟潈闄�
+ * meta : {
+    noCache: true                   // 濡傛灉璁剧疆涓簍rue锛屽垯涓嶄細琚� <keep-alive> 缂撳瓨(榛樿 false)
+    title: 'title'                  // 璁剧疆璇ヨ矾鐢卞湪渚ц竟鏍忓拰闈㈠寘灞戜腑灞曠ず鐨勫悕瀛�
+    icon: 'svg-name'                // 璁剧疆璇ヨ矾鐢辩殑鍥炬爣锛屽搴旇矾寰剆rc/assets/icons/svg
+    breadcrumb: false               // 濡傛灉璁剧疆涓篺alse锛屽垯涓嶄細鍦╞readcrumb闈㈠寘灞戜腑鏄剧ず
+    activeMenu: '/system/user'      // 褰撹矾鐢辫缃簡璇ュ睘鎬э紝鍒欎細楂樹寒鐩稿搴旂殑渚ц竟鏍忋��
+  }
+ */
+
+// 鍏叡璺敱
+export const constantRoutes = [
+  {
+    path: '/redirect',
+    component: Layout,
+    hidden: true,
+    children: [
+      {
+        path: '/redirect/:path(.*)',
+        component: () => import('@/views/redirect')
+      }
+    ]
+  },
+  {
+    path: '/login',
+    component: () => import('@/views/login'),
+    hidden: true
+  },
+  {
+    path: '/register',
+    component: () => import('@/views/register'),
+    hidden: true
+  },
+  {
+    path: '/404',
+    component: () => import('@/views/error/404'),
+    hidden: true
+  },
+  {
+    path: '/401',
+    component: () => import('@/views/error/401'),
+    hidden: true
+  },
+  {
+    path: '',
+    component: Layout,
+    redirect: 'index',
+    children: [
+      {
+        path: 'index',
+        component: () => import('@/views/index'),
+        name: 'Index',
+        meta: { title: '棣栭〉', icon: 'dashboard', affix: true }
+      }
+    ]
+  },
+  {
+    path: '/user',
+    component: Layout,
+    hidden: true,
+    redirect: 'noredirect',
+    children: [
+      {
+        path: 'profile',
+        component: () => import('@/views/system/user/profile/index'),
+        name: 'Profile',
+        meta: { title: '涓汉涓績', icon: 'user' }
+      }
+    ]
+  }
+]
+
+// 鍔ㄦ�佽矾鐢憋紝鍩轰簬鐢ㄦ埛鏉冮檺鍔ㄦ�佸幓鍔犺浇
+export const dynamicRoutes = [
+  {
+    path: '/system/user-auth',
+    component: Layout,
+    hidden: true,
+    permissions: ['system:user:edit'],
+    children: [
+      {
+        path: 'role/:userId(\\d+)',
+        component: () => import('@/views/system/user/authRole'),
+        name: 'AuthRole',
+        meta: { title: '鍒嗛厤瑙掕壊', activeMenu: '/system/user' }
+      }
+    ]
+  },
+  {
+    path: '/system/role-auth',
+    component: Layout,
+    hidden: true,
+    permissions: ['system:role:edit'],
+    children: [
+      {
+        path: 'user/:roleId(\\d+)',
+        component: () => import('@/views/system/role/authUser'),
+        name: 'AuthUser',
+        meta: { title: '鍒嗛厤鐢ㄦ埛', activeMenu: '/system/role' }
+      }
+    ]
+  },
+  {
+    path: '/system/dict-data',
+    component: Layout,
+    hidden: true,
+    permissions: ['system:dict:list'],
+    children: [
+      {
+        path: 'index/:dictId(\\d+)',
+        component: () => import('@/views/system/dict/data'),
+        name: 'Data',
+        meta: { title: '瀛楀吀鏁版嵁', activeMenu: '/system/dict' }
+      }
+    ]
+  },
+  {
+    path: '/monitor/job-log',
+    component: Layout,
+    hidden: true,
+    permissions: ['monitor:job:list'],
+    children: [
+      {
+        path: 'index/:jobId(\\d+)',
+        component: () => import('@/views/monitor/job/log'),
+        name: 'JobLog',
+        meta: { title: '璋冨害鏃ュ織', activeMenu: '/monitor/job' }
+      }
+    ]
+  },
+  {
+    path: '/tool/gen-edit',
+    component: Layout,
+    hidden: true,
+    permissions: ['tool:gen:edit'],
+    children: [
+      {
+        path: 'index/:tableId(\\d+)',
+        component: () => import('@/views/tool/gen/editTable'),
+        name: 'GenEdit',
+        meta: { title: '淇敼鐢熸垚閰嶇疆', activeMenu: '/tool/gen' }
+      }
+    ]
+  }
+]
+
+// 闃叉杩炵画鐐瑰嚮澶氭璺敱鎶ラ敊
+let routerPush = Router.prototype.push;
+let routerReplace = Router.prototype.replace;
+// push
+Router.prototype.push = function push(location) {
+  return routerPush.call(this, location).catch(err => err)
+}
+// replace
+Router.prototype.replace = function push(location) {
+  return routerReplace.call(this, location).catch(err => err)
+}
+
+export default new Router({
+  mode: 'history', // 鍘绘帀url涓殑#
+  scrollBehavior: () => ({ y: 0 }),
+  routes: constantRoutes
+})
diff --git a/ruoyi-ui/src/settings.js b/ruoyi-ui/src/settings.js
new file mode 100644
index 0000000..6a0b09f
--- /dev/null
+++ b/ruoyi-ui/src/settings.js
@@ -0,0 +1,44 @@
+module.exports = {
+  /**
+   * 渚ц竟鏍忎富棰� 娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light
+   */
+  sideTheme: 'theme-dark',
+
+  /**
+   * 鏄惁绯荤粺甯冨眬閰嶇疆
+   */
+  showSettings: false,
+
+  /**
+   * 鏄惁鏄剧ず椤堕儴瀵艰埅
+   */
+  topNav: false,
+
+  /**
+   * 鏄惁鏄剧ず tagsView
+   */
+  tagsView: true,
+
+  /**
+   * 鏄惁鍥哄畾澶撮儴
+   */
+  fixedHeader: false,
+
+  /**
+   * 鏄惁鏄剧ずlogo
+   */
+  sidebarLogo: true,
+
+  /**
+   * 鏄惁鏄剧ず鍔ㄦ�佹爣棰�
+   */
+  dynamicTitle: false,
+
+  /**
+   * @type {string | array} 'production' | ['production', 'development']
+   * @description Need show err logs component.
+   * The default is only used in the production env
+   * If you want to also use it in dev, you can pass ['production', 'development']
+   */
+  errorLog: 'production'
+}
diff --git a/ruoyi-ui/src/store/getters.js b/ruoyi-ui/src/store/getters.js
new file mode 100644
index 0000000..8adb1b6
--- /dev/null
+++ b/ruoyi-ui/src/store/getters.js
@@ -0,0 +1,19 @@
+const getters = {
+  sidebar: state => state.app.sidebar,
+  size: state => state.app.size,
+  device: state => state.app.device,
+  dict: state => state.dict.dict,
+  visitedViews: state => state.tagsView.visitedViews,
+  cachedViews: state => state.tagsView.cachedViews,
+  token: state => state.user.token,
+  avatar: state => state.user.avatar,
+  name: state => state.user.name,
+  introduction: state => state.user.introduction,
+  roles: state => state.user.roles,
+  permissions: state => state.user.permissions,
+  permission_routes: state => state.permission.routes,
+  topbarRouters:state => state.permission.topbarRouters,
+  defaultRoutes:state => state.permission.defaultRoutes,
+  sidebarRouters:state => state.permission.sidebarRouters,
+}
+export default getters
diff --git a/ruoyi-ui/src/store/index.js b/ruoyi-ui/src/store/index.js
new file mode 100644
index 0000000..97aaef8
--- /dev/null
+++ b/ruoyi-ui/src/store/index.js
@@ -0,0 +1,25 @@
+import Vue from 'vue'
+import Vuex from 'vuex'
+import app from './modules/app'
+import dict from './modules/dict'
+import user from './modules/user'
+import tagsView from './modules/tagsView'
+import permission from './modules/permission'
+import settings from './modules/settings'
+import getters from './getters'
+
+Vue.use(Vuex)
+
+const store = new Vuex.Store({
+  modules: {
+    app,
+    dict,
+    user,
+    tagsView,
+    permission,
+    settings
+  },
+  getters
+})
+
+export default store
diff --git a/ruoyi-ui/src/store/modules/app.js b/ruoyi-ui/src/store/modules/app.js
new file mode 100644
index 0000000..3e22d1c
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/app.js
@@ -0,0 +1,66 @@
+import Cookies from 'js-cookie'
+
+const state = {
+  sidebar: {
+    opened: Cookies.get('sidebarStatus') ? !!+Cookies.get('sidebarStatus') : true,
+    withoutAnimation: false,
+    hide: false
+  },
+  device: 'desktop',
+  size: Cookies.get('size') || 'medium'
+}
+
+const mutations = {
+  TOGGLE_SIDEBAR: state => {
+    if (state.sidebar.hide) {
+      return false;
+    }
+    state.sidebar.opened = !state.sidebar.opened
+    state.sidebar.withoutAnimation = false
+    if (state.sidebar.opened) {
+      Cookies.set('sidebarStatus', 1)
+    } else {
+      Cookies.set('sidebarStatus', 0)
+    }
+  },
+  CLOSE_SIDEBAR: (state, withoutAnimation) => {
+    Cookies.set('sidebarStatus', 0)
+    state.sidebar.opened = false
+    state.sidebar.withoutAnimation = withoutAnimation
+  },
+  TOGGLE_DEVICE: (state, device) => {
+    state.device = device
+  },
+  SET_SIZE: (state, size) => {
+    state.size = size
+    Cookies.set('size', size)
+  },
+  SET_SIDEBAR_HIDE: (state, status) => {
+    state.sidebar.hide = status
+  }
+}
+
+const actions = {
+  toggleSideBar({ commit }) {
+    commit('TOGGLE_SIDEBAR')
+  },
+  closeSideBar({ commit }, { withoutAnimation }) {
+    commit('CLOSE_SIDEBAR', withoutAnimation)
+  },
+  toggleDevice({ commit }, device) {
+    commit('TOGGLE_DEVICE', device)
+  },
+  setSize({ commit }, size) {
+    commit('SET_SIZE', size)
+  },
+  toggleSideBarHide({ commit }, status) {
+    commit('SET_SIDEBAR_HIDE', status)
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
diff --git a/ruoyi-ui/src/store/modules/dict.js b/ruoyi-ui/src/store/modules/dict.js
new file mode 100644
index 0000000..7a1b2f0
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/dict.js
@@ -0,0 +1,50 @@
+const state = {
+  dict: new Array()
+}
+const mutations = {
+  SET_DICT: (state, { key, value }) => {
+    if (key !== null && key !== "") {
+      state.dict.push({
+        key: key,
+        value: value
+      })
+    }
+  },
+  REMOVE_DICT: (state, key) => {
+    try {
+      for (let i = 0; i < state.dict.length; i++) {
+        if (state.dict[i].key == key) {
+          state.dict.splice(i, 1)
+          return true
+        }
+      }
+    } catch (e) {
+    }
+  },
+  CLEAN_DICT: (state) => {
+    state.dict = new Array()
+  }
+}
+
+const actions = {
+  // 璁剧疆瀛楀吀
+  setDict({ commit }, data) {
+    commit('SET_DICT', data)
+  },
+  // 鍒犻櫎瀛楀吀
+  removeDict({ commit }, key) {
+    commit('REMOVE_DICT', key)
+  },
+  // 娓呯┖瀛楀吀
+  cleanDict({ commit }) {
+    commit('CLEAN_DICT')
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+
diff --git a/ruoyi-ui/src/store/modules/permission.js b/ruoyi-ui/src/store/modules/permission.js
new file mode 100644
index 0000000..b3c216a
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/permission.js
@@ -0,0 +1,137 @@
+import auth from '@/plugins/auth'
+import router, { constantRoutes, dynamicRoutes } from '@/router'
+import { getRouters } from '@/api/menu'
+import Layout from '@/layout/index'
+import ParentView from '@/components/ParentView'
+import InnerLink from '@/layout/components/InnerLink'
+
+const permission = {
+  state: {
+    routes: [],
+    addRoutes: [],
+    defaultRoutes: [],
+    topbarRouters: [],
+    sidebarRouters: []
+  },
+  mutations: {
+    SET_ROUTES: (state, routes) => {
+      state.addRoutes = routes
+      state.routes = constantRoutes.concat(routes)
+    },
+    SET_DEFAULT_ROUTES: (state, routes) => {
+      state.defaultRoutes = constantRoutes.concat(routes)
+    },
+    SET_TOPBAR_ROUTES: (state, routes) => {
+      state.topbarRouters = routes
+    },
+    SET_SIDEBAR_ROUTERS: (state, routes) => {
+      state.sidebarRouters = routes
+    },
+  },
+  actions: {
+    // 鐢熸垚璺敱
+    GenerateRoutes({ commit }) {
+      return new Promise(resolve => {
+        // 鍚戝悗绔姹傝矾鐢辨暟鎹�
+        getRouters().then(res => {
+          const sdata = JSON.parse(JSON.stringify(res.data))
+          const rdata = JSON.parse(JSON.stringify(res.data))
+          const sidebarRoutes = filterAsyncRouter(sdata)
+          const rewriteRoutes = filterAsyncRouter(rdata, false, true)
+          const asyncRoutes = filterDynamicRoutes(dynamicRoutes);
+          rewriteRoutes.push({ path: '*', redirect: '/404', hidden: true })
+          router.addRoutes(asyncRoutes);
+          commit('SET_ROUTES', rewriteRoutes)
+          commit('SET_SIDEBAR_ROUTERS', constantRoutes.concat(sidebarRoutes))
+          commit('SET_DEFAULT_ROUTES', sidebarRoutes)
+          commit('SET_TOPBAR_ROUTES', sidebarRoutes)
+          resolve(rewriteRoutes)
+        })
+      })
+    }
+  }
+}
+
+// 閬嶅巻鍚庡彴浼犳潵鐨勮矾鐢卞瓧绗︿覆锛岃浆鎹负缁勪欢瀵硅薄
+function filterAsyncRouter(asyncRouterMap, lastRouter = false, type = false) {
+  return asyncRouterMap.filter(route => {
+    if (type && route.children) {
+      route.children = filterChildren(route.children)
+    }
+    if (route.component) {
+      // Layout ParentView 缁勪欢鐗规畩澶勭悊
+      if (route.component === 'Layout') {
+        route.component = Layout
+      } else if (route.component === 'ParentView') {
+        route.component = ParentView
+      } else if (route.component === 'InnerLink') {
+        route.component = InnerLink
+      } else {
+        route.component = loadView(route.component)
+      }
+    }
+    if (route.children != null && route.children && route.children.length) {
+      route.children = filterAsyncRouter(route.children, route, type)
+    } else {
+      delete route['children']
+      delete route['redirect']
+    }
+    return true
+  })
+}
+
+function filterChildren(childrenMap, lastRouter = false) {
+  var children = []
+  childrenMap.forEach((el, index) => {
+    if (el.children && el.children.length) {
+      if (el.component === 'ParentView' && !lastRouter) {
+        el.children.forEach(c => {
+          c.path = el.path + '/' + c.path
+          if (c.children && c.children.length) {
+            children = children.concat(filterChildren(c.children, c))
+            return
+          }
+          children.push(c)
+        })
+        return
+      }
+    }
+    if (lastRouter) {
+      el.path = lastRouter.path + '/' + el.path
+      if (el.children && el.children.length) {
+        children = children.concat(filterChildren(el.children, el))
+        return
+      }
+    }
+    children = children.concat(el)
+  })
+  return children
+}
+
+// 鍔ㄦ�佽矾鐢遍亶鍘嗭紝楠岃瘉鏄惁鍏峰鏉冮檺
+export function filterDynamicRoutes(routes) {
+  const res = []
+  routes.forEach(route => {
+    if (route.permissions) {
+      if (auth.hasPermiOr(route.permissions)) {
+        res.push(route)
+      }
+    } else if (route.roles) {
+      if (auth.hasRoleOr(route.roles)) {
+        res.push(route)
+      }
+    }
+  })
+  return res
+}
+
+export const loadView = (view) => {
+  if (process.env.NODE_ENV === 'development') {
+    return (resolve) => require([`@/views/${view}`], resolve)
+  } else {
+    // 浣跨敤 import 瀹炵幇鐢熶骇鐜鐨勮矾鐢辨噿鍔犺浇
+    return () => import(`@/views/${view}`)
+  }
+}
+
+export default permission
diff --git a/ruoyi-ui/src/store/modules/settings.js b/ruoyi-ui/src/store/modules/settings.js
new file mode 100644
index 0000000..2455a1e
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/settings.js
@@ -0,0 +1,42 @@
+import defaultSettings from '@/settings'
+
+const { sideTheme, showSettings, topNav, tagsView, fixedHeader, sidebarLogo, dynamicTitle } = defaultSettings
+
+const storageSetting = JSON.parse(localStorage.getItem('layout-setting')) || ''
+const state = {
+  title: '',
+  theme: storageSetting.theme || '#409EFF',
+  sideTheme: storageSetting.sideTheme || sideTheme,
+  showSettings: showSettings,
+  topNav: storageSetting.topNav === undefined ? topNav : storageSetting.topNav,
+  tagsView: storageSetting.tagsView === undefined ? tagsView : storageSetting.tagsView,
+  fixedHeader: storageSetting.fixedHeader === undefined ? fixedHeader : storageSetting.fixedHeader,
+  sidebarLogo: storageSetting.sidebarLogo === undefined ? sidebarLogo : storageSetting.sidebarLogo,
+  dynamicTitle: storageSetting.dynamicTitle === undefined ? dynamicTitle : storageSetting.dynamicTitle
+}
+const mutations = {
+  CHANGE_SETTING: (state, { key, value }) => {
+    if (state.hasOwnProperty(key)) {
+      state[key] = value
+    }
+  }
+}
+
+const actions = {
+  // 淇敼甯冨眬璁剧疆
+  changeSetting({ commit }, data) {
+    commit('CHANGE_SETTING', data)
+  },
+  // 璁剧疆缃戦〉鏍囬
+  setTitle({ commit }, title) {
+    state.title = title
+  }
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
+
diff --git a/ruoyi-ui/src/store/modules/tagsView.js b/ruoyi-ui/src/store/modules/tagsView.js
new file mode 100644
index 0000000..5fc011c
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/tagsView.js
@@ -0,0 +1,228 @@
+const state = {
+  visitedViews: [],
+  cachedViews: [],
+  iframeViews: []
+}
+
+const mutations = {
+  ADD_IFRAME_VIEW: (state, view) => {
+    if (state.iframeViews.some(v => v.path === view.path)) return
+    state.iframeViews.push(
+      Object.assign({}, view, {
+        title: view.meta.title || 'no-name'
+      })
+    )
+  },
+  ADD_VISITED_VIEW: (state, view) => {
+    if (state.visitedViews.some(v => v.path === view.path)) return
+    state.visitedViews.push(
+      Object.assign({}, view, {
+        title: view.meta.title || 'no-name'
+      })
+    )
+  },
+  ADD_CACHED_VIEW: (state, view) => {
+    if (state.cachedViews.includes(view.name)) return
+    if (view.meta && !view.meta.noCache) {
+      state.cachedViews.push(view.name)
+    }
+  },
+  DEL_VISITED_VIEW: (state, view) => {
+    for (const [i, v] of state.visitedViews.entries()) {
+      if (v.path === view.path) {
+        state.visitedViews.splice(i, 1)
+        break
+      }
+    }
+    state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
+  },
+  DEL_IFRAME_VIEW: (state, view) => {
+    state.iframeViews = state.iframeViews.filter(item => item.path !== view.path)
+  },
+  DEL_CACHED_VIEW: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    index > -1 && state.cachedViews.splice(index, 1)
+  },
+
+  DEL_OTHERS_VISITED_VIEWS: (state, view) => {
+    state.visitedViews = state.visitedViews.filter(v => {
+      return v.meta.affix || v.path === view.path
+    })
+    state.iframeViews = state.iframeViews.filter(item => item.path === view.path)
+  },
+  DEL_OTHERS_CACHED_VIEWS: (state, view) => {
+    const index = state.cachedViews.indexOf(view.name)
+    if (index > -1) {
+      state.cachedViews = state.cachedViews.slice(index, index + 1)
+    } else {
+      state.cachedViews = []
+    }
+  },
+  DEL_ALL_VISITED_VIEWS: state => {
+    // keep affix tags
+    const affixTags = state.visitedViews.filter(tag => tag.meta.affix)
+    state.visitedViews = affixTags
+    state.iframeViews = []
+  },
+  DEL_ALL_CACHED_VIEWS: state => {
+    state.cachedViews = []
+  },
+  UPDATE_VISITED_VIEW: (state, view) => {
+    for (let v of state.visitedViews) {
+      if (v.path === view.path) {
+        v = Object.assign(v, view)
+        break
+      }
+    }
+  },
+  DEL_RIGHT_VIEWS: (state, view) => {
+    const index = state.visitedViews.findIndex(v => v.path === view.path)
+    if (index === -1) {
+      return
+    }
+    state.visitedViews = state.visitedViews.filter((item, idx) => {
+      if (idx <= index || (item.meta && item.meta.affix)) {
+        return true
+      }
+      const i = state.cachedViews.indexOf(item.name)
+      if (i > -1) {
+        state.cachedViews.splice(i, 1)
+      }
+      if(item.meta.link) {
+        const fi = state.iframeViews.findIndex(v => v.path === item.path)
+        state.iframeViews.splice(fi, 1)
+      }
+      return false
+    })
+  },
+  DEL_LEFT_VIEWS: (state, view) => {
+    const index = state.visitedViews.findIndex(v => v.path === view.path)
+    if (index === -1) {
+      return
+    }
+    state.visitedViews = state.visitedViews.filter((item, idx) => {
+      if (idx >= index || (item.meta && item.meta.affix)) {
+        return true
+      }
+      const i = state.cachedViews.indexOf(item.name)
+      if (i > -1) {
+        state.cachedViews.splice(i, 1)
+      }
+      if(item.meta.link) {
+        const fi = state.iframeViews.findIndex(v => v.path === item.path)
+        state.iframeViews.splice(fi, 1)
+      }
+      return false
+    })
+  }
+}
+
+const actions = {
+  addView({ dispatch }, view) {
+    dispatch('addVisitedView', view)
+    dispatch('addCachedView', view)
+  },
+  addIframeView({ commit }, view) {
+    commit('ADD_IFRAME_VIEW', view)
+  },
+  addVisitedView({ commit }, view) {
+    commit('ADD_VISITED_VIEW', view)
+  },
+  addCachedView({ commit }, view) {
+    commit('ADD_CACHED_VIEW', view)
+  },
+  delView({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delVisitedView', view)
+      dispatch('delCachedView', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delVisitedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_VISITED_VIEW', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delIframeView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_IFRAME_VIEW', view)
+      resolve([...state.iframeViews])
+    })
+  },
+  delCachedView({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_CACHED_VIEW', view)
+      resolve([...state.cachedViews])
+    })
+  },
+  delOthersViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delOthersVisitedViews', view)
+      dispatch('delOthersCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delOthersVisitedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_VISITED_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delOthersCachedViews({ commit, state }, view) {
+    return new Promise(resolve => {
+      commit('DEL_OTHERS_CACHED_VIEWS', view)
+      resolve([...state.cachedViews])
+    })
+  },
+  delAllViews({ dispatch, state }, view) {
+    return new Promise(resolve => {
+      dispatch('delAllVisitedViews', view)
+      dispatch('delAllCachedViews', view)
+      resolve({
+        visitedViews: [...state.visitedViews],
+        cachedViews: [...state.cachedViews]
+      })
+    })
+  },
+  delAllVisitedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_VISITED_VIEWS')
+      resolve([...state.visitedViews])
+    })
+  },
+  delAllCachedViews({ commit, state }) {
+    return new Promise(resolve => {
+      commit('DEL_ALL_CACHED_VIEWS')
+      resolve([...state.cachedViews])
+    })
+  },
+  updateVisitedView({ commit }, view) {
+    commit('UPDATE_VISITED_VIEW', view)
+  },
+  delRightTags({ commit }, view) {
+    return new Promise(resolve => {
+      commit('DEL_RIGHT_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+  delLeftTags({ commit }, view) {
+    return new Promise(resolve => {
+      commit('DEL_LEFT_VIEWS', view)
+      resolve([...state.visitedViews])
+    })
+  },
+}
+
+export default {
+  namespaced: true,
+  state,
+  mutations,
+  actions
+}
diff --git a/ruoyi-ui/src/store/modules/user.js b/ruoyi-ui/src/store/modules/user.js
new file mode 100644
index 0000000..63e6ba2
--- /dev/null
+++ b/ruoyi-ui/src/store/modules/user.js
@@ -0,0 +1,106 @@
+import { login, logout, getInfo } from '@/api/login'
+import { getToken, setToken, removeToken } from '@/utils/auth'
+import { isHttp, isEmpty } from "@/utils/validate"
+import defAva from '@/assets/images/profile.jpg'
+
+const user = {
+  state: {
+    token: getToken(),
+    id: '',
+    name: '',
+    avatar: '',
+    roles: [],
+    permissions: []
+  },
+
+  mutations: {
+    SET_TOKEN: (state, token) => {
+      state.token = token
+    },
+    SET_ID: (state, id) => {
+      state.id = id
+    },
+    SET_NAME: (state, name) => {
+      state.name = name
+    },
+    SET_AVATAR: (state, avatar) => {
+      state.avatar = avatar
+    },
+    SET_ROLES: (state, roles) => {
+      state.roles = roles
+    },
+    SET_PERMISSIONS: (state, permissions) => {
+      state.permissions = permissions
+    }
+  },
+
+  actions: {
+    // 鐧诲綍
+    Login({ commit }, userInfo) {
+      const username = userInfo.username.trim()
+      const password = userInfo.password
+      const code = userInfo.code
+      const uuid = userInfo.uuid
+      return new Promise((resolve, reject) => {
+        login(username, password, code, uuid).then(res => {
+          setToken(res.token)
+          commit('SET_TOKEN', res.token)
+          resolve()
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 鑾峰彇鐢ㄦ埛淇℃伅
+    GetInfo({ commit, state }) {
+      return new Promise((resolve, reject) => {
+        getInfo().then(res => {
+          const user = res.user
+          let avatar = user.avatar || ""
+          if (!isHttp(avatar)) {
+            avatar = (isEmpty(avatar)) ? defAva : process.env.VUE_APP_BASE_API + avatar
+          }
+          if (res.roles && res.roles.length > 0) { // 楠岃瘉杩斿洖鐨剅oles鏄惁鏄竴涓潪绌烘暟缁�
+            commit('SET_ROLES', res.roles)
+            commit('SET_PERMISSIONS', res.permissions)
+          } else {
+            commit('SET_ROLES', ['ROLE_DEFAULT'])
+          }
+          commit('SET_ID', user.userId)
+          commit('SET_NAME', user.userName)
+          commit('SET_AVATAR', avatar)
+          resolve(res)
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 閫�鍑虹郴缁�
+    LogOut({ commit, state }) {
+      return new Promise((resolve, reject) => {
+        logout(state.token).then(() => {
+          commit('SET_TOKEN', '')
+          commit('SET_ROLES', [])
+          commit('SET_PERMISSIONS', [])
+          removeToken()
+          resolve()
+        }).catch(error => {
+          reject(error)
+        })
+      })
+    },
+
+    // 鍓嶇 鐧诲嚭
+    FedLogOut({ commit }) {
+      return new Promise(resolve => {
+        commit('SET_TOKEN', '')
+        removeToken()
+        resolve()
+      })
+    }
+  }
+}
+
+export default user
diff --git a/ruoyi-ui/src/utils/auth.js b/ruoyi-ui/src/utils/auth.js
new file mode 100644
index 0000000..08a43d6
--- /dev/null
+++ b/ruoyi-ui/src/utils/auth.js
@@ -0,0 +1,15 @@
+import Cookies from 'js-cookie'
+
+const TokenKey = 'Admin-Token'
+
+export function getToken() {
+  return Cookies.get(TokenKey)
+}
+
+export function setToken(token) {
+  return Cookies.set(TokenKey, token)
+}
+
+export function removeToken() {
+  return Cookies.remove(TokenKey)
+}
diff --git a/ruoyi-ui/src/utils/dict/Dict.js b/ruoyi-ui/src/utils/dict/Dict.js
new file mode 100644
index 0000000..104bd6e
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/Dict.js
@@ -0,0 +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
+    })
+}
diff --git a/ruoyi-ui/src/utils/dict/DictConverter.js b/ruoyi-ui/src/utils/dict/DictConverter.js
new file mode 100644
index 0000000..0cf5df8
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/DictConverter.js
@@ -0,0 +1,17 @@
+import DictOptions from './DictOptions'
+import DictData from './DictData'
+
+export default function(dict, dictMeta) {
+  const label = determineDictField(dict, dictMeta.labelField, ...DictOptions.DEFAULT_LABEL_FIELDS)
+  const value = determineDictField(dict, dictMeta.valueField, ...DictOptions.DEFAULT_VALUE_FIELDS)
+  return new DictData(dict[label], dict[value], dict)
+}
+
+/**
+ * 纭畾瀛楀吀瀛楁
+ * @param {DictData} dict
+ * @param  {...String} fields
+ */
+function determineDictField(dict, ...fields) {
+  return fields.find(f => Object.prototype.hasOwnProperty.call(dict, f))
+}
diff --git a/ruoyi-ui/src/utils/dict/DictData.js b/ruoyi-ui/src/utils/dict/DictData.js
new file mode 100644
index 0000000..afc763e
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/DictData.js
@@ -0,0 +1,13 @@
+/**
+ * @classdesc 瀛楀吀鏁版嵁
+ * @property {String} label 鏍囩
+ * @property {*} value 鏍囩
+ * @property {Object} raw 鍘熷鏁版嵁
+ */
+export default class DictData {
+  constructor(label, value, raw) {
+    this.label = label
+    this.value = value
+    this.raw = raw
+  }
+}
diff --git a/ruoyi-ui/src/utils/dict/DictMeta.js b/ruoyi-ui/src/utils/dict/DictMeta.js
new file mode 100644
index 0000000..9779daa
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/DictMeta.js
@@ -0,0 +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
+  }
+}
+
+
+/**
+ * 瑙f瀽瀛楀吀鍏冩暟鎹�
+ * @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
new file mode 100644
index 0000000..338a94e
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/DictOptions.js
@@ -0,0 +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([])
+      },
+      /**
+       * 瀛楀吀鍝嶅簲鏁版嵁杞崲鍣紝鏂规硶绛惧悕涓篺unction(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/dict/index.js b/ruoyi-ui/src/utils/dict/index.js
new file mode 100644
index 0000000..215eb9e
--- /dev/null
+++ b/ruoyi-ui/src/utils/dict/index.js
@@ -0,0 +1,33 @@
+import Dict from './Dict'
+import { mergeOptions } from './DictOptions'
+
+export default function(Vue, options) {
+  mergeOptions(options)
+  Vue.mixin({
+    data() {
+      if (this.$options === undefined || this.$options.dicts === undefined || this.$options.dicts === null) {
+        return {}
+      }
+      const dict = new Dict()
+      dict.owner = this
+      return {
+        dict
+      }
+    },
+    created() {
+      if (!(this.dict instanceof Dict)) {
+        return
+      }
+      options.onCreated && options.onCreated(this.dict)
+      this.dict.init(this.$options.dicts).then(() => {
+        options.onReady && options.onReady(this.dict)
+        this.$nextTick(() => {
+          this.$emit('dictReady', this.dict)
+          if (this.$options.methods && this.$options.methods.onDictReady instanceof Function) {
+            this.$options.methods.onDictReady.call(this, this.dict)
+          }
+        })
+      })
+    },
+  })
+}
diff --git a/ruoyi-ui/src/utils/errorCode.js b/ruoyi-ui/src/utils/errorCode.js
new file mode 100644
index 0000000..d2111ee
--- /dev/null
+++ b/ruoyi-ui/src/utils/errorCode.js
@@ -0,0 +1,6 @@
+export default {
+  '401': '璁よ瘉澶辫触锛屾棤娉曡闂郴缁熻祫婧�',
+  '403': '褰撳墠鎿嶄綔娌℃湁鏉冮檺',
+  '404': '璁块棶璧勬簮涓嶅瓨鍦�',
+  'default': '绯荤粺鏈煡閿欒锛岃鍙嶉缁欑鐞嗗憳'
+}
diff --git a/ruoyi-ui/src/utils/generator/config.js b/ruoyi-ui/src/utils/generator/config.js
new file mode 100644
index 0000000..7abf227
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/config.js
@@ -0,0 +1,438 @@
+export const formConf = {
+  formRef: 'elForm',
+  formModel: 'formData',
+  size: 'medium',
+  labelPosition: 'right',
+  labelWidth: 100,
+  formRules: 'rules',
+  gutter: 15,
+  disabled: false,
+  span: 24,
+  formBtns: true
+}
+
+export const inputComponents = [
+  {
+    label: '鍗曡鏂囨湰',
+    tag: 'el-input',
+    tagIcon: 'input',
+    placeholder: '璇疯緭鍏�',
+    defaultValue: undefined,
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    clearable: true,
+    prepend: '',
+    append: '',
+    'prefix-icon': '',
+    'suffix-icon': '',
+    maxlength: null,
+    'show-word-limit': false,
+    readonly: false,
+    disabled: false,
+    required: true,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/input'
+  },
+  {
+    label: '澶氳鏂囨湰',
+    tag: 'el-input',
+    tagIcon: 'textarea',
+    type: 'textarea',
+    placeholder: '璇疯緭鍏�',
+    defaultValue: undefined,
+    span: 24,
+    labelWidth: null,
+    autosize: {
+      minRows: 4,
+      maxRows: 4
+    },
+    style: { width: '100%' },
+    maxlength: null,
+    'show-word-limit': false,
+    readonly: false,
+    disabled: false,
+    required: true,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/input'
+  },
+  {
+    label: '瀵嗙爜',
+    tag: 'el-input',
+    tagIcon: 'password',
+    placeholder: '璇疯緭鍏�',
+    defaultValue: undefined,
+    span: 24,
+    'show-password': true,
+    labelWidth: null,
+    style: { width: '100%' },
+    clearable: true,
+    prepend: '',
+    append: '',
+    'prefix-icon': '',
+    'suffix-icon': '',
+    maxlength: null,
+    'show-word-limit': false,
+    readonly: false,
+    disabled: false,
+    required: true,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/input'
+  },
+  {
+    label: '璁℃暟鍣�',
+    tag: 'el-input-number',
+    tagIcon: 'number',
+    placeholder: '',
+    defaultValue: undefined,
+    span: 24,
+    labelWidth: null,
+    min: undefined,
+    max: undefined,
+    step: undefined,
+    'step-strictly': false,
+    precision: undefined,
+    'controls-position': '',
+    disabled: false,
+    required: true,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/input-number'
+  }
+]
+
+export const selectComponents = [
+  {
+    label: '涓嬫媺閫夋嫨',
+    tag: 'el-select',
+    tagIcon: 'select',
+    placeholder: '璇烽�夋嫨',
+    defaultValue: undefined,
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    clearable: true,
+    disabled: false,
+    required: true,
+    filterable: false,
+    multiple: false,
+    options: [{
+      label: '閫夐」涓�',
+      value: 1
+    }, {
+      label: '閫夐」浜�',
+      value: 2
+    }],
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/select'
+  },
+  {
+    label: '绾ц仈閫夋嫨',
+    tag: 'el-cascader',
+    tagIcon: 'cascader',
+    placeholder: '璇烽�夋嫨',
+    defaultValue: [],
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    props: {
+      props: {
+        multiple: false
+      }
+    },
+    'show-all-levels': true,
+    disabled: false,
+    clearable: true,
+    filterable: false,
+    required: true,
+    options: [{
+      id: 1,
+      value: 1,
+      label: '閫夐」1',
+      children: [{
+        id: 2,
+        value: 2,
+        label: '閫夐」1-1'
+      }]
+    }],
+    dataType: 'dynamic',
+    labelKey: 'label',
+    valueKey: 'value',
+    childrenKey: 'children',
+    separator: '/',
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/cascader'
+  },
+  {
+    label: '鍗曢�夋缁�',
+    tag: 'el-radio-group',
+    tagIcon: 'radio',
+    defaultValue: undefined,
+    span: 24,
+    labelWidth: null,
+    style: {},
+    optionType: 'default',
+    border: false,
+    size: 'medium',
+    disabled: false,
+    required: true,
+    options: [{
+      label: '閫夐」涓�',
+      value: 1
+    }, {
+      label: '閫夐」浜�',
+      value: 2
+    }],
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/radio'
+  },
+  {
+    label: '澶氶�夋缁�',
+    tag: 'el-checkbox-group',
+    tagIcon: 'checkbox',
+    defaultValue: [],
+    span: 24,
+    labelWidth: null,
+    style: {},
+    optionType: 'default',
+    border: false,
+    size: 'medium',
+    disabled: false,
+    required: true,
+    options: [{
+      label: '閫夐」涓�',
+      value: 1
+    }, {
+      label: '閫夐」浜�',
+      value: 2
+    }],
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/checkbox'
+  },
+  {
+    label: '寮�鍏�',
+    tag: 'el-switch',
+    tagIcon: 'switch',
+    defaultValue: false,
+    span: 24,
+    labelWidth: null,
+    style: {},
+    disabled: false,
+    required: true,
+    'active-text': '',
+    'inactive-text': '',
+    'active-color': null,
+    'inactive-color': null,
+    'active-value': true,
+    'inactive-value': false,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/switch'
+  },
+  {
+    label: '婊戝潡',
+    tag: 'el-slider',
+    tagIcon: 'slider',
+    defaultValue: null,
+    span: 24,
+    labelWidth: null,
+    disabled: false,
+    required: true,
+    min: 0,
+    max: 100,
+    step: 1,
+    'show-stops': false,
+    range: false,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/slider'
+  },
+  {
+    label: '鏃堕棿閫夋嫨',
+    tag: 'el-time-picker',
+    tagIcon: 'time',
+    placeholder: '璇烽�夋嫨',
+    defaultValue: null,
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    disabled: false,
+    clearable: true,
+    required: true,
+    'picker-options': {
+      selectableRange: '00:00:00-23:59:59'
+    },
+    format: 'HH:mm:ss',
+    'value-format': 'HH:mm:ss',
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+  },
+  {
+    label: '鏃堕棿鑼冨洿',
+    tag: 'el-time-picker',
+    tagIcon: 'time-range',
+    defaultValue: null,
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    disabled: false,
+    clearable: true,
+    required: true,
+    'is-range': true,
+    'range-separator': '鑷�',
+    'start-placeholder': '寮�濮嬫椂闂�',
+    'end-placeholder': '缁撴潫鏃堕棿',
+    format: 'HH:mm:ss',
+    'value-format': 'HH:mm:ss',
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/time-picker'
+  },
+  {
+    label: '鏃ユ湡閫夋嫨',
+    tag: 'el-date-picker',
+    tagIcon: 'date',
+    placeholder: '璇烽�夋嫨',
+    defaultValue: null,
+    type: 'date',
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    disabled: false,
+    clearable: true,
+    required: true,
+    format: 'yyyy-MM-dd',
+    'value-format': 'yyyy-MM-dd',
+    readonly: false,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+  },
+  {
+    label: '鏃ユ湡鑼冨洿',
+    tag: 'el-date-picker',
+    tagIcon: 'date-range',
+    defaultValue: null,
+    span: 24,
+    labelWidth: null,
+    style: { width: '100%' },
+    type: 'daterange',
+    'range-separator': '鑷�',
+    'start-placeholder': '寮�濮嬫棩鏈�',
+    'end-placeholder': '缁撴潫鏃ユ湡',
+    disabled: false,
+    clearable: true,
+    required: true,
+    format: 'yyyy-MM-dd',
+    'value-format': 'yyyy-MM-dd',
+    readonly: false,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/date-picker'
+  },
+  {
+    label: '璇勫垎',
+    tag: 'el-rate',
+    tagIcon: 'rate',
+    defaultValue: 0,
+    span: 24,
+    labelWidth: null,
+    style: {},
+    max: 5,
+    'allow-half': false,
+    'show-text': false,
+    'show-score': false,
+    disabled: false,
+    required: true,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/rate'
+  },
+  {
+    label: '棰滆壊閫夋嫨',
+    tag: 'el-color-picker',
+    tagIcon: 'color',
+    defaultValue: null,
+    labelWidth: null,
+    'show-alpha': false,
+    'color-format': '',
+    disabled: false,
+    required: true,
+    size: 'medium',
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/color-picker'
+  },
+  {
+    label: '涓婁紶',
+    tag: 'el-upload',
+    tagIcon: 'upload',
+    action: 'https://jsonplaceholder.typicode.com/posts/',
+    defaultValue: null,
+    labelWidth: null,
+    disabled: false,
+    required: true,
+    accept: '',
+    name: 'file',
+    'auto-upload': true,
+    showTip: false,
+    buttonText: '鐐瑰嚮涓婁紶',
+    fileSize: 2,
+    sizeUnit: 'MB',
+    'list-type': 'text',
+    multiple: false,
+    regList: [],
+    changeTag: true,
+    document: 'https://element.eleme.cn/#/zh-CN/component/upload'
+  }
+]
+
+export const layoutComponents = [
+  {
+    layout: 'rowFormItem',
+    tagIcon: 'row',
+    type: 'default',
+    justify: 'start',
+    align: 'top',
+    label: '琛屽鍣�',
+    layoutTree: true,
+    children: [],
+    document: 'https://element.eleme.cn/#/zh-CN/component/layout'
+  },
+  {
+    layout: 'colFormItem',
+    label: '鎸夐挳',
+    changeTag: true,
+    labelWidth: null,
+    tag: 'el-button',
+    tagIcon: 'button',
+    span: 24,
+    default: '涓昏鎸夐挳',
+    type: 'primary',
+    icon: 'el-icon-search',
+    size: 'medium',
+    disabled: false,
+    document: 'https://element.eleme.cn/#/zh-CN/component/button'
+  }
+]
+
+// 缁勪欢rule鐨勮Е鍙戞柟寮忥紝鏃犺Е鍙戞柟寮忕殑缁勪欢涓嶇敓鎴恟ule
+export const trigger = {
+  'el-input': 'blur',
+  'el-input-number': 'blur',
+  'el-select': 'change',
+  'el-radio-group': 'change',
+  'el-checkbox-group': 'change',
+  'el-cascader': 'change',
+  'el-time-picker': 'change',
+  'el-date-picker': 'change',
+  'el-rate': 'change'
+}
diff --git a/ruoyi-ui/src/utils/generator/css.js b/ruoyi-ui/src/utils/generator/css.js
new file mode 100644
index 0000000..c1c62e6
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/css.js
@@ -0,0 +1,18 @@
+const styles = {
+  'el-rate': '.el-rate{display: inline-block; vertical-align: text-top;}',
+  'el-upload': '.el-upload__tip{line-height: 1.2;}'
+}
+
+function addCss(cssList, el) {
+  const css = styles[el.tag]
+  css && cssList.indexOf(css) === -1 && cssList.push(css)
+  if (el.children) {
+    el.children.forEach(el2 => addCss(cssList, el2))
+  }
+}
+
+export function makeUpCss(conf) {
+  const cssList = []
+  conf.fields.forEach(el => addCss(cssList, el))
+  return cssList.join('\n')
+}
diff --git a/ruoyi-ui/src/utils/generator/drawingDefault.js b/ruoyi-ui/src/utils/generator/drawingDefault.js
new file mode 100644
index 0000000..09f133c
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/drawingDefault.js
@@ -0,0 +1,29 @@
+export default [
+  {
+    layout: 'colFormItem',
+    tagIcon: 'input',
+    label: '鎵嬫満鍙�',
+    vModel: 'mobile',
+    formId: 6,
+    tag: 'el-input',
+    placeholder: '璇疯緭鍏ユ墜鏈哄彿',
+    defaultValue: '',
+    span: 24,
+    style: { width: '100%' },
+    clearable: true,
+    prepend: '',
+    append: '',
+    'prefix-icon': 'el-icon-mobile',
+    'suffix-icon': '',
+    maxlength: 11,
+    'show-word-limit': true,
+    readonly: false,
+    disabled: false,
+    required: true,
+    changeTag: true,
+    regList: [{
+      pattern: '/^1(3|4|5|7|8|9)\\d{9}$/',
+      message: '鎵嬫満鍙锋牸寮忛敊璇�'
+    }]
+  }
+]
diff --git a/ruoyi-ui/src/utils/generator/html.js b/ruoyi-ui/src/utils/generator/html.js
new file mode 100644
index 0000000..9bcc536
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/html.js
@@ -0,0 +1,359 @@
+/* eslint-disable max-len */
+import { trigger } from './config'
+
+let confGlobal
+let someSpanIsNot24
+
+export function dialogWrapper(str) {
+  return `<el-dialog v-bind="$attrs" v-on="$listeners" @open="onOpen" @close="onClose" title="Dialog Title">
+    ${str}
+    <div slot="footer">
+      <el-button @click="close">鍙栨秷</el-button>
+      <el-button type="primary" @click="handleConfirm">纭畾</el-button>
+    </div>
+  </el-dialog>`
+}
+
+export function vueTemplate(str) {
+  return `<template>
+    <div>
+      ${str}
+    </div>
+  </template>`
+}
+
+export function vueScript(str) {
+  return `<script>
+    ${str}
+  </script>`
+}
+
+export function cssStyle(cssStr) {
+  return `<style>
+    ${cssStr}
+  </style>`
+}
+
+function buildFormTemplate(conf, child, type) {
+  let labelPosition = ''
+  if (conf.labelPosition !== 'right') {
+    labelPosition = `label-position="${conf.labelPosition}"`
+  }
+  const disabled = conf.disabled ? `:disabled="${conf.disabled}"` : ''
+  let str = `<el-form ref="${conf.formRef}" :model="${conf.formModel}" :rules="${conf.formRules}" size="${conf.size}" ${disabled} label-width="${conf.labelWidth}px" ${labelPosition}>
+      ${child}
+      ${buildFromBtns(conf, type)}
+    </el-form>`
+  if (someSpanIsNot24) {
+    str = `<el-row :gutter="${conf.gutter}">
+        ${str}
+      </el-row>`
+  }
+  return str
+}
+
+function buildFromBtns(conf, type) {
+  let str = ''
+  if (conf.formBtns && type === 'file') {
+    str = `<el-form-item size="large">
+          <el-button type="primary" @click="submitForm">鎻愪氦</el-button>
+          <el-button @click="resetForm">閲嶇疆</el-button>
+        </el-form-item>`
+    if (someSpanIsNot24) {
+      str = `<el-col :span="24">
+          ${str}
+        </el-col>`
+    }
+  }
+  return str
+}
+
+// span涓嶄负24鐨勭敤el-col鍖呰9
+function colWrapper(element, str) {
+  if (someSpanIsNot24 || element.span !== 24) {
+    return `<el-col :span="${element.span}">
+      ${str}
+    </el-col>`
+  }
+  return str
+}
+
+const layouts = {
+  colFormItem(element) {
+    let labelWidth = ''
+    if (element.labelWidth && element.labelWidth !== confGlobal.labelWidth) {
+      labelWidth = `label-width="${element.labelWidth}px"`
+    }
+    const required = !trigger[element.tag] && element.required ? 'required' : ''
+    const tagDom = tags[element.tag] ? tags[element.tag](element) : null
+    let str = `<el-form-item ${labelWidth} label="${element.label}" prop="${element.vModel}" ${required}>
+        ${tagDom}
+      </el-form-item>`
+    str = colWrapper(element, str)
+    return str
+  },
+  rowFormItem(element) {
+    const type = element.type === 'default' ? '' : `type="${element.type}"`
+    const justify = element.type === 'default' ? '' : `justify="${element.justify}"`
+    const align = element.type === 'default' ? '' : `align="${element.align}"`
+    const gutter = element.gutter ? `gutter="${element.gutter}"` : ''
+    const children = element.children.map(el => layouts[el.layout](el))
+    let str = `<el-row ${type} ${justify} ${align} ${gutter}>
+      ${children.join('\n')}
+    </el-row>`
+    str = colWrapper(element, str)
+    return str
+  }
+}
+
+const tags = {
+  'el-button': el => {
+    const {
+      tag, disabled
+    } = attrBuilder(el)
+    const type = el.type ? `type="${el.type}"` : ''
+    const icon = el.icon ? `icon="${el.icon}"` : ''
+    const size = el.size ? `size="${el.size}"` : ''
+    let child = buildElButtonChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${type} ${icon} ${size} ${disabled}>${child}</${el.tag}>`
+  },
+  'el-input': el => {
+    const {
+      disabled, vModel, clearable, placeholder, width
+    } = attrBuilder(el)
+    const maxlength = el.maxlength ? `:maxlength="${el.maxlength}"` : ''
+    const showWordLimit = el['show-word-limit'] ? 'show-word-limit' : ''
+    const readonly = el.readonly ? 'readonly' : ''
+    const prefixIcon = el['prefix-icon'] ? `prefix-icon='${el['prefix-icon']}'` : ''
+    const suffixIcon = el['suffix-icon'] ? `suffix-icon='${el['suffix-icon']}'` : ''
+    const showPassword = el['show-password'] ? 'show-password' : ''
+    const type = el.type ? `type="${el.type}"` : ''
+    const autosize = el.autosize && el.autosize.minRows
+      ? `:autosize="{minRows: ${el.autosize.minRows}, maxRows: ${el.autosize.maxRows}}"`
+      : ''
+    let child = buildElInputChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${vModel} ${type} ${placeholder} ${maxlength} ${showWordLimit} ${readonly} ${disabled} ${clearable} ${prefixIcon} ${suffixIcon} ${showPassword} ${autosize} ${width}>${child}</${el.tag}>`
+  },
+  'el-input-number': el => {
+    const { disabled, vModel, placeholder } = attrBuilder(el)
+    const controlsPosition = el['controls-position'] ? `controls-position=${el['controls-position']}` : ''
+    const min = el.min ? `:min='${el.min}'` : ''
+    const max = el.max ? `:max='${el.max}'` : ''
+    const step = el.step ? `:step='${el.step}'` : ''
+    const stepStrictly = el['step-strictly'] ? 'step-strictly' : ''
+    const precision = el.precision ? `:precision='${el.precision}'` : ''
+
+    return `<${el.tag} ${vModel} ${placeholder} ${step} ${stepStrictly} ${precision} ${controlsPosition} ${min} ${max} ${disabled}></${el.tag}>`
+  },
+  'el-select': el => {
+    const {
+      disabled, vModel, clearable, placeholder, width
+    } = attrBuilder(el)
+    const filterable = el.filterable ? 'filterable' : ''
+    const multiple = el.multiple ? 'multiple' : ''
+    let child = buildElSelectChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${vModel} ${placeholder} ${disabled} ${multiple} ${filterable} ${clearable} ${width}>${child}</${el.tag}>`
+  },
+  'el-radio-group': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const size = `size="${el.size}"`
+    let child = buildElRadioGroupChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${vModel} ${size} ${disabled}>${child}</${el.tag}>`
+  },
+  'el-checkbox-group': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const size = `size="${el.size}"`
+    const min = el.min ? `:min="${el.min}"` : ''
+    const max = el.max ? `:max="${el.max}"` : ''
+    let child = buildElCheckboxGroupChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${vModel} ${min} ${max} ${size} ${disabled}>${child}</${el.tag}>`
+  },
+  'el-switch': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const activeText = el['active-text'] ? `active-text="${el['active-text']}"` : ''
+    const inactiveText = el['inactive-text'] ? `inactive-text="${el['inactive-text']}"` : ''
+    const activeColor = el['active-color'] ? `active-color="${el['active-color']}"` : ''
+    const inactiveColor = el['inactive-color'] ? `inactive-color="${el['inactive-color']}"` : ''
+    const activeValue = el['active-value'] !== true ? `:active-value='${JSON.stringify(el['active-value'])}'` : ''
+    const inactiveValue = el['inactive-value'] !== false ? `:inactive-value='${JSON.stringify(el['inactive-value'])}'` : ''
+
+    return `<${el.tag} ${vModel} ${activeText} ${inactiveText} ${activeColor} ${inactiveColor} ${activeValue} ${inactiveValue} ${disabled}></${el.tag}>`
+  },
+  'el-cascader': el => {
+    const {
+      disabled, vModel, clearable, placeholder, width
+    } = attrBuilder(el)
+    const options = el.options ? `:options="${el.vModel}Options"` : ''
+    const props = el.props ? `:props="${el.vModel}Props"` : ''
+    const showAllLevels = el['show-all-levels'] ? '' : ':show-all-levels="false"'
+    const filterable = el.filterable ? 'filterable' : ''
+    const separator = el.separator === '/' ? '' : `separator="${el.separator}"`
+
+    return `<${el.tag} ${vModel} ${options} ${props} ${width} ${showAllLevels} ${placeholder} ${separator} ${filterable} ${clearable} ${disabled}></${el.tag}>`
+  },
+  'el-slider': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const min = el.min ? `:min='${el.min}'` : ''
+    const max = el.max ? `:max='${el.max}'` : ''
+    const step = el.step ? `:step='${el.step}'` : ''
+    const range = el.range ? 'range' : ''
+    const showStops = el['show-stops'] ? `:show-stops="${el['show-stops']}"` : ''
+
+    return `<${el.tag} ${min} ${max} ${step} ${vModel} ${range} ${showStops} ${disabled}></${el.tag}>`
+  },
+  'el-time-picker': el => {
+    const {
+      disabled, vModel, clearable, placeholder, width
+    } = attrBuilder(el)
+    const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
+    const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
+    const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
+    const isRange = el['is-range'] ? 'is-range' : ''
+    const format = el.format ? `format="${el.format}"` : ''
+    const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
+    const pickerOptions = el['picker-options'] ? `:picker-options='${JSON.stringify(el['picker-options'])}'` : ''
+
+    return `<${el.tag} ${vModel} ${isRange} ${format} ${valueFormat} ${pickerOptions} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${disabled}></${el.tag}>`
+  },
+  'el-date-picker': el => {
+    const {
+      disabled, vModel, clearable, placeholder, width
+    } = attrBuilder(el)
+    const startPlaceholder = el['start-placeholder'] ? `start-placeholder="${el['start-placeholder']}"` : ''
+    const endPlaceholder = el['end-placeholder'] ? `end-placeholder="${el['end-placeholder']}"` : ''
+    const rangeSeparator = el['range-separator'] ? `range-separator="${el['range-separator']}"` : ''
+    const format = el.format ? `format="${el.format}"` : ''
+    const valueFormat = el['value-format'] ? `value-format="${el['value-format']}"` : ''
+    const type = el.type === 'date' ? '' : `type="${el.type}"`
+    const readonly = el.readonly ? 'readonly' : ''
+
+    return `<${el.tag} ${type} ${vModel} ${format} ${valueFormat} ${width} ${placeholder} ${startPlaceholder} ${endPlaceholder} ${rangeSeparator} ${clearable} ${readonly} ${disabled}></${el.tag}>`
+  },
+  'el-rate': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const max = el.max ? `:max='${el.max}'` : ''
+    const allowHalf = el['allow-half'] ? 'allow-half' : ''
+    const showText = el['show-text'] ? 'show-text' : ''
+    const showScore = el['show-score'] ? 'show-score' : ''
+
+    return `<${el.tag} ${vModel} ${allowHalf} ${showText} ${showScore} ${disabled}></${el.tag}>`
+  },
+  'el-color-picker': el => {
+    const { disabled, vModel } = attrBuilder(el)
+    const size = `size="${el.size}"`
+    const showAlpha = el['show-alpha'] ? 'show-alpha' : ''
+    const colorFormat = el['color-format'] ? `color-format="${el['color-format']}"` : ''
+
+    return `<${el.tag} ${vModel} ${size} ${showAlpha} ${colorFormat} ${disabled}></${el.tag}>`
+  },
+  'el-upload': el => {
+    const disabled = el.disabled ? ':disabled=\'true\'' : ''
+    const action = el.action ? `:action="${el.vModel}Action"` : ''
+    const multiple = el.multiple ? 'multiple' : ''
+    const listType = el['list-type'] !== 'text' ? `list-type="${el['list-type']}"` : ''
+    const accept = el.accept ? `accept="${el.accept}"` : ''
+    const name = el.name !== 'file' ? `name="${el.name}"` : ''
+    const autoUpload = el['auto-upload'] === false ? ':auto-upload="false"' : ''
+    const beforeUpload = `:before-upload="${el.vModel}BeforeUpload"`
+    const fileList = `:file-list="${el.vModel}fileList"`
+    const ref = `ref="${el.vModel}"`
+    let child = buildElUploadChild(el)
+
+    if (child) child = `\n${child}\n` // 鎹㈣
+    return `<${el.tag} ${ref} ${fileList} ${action} ${autoUpload} ${multiple} ${beforeUpload} ${listType} ${accept} ${name} ${disabled}>${child}</${el.tag}>`
+  }
+}
+
+function attrBuilder(el) {
+  return {
+    vModel: `v-model="${confGlobal.formModel}.${el.vModel}"`,
+    clearable: el.clearable ? 'clearable' : '',
+    placeholder: el.placeholder ? `placeholder="${el.placeholder}"` : '',
+    width: el.style && el.style.width ? ':style="{width: \'100%\'}"' : '',
+    disabled: el.disabled ? ':disabled=\'true\'' : ''
+  }
+}
+
+// el-buttin 瀛愮骇
+function buildElButtonChild(conf) {
+  const children = []
+  if (conf.default) {
+    children.push(conf.default)
+  }
+  return children.join('\n')
+}
+
+// el-input innerHTML
+function buildElInputChild(conf) {
+  const children = []
+  if (conf.prepend) {
+    children.push(`<template slot="prepend">${conf.prepend}</template>`)
+  }
+  if (conf.append) {
+    children.push(`<template slot="append">${conf.append}</template>`)
+  }
+  return children.join('\n')
+}
+
+function buildElSelectChild(conf) {
+  const children = []
+  if (conf.options && conf.options.length) {
+    children.push(`<el-option v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.label" :value="item.value" :disabled="item.disabled"></el-option>`)
+  }
+  return children.join('\n')
+}
+
+function buildElRadioGroupChild(conf) {
+  const children = []
+  if (conf.options && conf.options.length) {
+    const tag = conf.optionType === 'button' ? 'el-radio-button' : 'el-radio'
+    const border = conf.border ? 'border' : ''
+    children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
+  }
+  return children.join('\n')
+}
+
+function buildElCheckboxGroupChild(conf) {
+  const children = []
+  if (conf.options && conf.options.length) {
+    const tag = conf.optionType === 'button' ? 'el-checkbox-button' : 'el-checkbox'
+    const border = conf.border ? 'border' : ''
+    children.push(`<${tag} v-for="(item, index) in ${conf.vModel}Options" :key="index" :label="item.value" :disabled="item.disabled" ${border}>{{item.label}}</${tag}>`)
+  }
+  return children.join('\n')
+}
+
+function buildElUploadChild(conf) {
+  const list = []
+  if (conf['list-type'] === 'picture-card') list.push('<i class="el-icon-plus"></i>')
+  else list.push(`<el-button size="small" type="primary" icon="el-icon-upload">${conf.buttonText}</el-button>`)
+  if (conf.showTip) list.push(`<div slot="tip" class="el-upload__tip">鍙兘涓婁紶涓嶈秴杩� ${conf.fileSize}${conf.sizeUnit} 鐨�${conf.accept}鏂囦欢</div>`)
+  return list.join('\n')
+}
+
+export function makeUpHtml(conf, type) {
+  const htmlList = []
+  confGlobal = conf
+  someSpanIsNot24 = conf.fields.some(item => item.span !== 24)
+  conf.fields.forEach(el => {
+    htmlList.push(layouts[el.layout](el))
+  })
+  const htmlStr = htmlList.join('\n')
+
+  let temp = buildFormTemplate(conf, htmlStr, type)
+  if (type === 'dialog') {
+    temp = dialogWrapper(temp)
+  }
+  confGlobal = null
+  return temp
+}
diff --git a/ruoyi-ui/src/utils/generator/icon.json b/ruoyi-ui/src/utils/generator/icon.json
new file mode 100644
index 0000000..2d9999a
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/icon.json
@@ -0,0 +1 @@
+["platform-eleme","eleme","delete-solid","delete","s-tools","setting","user-solid","user","phone","phone-outline","more","more-outline","star-on","star-off","s-goods","goods","warning","warning-outline","question","info","remove","circle-plus","success","error","zoom-in","zoom-out","remove-outline","circle-plus-outline","circle-check","circle-close","s-help","help","minus","plus","check","close","picture","picture-outline","picture-outline-round","upload","upload2","download","camera-solid","camera","video-camera-solid","video-camera","message-solid","bell","s-cooperation","s-order","s-platform","s-fold","s-unfold","s-operation","s-promotion","s-home","s-release","s-ticket","s-management","s-open","s-shop","s-marketing","s-flag","s-comment","s-finance","s-claim","s-custom","s-opportunity","s-data","s-check","s-grid","menu","share","d-caret","caret-left","caret-right","caret-bottom","caret-top","bottom-left","bottom-right","back","right","bottom","top","top-left","top-right","arrow-left","arrow-right","arrow-down","arrow-up","d-arrow-left","d-arrow-right","video-pause","video-play","refresh","refresh-right","refresh-left","finished","sort","sort-up","sort-down","rank","loading","view","c-scale-to-original","date","edit","edit-outline","folder","folder-opened","folder-add","folder-remove","folder-delete","folder-checked","tickets","document-remove","document-delete","document-copy","document-checked","document","document-add","printer","paperclip","takeaway-box","search","monitor","attract","mobile","scissors","umbrella","headset","brush","mouse","coordinate","magic-stick","reading","data-line","data-board","pie-chart","data-analysis","collection-tag","film","suitcase","suitcase-1","receiving","collection","files","notebook-1","notebook-2","toilet-paper","office-building","school","table-lamp","house","no-smoking","smoking","shopping-cart-full","shopping-cart-1","shopping-cart-2","shopping-bag-1","shopping-bag-2","sold-out","sell","present","box","bank-card","money","coin","wallet","discount","price-tag","news","guide","male","female","thumb","cpu","link","connection","open","turn-off","set-up","chat-round","chat-line-round","chat-square","chat-dot-round","chat-dot-square","chat-line-square","message","postcard","position","turn-off-microphone","microphone","close-notification","bangzhu","time","odometer","crop","aim","switch-button","full-screen","copy-document","mic","stopwatch","medal-1","medal","trophy","trophy-1","first-aid-kit","discover","place","location","location-outline","location-information","add-location","delete-location","map-location","alarm-clock","timer","watch-1","watch","lock","unlock","key","service","mobile-phone","bicycle","truck","ship","basketball","football","soccer","baseball","wind-power","light-rain","lightning","heavy-rain","sunrise","sunrise-1","sunset","sunny","cloudy","partly-cloudy","cloudy-and-sunny","moon","moon-night","dish","dish-1","food","chicken","fork-spoon","knife-fork","burger","tableware","sugar","dessert","ice-cream","hot-water","water-cup","coffee-cup","cold-drink","goblet","goblet-full","goblet-square","goblet-square-full","refrigerator","grape","watermelon","cherry","apple","pear","orange","coffee","ice-tea","ice-drink","milk-tea","potato-strips","lollipop","ice-cream-square","ice-cream-round"]
\ No newline at end of file
diff --git a/ruoyi-ui/src/utils/generator/js.js b/ruoyi-ui/src/utils/generator/js.js
new file mode 100644
index 0000000..ee8668d
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/js.js
@@ -0,0 +1,235 @@
+import { exportDefault, titleCase } from '@/utils/index'
+import { trigger } from './config'
+
+const units = {
+  KB: '1024',
+  MB: '1024 / 1024',
+  GB: '1024 / 1024 / 1024'
+}
+let confGlobal
+const inheritAttrs = {
+  file: '',
+  dialog: 'inheritAttrs: false,'
+}
+
+
+export function makeUpJs(conf, type) {
+  confGlobal = conf = JSON.parse(JSON.stringify(conf))
+  const dataList = []
+  const ruleList = []
+  const optionsList = []
+  const propsList = []
+  const methodList = mixinMethod(type)
+  const uploadVarList = []
+
+  conf.fields.forEach(el => {
+    buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
+  })
+
+  const script = buildexport(
+    conf,
+    type,
+    dataList.join('\n'),
+    ruleList.join('\n'),
+    optionsList.join('\n'),
+    uploadVarList.join('\n'),
+    propsList.join('\n'),
+    methodList.join('\n')
+  )
+  confGlobal = null
+  return script
+}
+
+function buildAttributes(el, dataList, ruleList, optionsList, methodList, propsList, uploadVarList) {
+  buildData(el, dataList)
+  buildRules(el, ruleList)
+
+  if (el.options && el.options.length) {
+    buildOptions(el, optionsList)
+    if (el.dataType === 'dynamic') {
+      const model = `${el.vModel}Options`
+      const options = titleCase(model)
+      buildOptionMethod(`get${options}`, model, methodList)
+    }
+  }
+
+  if (el.props && el.props.props) {
+    buildProps(el, propsList)
+  }
+
+  if (el.action && el.tag === 'el-upload') {
+    uploadVarList.push(
+      `${el.vModel}Action: '${el.action}',
+      ${el.vModel}fileList: [],`
+    )
+    methodList.push(buildBeforeUpload(el))
+    if (!el['auto-upload']) {
+      methodList.push(buildSubmitUpload(el))
+    }
+  }
+
+  if (el.children) {
+    el.children.forEach(el2 => {
+      buildAttributes(el2, dataList, ruleList, optionsList, methodList, propsList, uploadVarList)
+    })
+  }
+}
+
+function mixinMethod(type) {
+  const list = []; const
+    minxins = {
+      file: confGlobal.formBtns ? {
+        submitForm: `submitForm() {
+        this.$refs['${confGlobal.formRef}'].validate(valid => {
+          if(!valid) return
+          // TODO 鎻愪氦琛ㄥ崟
+        })
+      },`,
+        resetForm: `resetForm() {
+        this.$refs['${confGlobal.formRef}'].resetFields()
+      },`
+      } : null,
+      dialog: {
+        onOpen: 'onOpen() {},',
+        onClose: `onClose() {
+        this.$refs['${confGlobal.formRef}'].resetFields()
+      },`,
+        close: `close() {
+        this.$emit('update:visible', false)
+      },`,
+        handleConfirm: `handleConfirm() {
+        this.$refs['${confGlobal.formRef}'].validate(valid => {
+          if(!valid) return
+          this.close()
+        })
+      },`
+      }
+    }
+
+  const methods = minxins[type]
+  if (methods) {
+    Object.keys(methods).forEach(key => {
+      list.push(methods[key])
+    })
+  }
+
+  return list
+}
+
+function buildData(conf, dataList) {
+  if (conf.vModel === undefined) return
+  let defaultValue
+  if (typeof (conf.defaultValue) === 'string' && !conf.multiple) {
+    defaultValue = `'${conf.defaultValue}'`
+  } else {
+    defaultValue = `${JSON.stringify(conf.defaultValue)}`
+  }
+  dataList.push(`${conf.vModel}: ${defaultValue},`)
+}
+
+function buildRules(conf, ruleList) {
+  if (conf.vModel === undefined) return
+  const rules = []
+  if (trigger[conf.tag]) {
+    if (conf.required) {
+      const type = Array.isArray(conf.defaultValue) ? 'type: \'array\',' : ''
+      let message = Array.isArray(conf.defaultValue) ? `璇疯嚦灏戦�夋嫨涓�涓�${conf.vModel}` : conf.placeholder
+      if (message === undefined) message = `${conf.label}涓嶈兘涓虹┖`
+      rules.push(`{ required: true, ${type} message: '${message}', trigger: '${trigger[conf.tag]}' }`)
+    }
+    if (conf.regList && Array.isArray(conf.regList)) {
+      conf.regList.forEach(item => {
+        if (item.pattern) {
+          rules.push(`{ pattern: ${eval(item.pattern)}, message: '${item.message}', trigger: '${trigger[conf.tag]}' }`)
+        }
+      })
+    }
+    ruleList.push(`${conf.vModel}: [${rules.join(',')}],`)
+  }
+}
+
+function buildOptions(conf, optionsList) {
+  if (conf.vModel === undefined) return
+  if (conf.dataType === 'dynamic') { conf.options = [] }
+  const str = `${conf.vModel}Options: ${JSON.stringify(conf.options)},`
+  optionsList.push(str)
+}
+
+function buildProps(conf, propsList) {
+  if (conf.dataType === 'dynamic') {
+    conf.valueKey !== 'value' && (conf.props.props.value = conf.valueKey)
+    conf.labelKey !== 'label' && (conf.props.props.label = conf.labelKey)
+    conf.childrenKey !== 'children' && (conf.props.props.children = conf.childrenKey)
+  }
+  const str = `${conf.vModel}Props: ${JSON.stringify(conf.props.props)},`
+  propsList.push(str)
+}
+
+function buildBeforeUpload(conf) {
+  const unitNum = units[conf.sizeUnit]; let rightSizeCode = ''; let acceptCode = ''; const
+    returnList = []
+  if (conf.fileSize) {
+    rightSizeCode = `let isRightSize = file.size / ${unitNum} < ${conf.fileSize}
+    if(!isRightSize){
+      this.$message.error('鏂囦欢澶у皬瓒呰繃 ${conf.fileSize}${conf.sizeUnit}')
+    }`
+    returnList.push('isRightSize')
+  }
+  if (conf.accept) {
+    acceptCode = `let isAccept = new RegExp('${conf.accept}').test(file.type)
+    if(!isAccept){
+      this.$message.error('搴旇閫夋嫨${conf.accept}绫诲瀷鐨勬枃浠�')
+    }`
+    returnList.push('isAccept')
+  }
+  const str = `${conf.vModel}BeforeUpload(file) {
+    ${rightSizeCode}
+    ${acceptCode}
+    return ${returnList.join('&&')}
+  },`
+  return returnList.length ? str : ''
+}
+
+function buildSubmitUpload(conf) {
+  const str = `submitUpload() {
+    this.$refs['${conf.vModel}'].submit()
+  },`
+  return str
+}
+
+function buildOptionMethod(methodName, model, methodList) {
+  const str = `${methodName}() {
+    // TODO 鍙戣捣璇锋眰鑾峰彇鏁版嵁
+    this.${model}
+  },`
+  methodList.push(str)
+}
+
+function buildexport(conf, type, data, rules, selectOptions, uploadVar, props, methods) {
+  const str = `${exportDefault}{
+  ${inheritAttrs[type]}
+  components: {},
+  props: [],
+  data () {
+    return {
+      ${conf.formModel}: {
+        ${data}
+      },
+      ${conf.formRules}: {
+        ${rules}
+      },
+      ${uploadVar}
+      ${selectOptions}
+      ${props}
+    }
+  },
+  computed: {},
+  watch: {},
+  created () {},
+  mounted () {},
+  methods: {
+    ${methods}
+  }
+}`
+  return str
+}
diff --git a/ruoyi-ui/src/utils/generator/render.js b/ruoyi-ui/src/utils/generator/render.js
new file mode 100644
index 0000000..e8640f0
--- /dev/null
+++ b/ruoyi-ui/src/utils/generator/render.js
@@ -0,0 +1,126 @@
+import { makeMap } from '@/utils/index'
+
+// 鍙傝�僪ttps://github.com/vuejs/vue/blob/v2.6.10/src/platforms/web/server/util.js
+const isAttr = makeMap(
+  'accept,accept-charset,accesskey,action,align,alt,async,autocomplete,'
+  + 'autofocus,autoplay,autosave,bgcolor,border,buffered,challenge,charset,'
+  + 'checked,cite,class,code,codebase,color,cols,colspan,content,http-equiv,'
+  + 'name,contenteditable,contextmenu,controls,coords,data,datetime,default,'
+  + 'defer,dir,dirname,disabled,download,draggable,dropzone,enctype,method,for,'
+  + 'form,formaction,headers,height,hidden,high,href,hreflang,http-equiv,'
+  + 'icon,id,ismap,itemprop,keytype,kind,label,lang,language,list,loop,low,'
+  + 'manifest,max,maxlength,media,method,GET,POST,min,multiple,email,file,'
+  + 'muted,name,novalidate,open,optimum,pattern,ping,placeholder,poster,'
+  + 'preload,radiogroup,readonly,rel,required,reversed,rows,rowspan,sandbox,'
+  + 'scope,scoped,seamless,selected,shape,size,type,text,password,sizes,span,'
+  + 'spellcheck,src,srcdoc,srclang,srcset,start,step,style,summary,tabindex,'
+  + 'target,title,type,usemap,value,width,wrap'
+)
+
+function vModel(self, dataObject, defaultValue) {
+  dataObject.props.value = defaultValue
+
+  dataObject.on.input = val => {
+    self.$emit('input', val)
+  }
+}
+
+const componentChild = {
+  'el-button': {
+    default(h, conf, key) {
+      return conf[key]
+    },
+  },
+  'el-input': {
+    prepend(h, conf, key) {
+      return <template slot="prepend">{conf[key]}</template>
+    },
+    append(h, conf, key) {
+      return <template slot="append">{conf[key]}</template>
+    }
+  },
+  'el-select': {
+    options(h, conf, key) {
+      const list = []
+      conf.options.forEach(item => {
+        list.push(<el-option label={item.label} value={item.value} disabled={item.disabled}></el-option>)
+      })
+      return list
+    }
+  },
+  'el-radio-group': {
+    options(h, conf, key) {
+      const list = []
+      conf.options.forEach(item => {
+        if (conf.optionType === 'button') list.push(<el-radio-button label={item.value}>{item.label}</el-radio-button>)
+        else list.push(<el-radio label={item.value} border={conf.border}>{item.label}</el-radio>)
+      })
+      return list
+    }
+  },
+  'el-checkbox-group': {
+    options(h, conf, key) {
+      const list = []
+      conf.options.forEach(item => {
+        if (conf.optionType === 'button') {
+          list.push(<el-checkbox-button label={item.value}>{item.label}</el-checkbox-button>)
+        } else {
+          list.push(<el-checkbox label={item.value} border={conf.border}>{item.label}</el-checkbox>)
+        }
+      })
+      return list
+    }
+  },
+  'el-upload': {
+    'list-type': (h, conf, key) => {
+      const list = []
+      if (conf['list-type'] === 'picture-card') {
+        list.push(<i class="el-icon-plus"></i>)
+      } else {
+        list.push(<el-button size="small" type="primary" icon="el-icon-upload">{conf.buttonText}</el-button>)
+      }
+      if (conf.showTip) {
+        list.push(<div slot="tip" class="el-upload__tip">鍙兘涓婁紶涓嶈秴杩� {conf.fileSize}{conf.sizeUnit} 鐨剓conf.accept}鏂囦欢</div>)
+      }
+      return list
+    }
+  }
+}
+
+export default {
+  render(h) {
+    const dataObject = {
+      attrs: {},
+      props: {},
+      on: {},
+      style: {}
+    }
+    const confClone = JSON.parse(JSON.stringify(this.conf))
+    const children = []
+
+    const childObjs = componentChild[confClone.tag]
+    if (childObjs) {
+      Object.keys(childObjs).forEach(key => {
+        const childFunc = childObjs[key]
+        if (confClone[key]) {
+          children.push(childFunc(h, confClone, key))
+        }
+      })
+    }
+
+    Object.keys(confClone).forEach(key => {
+      const val = confClone[key]
+      if (key === 'vModel') {
+        vModel(this, dataObject, confClone.defaultValue)
+      } else if (dataObject[key]) {
+        dataObject[key] = val
+      } else if (!isAttr(key)) {
+        dataObject.props[key] = val
+      } else {
+        dataObject.attrs[key] = val
+      }
+    })
+    return h(this.conf.tag, dataObject, children)
+  },
+  props: ['conf']
+}
diff --git a/ruoyi-ui/src/utils/index.js b/ruoyi-ui/src/utils/index.js
new file mode 100644
index 0000000..df5db12
--- /dev/null
+++ b/ruoyi-ui/src/utils/index.js
@@ -0,0 +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
+      // 濡傛灉璁惧畾涓篿mmediate===true锛屽洜涓哄紑濮嬭竟鐣屽凡缁忚皟鐢ㄨ繃浜嗘澶勬棤闇�璋冪敤
+      if (!immediate) {
+        result = func.apply(context, args)
+        if (!timeout) context = args = null
+      }
+    }
+  }
+
+  return function(...args) {
+    context = this
+    timestamp = +new Date()
+    const callNow = immediate && !timeout
+    // 濡傛灉寤舵椂涓嶅瓨鍦紝閲嶆柊璁惧畾寤舵椂
+    if (!timeout) timeout = setTimeout(later, wait)
+    if (callNow) {
+      result = func.apply(context, args)
+      context = args = null
+    }
+
+    return result
+  }
+}
+
+/**
+ * This is just a simple version of deep copy
+ * Has a lot of edge cases bug
+ * If you want to use a perfect deep copy, use lodash's _.cloneDeep
+ * @param {Object} source
+ * @returns {Object}
+ */
+export function deepClone(source) {
+  if (!source && typeof source !== 'object') {
+    throw new Error('error arguments', 'deepClone')
+  }
+  const targetObj = source.constructor === Array ? [] : {}
+  Object.keys(source).forEach(keys => {
+    if (source[keys] && typeof source[keys] === 'object') {
+      targetObj[keys] = deepClone(source[keys])
+    } else {
+      targetObj[keys] = source[keys]
+    }
+  })
+  return targetObj
+}
+
+/**
+ * @param {Array} arr
+ * @returns {Array}
+ */
+export function uniqueArr(arr) {
+  return Array.from(new Set(arr))
+}
+
+/**
+ * @returns {string}
+ */
+export function createUniqueString() {
+  const timestamp = +new Date() + ''
+  const randomNum = parseInt((1 + Math.random()) * 65536) + ''
+  return (+(randomNum + timestamp)).toString(32)
+}
+
+/**
+ * Check if an element has a class
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ * @returns {boolean}
+ */
+export function hasClass(ele, cls) {
+  return !!ele.className.match(new RegExp('(\\s|^)' + cls + '(\\s|$)'))
+}
+
+/**
+ * Add class to element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function addClass(ele, cls) {
+  if (!hasClass(ele, cls)) ele.className += ' ' + cls
+}
+
+/**
+ * Remove class from element
+ * @param {HTMLElement} elm
+ * @param {string} cls
+ */
+export function removeClass(ele, cls) {
+  if (hasClass(ele, cls)) {
+    const reg = new RegExp('(\\s|^)' + cls + '(\\s|$)')
+    ele.className = ele.className.replace(reg, ' ')
+  }
+}
+
+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/jsencrypt.js b/ruoyi-ui/src/utils/jsencrypt.js
new file mode 100644
index 0000000..78d9523
--- /dev/null
+++ b/ruoyi-ui/src/utils/jsencrypt.js
@@ -0,0 +1,30 @@
+import JSEncrypt from 'jsencrypt/bin/jsencrypt.min'
+
+// 瀵嗛挜瀵圭敓鎴� http://web.chacuo.net/netrsakeypair
+
+const publicKey = 'MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdH\n' +
+  'nzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ=='
+
+const privateKey = 'MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY\n' +
+  '7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKN\n' +
+  'PuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gA\n' +
+  'kM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWow\n' +
+  'cSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99Ecv\n' +
+  'DQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthh\n' +
+  'YhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3\n' +
+  'UP8iWi1Qw0Y='
+
+// 鍔犲瘑
+export function encrypt(txt) {
+  const encryptor = new JSEncrypt()
+  encryptor.setPublicKey(publicKey) // 璁剧疆鍏挜
+  return encryptor.encrypt(txt) // 瀵规暟鎹繘琛屽姞瀵�
+}
+
+// 瑙e瘑
+export function decrypt(txt) {
+  const encryptor = new JSEncrypt()
+  encryptor.setPrivateKey(privateKey) // 璁剧疆绉侀挜
+  return encryptor.decrypt(txt) // 瀵规暟鎹繘琛岃В瀵�
+}
+
diff --git a/ruoyi-ui/src/utils/permission.js b/ruoyi-ui/src/utils/permission.js
new file mode 100644
index 0000000..189a716
--- /dev/null
+++ b/ruoyi-ui/src/utils/permission.js
@@ -0,0 +1,47 @@
+import store from '@/store'
+
+/**
+ * 瀛楃鏉冮檺鏍¢獙
+ * @param {Array} value 鏍¢獙鍊�
+ * @returns {Boolean}
+ */
+export function checkPermi(value) {
+  if (value && value instanceof Array && value.length > 0) {
+    const permissions = store.getters && store.getters.permissions
+    const permissionDatas = value
+    const all_permission = "*:*:*";
+
+    const hasPermission = permissions.some(permission => {
+      return all_permission === permission || permissionDatas.includes(permission)
+    })
+
+    return hasPermission;
+
+  } else {
+    console.error(`need roles! Like checkPermi="['system:user:add','system:user:edit']"`)
+    return false
+  }
+}
+
+/**
+ * 瑙掕壊鏉冮檺鏍¢獙
+ * @param {Array} value 鏍¢獙鍊�
+ * @returns {Boolean}
+ */
+export function checkRole(value) {
+  if (value && value instanceof Array && value.length > 0) {
+    const roles = store.getters && store.getters.roles
+    const permissionRoles = value
+    const super_admin = "admin";
+
+    const hasRole = roles.some(role => {
+      return super_admin === role || permissionRoles.includes(role)
+    })
+
+    return hasRole;
+
+  } else {
+    console.error(`need roles! Like checkRole="['admin','editor']"`)
+    return false
+  }
+}
\ No newline at end of file
diff --git a/ruoyi-ui/src/utils/request.js b/ruoyi-ui/src/utils/request.js
new file mode 100644
index 0000000..ffb0d21
--- /dev/null
+++ b/ruoyi-ui/src/utils/request.js
@@ -0,0 +1,152 @@
+import axios from 'axios'
+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 cache from '@/plugins/cache'
+import { saveAs } from 'file-saver'
+
+let downloadLoadingInstance;
+// 鏄惁鏄剧ず閲嶆柊鐧诲綍
+export let isRelogin = { show: false };
+
+axios.defaults.headers['Content-Type'] = 'application/json;charset=utf-8'
+// 鍒涘缓axios瀹炰緥
+const service = axios.create({
+  // axios涓姹傞厤缃湁baseURL閫夐」锛岃〃绀鸿姹俇RL鍏叡閮ㄥ垎
+  baseURL: process.env.VUE_APP_BASE_API,
+  // 瓒呮椂
+  timeout: 10000
+})
+
+// request鎷︽埅鍣�
+service.interceptors.request.use(config => {
+  // 鏄惁闇�瑕佽缃� token
+  const isToken = (config.headers || {}).isToken === false
+  // 鏄惁闇�瑕侀槻姝㈡暟鎹噸澶嶆彁浜�
+  const isRepeatSubmit = (config.headers || {}).repeatSubmit === false
+  if (getToken() && !isToken) {
+    config.headers['Authorization'] = 'Bearer ' + getToken() // 璁╂瘡涓姹傛惡甯﹁嚜瀹氫箟token 璇锋牴鎹疄闄呮儏鍐佃嚜琛屼慨鏀�
+  }
+  // get璇锋眰鏄犲皠params鍙傛暟
+  if (config.method === 'get' && config.params) {
+    let url = config.url + '?' + tansParams(config.params);
+    url = url.slice(0, -1);
+    config.params = {};
+    config.url = url;
+  }
+  if (!isRepeatSubmit && (config.method === 'post' || config.method === 'put')) {
+    const requestObj = {
+      url: config.url,
+      data: typeof config.data === 'object' ? JSON.stringify(config.data) : config.data,
+      time: new Date().getTime()
+    }
+    const requestSize = Object.keys(JSON.stringify(requestObj)).length; // 璇锋眰鏁版嵁澶у皬
+    const limitSize = 5 * 1024 * 1024; // 闄愬埗瀛樻斁鏁版嵁5M
+    if (requestSize >= limitSize) {
+      console.warn(`[${config.url}]: ` + '璇锋眰鏁版嵁澶у皬瓒呭嚭鍏佽鐨�5M闄愬埗锛屾棤娉曡繘琛岄槻閲嶅鎻愪氦楠岃瘉銆�')
+      return config;
+    }
+    const sessionObj = cache.session.getJSON('sessionObj')
+    if (sessionObj === undefined || sessionObj === null || sessionObj === '') {
+      cache.session.setJSON('sessionObj', requestObj)
+    } else {
+      const s_url = sessionObj.url;                  // 璇锋眰鍦板潃
+      const s_data = sessionObj.data;                // 璇锋眰鏁版嵁
+      const s_time = sessionObj.time;                // 璇锋眰鏃堕棿
+      const interval = 1000;                         // 闂撮殧鏃堕棿(ms)锛屽皬浜庢鏃堕棿瑙嗕负閲嶅鎻愪氦
+      if (s_data === requestObj.data && requestObj.time - s_time < interval && s_url === requestObj.url) {
+        const message = '鏁版嵁姝e湪澶勭悊锛岃鍕块噸澶嶆彁浜�';
+        console.warn(`[${s_url}]: ` + message)
+        return Promise.reject(new Error(message))
+      } else {
+        cache.session.setJSON('sessionObj', requestObj)
+      }
+    }
+  }
+  return config
+}, error => {
+    console.log(error)
+    Promise.reject(error)
+})
+
+// 鍝嶅簲鎷︽埅鍣�
+service.interceptors.response.use(res => {
+    // 鏈缃姸鎬佺爜鍒欓粯璁ゆ垚鍔熺姸鎬�
+    const code = res.data.code || 200;
+    // 鑾峰彇閿欒淇℃伅
+    const msg = errorCode[code] || res.data.msg || errorCode['default']
+    // 浜岃繘鍒舵暟鎹垯鐩存帴杩斿洖
+    if (res.request.responseType ===  'blob' || res.request.responseType ===  'arraybuffer') {
+      return res.data
+    }
+    if (code === 401) {
+      if (!isRelogin.show) {
+        isRelogin.show = true;
+        MessageBox.confirm('鐧诲綍鐘舵�佸凡杩囨湡锛屾偍鍙互缁х画鐣欏湪璇ラ〉闈紝鎴栬�呴噸鏂扮櫥褰�', '绯荤粺鎻愮ず', { confirmButtonText: '閲嶆柊鐧诲綍', cancelButtonText: '鍙栨秷', type: 'warning' }).then(() => {
+          isRelogin.show = false;
+          store.dispatch('LogOut').then(() => {
+            location.href = '/index';
+          })
+      }).catch(() => {
+        isRelogin.show = false;
+      });
+    }
+      return Promise.reject('鏃犳晥鐨勪細璇濓紝鎴栬�呬細璇濆凡杩囨湡锛岃閲嶆柊鐧诲綍銆�')
+    } else if (code === 500) {
+      Message({ message: msg, type: 'error' })
+      return Promise.reject(new Error(msg))
+    } else if (code === 601) {
+      Message({ message: msg, type: 'warning' })
+      return Promise.reject('error')
+    } else if (code !== 200) {
+      Notification.error({ title: msg })
+      return Promise.reject('error')
+    } else {
+      return res.data
+    }
+  },
+  error => {
+    console.log('err' + error)
+    let { message } = error;
+    if (message == "Network Error") {
+      message = "鍚庣鎺ュ彛杩炴帴寮傚父";
+    } else if (message.includes("timeout")) {
+      message = "绯荤粺鎺ュ彛璇锋眰瓒呮椂";
+    } else if (message.includes("Request failed with status code")) {
+      message = "绯荤粺鎺ュ彛" + message.substr(message.length - 3) + "寮傚父";
+    }
+    Message({ message: message, type: 'error', duration: 5 * 1000 })
+    return Promise.reject(error)
+  }
+)
+
+// 閫氱敤涓嬭浇鏂规硶
+export function download(url, params, filename, config) {
+  downloadLoadingInstance = Loading.service({ text: "姝e湪涓嬭浇鏁版嵁锛岃绋嶅��", spinner: "el-icon-loading", background: "rgba(0, 0, 0, 0.7)", })
+  return service.post(url, params, {
+    transformRequest: [(params) => { return tansParams(params) }],
+    headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
+    responseType: 'blob',
+    ...config
+  }).then(async (data) => {
+    const isBlob = blobValidate(data);
+    if (isBlob) {
+      const blob = new Blob([data])
+      saveAs(blob, filename)
+    } else {
+      const resText = await data.text();
+      const rspObj = JSON.parse(resText);
+      const errMsg = errorCode[rspObj.code] || rspObj.msg || errorCode['default']
+      Message.error(errMsg);
+    }
+    downloadLoadingInstance.close();
+  }).catch((r) => {
+    console.error(r)
+    Message.error('涓嬭浇鏂囦欢鍑虹幇閿欒锛岃鑱旂郴绠$悊鍛橈紒')
+    downloadLoadingInstance.close();
+  })
+}
+
+export default service
diff --git a/ruoyi-ui/src/utils/ruoyi.js b/ruoyi-ui/src/utils/ruoyi.js
new file mode 100644
index 0000000..44bf9c4
--- /dev/null
+++ b/ruoyi-ui/src/utils/ruoyi.js
@@ -0,0 +1,233 @@
+
+
+/**
+ * 閫氱敤js鏂规硶灏佽澶勭悊
+ * Copyright (c) 2019 ruoyi
+ */
+
+// 鏃ユ湡鏍煎紡鍖�
+export function parseTime(time, pattern) {
+  if (arguments.length === 0 || !time) {
+    return null
+  }
+  const format = pattern || '{y}-{m}-{d} {h}:{i}:{s}'
+  let date
+  if (typeof time === 'object') {
+    date = time
+  } else {
+    if ((typeof time === 'string') && (/^[0-9]+$/.test(time))) {
+      time = parseInt(time)
+    } else if (typeof time === 'string') {
+      time = time.replace(new RegExp(/-/gm), '/').replace('T', ' ').replace(new RegExp(/\.[\d]{3}/gm), '');
+    }
+    if ((typeof time === 'number') && (time.toString().length === 10)) {
+      time = time * 1000
+    }
+    date = new Date(time)
+  }
+  const formatObj = {
+    y: date.getFullYear(),
+    m: date.getMonth() + 1,
+    d: date.getDate(),
+    h: date.getHours(),
+    i: date.getMinutes(),
+    s: date.getSeconds(),
+    a: date.getDay()
+  }
+  const time_str = format.replace(/{(y|m|d|h|i|s|a)+}/g, (result, key) => {
+    let value = formatObj[key]
+    // Note: getDay() returns 0 on Sunday
+    if (key === 'a') { return ['鏃�', '涓�', '浜�', '涓�', '鍥�', '浜�', '鍏�'][value] }
+    if (result.length > 0 && value < 10) {
+      value = '0' + value
+    }
+    return value || 0
+  })
+  return time_str
+}
+
+// 琛ㄥ崟閲嶇疆
+export function resetForm(refName) {
+  if (this.$refs[refName]) {
+    this.$refs[refName].resetFields();
+  }
+}
+
+// 娣诲姞鏃ユ湡鑼冨洿
+export function addDateRange(params, dateRange, propName) {
+  let search = params;
+  search.params = typeof (search.params) === 'object' && search.params !== null && !Array.isArray(search.params) ? search.params : {};
+  dateRange = Array.isArray(dateRange) ? dateRange : [];
+  if (typeof (propName) === 'undefined') {
+    search.params['beginTime'] = dateRange[0];
+    search.params['endTime'] = dateRange[1];
+  } else {
+    search.params['begin' + propName] = dateRange[0];
+    search.params['end' + propName] = dateRange[1];
+  }
+  return search;
+}
+
+// 鍥炴樉鏁版嵁瀛楀吀
+export function selectDictLabel(datas, value) {
+  if (value === undefined) {
+    return "";
+  }
+  var actions = [];
+  Object.keys(datas).some((key) => {
+    if (datas[key].value == ('' + value)) {
+      actions.push(datas[key].label);
+      return true;
+    }
+  })
+  if (actions.length === 0) {
+    actions.push(value);
+  }
+  return actions.join('');
+}
+
+// 鍥炴樉鏁版嵁瀛楀吀锛堝瓧绗︿覆銆佹暟缁勶級
+export function selectDictLabels(datas, value, separator) {
+  if (value === undefined || value.length ===0) {
+    return "";
+  }
+  if (Array.isArray(value)) {
+    value = value.join(",");
+  }
+  var actions = [];
+  var currentSeparator = undefined === separator ? "," : separator;
+  var temp = value.split(currentSeparator);
+  Object.keys(value.split(currentSeparator)).some((val) => {
+    var match = false;
+    Object.keys(datas).some((key) => {
+      if (datas[key].value == ('' + temp[val])) {
+        actions.push(datas[key].label + currentSeparator);
+        match = true;
+      }
+    })
+    if (!match) {
+      actions.push(temp[val] + currentSeparator);
+    }
+  })
+  return actions.join('').substring(0, actions.join('').length - 1);
+}
+
+// 瀛楃涓叉牸寮忓寲(%s )
+export function sprintf(str) {
+  var args = arguments, flag = true, i = 1;
+  str = str.replace(/%s/g, function () {
+    var arg = args[i++];
+    if (typeof arg === 'undefined') {
+      flag = false;
+      return '';
+    }
+    return arg;
+  });
+  return flag ? str : '';
+}
+
+// 杞崲瀛楃涓诧紝undefined,null绛夎浆鍖栦负""
+export function parseStrEmpty(str) {
+  if (!str || str == "undefined" || str == "null") {
+    return "";
+  }
+  return str;
+}
+
+// 鏁版嵁鍚堝苟
+export function mergeRecursive(source, target) {
+  for (var p in target) {
+    try {
+      if (target[p].constructor == Object) {
+        source[p] = mergeRecursive(source[p], target[p]);
+      } else {
+        source[p] = target[p];
+      }
+    } catch (e) {
+      source[p] = target[p];
+    }
+  }
+  return source;
+};
+
+/**
+ * 鏋勯�犳爲鍨嬬粨鏋勬暟鎹�
+ * @param {*} data 鏁版嵁婧�
+ * @param {*} id id瀛楁 榛樿 'id'
+ * @param {*} parentId 鐖惰妭鐐瑰瓧娈� 榛樿 'parentId'
+ * @param {*} children 瀛╁瓙鑺傜偣瀛楁 榛樿 'children'
+ */
+export function handleTree(data, id, parentId, children) {
+  let config = {
+    id: id || 'id',
+    parentId: parentId || 'parentId',
+    childrenList: children || 'children'
+  };
+
+  var childrenListMap = {};
+  var nodeIds = {};
+  var tree = [];
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (childrenListMap[parentId] == null) {
+      childrenListMap[parentId] = [];
+    }
+    nodeIds[d[config.id]] = d;
+    childrenListMap[parentId].push(d);
+  }
+
+  for (let d of data) {
+    let parentId = d[config.parentId];
+    if (nodeIds[parentId] == null) {
+      tree.push(d);
+    }
+  }
+
+  for (let t of tree) {
+    adaptToChildrenList(t);
+  }
+
+  function adaptToChildrenList(o) {
+    if (childrenListMap[o[config.id]] !== null) {
+      o[config.childrenList] = childrenListMap[o[config.id]];
+    }
+    if (o[config.childrenList]) {
+      for (let c of o[config.childrenList]) {
+        adaptToChildrenList(c);
+      }
+    }
+  }
+  return tree;
+}
+
+/**
+* 鍙傛暟澶勭悊
+* @param {*} params  鍙傛暟
+*/
+export function tansParams(params) {
+  let result = ''
+  for (const propName of Object.keys(params)) {
+    const value = params[propName];
+    var part = encodeURIComponent(propName) + "=";
+    if (value !== null && value !== "" && typeof (value) !== "undefined") {
+      if (typeof value === 'object') {
+        for (const key of Object.keys(value)) {
+          if (value[key] !== null && value[key] !== "" && typeof (value[key]) !== 'undefined') {
+            let params = propName + '[' + key + ']';
+            var subPart = encodeURIComponent(params) + "=";
+            result += subPart + encodeURIComponent(value[key]) + "&";
+          }
+        }
+      } else {
+        result += part + encodeURIComponent(value) + "&";
+      }
+    }
+  }
+  return result
+}
+
+// 楠岃瘉鏄惁涓篵lob鏍煎紡
+export function blobValidate(data) {
+  return data.type !== 'application/json'
+}
diff --git a/ruoyi-ui/src/utils/scroll-to.js b/ruoyi-ui/src/utils/scroll-to.js
new file mode 100644
index 0000000..c5d8e04
--- /dev/null
+++ b/ruoyi-ui/src/utils/scroll-to.js
@@ -0,0 +1,58 @@
+Math.easeInOutQuad = function(t, b, c, d) {
+  t /= d / 2
+  if (t < 1) {
+    return c / 2 * t * t + b
+  }
+  t--
+  return -c / 2 * (t * (t - 2) - 1) + b
+}
+
+// requestAnimationFrame for Smart Animating http://goo.gl/sx5sts
+var requestAnimFrame = (function() {
+  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || function(callback) { window.setTimeout(callback, 1000 / 60) }
+})()
+
+/**
+ * Because it's so fucking difficult to detect the scrolling element, just move them all
+ * @param {number} amount
+ */
+function move(amount) {
+  document.documentElement.scrollTop = amount
+  document.body.parentNode.scrollTop = amount
+  document.body.scrollTop = amount
+}
+
+function position() {
+  return document.documentElement.scrollTop || document.body.parentNode.scrollTop || document.body.scrollTop
+}
+
+/**
+ * @param {number} to
+ * @param {number} duration
+ * @param {Function} callback
+ */
+export function scrollTo(to, duration, callback) {
+  const start = position()
+  const change = to - start
+  const increment = 20
+  let currentTime = 0
+  duration = (typeof (duration) === 'undefined') ? 500 : duration
+  var animateScroll = function() {
+    // increment the time
+    currentTime += increment
+    // find the value with the quadratic in-out easing function
+    var val = Math.easeInOutQuad(currentTime, start, change, duration)
+    // move the document.body
+    move(val)
+    // do the animation unless its over
+    if (currentTime < duration) {
+      requestAnimFrame(animateScroll)
+    } else {
+      if (callback && typeof (callback) === 'function') {
+        // the animation is done so lets callback
+        callback()
+      }
+    }
+  }
+  animateScroll()
+}
diff --git a/ruoyi-ui/src/utils/validate.js b/ruoyi-ui/src/utils/validate.js
new file mode 100644
index 0000000..6a4c0c5
--- /dev/null
+++ b/ruoyi-ui/src/utils/validate.js
@@ -0,0 +1,114 @@
+/**
+ * 璺緞鍖归厤鍣�
+ * @param {string} pattern
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isPathMatch(pattern, path) {
+  const regexPattern = pattern.replace(/\//g, '\\/').replace(/\*\*/g, '.*').replace(/\*/g, '[^\\/]*')
+  const regex = new RegExp(`^${regexPattern}$`)
+  return regex.test(path)
+}
+
+/**
+ * 鍒ゆ柇value瀛楃涓叉槸鍚︿负绌� 
+ * @param {string} value
+ * @returns {Boolean}
+ */
+export function isEmpty(value) {
+  if (value == null || value == "" || value == undefined || value == "undefined") {
+    return true
+  }
+  return false
+}
+
+/**
+ * 鍒ゆ柇url鏄惁鏄痟ttp鎴杊ttps 
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function isHttp(url) {
+  return url.indexOf('http://') !== -1 || url.indexOf('https://') !== -1
+}
+
+/**
+ * 鍒ゆ柇path鏄惁涓哄閾�
+ * @param {string} path
+ * @returns {Boolean}
+ */
+export function isExternal(path) {
+  return /^(https?:|mailto:|tel:)/.test(path)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUsername(str) {
+  const valid_map = ['admin', 'editor']
+  return valid_map.indexOf(str.trim()) >= 0
+}
+
+/**
+ * @param {string} url
+ * @returns {Boolean}
+ */
+export function validURL(url) {
+  const reg = /^(https?|ftp):\/\/([a-zA-Z0-9.-]+(:[a-zA-Z0-9.&%$-]+)*@)*((25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]?)(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}|([a-zA-Z0-9-]+\.)*[a-zA-Z0-9-]+\.(com|edu|gov|int|mil|net|org|biz|arpa|info|name|pro|aero|coop|museum|[a-zA-Z]{2}))(:[0-9]+)*(\/($|[a-zA-Z0-9.,?'\\+&%$#=~_-]+))*$/
+  return reg.test(url)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validLowerCase(str) {
+  const reg = /^[a-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validUpperCase(str) {
+  const reg = /^[A-Z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function validAlphabets(str) {
+  const reg = /^[A-Za-z]+$/
+  return reg.test(str)
+}
+
+/**
+ * @param {string} email
+ * @returns {Boolean}
+ */
+export function validEmail(email) {
+  const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/
+  return reg.test(email)
+}
+
+/**
+ * @param {string} str
+ * @returns {Boolean}
+ */
+export function isString(str) {
+  return typeof str === 'string' || str instanceof String
+}
+
+/**
+ * @param {Array} arg
+ * @returns {Boolean}
+ */
+export function isArray(arg) {
+  if (typeof Array.isArray === 'undefined') {
+    return Object.prototype.toString.call(arg) === '[object Array]'
+  }
+  return Array.isArray(arg)
+}
diff --git a/ruoyi-ui/src/views/dashboard/BarChart.vue b/ruoyi-ui/src/views/dashboard/BarChart.vue
new file mode 100644
index 0000000..88e7ef6
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/BarChart.vue
@@ -0,0 +1,102 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 6000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
+            type: 'shadow' // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
+          }
+        },
+        grid: {
+          top: 10,
+          left: '2%',
+          right: '2%',
+          bottom: '3%',
+          containLabel: true
+        },
+        xAxis: [{
+          type: 'category',
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          axisTick: {
+            alignWithLabel: true
+          }
+        }],
+        yAxis: [{
+          type: 'value',
+          axisTick: {
+            show: false
+          }
+        }],
+        series: [{
+          name: 'pageA',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [79, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageB',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [80, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }, {
+          name: 'pageC',
+          type: 'bar',
+          stack: 'vistors',
+          barWidth: '60%',
+          data: [30, 52, 200, 334, 390, 330, 220],
+          animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/LineChart.vue b/ruoyi-ui/src/views/dashboard/LineChart.vue
new file mode 100644
index 0000000..702ff73
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/LineChart.vue
@@ -0,0 +1,135 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '350px'
+    },
+    autoResize: {
+      type: Boolean,
+      default: true
+    },
+    chartData: {
+      type: Object,
+      required: true
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  watch: {
+    chartData: {
+      deep: true,
+      handler(val) {
+        this.setOptions(val)
+      }
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+      this.setOptions(this.chartData)
+    },
+    setOptions({ expectedData, actualData } = {}) {
+      this.chart.setOption({
+        xAxis: {
+          data: ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun'],
+          boundaryGap: false,
+          axisTick: {
+            show: false
+          }
+        },
+        grid: {
+          left: 10,
+          right: 10,
+          bottom: 20,
+          top: 30,
+          containLabel: true
+        },
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: {
+            type: 'cross'
+          },
+          padding: [5, 10]
+        },
+        yAxis: {
+          axisTick: {
+            show: false
+          }
+        },
+        legend: {
+          data: ['expected', 'actual']
+        },
+        series: [{
+          name: 'expected', itemStyle: {
+            normal: {
+              color: '#FF005A',
+              lineStyle: {
+                color: '#FF005A',
+                width: 2
+              }
+            }
+          },
+          smooth: true,
+          type: 'line',
+          data: expectedData,
+          animationDuration: 2800,
+          animationEasing: 'cubicInOut'
+        },
+        {
+          name: 'actual',
+          smooth: true,
+          type: 'line',
+          itemStyle: {
+            normal: {
+              color: '#3888fa',
+              lineStyle: {
+                color: '#3888fa',
+                width: 2
+              },
+              areaStyle: {
+                color: '#f3f8ff'
+              }
+            }
+          },
+          data: actualData,
+          animationDuration: 2800,
+          animationEasing: 'quadraticOut'
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/PanelGroup.vue b/ruoyi-ui/src/views/dashboard/PanelGroup.vue
new file mode 100644
index 0000000..1a1081f
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/PanelGroup.vue
@@ -0,0 +1,181 @@
+<template>
+  <el-row :gutter="40" class="panel-group">
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('newVisitis')">
+        <div class="card-panel-icon-wrapper icon-people">
+          <svg-icon icon-class="peoples" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            璁垮
+          </div>
+          <count-to :start-val="0" :end-val="102400" :duration="2600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('messages')">
+        <div class="card-panel-icon-wrapper icon-message">
+          <svg-icon icon-class="message" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            娑堟伅
+          </div>
+          <count-to :start-val="0" :end-val="81212" :duration="3000" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('purchases')">
+        <div class="card-panel-icon-wrapper icon-money">
+          <svg-icon icon-class="money" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            閲戦
+          </div>
+          <count-to :start-val="0" :end-val="9280" :duration="3200" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+    <el-col :xs="12" :sm="12" :lg="6" class="card-panel-col">
+      <div class="card-panel" @click="handleSetLineChartData('shoppings')">
+        <div class="card-panel-icon-wrapper icon-shopping">
+          <svg-icon icon-class="shopping" class-name="card-panel-icon" />
+        </div>
+        <div class="card-panel-description">
+          <div class="card-panel-text">
+            璁㈠崟
+          </div>
+          <count-to :start-val="0" :end-val="13600" :duration="3600" class="card-panel-num" />
+        </div>
+      </div>
+    </el-col>
+  </el-row>
+</template>
+
+<script>
+import CountTo from 'vue-count-to'
+
+export default {
+  components: {
+    CountTo
+  },
+  methods: {
+    handleSetLineChartData(type) {
+      this.$emit('handleSetLineChartData', type)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.panel-group {
+  margin-top: 18px;
+
+  .card-panel-col {
+    margin-bottom: 32px;
+  }
+
+  .card-panel {
+    height: 108px;
+    cursor: pointer;
+    font-size: 12px;
+    position: relative;
+    overflow: hidden;
+    color: #666;
+    background: #fff;
+    box-shadow: 4px 4px 40px rgba(0, 0, 0, .05);
+    border-color: rgba(0, 0, 0, .05);
+
+    &:hover {
+      .card-panel-icon-wrapper {
+        color: #fff;
+      }
+
+      .icon-people {
+        background: #40c9c6;
+      }
+
+      .icon-message {
+        background: #36a3f7;
+      }
+
+      .icon-money {
+        background: #f4516c;
+      }
+
+      .icon-shopping {
+        background: #34bfa3
+      }
+    }
+
+    .icon-people {
+      color: #40c9c6;
+    }
+
+    .icon-message {
+      color: #36a3f7;
+    }
+
+    .icon-money {
+      color: #f4516c;
+    }
+
+    .icon-shopping {
+      color: #34bfa3
+    }
+
+    .card-panel-icon-wrapper {
+      float: left;
+      margin: 14px 0 0 14px;
+      padding: 16px;
+      transition: all 0.38s ease-out;
+      border-radius: 6px;
+    }
+
+    .card-panel-icon {
+      float: left;
+      font-size: 48px;
+    }
+
+    .card-panel-description {
+      float: right;
+      font-weight: bold;
+      margin: 26px;
+      margin-left: 0px;
+
+      .card-panel-text {
+        line-height: 18px;
+        color: rgba(0, 0, 0, 0.45);
+        font-size: 16px;
+        margin-bottom: 12px;
+      }
+
+      .card-panel-num {
+        font-size: 20px;
+      }
+    }
+  }
+}
+
+@media (max-width:550px) {
+  .card-panel-description {
+    display: none;
+  }
+
+  .card-panel-icon-wrapper {
+    float: none !important;
+    width: 100%;
+    height: 100%;
+    margin: 0 !important;
+
+    .svg-icon {
+      display: block;
+      margin: 14px auto !important;
+      float: none !important;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/dashboard/PieChart.vue b/ruoyi-ui/src/views/dashboard/PieChart.vue
new file mode 100644
index 0000000..63f0d84
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/PieChart.vue
@@ -0,0 +1,79 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'item',
+          formatter: '{a} <br/>{b} : {c} ({d}%)'
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Industries', 'Technology', 'Forex', 'Gold', 'Forecasts']
+        },
+        series: [
+          {
+            name: 'WEEKLY WRITE ARTICLES',
+            type: 'pie',
+            roseType: 'radius',
+            radius: [15, 95],
+            center: ['50%', '38%'],
+            data: [
+              { value: 320, name: 'Industries' },
+              { value: 240, name: 'Technology' },
+              { value: 149, name: 'Forex' },
+              { value: 100, name: 'Gold' },
+              { value: 59, name: 'Forecasts' }
+            ],
+            animationEasing: 'cubicInOut',
+            animationDuration: 2600
+          }
+        ]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/RaddarChart.vue b/ruoyi-ui/src/views/dashboard/RaddarChart.vue
new file mode 100644
index 0000000..312e018
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/RaddarChart.vue
@@ -0,0 +1,116 @@
+<template>
+  <div :class="className" :style="{height:height,width:width}" />
+</template>
+
+<script>
+import * as echarts from 'echarts'
+require('echarts/theme/macarons') // echarts theme
+import resize from './mixins/resize'
+
+const animationDuration = 3000
+
+export default {
+  mixins: [resize],
+  props: {
+    className: {
+      type: String,
+      default: 'chart'
+    },
+    width: {
+      type: String,
+      default: '100%'
+    },
+    height: {
+      type: String,
+      default: '300px'
+    }
+  },
+  data() {
+    return {
+      chart: null
+    }
+  },
+  mounted() {
+    this.$nextTick(() => {
+      this.initChart()
+    })
+  },
+  beforeDestroy() {
+    if (!this.chart) {
+      return
+    }
+    this.chart.dispose()
+    this.chart = null
+  },
+  methods: {
+    initChart() {
+      this.chart = echarts.init(this.$el, 'macarons')
+
+      this.chart.setOption({
+        tooltip: {
+          trigger: 'axis',
+          axisPointer: { // 鍧愭爣杞存寚绀哄櫒锛屽潗鏍囪酱瑙﹀彂鏈夋晥
+            type: 'shadow' // 榛樿涓虹洿绾匡紝鍙�変负锛�'line' | 'shadow'
+          }
+        },
+        radar: {
+          radius: '66%',
+          center: ['50%', '42%'],
+          splitNumber: 8,
+          splitArea: {
+            areaStyle: {
+              color: 'rgba(127,95,132,.3)',
+              opacity: 1,
+              shadowBlur: 45,
+              shadowColor: 'rgba(0,0,0,.5)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 15
+            }
+          },
+          indicator: [
+            { name: 'Sales', max: 10000 },
+            { name: 'Administration', max: 20000 },
+            { name: 'Information Techology', max: 20000 },
+            { name: 'Customer Support', max: 20000 },
+            { name: 'Development', max: 20000 },
+            { name: 'Marketing', max: 20000 }
+          ]
+        },
+        legend: {
+          left: 'center',
+          bottom: '10',
+          data: ['Allocated Budget', 'Expected Spending', 'Actual Spending']
+        },
+        series: [{
+          type: 'radar',
+          symbolSize: 0,
+          areaStyle: {
+            normal: {
+              shadowBlur: 13,
+              shadowColor: 'rgba(0,0,0,.2)',
+              shadowOffsetX: 0,
+              shadowOffsetY: 10,
+              opacity: 1
+            }
+          },
+          data: [
+            {
+              value: [5000, 7000, 12000, 11000, 15000, 14000],
+              name: 'Allocated Budget'
+            },
+            {
+              value: [4000, 9000, 15000, 15000, 13000, 11000],
+              name: 'Expected Spending'
+            },
+            {
+              value: [5500, 11000, 12000, 15000, 12000, 12000],
+              name: 'Actual Spending'
+            }
+          ],
+          animationDuration: animationDuration
+        }]
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/dashboard/mixins/resize.js b/ruoyi-ui/src/views/dashboard/mixins/resize.js
new file mode 100644
index 0000000..b1e76e9
--- /dev/null
+++ b/ruoyi-ui/src/views/dashboard/mixins/resize.js
@@ -0,0 +1,56 @@
+import { debounce } from '@/utils'
+
+export default {
+  data() {
+    return {
+      $_sidebarElm: null,
+      $_resizeHandler: null
+    }
+  },
+  mounted() {
+    this.initListener()
+  },
+  activated() {
+    if (!this.$_resizeHandler) {
+      // avoid duplication init
+      this.initListener()
+    }
+
+    // when keep-alive chart activated, auto resize
+    this.resize()
+  },
+  beforeDestroy() {
+    this.destroyListener()
+  },
+  deactivated() {
+    this.destroyListener()
+  },
+  methods: {
+    // use $_ for mixins properties
+    // https://vuejs.org/v2/style-guide/index.html#Private-property-names-essential
+    $_sidebarResizeHandler(e) {
+      if (e.propertyName === 'width') {
+        this.$_resizeHandler()
+      }
+    },
+    initListener() {
+      this.$_resizeHandler = debounce(() => {
+        this.resize()
+      }, 100)
+      window.addEventListener('resize', this.$_resizeHandler)
+
+      this.$_sidebarElm = document.getElementsByClassName('sidebar-container')[0]
+      this.$_sidebarElm && this.$_sidebarElm.addEventListener('transitionend', this.$_sidebarResizeHandler)
+    },
+    destroyListener() {
+      window.removeEventListener('resize', this.$_resizeHandler)
+      this.$_resizeHandler = null
+
+      this.$_sidebarElm && this.$_sidebarElm.removeEventListener('transitionend', this.$_sidebarResizeHandler)
+    },
+    resize() {
+      const { chart } = this
+      chart && chart.resize()
+    }
+  }
+}
diff --git a/ruoyi-ui/src/views/error/401.vue b/ruoyi-ui/src/views/error/401.vue
new file mode 100644
index 0000000..448b6ec
--- /dev/null
+++ b/ruoyi-ui/src/views/error/401.vue
@@ -0,0 +1,88 @@
+<template>
+  <div class="errPage-container">
+    <el-button icon="arrow-left" class="pan-back-btn" @click="back">
+      杩斿洖
+    </el-button>
+    <el-row>
+      <el-col :span="12">
+        <h1 class="text-jumbo text-ginormous">
+          401閿欒!
+        </h1>
+        <h2>鎮ㄦ病鏈夎闂潈闄愶紒</h2>
+        <h6>瀵逛笉璧凤紝鎮ㄦ病鏈夎闂潈闄愶紝璇蜂笉瑕佽繘琛岄潪娉曟搷浣滐紒鎮ㄥ彲浠ヨ繑鍥炰富椤甸潰</h6>
+        <ul class="list-unstyled">
+          <li class="link-type">
+            <router-link to="/">
+              鍥為椤�
+            </router-link>
+          </li>
+        </ul>
+      </el-col>
+      <el-col :span="12">
+        <img :src="errGif" width="313" height="428" alt="Girl has dropped her ice cream.">
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import errGif from '@/assets/401_images/401.gif'
+
+export default {
+  name: 'Page401',
+  data() {
+    return {
+      errGif: errGif + '?' + +new Date()
+    }
+  },
+  methods: {
+    back() {
+      if (this.$route.query.noGoBack) {
+        this.$router.push({ path: '/' })
+      } else {
+        this.$router.go(-1)
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+  .errPage-container {
+    width: 800px;
+    max-width: 100%;
+    margin: 100px auto;
+    .pan-back-btn {
+      background: #008489;
+      color: #fff;
+      border: none!important;
+    }
+    .pan-gif {
+      margin: 0 auto;
+      display: block;
+    }
+    .pan-img {
+      display: block;
+      margin: 0 auto;
+      width: 100%;
+    }
+    .text-jumbo {
+      font-size: 60px;
+      font-weight: 700;
+      color: #484848;
+    }
+    .list-unstyled {
+      font-size: 14px;
+      li {
+        padding-bottom: 5px;
+      }
+      a {
+        color: #008489;
+        text-decoration: none;
+        &:hover {
+          text-decoration: underline;
+        }
+      }
+    }
+  }
+</style>
diff --git a/ruoyi-ui/src/views/error/404.vue b/ruoyi-ui/src/views/error/404.vue
new file mode 100644
index 0000000..96f075c
--- /dev/null
+++ b/ruoyi-ui/src/views/error/404.vue
@@ -0,0 +1,233 @@
+<template>
+  <div class="wscn-http404-container">
+    <div class="wscn-http404">
+      <div class="pic-404">
+        <img class="pic-404__parent" src="@/assets/404_images/404.png" alt="404">
+        <img class="pic-404__child left" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child mid" src="@/assets/404_images/404_cloud.png" alt="404">
+        <img class="pic-404__child right" src="@/assets/404_images/404_cloud.png" alt="404">
+      </div>
+      <div class="bullshit">
+        <div class="bullshit__oops">
+          404閿欒!
+        </div>
+        <div class="bullshit__headline">
+          {{ message }}
+        </div>
+        <div class="bullshit__info">
+          瀵逛笉璧凤紝鎮ㄦ鍦ㄥ鎵剧殑椤甸潰涓嶅瓨鍦ㄣ�傚皾璇曟鏌RL鐨勯敊璇紝鐒跺悗鎸夋祻瑙堝櫒涓婄殑鍒锋柊鎸夐挳鎴栧皾璇曞湪鎴戜滑鐨勫簲鐢ㄧ▼搴忎腑鎵惧埌鍏朵粬鍐呭銆�
+        </div>
+        <router-link to="/" class="bullshit__return-home">
+          杩斿洖棣栭〉
+        </router-link>
+      </div>
+    </div>
+  </div>
+</template>
+
+<script>
+
+export default {
+  name: 'Page404',
+  computed: {
+    message() {
+      return '鎵句笉鍒扮綉椤碉紒'
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.wscn-http404-container{
+  transform: translate(-50%,-50%);
+  position: absolute;
+  top: 40%;
+  left: 50%;
+}
+.wscn-http404 {
+  position: relative;
+  width: 1200px;
+  padding: 0 50px;
+  overflow: hidden;
+  .pic-404 {
+    position: relative;
+    float: left;
+    width: 600px;
+    overflow: hidden;
+    &__parent {
+      width: 100%;
+    }
+    &__child {
+      position: absolute;
+      &.left {
+        width: 80px;
+        top: 17px;
+        left: 220px;
+        opacity: 0;
+        animation-name: cloudLeft;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      &.mid {
+        width: 46px;
+        top: 10px;
+        left: 420px;
+        opacity: 0;
+        animation-name: cloudMid;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1.2s;
+      }
+      &.right {
+        width: 62px;
+        top: 100px;
+        left: 500px;
+        opacity: 0;
+        animation-name: cloudRight;
+        animation-duration: 2s;
+        animation-timing-function: linear;
+        animation-fill-mode: forwards;
+        animation-delay: 1s;
+      }
+      @keyframes cloudLeft {
+        0% {
+          top: 17px;
+          left: 220px;
+          opacity: 0;
+        }
+        20% {
+          top: 33px;
+          left: 188px;
+          opacity: 1;
+        }
+        80% {
+          top: 81px;
+          left: 92px;
+          opacity: 1;
+        }
+        100% {
+          top: 97px;
+          left: 60px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudMid {
+        0% {
+          top: 10px;
+          left: 420px;
+          opacity: 0;
+        }
+        20% {
+          top: 40px;
+          left: 360px;
+          opacity: 1;
+        }
+        70% {
+          top: 130px;
+          left: 180px;
+          opacity: 1;
+        }
+        100% {
+          top: 160px;
+          left: 120px;
+          opacity: 0;
+        }
+      }
+      @keyframes cloudRight {
+        0% {
+          top: 100px;
+          left: 500px;
+          opacity: 0;
+        }
+        20% {
+          top: 120px;
+          left: 460px;
+          opacity: 1;
+        }
+        80% {
+          top: 180px;
+          left: 340px;
+          opacity: 1;
+        }
+        100% {
+          top: 200px;
+          left: 300px;
+          opacity: 0;
+        }
+      }
+    }
+  }
+  .bullshit {
+    position: relative;
+    float: left;
+    width: 300px;
+    padding: 30px 0;
+    overflow: hidden;
+    &__oops {
+      font-size: 32px;
+      font-weight: bold;
+      line-height: 40px;
+      color: #1482f0;
+      opacity: 0;
+      margin-bottom: 20px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-fill-mode: forwards;
+    }
+    &__headline {
+      font-size: 20px;
+      line-height: 24px;
+      color: #222;
+      font-weight: bold;
+      opacity: 0;
+      margin-bottom: 10px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.1s;
+      animation-fill-mode: forwards;
+    }
+    &__info {
+      font-size: 13px;
+      line-height: 21px;
+      color: grey;
+      opacity: 0;
+      margin-bottom: 30px;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.2s;
+      animation-fill-mode: forwards;
+    }
+    &__return-home {
+      display: block;
+      float: left;
+      width: 110px;
+      height: 36px;
+      background: #1482f0;
+      border-radius: 100px;
+      text-align: center;
+      color: #ffffff;
+      opacity: 0;
+      font-size: 14px;
+      line-height: 36px;
+      cursor: pointer;
+      animation-name: slideUp;
+      animation-duration: 0.5s;
+      animation-delay: 0.3s;
+      animation-fill-mode: forwards;
+    }
+    @keyframes slideUp {
+      0% {
+        transform: translateY(60px);
+        opacity: 0;
+      }
+      100% {
+        transform: translateY(0);
+        opacity: 1;
+      }
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/index.vue b/ruoyi-ui/src/views/index.vue
new file mode 100644
index 0000000..070ace8
--- /dev/null
+++ b/ruoyi-ui/src/views/index.vue
@@ -0,0 +1,1107 @@
+<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锛孋RM锛孫A绛夌瓑锛屽綋鐒讹紝鎮ㄤ篃鍙互瀵瑰ス杩涜娣卞害瀹氬埗锛屼互鍋氬嚭鏇村己绯荤粺銆傛墍鏈夊墠绔悗鍙颁唬鐮佸皝瑁呰繃鍚庡崄鍒嗙簿绠�鏄撲笂鎵嬶紝鍑洪敊姒傜巼浣庛�傚悓鏃舵敮鎸佺Щ鍔ㄥ鎴风璁块棶銆傜郴缁熶細闄嗙画鏇存柊涓�浜涘疄鐢ㄥ姛鑳姐��
+        </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> <a href="http://qm.qq.com/cgi-bin/qm/qr?_wv=1027&k=SUc-msaypcqB2UTFif4eqGlBHkKcvMNP&authKey=JdQBouY2PG%2BS%2BCzAfIgbCGNgxyahpfh24IW%2F03rPxGilhqVbisLma%2FFFnt79DHNh&noverify=0&group_code=151450850" target="_blank">151450850</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>鏀寔鑷畾涔夋樉绀篍xcel灞炴�у垪</li>
+                <li>鎿嶄綔鏃ュ織璁板綍DELETE璇锋眰鍙傛暟</li>
+                <li>鐧藉悕鍗曟敮鎸佸閫氶厤绗﹁矾寰勫尮閰�</li>
+                <li>鏍℃鏂囦欢鍚嶆槸鍚﹀寘鍚壒娈婂瓧绗�</li>
+                <li>浠g爜鐢熸垚鍒涘缓琛ㄥ睆钄借繚瑙勭殑瀛楃</li>
+                <li>鑿滃崟闈㈠寘灞戝鑸敮鎸佸灞傜骇鏄剧ず</li>
+                <li>Excel娉ㄨВ鏀寔wrapText鏄惁鍏佽鍐呭鎹㈣</li>
+                <li>浠g爜鐢熸垚鏂板閰嶇疆鏄惁鍏佽鏂囦欢瑕嗙洊鍒版湰鍦�</li>
+                <li>淇瑙掕壊绂佺敤鏉冮檺涓嶅け鏁堥棶棰�</li>
+                <li>淇浠g爜鐢熸垚涓婄骇鑿滃崟鏄剧ず闂</li>
+                <li>淇瀵煎嚭瀛愬垪琛ㄥ璞″彧鑳藉湪鏈�鍚庣殑闂</li>
+                <li>淇TopNav鏃犳硶姝g‘鑾峰彇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>浠g爜鐢熸垚鏂板鍒涘缓琛ㄧ粨鏋勫姛鑳�</li>
+                <li>瀹氭椂浠诲姟鐧藉悕鍗曢厤缃寖鍥寸缉灏�</li>
+                <li>浼樺寲浠g爜鐢熸垚涓诲瓙琛ㄥ叧鑱旀煡璇㈡柟寮�</li>
+                <li>Excel娉ㄨВ鏂板灞炴�omboReadDict</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浠ュ吋瀹筺ode18+</li>
+                <li>鍗囩骇spring-security鍒板畨鍏ㄧ増鏈紝闃叉婕忔礊椋庨櫓</li>
+                <li>鍗囩骇spring-framework鍒板畨鍏ㄧ増鏈紝闃叉婕忔礊椋庨櫓</li>
+                <li>浼樺寲鑷畾涔塜SS娉ㄨВ鍖归厤鏂瑰紡</li>
+                <li>浼樺寲缂撳瓨鐩戞帶閿悕鍒楄〃鎺掑簭鏄剧ず</li>
+                <li>浼樺寲瀹氭椂浠诲姟鏃ュ織榛樿鎸夋椂闂存帓搴�</li>
+                <li>浼樺寲榛樿鏂囦欢澶у皬瓒呰繃2G鏃犳晥鐨勯棶棰�</li>
+                <li>浼樺寲鏌ヨ〃鐗规畩瀛楃浣跨敤鍙嶆枩鏉犺繘琛岃浆涔�</li>
+                <li>浼樺寲瀹氭椂浠诲姟cron琛ㄨ揪寮忓皬鏃堕厤缃樉绀洪敊璇棶棰�</li>
+                <li>浼樺寲澶氫釜鑷畾鏁版嵁鏉冮檺浣跨敤in鏌ヨ,閬垮厤澶氭鎷兼帴</li>
+                <li>浼樺寲瀵煎叆Excel鏃惰缃甦ictType灞炴�ч噸澶嶆煡缂撳瓨闂</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>浠g爜鐢熸垚鏀寔閫夋嫨鍓嶇妯℃澘绫诲瀷</li>
+                <li>鏄鹃殣鍒楃粍浠舵敮鎸佸閫夋寮瑰嚭绫诲瀷</li>
+                <li>閫氱敤鎺掑簭灞炴�rderBy鍙傛暟闄愬埗闀垮害</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>淇澶栭摼甯︾鍙e嚭鐜扮殑寮傚父</li>
+                <li>淇鏍戞ā鏉跨埗绾х紪鐮佸彉閲忛敊璇�</li>
+                <li>淇瀛楀吀琛ㄨ鎯呴〉闈㈡悳绱㈤棶棰�</li>
+                <li>淇鍐呴摼iframe娌℃湁浼犻�掑弬鏁伴棶棰�</li>
+                <li>淇鑷畾涔夊瓧鍏告牱寮忎笉鐢熸晥鐨勯棶棰�</li>
+                <li>淇瀛楀吀缂撳瓨鍒犻櫎鏂规硶鍙傛暟閿欒闂</li>
+                <li>淇Excel瀵煎叆鏁版嵁涓存椂鏂囦欢鏃犳硶鍒犻櫎闂</li>
+                <li>淇鏈櫥褰曞甫鍙傛暟璁块棶鎴愬姛鍚庡弬鏁颁涪澶遍棶棰�</li>
+                <li>淇HeaderSearch缁勪欢璺宠浆query鍙傛暟涓㈠け闂</li>
+                <li>淇浠g爜鐢熸垚瀵煎叆鍚庡繀濉」涓庢暟鎹簱涓嶅尮閰嶉棶棰�</li>
+                <li>淇Excels瀵煎叆鏃舵棤娉曡幏鍙栧埌dictType瀛楀吀鍊奸棶棰�</li>
+                <li>浼樺寲涓嬭浇zip鏂规硶鏂板閬僵灞�</li>
+                <li>浼樺寲澶村儚涓婁紶鍙傛暟鏂板鏂囦欢鍚嶇О</li>
+                <li>浼樺寲瀛楀吀鏍囩鏀寔鑷畾涔夊垎闅旂</li>
+                <li>浼樺寲鑿滃崟绠$悊绫诲瀷涓烘寜閽姸鎬佸彲閫�</li>
+                <li>浼樺寲鍓嶇闃查噸澶嶆彁浜ゆ暟鎹ぇ灏忛檺鍒�</li>
+                <li>浼樺寲TopNav鑿滃崟娌℃湁鍥炬爣svg涓嶆樉绀�</li>
+                <li>浼樺寲鏁板瓧閲戦澶у啓杞崲绮惧害涓㈠け闂</li>
+                <li>浼樺寲瀵屾枃鏈珽ditor缁勪欢妫�楠屽浘鐗囨牸寮�</li>
+                <li>浼樺寲椤电鍦‵irefox娴忚鍣ㄨ閬尅鐨勯棶棰�</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>淇寮�鍚疶opNav鍚庝竴绾ц彍鍗曡矾鐢卞弬鏁拌缃棤鏁堥棶棰�</li>
+                <li>淇DictTag缁勪欢value娌℃湁鍖归厤鐨勫�兼椂鍒欏睍绀簐alue</li>
+                <li>浼樺寲鏂囦欢涓嬭浇鍑虹幇鐨勫紓甯�</li>
+                <li>浼樺寲閫夋嫨鍥炬爣缁勪欢楂樹寒鍥炴樉</li>
+                <li>浼樺寲寮圭獥鍚庡鑸爮鍋忕Щ鐨勯棶棰�</li>
+                <li>浼樺寲淇敼瀵嗙爜鏃ュ織瀛樺偍鏄庢枃闂</li>
+                <li>浼樺寲椤电鏍忓叧闂叾浠栧嚭鐜扮殑寮傚父闂</li>
+                <li>浼樺寲椤电鍏抽棴宸︿晶閫夐」鎺掗櫎棣栭〉閫夐」</li>
+                <li>浼樺寲鍏抽棴褰撳墠tab椤佃烦杞渶鍙充晶tab椤�</li>
+                <li>浼樺寲缂撳瓨鍒楄〃娓呴櫎鎿嶄綔鎻愮ず涓嶅彉鐨勯棶棰�</li>
+                <li>浼樺寲瀛楃鏈娇鐢ㄤ笅鍒掔嚎涓嶈繘琛岄┘宄板紡澶勭悊</li>
+                <li>浼樺寲鐢ㄦ埛瀵煎叆鏇存柊鏃堕渶鑾峰彇鐢ㄦ埛缂栧彿闂</li>
+                <li>浼樺寲渚ц竟鏍忕殑骞冲彴鏍囬涓嶸UE_APP_TITLE淇濇寔鍚屾</li>
+                <li>浼樺寲瀵煎嚭Excel鏃惰缃甦ictType灞炴�ч噸澶嶆煡缂撳瓨闂</li>
+                <li>杩炴帴姹燚ruid鏀寔鏂扮殑閰嶇疆connectTimeout鍜宻ocketTimeout</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>寮�鍚疶opNav娌℃湁瀛愯彍鍗曢殣钘忎晶杈规爮</li>
+                <li>鍒犻櫎fuse鏃犳晥閫夐」maxPatternLength</li>
+                <li>浼樺寲瀵煎嚭瀵硅薄鐨勫瓙鍒楄〃涓虹┖浼氬嚭鐜癧]闂</li>
+                <li>浼樺寲缂栬緫澶村儚鏃堕�忔槑閮ㄥ垎浼氬彉鎴愰粦鑹查棶棰�</li>
+                <li>浼樺寲灏忓睆骞曚笂淇敼澶村儚鐣岄潰甯冨眬閿欎綅鐨勯棶棰�</li>
+                <li>淇浠g爜鐢熸垚鍕鹃�夊睘鎬ф棤鏁堥棶棰�</li>
+                <li>淇鏂囦欢涓婁紶缁勪欢鏍煎紡楠岃瘉闂</li>
+                <li>淇鍥炴樉鏁版嵁瀛楀吀鏁扮粍寮傚父闂</li>
+                <li>淇sheet瓒呭嚭鏈�澶ц鏁板紓甯搁棶棰�</li>
+                <li>淇Log娉ㄨВGET璇锋眰璁板綍涓嶅埌鍙傛暟闂</li>
+                <li>淇璋冨害鏃ュ織鐐瑰嚮澶氭鏁版嵁涓嶅彉鍖栫殑闂</li>
+                <li>淇涓婚棰滆壊鍦―rawer缁勪欢涓嶄細鍔犺浇闂</li>
+                <li>淇鏂囦欢鍚嶅寘鍚壒娈婂瓧绗︾殑鏂囦欢鏃犳硶涓嬭浇闂</li>
+                <li>淇table涓洿澶氭寜閽垏鎹富棰樿壊鏈敓鏁堜慨澶嶉棶棰�</li>
+                <li>淇鏌愪簺鐗规�х殑鐜鐢熸垚浠g爜鍙樹贡鐮乀XT鏂囦欢闂</li>
+                <li>淇浠g爜鐢熸垚鍥剧墖/鏂囦欢/鍗曢�夋椂閫夋嫨蹇呭~鏃犳硶鏍¢獙闂</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>鐧诲綍鏃ュ織鏂板瑙i攣璐︽埛鍔熻兘</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>浼樺寲浠g爜鐢熸垚鍚屾鍚庡�糔ULL闂</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>浠g爜鐢熸垚鏍戣〃鏂板(灞曞紑/鎶樺彔)</li>
+                <li>Excel娉ㄨВ鏀寔color瀛椾綋棰滆壊</li>
+                <li>鏂板Anonymous鍖垮悕璁块棶涓嶉壌鏉冩敞瑙�</li>
+                <li>鐢ㄦ埛澶村儚涓婁紶闄愬埗鍙兘涓哄浘鐗囨牸寮�</li>
+                <li>鎺ュ彛浣跨敤娉涘瀷浣垮叾鐪嬪埌鍝嶅簲灞炴�у瓧娈�</li>
+                <li>妫�鏌ュ畾鏃朵换鍔ean鎵�鍦ㄥ寘鍚嶆槸鍚︿负鐧藉悕鍗曢厤缃�</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>鍒犻櫎澶氫綑鐨剆alt瀛楁</li>
+                <li>鏂板鑾峰彇涓嶅甫鍚庣紑鏂囦欢鍚嶇О鏂规硶</li>
+                <li>鏂板鑾峰彇閰嶇疆鏂囦欢涓殑灞炴�у�兼柟娉�</li>
+                <li>鏂板鍐呭缂栫爜/瑙g爜鏂逛究鎻掍欢闆嗘垚浣跨敤</li>
+                <li>瀛楀吀绫诲瀷蹇呴』浠ュ瓧姣嶅紑澶达紝涓斿彧鑳戒负锛堝皬鍐欏瓧姣嶏紝鏁板瓧锛屼笅婊戠嚎锛�</li>
+                <li>浼樺寲璁剧疆鍒嗛〉鍙傛暟榛樿鍊�</li>
+                <li>浼樺寲瀵圭┖瀛楃涓插弬鏁板鐞嗙殑杩囨护</li>
+                <li>浼樺寲鏄剧ず椤哄簭orderNum绫诲瀷涓烘暣鍨�</li>
+                <li>浼樺寲琛ㄥ崟鏋勫缓鎸夐挳涓嶆樉绀烘鍒欐牎楠�</li>
+                <li>浼樺寲瀛楀吀鏁版嵁鍥炴樉鏍峰紡涓嬫媺妗嗘樉绀哄��</li>
+                <li>浼樺寲R鍝嶅簲鎴愬姛鐘舵�佺爜涓庡叏灞�淇濇寔涓�鑷�</li>
+                <li>浼樺寲druid寮�鍚痺all杩囨护鍣ㄥ嚭鐜扮殑寮傚父闂</li>
+                <li>浼樺寲鐢ㄦ埛绠$悊宸︿晶鏍戝瀷缁勪欢澧炲姞閫変腑楂樹寒淇濇寔</li>
+                <li>浼樺寲鏂板鐢ㄦ埛涓庤鑹蹭俊鎭�&鐢ㄦ埛涓庡矖浣嶄俊鎭�昏緫</li>
+                <li>浼樺寲榛樿涓嶅惎鐢ㄥ帇缂╂枃浠剁紦瀛橀槻姝ode_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>寮�鍚疶opNav娌℃湁瀛愯彍鍗曟儏鍐甸殣钘忎晶杈规爮</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>浠g爜鐢熸垚鍒楄〃鍥剧墖鏀寔棰勮</li>
+                <li>浠g爜鐢熸垚缂栬緫淇敼鎵撳紑鏂伴〉绛�</li>
+                <li>浠g爜鐢熸垚鏂板Java绫诲瀷Boolean</li>
+                <li>浠g爜鐢熸垚瀛愯〃鏀寔鏃ユ湡/瀛楀吀閰嶇疆</li>
+                <li>浠g爜鐢熸垚鍚屾淇濈暀蹇呭~/绫诲瀷閫夐」</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鍓嶇浠g爜鐢熸垚妯℃澘</li>
+                <li>鏂板鍥剧墖棰勮缁勪欢</li>
+                <li>鏂板鍘嬬缉鎻掍欢瀹炵幇鎵撳寘Gzip</li>
+                <li>鑷畾涔墄ss鏍¢獙娉ㄨВ瀹炵幇</li>
+                <li>鑷畾涔夋枃瀛楀鍒跺壀璐存寚浠�</li>
+                <li>浠g爜鐢熸垚棰勮鏀寔澶嶅埗鍐呭</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鍒版渶鏂扮増鏈瑅5.8.6</li>
+                <li>鍗囩骇fastjson鍒版渶鏂扮増1.2.79</li>
+                <li>鍗囩骇spring-boot鍒版渶鏂扮増鏈�2.5.8</li>
+                <li>鍗囩骇log4j2鍒�2.17.1锛岄槻姝㈡紡娲為闄�</li>
+                <li>浼樺寲涓嬭浇瑙f瀽blob寮傚父鎻愮ず</li>
+                <li>浼樺寲浠g爜鐢熸垚瀛楀吀缁勯噸澶嶉棶棰�</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渚濊禆锛岄槻姝dk8浠ヤ笂鍑虹幇鐨勫吋瀹归敊璇�</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鍒版渶鏂扮増鏈瑅5.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>浠g爜鐢熸垚鐐瑰嚮棰勮閲嶇疆婵�娲籺ab</li>
+                <li>AjaxResult閲嶅啓put鏂规硶锛屼互鏂逛究閾惧紡璋冪敤</li>
+                <li>浼樺寲鐧诲綍/楠岃瘉鐮佽姹俬eaders涓嶈缃畉oken</li>
+                <li>浼樺寲鐢ㄦ埛涓汉淇℃伅鎺ュ彛闃叉淇敼鐢ㄦ埛鍚�</li>
+                <li>浼樺寲Cron琛ㄨ揪寮忕敓鎴愬櫒鍏抽棴鏃堕攢姣侀伩鍏嶇紦瀛�</li>
+                <li>浼樺寲娉ㄥ唽鎴愬姛鎻愮ず娑堟伅绫诲瀷success</li>
+                <li>浼樺寲aop璇硶锛屼娇鐢╯pring鑷姩娉ㄥ叆娉ㄨВ</li>
+                <li>浼樺寲璁板綍鐧诲綍淇℃伅锛岀Щ闄や笉蹇呰鐨勪慨鏀�</li>
+                <li>浼樺寲mybatis鍏ㄥ眬榛樿鐨勬墽琛屽櫒</li>
+                <li>浼樺寲Excel瀵煎叆鍥剧墖鍙兘鍑虹幇鐨勫紓甯�</li>
+                <li>淇浠g爜鐢熸垚妯℃澘涓诲瓙琛ㄥ垹闄ょ己灏戜簨鍔�</li>
+                <li>淇鏃ュ織璁板綍鍙兘鍑虹幇鐨勮浆鎹㈠紓甯�</li>
+                <li>淇浠g爜鐢熸垚澶嶉�夋瀛楀吀閬楁紡闂</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>鏀寔鑷畾涔夋敞瑙e疄鐜版帴鍙i檺娴�</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>浠g爜鐢熸垚涓诲瓙琛ㄥ閫夎鏁版嵁</li>
+                <li>鏃ユ湡鑼冨洿鏀寔娣诲姞澶氱粍</li>
+                <li>鍗囩骇element-ui鍒版渶鏂扮増鏈�2.15.5</li>
+                <li>鍗囩骇oshi鍒版渶鏂扮増鏈瑅5.8.0</li>
+                <li>鍗囩骇commons.io鍒版渶鏂扮増鏈瑅2.11.0</li>
+                <li>瀹氭椂浠诲姟灞忚斀ldap杩滅▼璋冪敤</li>
+                <li>瀹氭椂浠诲姟灞忚斀http(s)杩滅▼璋冪敤</li>
+                <li>琛ュ厖瀹氭椂浠诲姟琛ㄥ瓧娈垫敞閲�</li>
+                <li>瀹氭椂浠诲姟瀵规鏌ュ紓甯歌繘琛屼簨鍔″洖婊�</li>
+                <li>鍚敤鐖堕儴闂ㄧ姸鎬佹帓闄ら《绾ц妭鐐�</li>
+                <li>瀵屾枃鏈柊澧炰笂浼犳枃浠跺ぇ灏忛檺鍒�</li>
+                <li>榛樿棣栭〉浣跨敤keep-alive缂撳瓨</li>
+                <li>淇敼浠g爜鐢熸垚瀛楀吀鍥炴樉鏍峰紡</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>浼樺寲浠g爜鐢熸垚妯℃澘</li>
+                <li>楠岃瘉鐮侀粯璁�20s瓒呮椂</li>
+                <li>BLOB涓嬭浇鏃舵竻闄RL瀵硅薄寮曠敤</li>
+                <li>浠g爜鐢熸垚瀵煎叆琛ㄦ寜鍒涘缓鏃堕棿鎺掑簭</li>
+                <li>淇浠g爜鐢熸垚椤甸潰鏁版嵁缂栬緫淇濆瓨涔嬪悗鎬绘槸璺宠浆绗竴椤电殑闂</li>
+                <li>淇甯afari娴忚鍣ㄦ棤娉曟牸寮忓寲utc鏃ユ湡鏍煎紡yyyy-MM-dd'T'HH:mm:ss.SSS闂</li>
+                <li>澶氬浘涓婁紶缁勪欢绉婚櫎澶氫綑鐨刟pi鍦板潃&楠岃瘉澶辫触瀵艰嚧鍥剧墖鍒犻櫎闂&鏃犳硶鍒犻櫎鐩稿簲鍥剧墖淇</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>瀵屾枃鏈粯璁や笂浼犺繑鍥瀠rl绫诲瀷</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鍒版渶鏂扮増鏈瑅5.7.4</li>
+                <li>鍗囩骇element-ui鍒版渶鏂扮増鏈�2.15.2</li>
+                <li>鍗囩骇pagehelper鍒版渶鏂扮増1.3.1</li>
+                <li>鍗囩骇commons.io鍒版渶鏂扮増鏈瑅2.10.0</li>
+                <li>鍗囩骇commons.fileupload鍒版渶鏂扮増鏈瑅1.4</li>
+                <li>鍗囩骇swagger鍒版渶鏂扮増鏈瑅3.0.0</li>
+                <li>淇鍏抽棴confirm鎻愮ず妗嗘帶鍒跺彴鎶ラ敊闂</li>
+                <li>淇瀛樺湪鐨凷QL娉ㄥ叆婕忔礊闂</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锛坒alse涓哄乏渚у鑸彍鍗曪紝true涓洪《閮ㄥ鑸彍鍗曪級</li>
+                <li>甯冨眬璁剧疆鏀寔淇濆瓨&閲嶇疆閰嶇疆</li>
+                <li>淇鏍戣〃鏁版嵁鏄剧ず涓嶅叏&鍔犺浇鎱㈤棶棰�</li>
+                <li>鏂板IE娴忚鍣ㄧ増鏈繃浣庢彁绀洪〉闈�</li>
+                <li>鐢ㄦ埛鐧诲綍鍚庤褰曟渶鍚庣櫥褰旾P&鏃堕棿</li>
+                <li>椤甸潰瀵煎嚭鎸夐挳鐐瑰嚮涔嬪悗娣诲姞閬僵</li>
+                <li>瀵屾枃鏈紪杈戝櫒鏀寔鑷畾涔変笂浼犲湴鍧�</li>
+                <li>瀵屾枃鏈紪杈戠粍浠舵柊澧瀝eadOnly灞炴��</li>
+                <li>椤电TagsView鏂板鍏抽棴鍙充晶鍔熻兘</li>
+                <li>鏄鹃殣鍒楃粍浠跺姞杞藉垵濮嬮粯璁ら殣钘忓垪</li>
+                <li>鍏抽棴澶村儚涓婁紶绐楀彛杩樺師榛樿鍥剧墖</li>
+                <li>涓汉淇℃伅娣诲姞鎵嬫満&閭閲嶅楠岃瘉</li>
+                <li>浠g爜鐢熸垚妯℃澘瀵煎嚭鎸夐挳鐐瑰嚮鍚庢坊鍔犻伄缃�</li>
+                <li>浠g爜鐢熸垚妯℃澘鏍戣〃鎿嶄綔鍒楁坊鍔犳柊澧炴寜閽�</li>
+                <li>浠g爜鐢熸垚妯℃澘淇涓诲瓙琛ㄥ瓧娈甸噸鍚嶉棶棰�</li>
+                <li>鍗囩骇fastjson鍒版渶鏂扮増1.2.76</li>
+                <li>鍗囩骇druid鍒版渶鏂扮増鏈瑅1.2.6</li>
+                <li>鍗囩骇mybatis鍒版渶鏂扮増3.5.6 闃绘杩滅▼浠g爜鎵ц婕忔礊</li>
+                <li>鍗囩骇oshi鍒版渶鏂扮増鏈瑅5.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>鏍戠骇缁撴瀯鏇存柊瀛愯妭鐐逛娇鐢╮eplaceFirst</li>
+                <li>浼樺寲ExcelUtil绌哄�煎鐞�</li>
+                <li>鏃ュ織璁板綍杩囨护BindingResult瀵硅薄锛岄槻姝㈠紓甯�</li>
+                <li>淇敼涓婚鍚巑ini绫诲瀷鎸夐挳鏃犳晥闂</li>
+                <li>浼樺寲閫氱敤涓嬭浇瀹屾垚鍚庡垹闄よ妭鐐�</li>
+                <li>閫氱敤Controller娣诲姞鍝嶅簲杩斿洖娑堟伅</li>
+                <li>鍏朵粬缁嗚妭浼樺寲</li>
+              </ol>
+            </el-collapse-item>
+            <el-collapse-item title="v3.4.0 - 2021-02-22">
+              <ol>
+                <li>浠g爜鐢熸垚妯℃澘鏀寔涓诲瓙琛�</li>
+                <li>琛ㄦ牸鍙充晶宸ュ叿鏍忕粍浠舵敮鎸佹樉闅愬垪</li>
+                <li>鍥剧墖缁勪欢娣诲姞棰勮&绉婚櫎鍔熻兘</li>
+                <li>Excel娉ㄨВ鏀寔Image鍥剧墖瀵煎嚭</li>
+                <li>鎿嶄綔鎸夐挳缁勮皟鏁翠负鏈寸礌鎸夐挳鏍峰紡</li>
+                <li>浠g爜鐢熸垚鏀寔鏂囦欢涓婁紶缁勪欢</li>
+                <li>浠g爜鐢熸垚鏃ユ湡鎺т欢鍖哄垎鑼冨洿</li>
+                <li>浠g爜鐢熸垚鏁版嵁搴撴枃鏈被鍨嬬敓鎴愯〃鍗曟枃鏈煙</li>
+                <li>鐢ㄦ埛鎵嬫満閭&鑿滃崟缁勪欢淇敼鍏佽绌哄瓧绗︿覆</li>
+                <li>鍗囩骇SpringBoot鍒版渶鏂扮増鏈�2.2.13 鎻愬崌鍚姩閫熷害</li>
+                <li>鍗囩骇druid鍒版渶鏂扮増鏈瑅1.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>鏉冮檺宸ュ叿绫诲鍔燼dmin鍒ゆ柇</li>
+                <li>瑙掕壊闈炶嚜瀹氫箟鏉冮檺鑼冨洿娓呯┖閫夋嫨鍊�</li>
+                <li>淇瀵煎叆鏁版嵁涓鸿礋娴偣鏁版椂涓㈠け绮惧害闂</li>
+                <li>绉婚櫎path-to-regexp姝e垯鍖归厤鎻掍欢</li>
+                <li>淇鐢熸垚鏍戣〃浠g爜寮傚父</li>
+                <li>淇敼ip瀛楁闀垮害闃叉ipv6鍦板潃闀垮害涓嶅</li>
+                <li>闃叉get璇锋眰鍙傛暟鍊间负false鎴�0绛夌壒娈婂�间細瀵艰嚧鏃犳硶姝g‘鐨勪紶鍙�</li>
+                <li>鐧诲綍鍚巔ush娣诲姞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>浠g爜鐢熸垚棰勮鏀寔楂樹寒鏄剧ず</li>
+                <li>鏀寔Get璇锋眰鏄犲皠Params鍙傛暟</li>
+                <li>鍒犻櫎鐢ㄦ埛鍜岃鑹茶В缁戝叧鑱�</li>
+                <li>鍘婚櫎鐢ㄦ埛鎵嬫満閭閮ㄩ棬蹇呭~楠岃瘉</li>
+                <li>Excel鏀寔娉ㄨВalign瀵归綈鏂瑰紡</li>
+                <li>Excel鏀寔瀵煎叆Boolean鍨嬫暟鎹�</li>
+                <li>浼樺寲澶村儚鏍峰紡锛岄紶鏍囩Щ鍏ユ偓鍋滈伄缃�</li>
+                <li>浠g爜鐢熸垚棰勮鎻愪緵婊氬姩鏈哄埗</li>
+                <li>浠g爜鐢熸垚鍒犻櫎澶氫綑鐨勬暟瀛梖loat绫诲瀷</li>
+                <li>淇杞崲瀛楃涓茬殑鐩爣瀛楃闆嗗睘鎬�</li>
+                <li>鍥炴樉鏁版嵁瀛楀吀闃叉绌哄�兼姤閿�</li>
+                <li>鏃ュ織璁板綍澧炲姞杩囨护澶氭枃浠跺満鏅�</li>
+                <li>淇敼缂撳瓨Set鏂规硶鍙兘瀵艰嚧宓屽鐨勯棶棰�</li>
+                <li>绉婚櫎鍓嶇涓�浜涘浣欑殑渚濊禆</li>
+                <li>闃叉瀹夊叏鎵弿YUI鍑虹幇鐨勯闄╂彁绀�</li>
+                <li>淇敼node-sass涓篸art-sass</li>
+                <li>鍗囩骇SpringBoot鍒版渶鏂扮増鏈�2.1.18</li>
+                <li>鍗囩骇poi鍒版渶鏂扮増鏈�4.1.2</li>
+                <li>鍗囩骇oshi鍒版渶鏂扮増鏈瑅5.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>浠g爜鐢熸垚鏀寔涓婁紶鎺т欢</li>
+                <li>鏂板鍥剧墖涓婁紶缁勪欢</li>
+                <li>璋冩暣榛樿棣栭〉</li>
+                <li>鍗囩骇druid鍒版渶鏂扮増鏈瑅1.2.2</li>
+                <li>mapperLocations閰嶇疆鏀寔鍒嗛殧绗�</li>
+                <li>鏉冮檺淇℃伅璋冩暣</li>
+                <li>璋冩暣sql榛樿鏃堕棿</li>
+                <li>瑙e喅浠g爜鐢熸垚娌℃湁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鍒版渶鏂扮増鏈瑅5.2.5</li>
+                <li>鍗囩骇druid鍒版渶鏂扮増鏈瑅1.2.1</li>
+                <li>鍗囩骇jjwt鍒扮増鏈�0.9.1</li>
+                <li>鍗囩骇fastjson鍒版渶鏂扮増1.2.74</li>
+                <li>淇敼sass涓簄ode-sass锛岄伩鍏峞l-icon鍥炬爣涔辩爜</li>
+                <li>浠g爜鐢熸垚鏀寔鍚屾鏁版嵁搴�</li>
+                <li>浠g爜鐢熸垚鏀寔瀵屾枃鏈帶浠�</li>
+                <li>浠g爜鐢熸垚椤甸潰鏃朵笉蹇界暐remark灞炴��</li>
+                <li>浠g爜鐢熸垚娣诲姞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>浠g爜鐢熸垚鏀寔閫夋嫨涓婄骇鑿滃崟</li>
+                <li>浠g爜鐢熸垚鏀寔鑷畾涔夎矾寰�</li>
+                <li>浠g爜鐢熸垚鏀寔澶嶉�夋</li>
+                <li>Excel瀵煎嚭瀵煎叆鏀寔dictType瀛楀吀绫诲瀷</li>
+                <li>Excel鏀寔鍒嗗壊瀛楃涓茬粍鍐呭</li>
+                <li>楠岃瘉鐮佺被鍨嬫敮鎸侊紙鏁扮粍璁$畻銆佸瓧绗﹂獙璇侊級</li>
+                <li>鍗囩骇vue-cli鐗堟湰鍒�4.4.4</li>
+                <li>淇敼 node-sass 涓� dart-sass</li>
+                <li>琛ㄥ崟绫诲瀷涓篒nteger/Long璁剧疆鏁村舰榛樿鍊�</li>
+                <li>浠g爜鐢熸垚鍣ㄩ粯璁apper璺緞涓庨粯璁apperScan璺緞涓嶄竴鑷�</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>淇浠g爜鐢熸垚瀵煎叆琛ㄧ粨鏋勫嚭鐜板紓甯搁〉闈笉鎻愰啋闂</li>
+                <li>淇浠g爜鐢熸垚鐐瑰嚮澶氭琛ㄤ慨鏀规暟鎹笉鍙樺寲鐨勯棶棰�</li>
+                <li>淇澶村儚涓婁紶鎴愬姛浜屾鎵撳紑鏃犳硶鏀瑰彉瑁佸壀妗嗗ぇ灏忓拰浣嶇疆闂</li>
+                <li>淇甯冨眬涓簊mall鑰卪ini鐢ㄦ埛琛ㄥ崟鏄剧ず閿欎綅闂</li>
+                <li>淇鐑儴缃插鑷寸殑寮烘崲寮傚父闂</li>
+                <li>淇敼鐢ㄦ埛绠$悊澶嶉�夋瀹藉害锛岄槻姝㈤儴鍒嗘祻瑙堝櫒鍑虹幇鐪佺暐鍙�</li>
+                <li>IpUtils宸ュ叿锛屾竻闄ss鐗规畩瀛楃锛岄槻姝ff娉ㄥ叆鏀诲嚮</li>
+                <li>鐢熸垚domain 濡傛灉鏄诞鐐瑰瀷 缁熶竴鐢˙igDecimal</li>
+                <li>瀹氭椂浠诲姟璋冩暣label-width锛岄槻姝㈤儴缃插嚭鐜伴敊浣�</li>
+                <li>璋冩暣琛ㄥご鍥哄畾鍒楅粯璁ゆ牱寮�</li>
+                <li>浠g爜鐢熸垚妯℃澘璋冩暣锛屽瓧娈典负String骞朵笖蹇呭~鍒欏姞绌轰覆鏉′欢</li>
+                <li>浠g爜鐢熸垚瀛楀吀Integer/Long浣跨敤parseInt</li>
+                <li>
+                  淇dict_sort涓嶅彲update涓�0鐨勯棶棰�&鏌ヨ杩斿洖澧炲姞dict_sort鍗囧簭鎺掑簭
+                </li>
+                <li>淇宀椾綅瀵煎嚭鏉冮檺娉ㄨВ</li>
+                <li>绂佹鍔犲瘑瀵嗘枃杩斿洖鍓嶇</li>
+                <li>淇浠g爜鐢熸垚椤甸潰涓殑鏌ヨ鏉′欢鍒涘缓鏃堕棿鏈敓鏁堢殑闂</li>
+                <li>淇棣栭〉鎼滅储鑿滃崟澶栭摼鏃犳硶鐐瑰嚮璺宠浆闂</li>
+                <li>淇鑿滃崟绠$悊閫夋嫨鍥炬爣锛宐ackspace鍒犻櫎鏃朵笉杩囨护鏁版嵁</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>褰搕ags-view婊氬姩鍏抽棴鍙抽敭鑿滃崟</li>
+                <li>瀛楀吀绠$悊娣诲姞缂撳瓨璇诲彇</li>
+                <li>鍙傛暟绠$悊鏀寔缂撳瓨鎿嶄綔</li>
+                <li>鏀寔涓�绾ц彍鍗曪紙鍜屼富椤靛悓绾э級鍦╩ain鍖哄煙鏄剧ず</li>
+                <li>闄愬埗澶栭摼鍦板潃蹇呴』浠ttp(s)寮�澶�</li>
+                <li>tagview & sidebar 涓婚棰滆壊涓巈lement ui(鍏ㄥ眬)鍚屾</li>
+                <li>淇敼鏁版嵁婧愮被鍨嬩紭鍏堢骇锛屽厛鏍规嵁鏂规硶锛屽啀鏍规嵁绫�</li>
+                <li>鏀寔鏄惁闇�瑕佽缃畉oken灞炴�э紝鑷畾涔夎繑鍥炵爜娑堟伅銆�</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绫诲瀷璇锋眰鏋勫缓鍙噸澶嶈鍙杋nputStream鐨剅equest</li>
+                <li>淇敼浠g爜鐢熸垚瀛楀吀瀛楁int绫诲瀷娌℃湁鑷姩閫変腑闂</li>
+                <li>vuex鐢ㄦ埛鍚嶅彇鍊间慨姝�</li>
+                <li>琛ㄦ牸鏍戞ā鏉垮幓鎺夊浣欑殑)</li>
+                <li>浠g爜鐢熸垚搴忓彿淇</li>
+                <li>鍏ㄥ睆鎯呭喌涓嬩笉璋冩暣涓婂杈硅窛</li>
+                <li>浠g爜鐢熸垚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>淇浠g爜鐢熸垚濡傛灉閫夋嫨瀛楀吀绫诲瀷缂哄け閫楀彿闂</li>
+                <li>鐧诲綍璇锋眰params鏇存崲涓篸ata锛岄槻姝㈡毚闇瞮rl</li>
+                <li>鏃ュ織杩斿洖鏃堕棿鏍煎紡澶勭悊</li>
+                <li>娣诲姞handle鎺у埗鍏佽鎷栧姩鐨勫厓绱�</li>
+                <li>甯冨眬璁剧疆鐐瑰嚮鎵╁ぇ鑼冨洿</li>
+                <li>浠g爜鐢熸垚鍒楀睘鎬ф帓搴忔煡璇�</li>
+                <li>浠g爜鐢熸垚鍒楁敮鎸佹嫋鍔ㄦ帓搴�</li>
+                <li>淇鏃堕棿鏍煎紡涓嶆敮鎸乮os闂</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>娣诲姞涓�涓墦鍖匴eb宸ョ▼bat</li>
+                <li>淇椤电榧犳爣婊氳疆鎸変笅鐨勬椂鍊欙紝鍙互鍏抽棴涓嶅彲鍏抽棴鐨則ag</li>
+                <li>淇鐐瑰嚮閫�鍑虹櫥褰曟湁鏃朵細鏃犳彁绀洪棶棰�</li>
+                <li>淇闃查噸澶嶆彁浜ゆ敞瑙f棤鏁堥棶棰�</li>
+                <li>淇閫氱煡鍏憡鎵归噺鍒犻櫎寮傚父闂</li>
+                <li>娣诲姞鑿滃崟鏃惰矾鐢卞湴鍧�蹇呭~闄愬埗</li>
+                <li>浠g爜鐢熸垚瀛楁鎻忚堪鍙紪杈�</li>
+                <li>淇鐢ㄦ埛淇敼涓汉淇℃伅瀵艰嚧缂撳瓨涓嶈繃鏈熼棶棰�</li>
+                <li>涓汉淇℃伅鍒涘缓鏃堕棿鑾峰彇姝g‘灞炴�у��</li>
+                <li>鎿嶄綔鏃ュ織璇︾粏鏄剧ず姝g‘绫诲瀷</li>
+                <li>瀵煎叆琛ㄥ崟鍑昏鏁版嵁鏃堕�変腑瀵瑰簲鐨勫閫夋</li>
+                <li>鎵归噺鏇挎崲琛ㄥ墠缂�閫昏緫璋冩暣</li>
+                <li>鍥哄畾閲嶅畾鍚戣矾寰勮〃杈惧紡</li>
+                <li>鍗囩骇element-ui鐗堟湰鍒�2.13.0</li>
+                <li>鎿嶄綔鏃ュ織鎺掑簭璋冩暣</li>
+                <li>淇charts鍒囨崲渚ц竟鏍忔垨鑰呯缉鏀剧獥鍙f樉绀篵ug</li>
+                <li>鍏朵粬缁嗚妭浼樺寲</li>
+              </ol>
+            </el-collapse-item>
+
+            <el-collapse-item title="v2.1.0 - 2020-02-24">
+              <ol>
+                <li>鏂板琛ㄥ崟鏋勫缓</li>
+                <li>浠g爜鐢熸垚鏀寔鏍戣〃缁撴瀯</li>
+                <li>鏂板鐢ㄦ埛瀵煎叆</li>
+                <li>淇鍔ㄦ�佸姞杞借矾鐢遍〉闈㈠埛鏂伴棶棰�</li>
+                <li>淇鍦板潃寮�鍏虫棤鏁堥棶棰�</li>
+                <li>姹夊寲閿欒鎻愮ず椤甸潰</li>
+                <li>浠g爜鐢熸垚宸茬煡闂淇敼</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鍜孍ditor涓嶆樉绀哄鐞�</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>鏂板浠g爜鐢熸垚</li>
+                <li>鏂板@RepeatSubmit娉ㄨВ锛岄槻姝㈤噸澶嶆彁浜�</li>
+                <li>鏂板鑿滃崟涓荤洰褰曟坊鍔�/鍒犻櫎鎿嶄綔</li>
+                <li>鏃ュ織璁板綍杩囨护鐗规畩瀵硅薄锛岄槻姝㈣浆鎹㈠紓甯�</li>
+                <li>淇敼浠g爜鐢熸垚璺敱鑴氭湰閿欒</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/index_v1.vue b/ruoyi-ui/src/views/index_v1.vue
new file mode 100644
index 0000000..d2d2ec6
--- /dev/null
+++ b/ruoyi-ui/src/views/index_v1.vue
@@ -0,0 +1,98 @@
+<template>
+  <div class="dashboard-editor-container">
+
+    <panel-group @handleSetLineChartData="handleSetLineChartData" />
+
+    <el-row style="background:#fff;padding:16px 16px 0;margin-bottom:32px;">
+      <line-chart :chart-data="lineChartData" />
+    </el-row>
+
+    <el-row :gutter="32">
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <raddar-chart />
+        </div>
+      </el-col>
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <pie-chart />
+        </div>
+      </el-col>
+      <el-col :xs="24" :sm="24" :lg="8">
+        <div class="chart-wrapper">
+          <bar-chart />
+        </div>
+      </el-col>
+    </el-row>
+
+    
+  </div>
+</template>
+
+<script>
+import PanelGroup from './dashboard/PanelGroup'
+import LineChart from './dashboard/LineChart'
+import RaddarChart from './dashboard/RaddarChart'
+import PieChart from './dashboard/PieChart'
+import BarChart from './dashboard/BarChart'
+
+const lineChartData = {
+  newVisitis: {
+    expectedData: [100, 120, 161, 134, 105, 160, 165],
+    actualData: [120, 82, 91, 154, 162, 140, 145]
+  },
+  messages: {
+    expectedData: [200, 192, 120, 144, 160, 130, 140],
+    actualData: [180, 160, 151, 106, 145, 150, 130]
+  },
+  purchases: {
+    expectedData: [80, 100, 121, 104, 105, 90, 100],
+    actualData: [120, 90, 100, 138, 142, 130, 130]
+  },
+  shoppings: {
+    expectedData: [130, 140, 141, 142, 145, 150, 160],
+    actualData: [120, 82, 91, 154, 162, 140, 130]
+  }
+}
+
+export default {
+  name: 'Index',
+  components: {
+    PanelGroup,
+    LineChart,
+    RaddarChart,
+    PieChart,
+    BarChart
+  },
+  data() {
+    return {
+      lineChartData: lineChartData.newVisitis
+    }
+  },
+  methods: {
+    handleSetLineChartData(type) {
+      this.lineChartData = lineChartData[type]
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.dashboard-editor-container {
+  padding: 32px;
+  background-color: rgb(240, 242, 245);
+  position: relative;
+
+  .chart-wrapper {
+    background: #fff;
+    padding: 16px 16px 0;
+    margin-bottom: 32px;
+  }
+}
+
+@media (max-width:1024px) {
+  .chart-wrapper {
+    padding: 8px;
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/login.vue b/ruoyi-ui/src/views/login.vue
new file mode 100644
index 0000000..6e2d936
--- /dev/null
+++ b/ruoyi-ui/src/views/login.vue
@@ -0,0 +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>
diff --git a/ruoyi-ui/src/views/monitor/cache/index.vue b/ruoyi-ui/src/views/monitor/cache/index.vue
new file mode 100644
index 0000000..8d2f378
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/cache/index.vue
@@ -0,0 +1,148 @@
+<template>
+  <div class="app-container">
+    <el-row>
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header"><span><i class="el-icon-monitor"></i> 鍩烘湰淇℃伅</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%">
+              <tbody>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">Redis鐗堟湰</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_version }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">杩愯妯″紡</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.redis_mode == "standalone" ? "鍗曟満" : "闆嗙兢" }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">绔彛</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.tcp_port }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">瀹㈡埛绔暟</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.connected_clients }}</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">杩愯鏃堕棿(澶�)</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.uptime_in_days }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">浣跨敤鍐呭瓨</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.used_memory_human }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">浣跨敤CPU</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ parseFloat(cache.info.used_cpu_user_children).toFixed(2) }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">鍐呭瓨閰嶇疆</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.maxmemory_human }}</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">AOF鏄惁寮�鍚�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.aof_enabled == "0" ? "鍚�" : "鏄�" }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">RDB鏄惁鎴愬姛</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.rdb_last_bgsave_status }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Key鏁伴噺</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.dbSize">{{ cache.dbSize }} </div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">缃戠粶鍏ュ彛/鍑哄彛</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="cache.info">{{ cache.info.instantaneous_input_kbps }}kps/{{cache.info.instantaneous_output_kbps}}kps</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span><i class="el-icon-pie-chart"></i> 鍛戒护缁熻</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <div ref="commandstats" style="height: 420px" />
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span><i class="el-icon-odometer"></i> 鍐呭瓨淇℃伅</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <div ref="usedmemory" style="height: 420px" />
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { getCache } from "@/api/monitor/cache";
+import * as echarts from "echarts";
+
+export default {
+  name: "Cache",
+  data() {
+    return {
+      // 缁熻鍛戒护淇℃伅
+      commandstats: null,
+      // 浣跨敤鍐呭瓨
+      usedmemory: null,
+      // cache淇℃伅
+      cache: []
+    }
+  },
+  created() {
+    this.getList();
+    this.openLoading();
+  },
+  methods: {
+    /** 鏌ョ紦瀛樿淇℃伅 */
+    getList() {
+      getCache().then((response) => {
+        this.cache = response.data;
+        this.$modal.closeLoading();
+
+        this.commandstats = echarts.init(this.$refs.commandstats, "macarons");
+        this.commandstats.setOption({
+          tooltip: {
+            trigger: "item",
+            formatter: "{a} <br/>{b} : {c} ({d}%)",
+          },
+          series: [
+            {
+              name: "鍛戒护",
+              type: "pie",
+              roseType: "radius",
+              radius: [15, 95],
+              center: ["50%", "38%"],
+              data: response.data.commandStats,
+              animationEasing: "cubicInOut",
+              animationDuration: 1000,
+            }
+          ]
+        });
+        this.usedmemory = echarts.init(this.$refs.usedmemory, "macarons");
+        this.usedmemory.setOption({
+          tooltip: {
+            formatter: "{b} <br/>{a} : " + this.cache.info.used_memory_human,
+          },
+          series: [
+            {
+              name: "宄板��",
+              type: "gauge",
+              min: 0,
+              max: 1000,
+              detail: {
+                formatter: this.cache.info.used_memory_human,
+              },
+              data: [
+                {
+                  value: parseFloat(this.cache.info.used_memory_human),
+                  name: "鍐呭瓨娑堣��",
+                }
+              ]
+            }
+          ]
+        });
+        window.addEventListener("resize", () => {
+          this.commandstats.resize();
+          this.usedmemory.resize();
+        });
+      });
+    },
+    // 鎵撳紑鍔犺浇灞�
+    openLoading() {
+      this.$modal.loading("姝e湪鍔犺浇缂撳瓨鐩戞帶鏁版嵁锛岃绋嶅�欙紒");
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/cache/list.vue b/ruoyi-ui/src/views/monitor/cache/list.vue
new file mode 100644
index 0000000..29a7c74
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/cache/list.vue
@@ -0,0 +1,241 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="10">
+      <el-col :span="8">
+        <el-card style="height: calc(100vh - 125px)">
+          <div slot="header">
+            <span><i class="el-icon-collection"></i> 缂撳瓨鍒楄〃</span>
+            <el-button
+              style="float: right; padding: 3px 0"
+              type="text"
+              icon="el-icon-refresh-right"
+              @click="refreshCacheNames()"
+            ></el-button>
+          </div>
+          <el-table
+            v-loading="loading"
+            :data="cacheNames"
+            :height="tableHeight"
+            highlight-current-row
+            @row-click="getCacheKeys"
+            style="width: 100%"
+          >
+            <el-table-column
+              label="搴忓彿"
+              width="60"
+              type="index"
+            ></el-table-column>
+
+            <el-table-column
+              label="缂撳瓨鍚嶇О"
+              align="center"
+              prop="cacheName"
+              :show-overflow-tooltip="true"
+              :formatter="nameFormatter"
+            ></el-table-column>
+
+            <el-table-column
+              label="澶囨敞"
+              align="center"
+              prop="remark"
+              :show-overflow-tooltip="true"
+            />
+            <el-table-column
+              label="鎿嶄綔"
+              width="60"
+              align="center"
+              class-name="small-padding fixed-width"
+            >
+              <template slot-scope="scope">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-delete"
+                  @click="handleClearCacheName(scope.row)"
+                ></el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+      </el-col>
+
+      <el-col :span="8">
+        <el-card style="height: calc(100vh - 125px)">
+          <div slot="header">
+            <span><i class="el-icon-key"></i> 閿悕鍒楄〃</span>
+            <el-button
+              style="float: right; padding: 3px 0"
+              type="text"
+              icon="el-icon-refresh-right"
+              @click="refreshCacheKeys()"
+            ></el-button>
+          </div>
+          <el-table
+            v-loading="subLoading"
+            :data="cacheKeys"
+            :height="tableHeight"
+            highlight-current-row
+            @row-click="handleCacheValue"
+            style="width: 100%"
+          >
+            <el-table-column
+              label="搴忓彿"
+              width="60"
+              type="index"
+            ></el-table-column>
+            <el-table-column
+              label="缂撳瓨閿悕"
+              align="center"
+              :show-overflow-tooltip="true"
+              :formatter="keyFormatter"
+            >
+            </el-table-column>
+            <el-table-column
+              label="鎿嶄綔"
+              width="60"
+              align="center"
+              class-name="small-padding fixed-width"
+            >
+              <template slot-scope="scope">
+                <el-button
+                  size="mini"
+                  type="text"
+                  icon="el-icon-delete"
+                  @click="handleClearCacheKey(scope.row)"
+                ></el-button>
+              </template>
+            </el-table-column>
+          </el-table>
+        </el-card>
+      </el-col>
+
+      <el-col :span="8">
+        <el-card :bordered="false" style="height: calc(100vh - 125px)">
+          <div slot="header">
+            <span><i class="el-icon-document"></i> 缂撳瓨鍐呭</span>
+            <el-button
+              style="float: right; padding: 3px 0"
+              type="text"
+              icon="el-icon-refresh-right"
+              @click="handleClearCacheAll()"
+              >娓呯悊鍏ㄩ儴</el-button
+            >
+          </div>
+          <el-form :model="cacheForm">
+            <el-row :gutter="32">
+              <el-col :offset="1" :span="22">
+                <el-form-item label="缂撳瓨鍚嶇О:" prop="cacheName">
+                  <el-input v-model="cacheForm.cacheName" :readOnly="true" />
+                </el-form-item>
+              </el-col>
+              <el-col :offset="1" :span="22">
+                <el-form-item label="缂撳瓨閿悕:" prop="cacheKey">
+                  <el-input v-model="cacheForm.cacheKey" :readOnly="true" />
+                </el-form-item>
+              </el-col>
+              <el-col :offset="1" :span="22">
+                <el-form-item label="缂撳瓨鍐呭:" prop="cacheValue">
+                  <el-input
+                    v-model="cacheForm.cacheValue"
+                    type="textarea"
+                    :rows="8"
+                    :readOnly="true"
+                  />
+                </el-form-item>
+              </el-col>
+            </el-row>
+          </el-form>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { listCacheName, listCacheKey, getCacheValue, clearCacheName, clearCacheKey, clearCacheAll } from "@/api/monitor/cache";
+
+export default {
+  name: "CacheList",
+  data() {
+    return {
+      cacheNames: [],
+      cacheKeys: [],
+      cacheForm: {},
+      loading: true,
+      subLoading: false,
+      nowCacheName: "",
+      tableHeight: window.innerHeight - 200
+    };
+  },
+  created() {
+    this.getCacheNames();
+  },
+  methods: {
+    /** 鏌ヨ缂撳瓨鍚嶇О鍒楄〃 */
+    getCacheNames() {
+      this.loading = true;
+      listCacheName().then(response => {
+        this.cacheNames = response.data;
+        this.loading = false;
+      });
+    },
+    /** 鍒锋柊缂撳瓨鍚嶇О鍒楄〃 */
+    refreshCacheNames() {
+      this.getCacheNames();
+      this.$modal.msgSuccess("鍒锋柊缂撳瓨鍒楄〃鎴愬姛");
+    },
+    /** 娓呯悊鎸囧畾鍚嶇О缂撳瓨 */
+    handleClearCacheName(row) {
+      clearCacheName(row.cacheName).then(response => {
+        this.$modal.msgSuccess("娓呯悊缂撳瓨鍚嶇О[" + row.cacheName + "]鎴愬姛");
+        this.getCacheKeys();
+      });
+    },
+    /** 鏌ヨ缂撳瓨閿悕鍒楄〃 */
+    getCacheKeys(row) {
+      const cacheName = row !== undefined ? row.cacheName : this.nowCacheName;
+      if (cacheName === "") {
+        return;
+      }
+      this.subLoading = true;
+      listCacheKey(cacheName).then(response => {
+        this.cacheKeys = response.data;
+        this.subLoading = false;
+        this.nowCacheName = cacheName;
+      });
+    },
+    /** 鍒锋柊缂撳瓨閿悕鍒楄〃 */
+    refreshCacheKeys() {
+      this.getCacheKeys();
+      this.$modal.msgSuccess("鍒锋柊閿悕鍒楄〃鎴愬姛");
+    },
+    /** 娓呯悊鎸囧畾閿悕缂撳瓨 */
+    handleClearCacheKey(cacheKey) {
+      clearCacheKey(cacheKey).then(response => {
+        this.$modal.msgSuccess("娓呯悊缂撳瓨閿悕[" + cacheKey + "]鎴愬姛");
+        this.getCacheKeys();
+      });
+    },
+    /** 鍒楄〃鍓嶇紑鍘婚櫎 */
+    nameFormatter(row) {
+      return row.cacheName.replace(":", "");
+    },
+    /** 閿悕鍓嶇紑鍘婚櫎 */
+    keyFormatter(cacheKey) {
+      return cacheKey.replace(this.nowCacheName, "");
+    },
+    /** 鏌ヨ缂撳瓨鍐呭璇︾粏 */
+    handleCacheValue(cacheKey) {
+      getCacheValue(this.nowCacheName, cacheKey).then(response => {
+        this.cacheForm = response.data;
+      });
+    },
+    /** 娓呯悊鍏ㄩ儴缂撳瓨 */
+    handleClearCacheAll() {
+      clearCacheAll().then(response => {
+        this.$modal.msgSuccess("娓呯悊鍏ㄩ儴缂撳瓨鎴愬姛");
+      });
+    }
+  },
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/druid/index.vue b/ruoyi-ui/src/views/monitor/druid/index.vue
new file mode 100644
index 0000000..c6ad585
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/druid/index.vue
@@ -0,0 +1,15 @@
+<template>
+  <i-frame :src="url" />
+</template>
+<script>
+import iFrame from "@/components/iFrame/index";
+export default {
+  name: "Druid",
+  components: { iFrame },
+  data() {
+    return {
+      url: process.env.VUE_APP_BASE_API + "/druid/login.html"
+    };
+  },
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/job/index.vue b/ruoyi-ui/src/views/monitor/job/index.vue
new file mode 100644
index 0000000..892c727
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/job/index.vue
@@ -0,0 +1,513 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="浠诲姟鍚嶇О" prop="jobName">
+        <el-input
+          v-model="queryParams.jobName"
+          placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="浠诲姟缁勫悕" prop="jobGroup">
+        <el-select v-model="queryParams.jobGroup" placeholder="璇烽�夋嫨浠诲姟缁勫悕" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_job_group"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="浠诲姟鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="璇烽�夋嫨浠诲姟鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_job_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['monitor:job: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="['monitor:job: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="['monitor:job: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="['monitor:job:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-s-operation"
+          size="mini"
+          @click="handleJobLog"
+          v-hasPermi="['monitor:job:query']"
+        >鏃ュ織</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="jobList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="浠诲姟缂栧彿" width="100" align="center" prop="jobId" />
+      <el-table-column label="浠诲姟鍚嶇О" align="center" prop="jobName" :show-overflow-tooltip="true" />
+      <el-table-column label="浠诲姟缁勫悕" align="center" prop="jobGroup">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="璋冪敤鐩爣瀛楃涓�" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+      <el-table-column label="cron鎵ц琛ㄨ揪寮�" align="center" prop="cronExpression" :show-overflow-tooltip="true" />
+      <el-table-column label="鐘舵��" align="center">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            active-value="0"
+            inactive-value="1"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" 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="['monitor:job:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['monitor:job:remove']"
+          >鍒犻櫎</el-button>
+          <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['monitor:job:changeStatus', 'monitor:job:query']">
+            <el-button size="mini" type="text" icon="el-icon-d-arrow-right">鏇村</el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item command="handleRun" icon="el-icon-caret-right"
+                v-hasPermi="['monitor:job:changeStatus']">鎵ц涓�娆�</el-dropdown-item>
+              <el-dropdown-item command="handleView" icon="el-icon-view"
+                v-hasPermi="['monitor:job:query']">浠诲姟璇︾粏</el-dropdown-item>
+              <el-dropdown-item command="handleJobLog" icon="el-icon-s-operation"
+                v-hasPermi="['monitor:job:query']">璋冨害鏃ュ織</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰畾鏃朵换鍔″璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="120px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟鍚嶇О" prop="jobName">
+              <el-input v-model="form.jobName" placeholder="璇疯緭鍏ヤ换鍔″悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟鍒嗙粍" prop="jobGroup">
+              <el-select v-model="form.jobGroup" placeholder="璇烽�夋嫨浠诲姟鍒嗙粍">
+                <el-option
+                  v-for="dict in dict.type.sys_job_group"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item prop="invokeTarget">
+              <span slot="label">
+                璋冪敤鏂规硶
+                <el-tooltip placement="top">
+                  <div slot="content">
+                    Bean璋冪敤绀轰緥锛歳yTask.ryParams('ry')
+                    <br />Class绫昏皟鐢ㄧず渚嬶細com.ruoyi.quartz.task.RyTask.ryParams('ry')
+                    <br />鍙傛暟璇存槑锛氭敮鎸佸瓧绗︿覆锛屽竷灏旂被鍨嬶紝闀挎暣鍨嬶紝娴偣鍨嬶紝鏁村瀷
+                  </div>
+                  <i class="el-icon-question"></i>
+                </el-tooltip>
+              </span>
+              <el-input v-model="form.invokeTarget" placeholder="璇疯緭鍏ヨ皟鐢ㄧ洰鏍囧瓧绗︿覆" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="cron琛ㄨ揪寮�" prop="cronExpression">
+              <el-input v-model="form.cronExpression" placeholder="璇疯緭鍏ron鎵ц琛ㄨ揪寮�">
+                <template slot="append">
+                  <el-button type="primary" @click="handleShowCron">
+                    鐢熸垚琛ㄨ揪寮�
+                    <i class="el-icon-time el-icon--right"></i>
+                  </el-button>
+                </template>
+              </el-input>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24" v-if="form.jobId !== undefined">
+            <el-form-item label="鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in dict.type.sys_job_status"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎵ц绛栫暐" prop="misfirePolicy">
+              <el-radio-group v-model="form.misfirePolicy" size="small">
+                <el-radio-button label="1">绔嬪嵆鎵ц</el-radio-button>
+                <el-radio-button label="2">鎵ц涓�娆�</el-radio-button>
+                <el-radio-button label="3">鏀惧純鎵ц</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄惁骞跺彂" prop="concurrent">
+              <el-radio-group v-model="form.concurrent" size="small">
+                <el-radio-button label="0">鍏佽</el-radio-button>
+                <el-radio-button label="1">绂佹</el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <el-dialog title="Cron琛ㄨ揪寮忕敓鎴愬櫒" :visible.sync="openCron" append-to-body destroy-on-close class="scrollbar">
+      <crontab @hide="openCron=false" @fill="crontabFill" :expression="expression"></crontab>
+    </el-dialog>
+
+    <!-- 浠诲姟鏃ュ織璇︾粏 -->
+    <el-dialog title="浠诲姟璇︾粏" :visible.sync="openView" width="700px" append-to-body>
+      <el-form ref="form" :model="form" label-width="120px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟缂栧彿锛�">{{ form.jobId }}</el-form-item>
+            <el-form-item label="浠诲姟鍚嶇О锛�">{{ form.jobName }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟鍒嗙粍锛�">{{ jobGroupFormat(form) }}</el-form-item>
+            <el-form-item label="鍒涘缓鏃堕棿锛�">{{ form.createTime }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="cron琛ㄨ揪寮忥細">{{ form.cronExpression }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="涓嬫鎵ц鏃堕棿锛�">{{ parseTime(form.nextValidTime) }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="璋冪敤鐩爣鏂规硶锛�">{{ form.invokeTarget }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟鐘舵�侊細">
+              <div v-if="form.status == 0">姝e父</div>
+              <div v-else-if="form.status == 1">鏆傚仠</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄惁骞跺彂锛�">
+              <div v-if="form.concurrent == 0">鍏佽</div>
+              <div v-else-if="form.concurrent == 1">绂佹</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鎵ц绛栫暐锛�">
+              <div v-if="form.misfirePolicy == 0">榛樿绛栫暐</div>
+              <div v-else-if="form.misfirePolicy == 1">绔嬪嵆鎵ц</div>
+              <div v-else-if="form.misfirePolicy == 2">鎵ц涓�娆�</div>
+              <div v-else-if="form.misfirePolicy == 3">鏀惧純鎵ц</div>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="openView = false">鍏� 闂�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listJob, getJob, delJob, addJob, updateJob, runJob, changeJobStatus } from "@/api/monitor/job";
+import Crontab from '@/components/Crontab'
+
+export default {
+  components: { Crontab },
+  name: "Job",
+  dicts: ['sys_job_group', 'sys_job_status'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瀹氭椂浠诲姟琛ㄦ牸鏁版嵁
+      jobList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁鏄剧ず璇︾粏寮瑰嚭灞�
+      openView: false,
+      // 鏄惁鏄剧ずCron琛ㄨ揪寮忓脊鍑哄眰
+      openCron: false,
+      // 浼犲叆鐨勮〃杈惧紡
+      expression: "",
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jobName: undefined,
+        jobGroup: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        jobName: [
+          { required: true, message: "浠诲姟鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        invokeTarget: [
+          { required: true, message: "璋冪敤鐩爣瀛楃涓蹭笉鑳戒负绌�", trigger: "blur" }
+        ],
+        cronExpression: [
+          { required: true, message: "cron鎵ц琛ㄨ揪寮忎笉鑳戒负绌�", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ瀹氭椂浠诲姟鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listJob(this.queryParams).then(response => {
+        this.jobList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 浠诲姟缁勫悕瀛楀吀缈昏瘧
+    jobGroupFormat(row, column) {
+      return this.selectDictLabel(this.dict.type.sys_job_group, row.jobGroup);
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        jobId: undefined,
+        jobName: undefined,
+        jobGroup: undefined,
+        invokeTarget: undefined,
+        cronExpression: undefined,
+        misfirePolicy: 1,
+        concurrent: 1,
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.jobId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    // 鏇村鎿嶄綔瑙﹀彂
+    handleCommand(command, row) {
+      switch (command) {
+        case "handleRun":
+          this.handleRun(row);
+          break;
+        case "handleView":
+          this.handleView(row);
+          break;
+        case "handleJobLog":
+          this.handleJobLog(row);
+          break;
+        default:
+          break;
+      }
+    },
+    // 浠诲姟鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal.confirm('纭瑕�"' + text + '""' + row.jobName + '"浠诲姟鍚楋紵').then(function() {
+        return changeJobStatus(row.jobId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "鎴愬姛");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
+    },
+    /* 绔嬪嵆鎵ц涓�娆� */
+    handleRun(row) {
+      this.$modal.confirm('纭瑕佺珛鍗虫墽琛屼竴娆�"' + row.jobName + '"浠诲姟鍚楋紵').then(function() {
+        return runJob(row.jobId, row.jobGroup);
+      }).then(() => {
+        this.$modal.msgSuccess("鎵ц鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 浠诲姟璇︾粏淇℃伅 */
+    handleView(row) {
+      getJob(row.jobId).then(response => {
+        this.form = response.data;
+        this.openView = true;
+      });
+    },
+    /** cron琛ㄨ揪寮忔寜閽搷浣� */
+    handleShowCron() {
+      this.expression = this.form.cronExpression;
+      this.openCron = true;
+    },
+    /** 纭畾鍚庡洖浼犲�� */
+    crontabFill(value) {
+      this.form.cronExpression = value;
+    },
+    /** 浠诲姟鏃ュ織鍒楄〃鏌ヨ */
+    handleJobLog(row) {
+      const jobId = row.jobId || 0;
+      this.$router.push('/monitor/job-log/index/' + jobId)
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞浠诲姟";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const jobId = row.jobId || this.ids;
+      getJob(jobId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼浠诲姟";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.jobId != undefined) {
+            updateJob(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addJob(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const jobIds = row.jobId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎瀹氭椂浠诲姟缂栧彿涓�"' + jobIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delJob(jobIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('monitor/job/export', {
+        ...this.queryParams
+      }, `job_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/job/log.vue b/ruoyi-ui/src/views/monitor/job/log.vue
new file mode 100644
index 0000000..60bee1d
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/job/log.vue
@@ -0,0 +1,295 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="浠诲姟鍚嶇О" prop="jobName">
+        <el-input
+          v-model="queryParams.jobName"
+          placeholder="璇疯緭鍏ヤ换鍔″悕绉�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="浠诲姟缁勫悕" prop="jobGroup">
+        <el-select
+          v-model="queryParams.jobGroup"
+          placeholder="璇烽�夋嫨浠诲姟缁勫悕"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_job_group"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎵ц鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="璇烽�夋嫨鎵ц鐘舵��"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎵ц鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['monitor:job:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+          v-hasPermi="['monitor:job: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="['monitor:job:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-close"
+          size="mini"
+          @click="handleClose"
+        >鍏抽棴</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="jobLogList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="鏃ュ織缂栧彿" width="80" align="center" prop="jobLogId" />
+      <el-table-column label="浠诲姟鍚嶇О" align="center" prop="jobName" :show-overflow-tooltip="true" />
+      <el-table-column label="浠诲姟缁勫悕" align="center" prop="jobGroup" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_job_group" :value="scope.row.jobGroup"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="璋冪敤鐩爣瀛楃涓�" align="center" prop="invokeTarget" :show-overflow-tooltip="true" />
+      <el-table-column label="鏃ュ織淇℃伅" align="center" prop="jobMessage" :show-overflow-tooltip="true" />
+      <el-table-column label="鎵ц鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎵ц鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row)"
+            v-hasPermi="['monitor:job:query']"
+          >璇︾粏</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 璋冨害鏃ュ織璇︾粏 -->
+    <el-dialog title="璋冨害鏃ュ織璇︾粏" :visible.sync="open" width="700px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鏃ュ織搴忓彿锛�">{{ form.jobLogId }}</el-form-item>
+            <el-form-item label="浠诲姟鍚嶇О锛�">{{ form.jobName }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="浠诲姟鍒嗙粍锛�">{{ form.jobGroup }}</el-form-item>
+            <el-form-item label="鎵ц鏃堕棿锛�">{{ form.createTime }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="璋冪敤鏂规硶锛�">{{ form.invokeTarget }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鏃ュ織淇℃伅锛�">{{ form.jobMessage }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鎵ц鐘舵�侊細">
+              <div v-if="form.status == 0">姝e父</div>
+              <div v-else-if="form.status == 1">澶辫触</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="寮傚父淇℃伅锛�" v-if="form.status == 1">{{ form.exceptionInfo }}</el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="open = false">鍏� 闂�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { getJob} from "@/api/monitor/job";
+import { listJobLog, delJobLog, cleanJobLog } from "@/api/monitor/jobLog";
+
+export default {
+  name: "JobLog",
+  dicts: ['sys_common_status', 'sys_job_group'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 璋冨害鏃ュ織琛ㄦ牸鏁版嵁
+      jobLogList: [],
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        jobName: undefined,
+        jobGroup: undefined,
+        status: undefined
+      }
+    };
+  },
+  created() {
+    const jobId = this.$route.params && this.$route.params.jobId;
+    if (jobId !== undefined && jobId != 0) {
+      getJob(jobId).then(response => {
+        this.queryParams.jobName = response.data.jobName;
+        this.queryParams.jobGroup = response.data.jobGroup;
+        this.getList();
+      });
+    } else {
+      this.getList();
+    }
+  },
+  methods: {
+    /** 鏌ヨ璋冨害鏃ュ織鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listJobLog(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.jobLogList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 杩斿洖鎸夐挳
+    handleClose() {
+      const obj = { path: "/monitor/job" };
+      this.$tab.closeOpenPage(obj);
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.jobLogId);
+      this.multiple = !selection.length;
+    },
+    /** 璇︾粏鎸夐挳鎿嶄綔 */
+    handleView(row) {
+      this.open = true;
+      this.form = row;
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const jobLogIds = this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎璋冨害鏃ュ織缂栧彿涓�"' + jobLogIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delJobLog(jobLogIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 娓呯┖鎸夐挳鎿嶄綔 */
+    handleClean() {
+      this.$modal.confirm('鏄惁纭娓呯┖鎵�鏈夎皟搴︽棩蹇楁暟鎹」锛�').then(function() {
+        return cleanJobLog();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("娓呯┖鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('/monitor/jobLog/export', {
+        ...this.queryParams
+      }, `log_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/monitor/logininfor/index.vue b/ruoyi-ui/src/views/monitor/logininfor/index.vue
new file mode 100644
index 0000000..d6af834
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/logininfor/index.vue
@@ -0,0 +1,246 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鐧诲綍鍦板潃" prop="ipaddr">
+        <el-input
+          v-model="queryParams.ipaddr"
+          placeholder="璇疯緭鍏ョ櫥褰曞湴鍧�"
+          clearable
+          style="width: 240px;"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+          clearable
+          style="width: 240px;"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="鐧诲綍鐘舵��"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鐧诲綍鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          :default-time="['00:00:00', '23:59:59']"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['monitor:logininfor:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+          v-hasPermi="['monitor:logininfor:remove']"
+        >娓呯┖</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-unlock"
+          size="mini"
+          :disabled="single"
+          @click="handleUnlock"
+          v-hasPermi="['monitor:logininfor:unlock']"
+        >瑙i攣</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-download"
+          size="mini"
+          @click="handleExport"
+          v-hasPermi="['monitor:logininfor:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="璁块棶缂栧彿" align="center" prop="infoId" />
+      <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" prop="userName" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
+      <el-table-column label="鐧诲綍鍦板潃" align="center" prop="ipaddr" width="130" :show-overflow-tooltip="true" />
+      <el-table-column label="鐧诲綍鍦扮偣" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
+      <el-table-column label="娴忚鍣�" align="center" prop="browser" :show-overflow-tooltip="true" />
+      <el-table-column label="鎿嶄綔绯荤粺" align="center" prop="os" />
+      <el-table-column label="鐧诲綍鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔淇℃伅" align="center" prop="msg" :show-overflow-tooltip="true" />
+      <el-table-column label="鐧诲綍鏃ユ湡" align="center" prop="loginTime" sortable="custom" :sort-orders="['descending', 'ascending']" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.loginTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+  </div>
+</template>
+
+<script>
+import { list, delLogininfor, cleanLogininfor, unlockLogininfor } from "@/api/monitor/logininfor";
+
+export default {
+  name: "Logininfor",
+  dicts: ['sys_common_status'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 閫夋嫨鐢ㄦ埛鍚�
+      selectName: "",
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ牸鏁版嵁
+      list: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 榛樿鎺掑簭
+      defaultSort: {prop: 'loginTime', order: 'descending'},
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        ipaddr: undefined,
+        userName: undefined,
+        status: undefined
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鐧诲綍鏃ュ織鍒楄〃 */
+    getList() {
+      this.loading = true;
+      list(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.list = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.queryParams.pageNum = 1;
+      this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
+    },
+    /** 澶氶�夋閫変腑鏁版嵁 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.infoId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+      this.selectName = selection.map(item => item.userName);
+    },
+    /** 鎺掑簭瑙﹀彂浜嬩欢 */
+    handleSortChange(column, prop, order) {
+      this.queryParams.orderByColumn = column.prop;
+      this.queryParams.isAsc = column.order;
+      this.getList();
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const infoIds = row.infoId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎璁块棶缂栧彿涓�"' + infoIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delLogininfor(infoIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 娓呯┖鎸夐挳鎿嶄綔 */
+    handleClean() {
+      this.$modal.confirm('鏄惁纭娓呯┖鎵�鏈夌櫥褰曟棩蹇楁暟鎹」锛�').then(function() {
+        return cleanLogininfor();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("娓呯┖鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瑙i攣鎸夐挳鎿嶄綔 */
+    handleUnlock() {
+      const username = this.selectName;
+      this.$modal.confirm('鏄惁纭瑙i攣鐢ㄦ埛"' + username + '"鏁版嵁椤�?').then(function() {
+        return unlockLogininfor(username);
+      }).then(() => {
+        this.$modal.msgSuccess("鐢ㄦ埛" + username + "瑙i攣鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('monitor/logininfor/export', {
+        ...this.queryParams
+      }, `logininfor_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
diff --git a/ruoyi-ui/src/views/monitor/online/index.vue b/ruoyi-ui/src/views/monitor/online/index.vue
new file mode 100644
index 0000000..ad613c9
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/online/index.vue
@@ -0,0 +1,122 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" label-width="68px">
+      <el-form-item label="鐧诲綍鍦板潃" prop="ipaddr">
+        <el-input
+          v-model="queryParams.ipaddr"
+          placeholder="璇疯緭鍏ョ櫥褰曞湴鍧�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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-table
+      v-loading="loading"
+      :data="list.slice((pageNum-1)*pageSize,pageNum*pageSize)"
+      style="width: 100%;"
+    >
+      <el-table-column label="搴忓彿" type="index" align="center">
+        <template slot-scope="scope">
+          <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="浼氳瘽缂栧彿" align="center" prop="tokenId" :show-overflow-tooltip="true" />
+      <el-table-column label="鐧诲綍鍚嶇О" align="center" prop="userName" :show-overflow-tooltip="true" />
+      <el-table-column label="閮ㄩ棬鍚嶇О" align="center" prop="deptName" />
+      <el-table-column label="涓绘満" align="center" prop="ipaddr" :show-overflow-tooltip="true" />
+      <el-table-column label="鐧诲綍鍦扮偣" align="center" prop="loginLocation" :show-overflow-tooltip="true" />
+      <el-table-column label="娴忚鍣�" align="center" prop="browser" />
+      <el-table-column label="鎿嶄綔绯荤粺" align="center" prop="os" />
+      <el-table-column label="鐧诲綍鏃堕棿" align="center" prop="loginTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.loginTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleForceLogout(scope.row)"
+            v-hasPermi="['monitor:online:forceLogout']"
+          >寮洪��</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
+  </div>
+</template>
+
+<script>
+import { list, forceLogout } from "@/api/monitor/online";
+
+export default {
+  name: "Online",
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ牸鏁版嵁
+      list: [],
+      pageNum: 1,
+      pageSize: 10,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        ipaddr: undefined,
+        userName: undefined
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鐧诲綍鏃ュ織鍒楄〃 */
+    getList() {
+      this.loading = true;
+      list(this.queryParams).then(response => {
+        this.list = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 寮洪��鎸夐挳鎿嶄綔 */
+    handleForceLogout(row) {
+      this.$modal.confirm('鏄惁纭寮洪��鍚嶇О涓�"' + row.userName + '"鐨勭敤鎴凤紵').then(function() {
+        return forceLogout(row.tokenId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("寮洪��鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
+
diff --git a/ruoyi-ui/src/views/monitor/operlog/index.vue b/ruoyi-ui/src/views/monitor/operlog/index.vue
new file mode 100644
index 0000000..4a1828f
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/operlog/index.vue
@@ -0,0 +1,323 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鎿嶄綔鍦板潃" prop="operIp">
+        <el-input
+          v-model="queryParams.operIp"
+          placeholder="璇疯緭鍏ユ搷浣滃湴鍧�"
+          clearable
+          style="width: 240px;"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绯荤粺妯″潡" prop="title">
+        <el-input
+          v-model="queryParams.title"
+          placeholder="璇疯緭鍏ョ郴缁熸ā鍧�"
+          clearable
+          style="width: 240px;"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎿嶄綔浜哄憳" prop="operName">
+        <el-input
+          v-model="queryParams.operName"
+          placeholder="璇疯緭鍏ユ搷浣滀汉鍛�"
+          clearable
+          style="width: 240px;"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绫诲瀷" prop="businessType">
+        <el-select
+          v-model="queryParams.businessType"
+          placeholder="鎿嶄綔绫诲瀷"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_oper_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="鎿嶄綔鐘舵��"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_common_status"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鎿嶄綔鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd HH:mm:ss"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+          :default-time="['00:00:00', '23:59:59']"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          :disabled="multiple"
+          @click="handleDelete"
+          v-hasPermi="['monitor:operlog:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-delete"
+          size="mini"
+          @click="handleClean"
+          v-hasPermi="['monitor:operlog: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="['monitor:operlog:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table ref="tables" v-loading="loading" :data="list" @selection-change="handleSelectionChange" :default-sort="defaultSort" @sort-change="handleSortChange">
+      <el-table-column type="selection" width="50" align="center" />
+      <el-table-column label="鏃ュ織缂栧彿" align="center" prop="operId" />
+      <el-table-column label="绯荤粺妯″潡" align="center" prop="title" :show-overflow-tooltip="true" />
+      <el-table-column label="鎿嶄綔绫诲瀷" align="center" prop="businessType">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_oper_type" :value="scope.row.businessType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔浜哄憳" align="center" prop="operName" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']" />
+      <el-table-column label="鎿嶄綔鍦板潃" align="center" prop="operIp" width="130" :show-overflow-tooltip="true" />
+      <el-table-column label="鎿嶄綔鍦扮偣" align="center" prop="operLocation" :show-overflow-tooltip="true" />
+      <el-table-column label="鎿嶄綔鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_common_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔鏃ユ湡" align="center" prop="operTime" width="160" sortable="custom" :sort-orders="['descending', 'ascending']">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.operTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="娑堣�楁椂闂�" align="center" prop="costTime" width="110" :show-overflow-tooltip="true" sortable="custom" :sort-orders="['descending', 'ascending']">
+        <template slot-scope="scope">
+          <span>{{ scope.row.costTime }}姣</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-view"
+            @click="handleView(scope.row,scope.index)"
+            v-hasPermi="['monitor:operlog:query']"
+          >璇︾粏</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 鎿嶄綔鏃ュ織璇︾粏 -->
+    <el-dialog title="鎿嶄綔鏃ュ織璇︾粏" :visible.sync="open" width="800px" append-to-body>
+      <el-form ref="form" :model="form" label-width="100px" size="mini">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鎿嶄綔妯″潡锛�">{{ form.title }} / {{ typeFormat(form) }}</el-form-item>
+            <el-form-item
+              label="鐧诲綍淇℃伅锛�"
+            >{{ form.operName }} / {{ form.operIp }} / {{ form.operLocation }}</el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="璇锋眰鍦板潃锛�">{{ form.operUrl }}</el-form-item>
+            <el-form-item label="璇锋眰鏂瑰紡锛�">{{ form.requestMethod }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鎿嶄綔鏂规硶锛�">{{ form.method }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="璇锋眰鍙傛暟锛�">{{ form.operParam }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="杩斿洖鍙傛暟锛�">{{ form.jsonResult }}</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鎿嶄綔鐘舵�侊細">
+              <div v-if="form.status === 0">姝e父</div>
+              <div v-else-if="form.status === 1">澶辫触</div>
+            </el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="娑堣�楁椂闂达細">{{ form.costTime }}姣</el-form-item>
+          </el-col>
+          <el-col :span="8">
+            <el-form-item label="鎿嶄綔鏃堕棿锛�">{{ parseTime(form.operTime) }}</el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="寮傚父淇℃伅锛�" v-if="form.status === 1">{{ form.errorMsg }}</el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button @click="open = false">鍏� 闂�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { list, delOperlog, cleanOperlog } from "@/api/monitor/operlog";
+
+export default {
+  name: "Operlog",
+  dicts: ['sys_oper_type', 'sys_common_status'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ牸鏁版嵁
+      list: [],
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 榛樿鎺掑簭
+      defaultSort: {prop: 'operTime', order: 'descending'},
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        operIp: undefined,
+        title: undefined,
+        operName: undefined,
+        businessType: undefined,
+        status: undefined
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鐧诲綍鏃ュ織 */
+    getList() {
+      this.loading = true;
+      list(this.addDateRange(this.queryParams, this.dateRange)).then( response => {
+          this.list = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鎿嶄綔鏃ュ織绫诲瀷瀛楀吀缈昏瘧
+    typeFormat(row, column) {
+      return this.selectDictLabel(this.dict.type.sys_oper_type, row.businessType);
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.queryParams.pageNum = 1;
+      this.$refs.tables.sort(this.defaultSort.prop, this.defaultSort.order)
+    },
+    /** 澶氶�夋閫変腑鏁版嵁 */
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.operId)
+      this.multiple = !selection.length
+    },
+    /** 鎺掑簭瑙﹀彂浜嬩欢 */
+    handleSortChange(column, prop, order) {
+      this.queryParams.orderByColumn = column.prop;
+      this.queryParams.isAsc = column.order;
+      this.getList();
+    },
+    /** 璇︾粏鎸夐挳鎿嶄綔 */
+    handleView(row) {
+      this.open = true;
+      this.form = row;
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const operIds = row.operId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎鏃ュ織缂栧彿涓�"' + operIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delOperlog(operIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 娓呯┖鎸夐挳鎿嶄綔 */
+    handleClean() {
+      this.$modal.confirm('鏄惁纭娓呯┖鎵�鏈夋搷浣滄棩蹇楁暟鎹」锛�').then(function() {
+        return cleanOperlog();
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("娓呯┖鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('monitor/operlog/export', {
+        ...this.queryParams
+      }, `operlog_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
+
diff --git a/ruoyi-ui/src/views/monitor/server/index.vue b/ruoyi-ui/src/views/monitor/server/index.vue
new file mode 100644
index 0000000..15ffc9a
--- /dev/null
+++ b/ruoyi-ui/src/views/monitor/server/index.vue
@@ -0,0 +1,207 @@
+<template>
+  <div class="app-container">
+    <el-row>
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span><i class="el-icon-cpu"></i> CPU</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="el-table__cell is-leaf"><div class="cell">灞炴��</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鍊�</div></th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鏍稿績鏁�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.cpuNum }}</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鐢ㄦ埛浣跨敤鐜�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.used }}%</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">绯荤粺浣跨敤鐜�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.sys }}%</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">褰撳墠绌洪棽鐜�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.cpu">{{ server.cpu.free }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="12" class="card-box">
+        <el-card>
+          <div slot="header"><span><i class="el-icon-tickets"></i> 鍐呭瓨</span></div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="el-table__cell is-leaf"><div class="cell">灞炴��</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鍐呭瓨</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">JVM</div></th>
+                </tr>
+              </thead>
+              <tbody>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鎬诲唴瀛�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.total }}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.total }}M</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">宸茬敤鍐呭瓨</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.used}}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.used}}M</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鍓╀綑鍐呭瓨</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem">{{ server.mem.free }}G</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.free }}M</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">浣跨敤鐜�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.mem" :class="{'text-danger': server.mem.usage > 80}">{{ server.mem.usage }}%</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm" :class="{'text-danger': server.jvm.usage > 80}">{{ server.jvm.usage }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span><i class="el-icon-monitor"></i> 鏈嶅姟鍣ㄤ俊鎭�</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <tbody>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鏈嶅姟鍣ㄥ悕绉�</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">鎿嶄綔绯荤粺</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.osName }}</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鏈嶅姟鍣↖P</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.computerIp }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">绯荤粺鏋舵瀯</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.osArch }}</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span><i class="el-icon-coffee-cup"></i> Java铏氭嫙鏈轰俊鎭�</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;table-layout:fixed;">
+              <tbody>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">Java鍚嶇О</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.name }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">Java鐗堟湰</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.version }}</div></td>
+                </tr>
+                <tr>
+                  <td class="el-table__cell is-leaf"><div class="cell">鍚姩鏃堕棿</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.startTime }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">杩愯鏃堕暱</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.runTime }}</div></td>
+                </tr>
+                <tr>
+                  <td colspan="1" class="el-table__cell is-leaf"><div class="cell">瀹夎璺緞</div></td>
+                  <td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.home }}</div></td>
+                </tr>
+                <tr>
+                  <td colspan="1" class="el-table__cell is-leaf"><div class="cell">椤圭洰璺緞</div></td>
+                  <td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.sys">{{ server.sys.userDir }}</div></td>
+                </tr>
+                <tr>
+                  <td colspan="1" class="el-table__cell is-leaf"><div class="cell">杩愯鍙傛暟</div></td>
+                  <td colspan="3" class="el-table__cell is-leaf"><div class="cell" v-if="server.jvm">{{ server.jvm.inputArgs }}</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+
+      <el-col :span="24" class="card-box">
+        <el-card>
+          <div slot="header">
+            <span><i class="el-icon-receiving"></i> 纾佺洏鐘舵��</span>
+          </div>
+          <div class="el-table el-table--enable-row-hover el-table--medium">
+            <table cellspacing="0" style="width: 100%;">
+              <thead>
+                <tr>
+                  <th class="el-table__cell el-table__cell is-leaf"><div class="cell">鐩樼璺緞</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鏂囦欢绯荤粺</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鐩樼绫诲瀷</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鎬诲ぇ灏�</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">鍙敤澶у皬</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">宸茬敤澶у皬</div></th>
+                  <th class="el-table__cell is-leaf"><div class="cell">宸茬敤鐧惧垎姣�</div></th>
+                </tr>
+              </thead>
+              <tbody v-if="server.sysFiles">
+                <tr v-for="(sysFile, index) in server.sysFiles" :key="index">
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.dirName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.sysTypeName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.typeName }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.total }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.free }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell">{{ sysFile.used }}</div></td>
+                  <td class="el-table__cell is-leaf"><div class="cell" :class="{'text-danger': sysFile.usage > 80}">{{ sysFile.usage }}%</div></td>
+                </tr>
+              </tbody>
+            </table>
+          </div>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import { getServer } from "@/api/monitor/server";
+
+export default {
+  name: "Server",
+  data() {
+    return {
+      // 鏈嶅姟鍣ㄤ俊鎭�
+      server: []
+    };
+  },
+  created() {
+    this.getList();
+    this.openLoading();
+  },
+  methods: {
+    /** 鏌ヨ鏈嶅姟鍣ㄤ俊鎭� */
+    getList() {
+      getServer().then(response => {
+        this.server = response.data;
+        this.$modal.closeLoading();
+      });
+    },
+    // 鎵撳紑鍔犺浇灞�
+    openLoading() {
+      this.$modal.loading("姝e湪鍔犺浇鏈嶅姟鐩戞帶鏁版嵁锛岃绋嶅�欙紒");
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/redirect.vue b/ruoyi-ui/src/views/redirect.vue
new file mode 100644
index 0000000..db4c1d6
--- /dev/null
+++ b/ruoyi-ui/src/views/redirect.vue
@@ -0,0 +1,12 @@
+<script>
+export default {
+  created() {
+    const { params, query } = this.$route
+    const { path } = params
+    this.$router.replace({ path: '/' + path, query })
+  },
+  render: function(h) {
+    return h() // avoid warning message
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/register.vue b/ruoyi-ui/src/views/register.vue
new file mode 100644
index 0000000..60d8bca
--- /dev/null
+++ b/ruoyi-ui/src/views/register.vue
@@ -0,0 +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>
diff --git a/ruoyi-ui/src/views/system/config/index.vue b/ruoyi-ui/src/views/system/config/index.vue
new file mode 100644
index 0000000..6bde2ee
--- /dev/null
+++ b/ruoyi-ui/src/views/system/config/index.vue
@@ -0,0 +1,343 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鍙傛暟鍚嶇О" prop="configName">
+        <el-input
+          v-model="queryParams.configName"
+          placeholder="璇疯緭鍏ュ弬鏁板悕绉�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍙傛暟閿悕" prop="configKey">
+        <el-input
+          v-model="queryParams.configKey"
+          placeholder="璇疯緭鍏ュ弬鏁伴敭鍚�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绯荤粺鍐呯疆" prop="configType">
+        <el-select v-model="queryParams.configType" placeholder="绯荤粺鍐呯疆" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_yes_no"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="['system:config: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="['system:config: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="['system:config: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="['system:config:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleRefreshCache"
+          v-hasPermi="['system:config:remove']"
+        >鍒锋柊缂撳瓨</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="configList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="鍙傛暟涓婚敭" align="center" prop="configId" />
+      <el-table-column label="鍙傛暟鍚嶇О" align="center" prop="configName" :show-overflow-tooltip="true" />
+      <el-table-column label="鍙傛暟閿悕" align="center" prop="configKey" :show-overflow-tooltip="true" />
+      <el-table-column label="鍙傛暟閿��" align="center" prop="configValue" :show-overflow-tooltip="true" />
+      <el-table-column label="绯荤粺鍐呯疆" align="center" prop="configType">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_yes_no" :value="scope.row.configType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:config:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:config:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="鍙傛暟鍚嶇О" prop="configName">
+          <el-input v-model="form.configName" placeholder="璇疯緭鍏ュ弬鏁板悕绉�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟閿悕" prop="configKey">
+          <el-input v-model="form.configKey" placeholder="璇疯緭鍏ュ弬鏁伴敭鍚�" />
+        </el-form-item>
+        <el-form-item label="鍙傛暟閿��" prop="configValue">
+          <el-input v-model="form.configValue" type="textarea" placeholder="璇疯緭鍏ュ弬鏁伴敭鍊�" />
+        </el-form-item>
+        <el-form-item label="绯荤粺鍐呯疆" prop="configType">
+          <el-radio-group v-model="form.configType">
+            <el-radio
+              v-for="dict in dict.type.sys_yes_no"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listConfig, getConfig, delConfig, addConfig, updateConfig, refreshCache } from "@/api/system/config";
+
+export default {
+  name: "Config",
+  dicts: ['sys_yes_no'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鍙傛暟琛ㄦ牸鏁版嵁
+      configList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        configName: undefined,
+        configKey: undefined,
+        configType: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        configName: [
+          { required: true, message: "鍙傛暟鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        configKey: [
+          { required: true, message: "鍙傛暟閿悕涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        configValue: [
+          { required: true, message: "鍙傛暟閿�间笉鑳戒负绌�", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鍙傛暟鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listConfig(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.configList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        configId: undefined,
+        configName: undefined,
+        configKey: undefined,
+        configValue: undefined,
+        configType: "Y",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞鍙傛暟";
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.configId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const configId = row.configId || this.ids
+      getConfig(configId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鍙傛暟";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.configId != undefined) {
+            updateConfig(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addConfig(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const configIds = row.configId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎鍙傛暟缂栧彿涓�"' + configIds + '"鐨勬暟鎹」锛�').then(function() {
+          return delConfig(configIds);
+        }).then(() => {
+          this.getList();
+          this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/config/export', {
+        ...this.queryParams
+      }, `config_${new Date().getTime()}.xlsx`)
+    },
+    /** 鍒锋柊缂撳瓨鎸夐挳鎿嶄綔 */
+    handleRefreshCache() {
+      refreshCache().then(() => {
+        this.$modal.msgSuccess("鍒锋柊鎴愬姛");
+      });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/dept/index.vue b/ruoyi-ui/src/views/system/dept/index.vue
new file mode 100644
index 0000000..e502b4e
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dept/index.vue
@@ -0,0 +1,340 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+      <el-form-item label="閮ㄩ棬鍚嶇О" prop="deptName">
+        <el-input
+          v-model="queryParams.deptName"
+          placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="閮ㄩ棬鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['system:dept: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="deptList"
+      row-key="deptId"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column prop="deptName" label="閮ㄩ棬鍚嶇О" width="260"></el-table-column>
+      <el-table-column prop="orderNum" label="鎺掑簭" width="200"></el-table-column>
+      <el-table-column prop="status" label="鐘舵��" width="100">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="200">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dept:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['system:dept:add']"
+          >鏂板</el-button>
+          <el-button
+            v-if="scope.row.parentId != 0"
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dept:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀归儴闂ㄥ璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="24" v-if="form.parentId !== 0">
+            <el-form-item label="涓婄骇閮ㄩ棬" prop="parentId">
+              <treeselect v-model="form.parentId" :options="deptOptions" :normalizer="normalizer" placeholder="閫夋嫨涓婄骇閮ㄩ棬" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="閮ㄩ棬鍚嶇О" prop="deptName">
+              <el-input v-model="form.deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄剧ず鎺掑簭" prop="orderNum">
+              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="璐熻矗浜�" prop="leader">
+              <el-input v-model="form.leader" placeholder="璇疯緭鍏ヨ礋璐d汉" maxlength="20" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鑱旂郴鐢佃瘽" prop="phone">
+              <el-input v-model="form.phone" placeholder="璇疯緭鍏ヨ仈绯荤數璇�" maxlength="11" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="閭" prop="email">
+              <el-input v-model="form.email" placeholder="璇疯緭鍏ラ偖绠�" maxlength="50" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閮ㄩ棬鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in dict.type.sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listDept, getDept, delDept, addDept, updateDept, listDeptExcludeChild } from "@/api/system/dept";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+
+export default {
+  name: "Dept",
+  dicts: ['sys_normal_disable'],
+  components: { Treeselect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 琛ㄦ牸鏍戞暟鎹�
+      deptList: [],
+      // 閮ㄩ棬鏍戦�夐」
+      deptOptions: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁灞曞紑锛岄粯璁ゅ叏閮ㄥ睍寮�
+      isExpandAll: true,
+      // 閲嶆柊娓叉煋琛ㄦ牸鐘舵��
+      refreshTable: true,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        deptName: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        parentId: [
+          { required: true, message: "涓婄骇閮ㄩ棬涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        deptName: [
+          { required: true, message: "閮ㄩ棬鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        orderNum: [
+          { required: true, message: "鏄剧ず鎺掑簭涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phone: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ閮ㄩ棬鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listDept(this.queryParams).then(response => {
+        this.deptList = this.handleTree(response.data, "deptId");
+        this.loading = false;
+      });
+    },
+    /** 杞崲閮ㄩ棬鏁版嵁缁撴瀯 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.deptId,
+        label: node.deptName,
+        children: node.children
+      };
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        deptId: undefined,
+        parentId: undefined,
+        deptName: undefined,
+        orderNum: undefined,
+        leader: undefined,
+        phone: undefined,
+        email: undefined,
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      if (row != undefined) {
+        this.form.parentId = row.deptId;
+      }
+      this.open = true;
+      this.title = "娣诲姞閮ㄩ棬";
+      listDept().then(response => {
+        this.deptOptions = this.handleTree(response.data, "deptId");
+      });
+    },
+    /** 灞曞紑/鎶樺彔鎿嶄綔 */
+    toggleExpandAll() {
+      this.refreshTable = false;
+      this.isExpandAll = !this.isExpandAll;
+      this.$nextTick(() => {
+        this.refreshTable = true;
+      });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      getDept(row.deptId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼閮ㄩ棬";
+        listDeptExcludeChild(row.deptId).then(response => {
+          this.deptOptions = this.handleTree(response.data, "deptId");
+          if (this.deptOptions.length == 0) {
+            const noResultsOptions = { deptId: this.form.parentId, deptName: this.form.parentName, children: [] };
+            this.deptOptions.push(noResultsOptions);
+          }
+        });
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.deptId != undefined) {
+            updateDept(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addDept(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$modal.confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.deptName + '"鐨勬暟鎹」锛�').then(function() {
+        return delDept(row.deptId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/dict/data.vue b/ruoyi-ui/src/views/system/dict/data.vue
new file mode 100644
index 0000000..3befe4a
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dict/data.vue
@@ -0,0 +1,402 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="瀛楀吀鍚嶇О" prop="dictType">
+        <el-select v-model="queryParams.dictType">
+          <el-option
+            v-for="item in typeOptions"
+            :key="item.dictId"
+            :label="item.dictName"
+            :value="item.dictType"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="瀛楀吀鏍囩" prop="dictLabel">
+        <el-input
+          v-model="queryParams.dictLabel"
+          placeholder="璇疯緭鍏ュ瓧鍏告爣绛�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="鏁版嵁鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['system:dict: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="['system:dict: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="['system:dict: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="['system:dict:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-close"
+          size="mini"
+          @click="handleClose"
+        >鍏抽棴</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="dataList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="瀛楀吀缂栫爜" align="center" prop="dictCode" />
+      <el-table-column label="瀛楀吀鏍囩" align="center" prop="dictLabel">
+        <template slot-scope="scope">
+          <span v-if="(scope.row.listClass == '' || scope.row.listClass == 'default') && (scope.row.cssClass == '' || scope.row.cssClass == null)">{{ scope.row.dictLabel }}</span>
+          <el-tag v-else :type="scope.row.listClass == 'primary' ? '' : scope.row.listClass" :class="scope.row.cssClass">{{ scope.row.dictLabel }}</el-tag>
+        </template>
+      </el-table-column>
+      <el-table-column label="瀛楀吀閿��" align="center" prop="dictValue" />
+      <el-table-column label="瀛楀吀鎺掑簭" align="center" prop="dictSort" />
+      <el-table-column label="鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dict:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dict:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="瀛楀吀绫诲瀷">
+          <el-input v-model="form.dictType" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏁版嵁鏍囩" prop="dictLabel">
+          <el-input v-model="form.dictLabel" placeholder="璇疯緭鍏ユ暟鎹爣绛�" />
+        </el-form-item>
+        <el-form-item label="鏁版嵁閿��" prop="dictValue">
+          <el-input v-model="form.dictValue" placeholder="璇疯緭鍏ユ暟鎹敭鍊�" />
+        </el-form-item>
+        <el-form-item label="鏍峰紡灞炴��" prop="cssClass">
+          <el-input v-model="form.cssClass" placeholder="璇疯緭鍏ユ牱寮忓睘鎬�" />
+        </el-form-item>
+        <el-form-item label="鏄剧ず鎺掑簭" prop="dictSort">
+          <el-input-number v-model="form.dictSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="鍥炴樉鏍峰紡" prop="listClass">
+          <el-select v-model="form.listClass">
+            <el-option
+              v-for="item in listClassOptions"
+              :key="item.value"
+              :label="item.label + '(' + item.value + ')'"
+              :value="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listData, getData, delData, addData, updateData } from "@/api/system/dict/data";
+import { optionselect as getDictOptionselect, getType } from "@/api/system/dict/type";
+
+export default {
+  name: "Data",
+  dicts: ['sys_normal_disable'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瀛楀吀琛ㄦ牸鏁版嵁
+      dataList: [],
+      // 榛樿瀛楀吀绫诲瀷
+      defaultDictType: "",
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏁版嵁鏍囩鍥炴樉鏍峰紡
+      listClassOptions: [
+        {
+          value: "default",
+          label: "榛樿"
+        },
+        {
+          value: "primary",
+          label: "涓昏"
+        },
+        {
+          value: "success",
+          label: "鎴愬姛"
+        },
+        {
+          value: "info",
+          label: "淇℃伅"
+        },
+        {
+          value: "warning",
+          label: "璀﹀憡"
+        },
+        {
+          value: "danger",
+          label: "鍗遍櫓"
+        }
+      ],
+      // 绫诲瀷鏁版嵁瀛楀吀
+      typeOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictType: undefined,
+        dictLabel: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        dictLabel: [
+          { required: true, message: "鏁版嵁鏍囩涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        dictValue: [
+          { required: true, message: "鏁版嵁閿�间笉鑳戒负绌�", trigger: "blur" }
+        ],
+        dictSort: [
+          { required: true, message: "鏁版嵁椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    const dictId = this.$route.params && this.$route.params.dictId;
+    this.getType(dictId);
+    this.getTypeList();
+  },
+  methods: {
+    /** 鏌ヨ瀛楀吀绫诲瀷璇︾粏 */
+    getType(dictId) {
+      getType(dictId).then(response => {
+        this.queryParams.dictType = response.data.dictType;
+        this.defaultDictType = response.data.dictType;
+        this.getList();
+      });
+    },
+    /** 鏌ヨ瀛楀吀绫诲瀷鍒楄〃 */
+    getTypeList() {
+      getDictOptionselect().then(response => {
+        this.typeOptions = response.data;
+      });
+    },
+    /** 鏌ヨ瀛楀吀鏁版嵁鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listData(this.queryParams).then(response => {
+        this.dataList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        dictCode: undefined,
+        dictLabel: undefined,
+        dictValue: undefined,
+        cssClass: undefined,
+        listClass: 'default',
+        dictSort: 0,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 杩斿洖鎸夐挳鎿嶄綔 */
+    handleClose() {
+      const obj = { path: "/system/dict" };
+      this.$tab.closeOpenPage(obj);
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.queryParams.dictType = this.defaultDictType;
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞瀛楀吀鏁版嵁";
+      this.form.dictType = this.queryParams.dictType;
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictCode)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const dictCode = row.dictCode || this.ids
+      getData(dictCode).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼瀛楀吀鏁版嵁";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.dictCode != undefined) {
+            updateData(this.form).then(response => {
+              this.$store.dispatch('dict/removeDict', this.queryParams.dictType);
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addData(this.form).then(response => {
+              this.$store.dispatch('dict/removeDict', this.queryParams.dictType);
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const dictCodes = row.dictCode || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎瀛楀吀缂栫爜涓�"' + dictCodes + '"鐨勬暟鎹」锛�').then(function() {
+        return delData(dictCodes);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+        this.$store.dispatch('dict/removeDict', this.queryParams.dictType);
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/dict/data/export', {
+        ...this.queryParams
+      }, `data_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/dict/index.vue b/ruoyi-ui/src/views/system/dict/index.vue
new file mode 100644
index 0000000..6ca5457
--- /dev/null
+++ b/ruoyi-ui/src/views/system/dict/index.vue
@@ -0,0 +1,347 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="瀛楀吀鍚嶇О" prop="dictName">
+        <el-input
+          v-model="queryParams.dictName"
+          placeholder="璇疯緭鍏ュ瓧鍏稿悕绉�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="瀛楀吀绫诲瀷" prop="dictType">
+        <el-input
+          v-model="queryParams.dictType"
+          placeholder="璇疯緭鍏ュ瓧鍏哥被鍨�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="瀛楀吀鐘舵��"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="['system:dict: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="['system:dict: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="['system:dict: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="['system:dict:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-refresh"
+          size="mini"
+          @click="handleRefreshCache"
+          v-hasPermi="['system:dict:remove']"
+        >鍒锋柊缂撳瓨</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="typeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="瀛楀吀缂栧彿" align="center" prop="dictId" />
+      <el-table-column label="瀛楀吀鍚嶇О" align="center" prop="dictName" :show-overflow-tooltip="true" />
+      <el-table-column label="瀛楀吀绫诲瀷" align="center" :show-overflow-tooltip="true">
+        <template slot-scope="scope">
+          <router-link :to="'/system/dict-data/index/' + scope.row.dictId" class="link-type">
+            <span>{{ scope.row.dictType }}</span>
+          </router-link>
+        </template>
+      </el-table-column>
+      <el-table-column label="鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="澶囨敞" align="center" prop="remark" :show-overflow-tooltip="true" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:dict:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:dict:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰弬鏁伴厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="瀛楀吀鍚嶇О" prop="dictName">
+          <el-input v-model="form.dictName" placeholder="璇疯緭鍏ュ瓧鍏稿悕绉�" />
+        </el-form-item>
+        <el-form-item label="瀛楀吀绫诲瀷" prop="dictType">
+          <el-input v-model="form.dictType" placeholder="璇疯緭鍏ュ瓧鍏哥被鍨�" />
+        </el-form-item>
+        <el-form-item label="鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listType, getType, delType, addType, updateType, refreshCache } from "@/api/system/dict/type";
+
+export default {
+  name: "Dict",
+  dicts: ['sys_normal_disable'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瀛楀吀琛ㄦ牸鏁版嵁
+      typeList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        dictName: undefined,
+        dictType: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        dictName: [
+          { required: true, message: "瀛楀吀鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        dictType: [
+          { required: true, message: "瀛楀吀绫诲瀷涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ瀛楀吀绫诲瀷鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listType(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.typeList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        dictId: undefined,
+        dictName: undefined,
+        dictType: undefined,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞瀛楀吀绫诲瀷";
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.dictId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const dictId = row.dictId || this.ids
+      getType(dictId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼瀛楀吀绫诲瀷";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.dictId != undefined) {
+            updateType(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addType(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const dictIds = row.dictId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎瀛楀吀缂栧彿涓�"' + dictIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delType(dictIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/dict/type/export', {
+        ...this.queryParams
+      }, `type_${new Date().getTime()}.xlsx`)
+    },
+    /** 鍒锋柊缂撳瓨鎸夐挳鎿嶄綔 */
+    handleRefreshCache() {
+      refreshCache().then(() => {
+        this.$modal.msgSuccess("鍒锋柊鎴愬姛");
+        this.$store.dispatch('dict/cleanDict');
+      });
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/menu/index.vue b/ruoyi-ui/src/views/system/menu/index.vue
new file mode 100644
index 0000000..c4b5003
--- /dev/null
+++ b/ruoyi-ui/src/views/system/menu/index.vue
@@ -0,0 +1,466 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+      <el-form-item label="鑿滃崟鍚嶇О" prop="menuName">
+        <el-input
+          v-model="queryParams.menuName"
+          placeholder="璇疯緭鍏ヨ彍鍗曞悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="鑿滃崟鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['system:menu: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="menuList"
+      row-key="menuId"
+      :default-expand-all="isExpandAll"
+      :tree-props="{children: 'children', hasChildren: 'hasChildren'}"
+    >
+      <el-table-column prop="menuName" label="鑿滃崟鍚嶇О" :show-overflow-tooltip="true" width="160"></el-table-column>
+      <el-table-column prop="icon" label="鍥炬爣" align="center" width="100">
+        <template slot-scope="scope">
+          <svg-icon :icon-class="scope.row.icon" />
+        </template>
+      </el-table-column>
+      <el-table-column prop="orderNum" label="鎺掑簭" width="60"></el-table-column>
+      <el-table-column prop="perms" label="鏉冮檺鏍囪瘑" :show-overflow-tooltip="true"></el-table-column>
+      <el-table-column prop="component" label="缁勪欢璺緞" :show-overflow-tooltip="true"></el-table-column>
+      <el-table-column prop="status" label="鐘舵��" width="80">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:menu:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-plus"
+            @click="handleAdd(scope.row)"
+            v-hasPermi="['system:menu:add']"
+          >鏂板</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:menu:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <!-- 娣诲姞鎴栦慨鏀硅彍鍗曞璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="680px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="涓婄骇鑿滃崟" prop="parentId">
+              <treeselect
+                v-model="form.parentId"
+                :options="menuOptions"
+                :normalizer="normalizer"
+                :show-count="true"
+                placeholder="閫夋嫨涓婄骇鑿滃崟"
+              />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="鑿滃崟绫诲瀷" prop="menuType">
+              <el-radio-group v-model="form.menuType">
+                <el-radio label="M">鐩綍</el-radio>
+                <el-radio label="C">鑿滃崟</el-radio>
+                <el-radio label="F">鎸夐挳</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24" v-if="form.menuType != 'F'">
+            <el-form-item label="鑿滃崟鍥炬爣" prop="icon">
+              <el-popover
+                placement="bottom-start"
+                width="460"
+                trigger="click"
+                @show="$refs['iconSelect'].reset()"
+              >
+                <IconSelect ref="iconSelect" @selected="selected" :active-icon="form.icon" />
+                <el-input slot="reference" v-model="form.icon" placeholder="鐐瑰嚮閫夋嫨鍥炬爣" readonly>
+                  <svg-icon
+                    v-if="form.icon"
+                    slot="prefix"
+                    :icon-class="form.icon"
+                    style="width: 25px;"
+                  />
+                  <i v-else slot="prefix" class="el-icon-search el-input__icon" />
+                </el-input>
+              </el-popover>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鑿滃崟鍚嶇О" prop="menuName">
+              <el-input v-model="form.menuName" placeholder="璇疯緭鍏ヨ彍鍗曞悕绉�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鏄剧ず鎺掑簭" prop="orderNum">
+              <el-input-number v-model="form.orderNum" controls-position="right" :min="0" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item prop="isFrame">
+              <span slot="label">
+                <el-tooltip content="閫夋嫨鏄閾惧垯璺敱鍦板潃闇�瑕佷互`http(s)://`寮�澶�" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                鏄惁澶栭摼
+              </span>
+              <el-radio-group v-model="form.isFrame">
+                <el-radio label="0">鏄�</el-radio>
+                <el-radio label="1">鍚�</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item prop="path">
+              <span slot="label">
+                <el-tooltip content="璁块棶鐨勮矾鐢卞湴鍧�锛屽锛歚user`锛屽澶栫綉鍦板潃闇�鍐呴摼璁块棶鍒欎互`http(s)://`寮�澶�" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                璺敱鍦板潃
+              </span>
+              <el-input v-model="form.path" placeholder="璇疯緭鍏ヨ矾鐢卞湴鍧�" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item prop="component">
+              <span slot="label">
+                <el-tooltip content="璁块棶鐨勭粍浠惰矾寰勶紝濡傦細`system/user/index`锛岄粯璁ゅ湪`views`鐩綍涓�" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                缁勪欢璺緞
+              </span>
+              <el-input v-model="form.component" placeholder="璇疯緭鍏ョ粍浠惰矾寰�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12" v-if="form.menuType != 'M'">
+            <el-form-item prop="perms">
+              <el-input v-model="form.perms" placeholder="璇疯緭鍏ユ潈闄愭爣璇�" maxlength="100" />
+              <span slot="label">
+                <el-tooltip content="鎺у埗鍣ㄤ腑瀹氫箟鐨勬潈闄愬瓧绗︼紝濡傦細@PreAuthorize(`@ss.hasPermi('system:user:list')`)" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                鏉冮檺瀛楃
+              </span>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item prop="query">
+              <el-input v-model="form.query" placeholder="璇疯緭鍏ヨ矾鐢卞弬鏁�" maxlength="255" />
+              <span slot="label">
+                <el-tooltip content='璁块棶璺敱鐨勯粯璁や紶閫掑弬鏁帮紝濡傦細`{"id": 1, "name": "ry"}`' placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                璺敱鍙傛暟
+              </span>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12" v-if="form.menuType == 'C'">
+            <el-form-item prop="isCache">
+              <span slot="label">
+                <el-tooltip content="閫夋嫨鏄垯浼氳`keep-alive`缂撳瓨锛岄渶瑕佸尮閰嶇粍浠剁殑`name`鍜屽湴鍧�淇濇寔涓�鑷�" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                鏄惁缂撳瓨
+              </span>
+              <el-radio-group v-model="form.isCache">
+                <el-radio label="0">缂撳瓨</el-radio>
+                <el-radio label="1">涓嶇紦瀛�</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12" v-if="form.menuType != 'F'">
+            <el-form-item prop="visible">
+              <span slot="label">
+                <el-tooltip content="閫夋嫨闅愯棌鍒欒矾鐢卞皢涓嶄細鍑虹幇鍦ㄤ晶杈规爮锛屼絾浠嶇劧鍙互璁块棶" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                鏄剧ず鐘舵��
+              </span>
+              <el-radio-group v-model="form.visible">
+                <el-radio
+                  v-for="dict in dict.type.sys_show_hide"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item prop="status">
+              <span slot="label">
+                <el-tooltip content="閫夋嫨鍋滅敤鍒欒矾鐢卞皢涓嶄細鍑虹幇鍦ㄤ晶杈规爮锛屼篃涓嶈兘琚闂�" placement="top">
+                <i class="el-icon-question"></i>
+                </el-tooltip>
+                鑿滃崟鐘舵��
+              </span>
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in dict.type.sys_normal_disable"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listMenu, getMenu, delMenu, addMenu, updateMenu } from "@/api/system/menu";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import IconSelect from "@/components/IconSelect";
+
+export default {
+  name: "Menu",
+  dicts: ['sys_show_hide', 'sys_normal_disable'],
+  components: { Treeselect, IconSelect },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鑿滃崟琛ㄦ牸鏍戞暟鎹�
+      menuList: [],
+      // 鑿滃崟鏍戦�夐」
+      menuOptions: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁灞曞紑锛岄粯璁ゅ叏閮ㄦ姌鍙�
+      isExpandAll: false,
+      // 閲嶆柊娓叉煋琛ㄦ牸鐘舵��
+      refreshTable: true,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        menuName: undefined,
+        visible: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        menuName: [
+          { required: true, message: "鑿滃崟鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        orderNum: [
+          { required: true, message: "鑿滃崟椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        path: [
+          { required: true, message: "璺敱鍦板潃涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    // 閫夋嫨鍥炬爣
+    selected(name) {
+      this.form.icon = name;
+    },
+    /** 鏌ヨ鑿滃崟鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listMenu(this.queryParams).then(response => {
+        this.menuList = this.handleTree(response.data, "menuId");
+        this.loading = false;
+      });
+    },
+    /** 杞崲鑿滃崟鏁版嵁缁撴瀯 */
+    normalizer(node) {
+      if (node.children && !node.children.length) {
+        delete node.children;
+      }
+      return {
+        id: node.menuId,
+        label: node.menuName,
+        children: node.children
+      };
+    },
+    /** 鏌ヨ鑿滃崟涓嬫媺鏍戠粨鏋� */
+    getTreeselect() {
+      listMenu().then(response => {
+        this.menuOptions = [];
+        const menu = { menuId: 0, menuName: '涓荤被鐩�', children: [] };
+        menu.children = this.handleTree(response.data, "menuId");
+        this.menuOptions.push(menu);
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        menuId: undefined,
+        parentId: 0,
+        menuName: undefined,
+        icon: undefined,
+        menuType: "M",
+        orderNum: undefined,
+        isFrame: "1",
+        isCache: "0",
+        visible: "0",
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd(row) {
+      this.reset();
+      this.getTreeselect();
+      if (row != null && row.menuId) {
+        this.form.parentId = row.menuId;
+      } else {
+        this.form.parentId = 0;
+      }
+      this.open = true;
+      this.title = "娣诲姞鑿滃崟";
+    },
+    /** 灞曞紑/鎶樺彔鎿嶄綔 */
+    toggleExpandAll() {
+      this.refreshTable = false;
+      this.isExpandAll = !this.isExpandAll;
+      this.$nextTick(() => {
+        this.refreshTable = true;
+      });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      this.getTreeselect();
+      getMenu(row.menuId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鑿滃崟";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.menuId != undefined) {
+            updateMenu(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addMenu(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      this.$modal.confirm('鏄惁纭鍒犻櫎鍚嶇О涓�"' + row.menuName + '"鐨勬暟鎹」锛�').then(function() {
+        return delMenu(row.menuId);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/notice/index.vue b/ruoyi-ui/src/views/system/notice/index.vue
new file mode 100644
index 0000000..7982b54
--- /dev/null
+++ b/ruoyi-ui/src/views/system/notice/index.vue
@@ -0,0 +1,312 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="鍏憡鏍囬" prop="noticeTitle">
+        <el-input
+          v-model="queryParams.noticeTitle"
+          placeholder="璇疯緭鍏ュ叕鍛婃爣棰�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎿嶄綔浜哄憳" prop="createBy">
+        <el-input
+          v-model="queryParams.createBy"
+          placeholder="璇疯緭鍏ユ搷浣滀汉鍛�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="绫诲瀷" prop="noticeType">
+        <el-select v-model="queryParams.noticeType" placeholder="鍏憡绫诲瀷" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_notice_type"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['system:notice: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="['system:notice: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="['system:notice:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="noticeList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="搴忓彿" align="center" prop="noticeId" width="100" />
+      <el-table-column
+        label="鍏憡鏍囬"
+        align="center"
+        prop="noticeTitle"
+        :show-overflow-tooltip="true"
+      />
+      <el-table-column label="鍏憡绫诲瀷" align="center" prop="noticeType" width="100">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_notice_type" :value="scope.row.noticeType"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鐘舵��" align="center" prop="status" width="100">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_notice_status" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鑰�" align="center" prop="createBy" width="100" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="100">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime, '{y}-{m}-{d}') }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:notice:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:notice:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰叕鍛婂璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="780px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鍏憡鏍囬" prop="noticeTitle">
+              <el-input v-model="form.noticeTitle" placeholder="璇疯緭鍏ュ叕鍛婃爣棰�" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鍏憡绫诲瀷" prop="noticeType">
+              <el-select v-model="form.noticeType" placeholder="璇烽�夋嫨鍏憡绫诲瀷">
+                <el-option
+                  v-for="dict in dict.type.sys_notice_type"
+                  :key="dict.value"
+                  :label="dict.label"
+                  :value="dict.value"
+                ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio
+                  v-for="dict in dict.type.sys_notice_status"
+                  :key="dict.value"
+                  :label="dict.value"
+                >{{dict.label}}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item label="鍐呭">
+              <editor v-model="form.noticeContent" :min-height="192"/>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listNotice, getNotice, delNotice, addNotice, updateNotice } from "@/api/system/notice";
+
+export default {
+  name: "Notice",
+  dicts: ['sys_notice_status', 'sys_notice_type'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鍏憡琛ㄦ牸鏁版嵁
+      noticeList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        noticeTitle: undefined,
+        createBy: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        noticeTitle: [
+          { required: true, message: "鍏憡鏍囬涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        noticeType: [
+          { required: true, message: "鍏憡绫诲瀷涓嶈兘涓虹┖", trigger: "change" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ鍏憡鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listNotice(this.queryParams).then(response => {
+        this.noticeList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        noticeId: undefined,
+        noticeTitle: undefined,
+        noticeType: undefined,
+        noticeContent: undefined,
+        status: "0"
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.noticeId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞鍏憡";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const noticeId = row.noticeId || this.ids
+      getNotice(noticeId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼鍏憡";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.noticeId != undefined) {
+            updateNotice(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addNotice(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const noticeIds = row.noticeId || this.ids
+      this.$modal.confirm('鏄惁纭鍒犻櫎鍏憡缂栧彿涓�"' + noticeIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delNotice(noticeIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/post/index.vue b/ruoyi-ui/src/views/system/post/index.vue
new file mode 100644
index 0000000..444bf63
--- /dev/null
+++ b/ruoyi-ui/src/views/system/post/index.vue
@@ -0,0 +1,309 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="宀椾綅缂栫爜" prop="postCode">
+        <el-input
+          v-model="queryParams.postCode"
+          placeholder="璇疯緭鍏ュ矖浣嶇紪鐮�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="宀椾綅鍚嶇О" prop="postName">
+        <el-input
+          v-model="queryParams.postName"
+          placeholder="璇疯緭鍏ュ矖浣嶅悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select v-model="queryParams.status" placeholder="宀椾綅鐘舵��" clearable>
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <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="['system:post: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="['system:post: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="['system:post: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="['system:post:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="postList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="宀椾綅缂栧彿" align="center" prop="postId" />
+      <el-table-column label="宀椾綅缂栫爜" align="center" prop="postCode" />
+      <el-table-column label="宀椾綅鍚嶇О" align="center" prop="postName" />
+      <el-table-column label="宀椾綅鎺掑簭" align="center" prop="postSort" />
+      <el-table-column label="鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:post:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:post:remove']"
+          >鍒犻櫎</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀瑰矖浣嶅璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-form-item label="宀椾綅鍚嶇О" prop="postName">
+          <el-input v-model="form.postName" placeholder="璇疯緭鍏ュ矖浣嶅悕绉�" />
+        </el-form-item>
+        <el-form-item label="宀椾綅缂栫爜" prop="postCode">
+          <el-input v-model="form.postCode" placeholder="璇疯緭鍏ョ紪鐮佸悕绉�" />
+        </el-form-item>
+        <el-form-item label="宀椾綅椤哄簭" prop="postSort">
+          <el-input-number v-model="form.postSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="宀椾綅鐘舵��" prop="status">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�" />
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listPost, getPost, delPost, addPost, updatePost } from "@/api/system/post";
+
+export default {
+  name: "Post",
+  dicts: ['sys_normal_disable'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 宀椾綅琛ㄦ牸鏁版嵁
+      postList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        postCode: undefined,
+        postName: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        postName: [
+          { required: true, message: "宀椾綅鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        postCode: [
+          { required: true, message: "宀椾綅缂栫爜涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        postSort: [
+          { required: true, message: "宀椾綅椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ宀椾綅鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listPost(this.queryParams).then(response => {
+        this.postList = response.rows;
+        this.total = response.total;
+        this.loading = false;
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        postId: undefined,
+        postCode: undefined,
+        postName: undefined,
+        postSort: 0,
+        status: "0",
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.postId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.open = true;
+      this.title = "娣诲姞宀椾綅";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const postId = row.postId || this.ids
+      getPost(postId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.title = "淇敼宀椾綅";
+      });
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.postId != undefined) {
+            updatePost(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addPost(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const postIds = row.postId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎宀椾綅缂栧彿涓�"' + postIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delPost(postIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/post/export', {
+        ...this.queryParams
+      }, `post_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/role/authUser.vue b/ruoyi-ui/src/views/system/role/authUser.vue
new file mode 100644
index 0000000..147aa33
--- /dev/null
+++ b/ruoyi-ui/src/views/system/role/authUser.vue
@@ -0,0 +1,199 @@
+<template>
+  <div class="app-container">
+     <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+      <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+        <el-input
+          v-model="queryParams.phonenumber"
+          placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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="openSelectUser"
+          v-hasPermi="['system:role:add']"
+        >娣诲姞鐢ㄦ埛</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="danger"
+          plain
+          icon="el-icon-circle-close"
+          size="mini"
+          :disabled="multiple"
+          @click="cancelAuthUserAll"
+          v-hasPermi="['system:role:remove']"
+        >鎵归噺鍙栨秷鎺堟潈</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="warning"
+          plain
+          icon="el-icon-close"
+          size="mini"
+          @click="handleClose"
+        >鍏抽棴</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="鐢ㄦ埛鍚嶇О" prop="userName" :show-overflow-tooltip="true" />
+      <el-table-column label="鐢ㄦ埛鏄电О" prop="nickName" :show-overflow-tooltip="true" />
+      <el-table-column label="閭" prop="email" :show-overflow-tooltip="true" />
+      <el-table-column label="鎵嬫満" prop="phonenumber" :show-overflow-tooltip="true" />
+      <el-table-column label="鐘舵��" align="center" prop="status">
+        <template slot-scope="scope">
+          <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-circle-close"
+            @click="cancelAuthUser(scope.row)"
+            v-hasPermi="['system:role:remove']"
+          >鍙栨秷鎺堟潈</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+    <select-user ref="select" :roleId="queryParams.roleId" @ok="handleQuery" />
+  </div>
+</template>
+
+<script>
+import { allocatedUserList, authUserCancel, authUserCancelAll } from "@/api/system/role";
+import selectUser from "./selectUser";
+
+export default {
+  name: "AuthUser",
+  dicts: ['sys_normal_disable'],
+  components: { selectUser },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鐢ㄦ埛缁�
+      userIds: [],
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleId: undefined,
+        userName: undefined,
+        phonenumber: undefined
+      }
+    };
+  },
+  created() {
+    const roleId = this.$route.params && this.$route.params.roleId;
+    if (roleId) {
+      this.queryParams.roleId = roleId;
+      this.getList();
+    }
+  },
+  methods: {
+    /** 鏌ヨ鎺堟潈鐢ㄦ埛鍒楄〃 */
+    getList() {
+      this.loading = true;
+      allocatedUserList(this.queryParams).then(response => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    // 杩斿洖鎸夐挳
+    handleClose() {
+      const obj = { path: "/system/role" };
+      this.$tab.closeOpenPage(obj);
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.userIds = selection.map(item => item.userId)
+      this.multiple = !selection.length
+    },
+    /** 鎵撳紑鎺堟潈鐢ㄦ埛琛ㄥ脊绐� */
+    openSelectUser() {
+      this.$refs.select.show();
+    },
+    /** 鍙栨秷鎺堟潈鎸夐挳鎿嶄綔 */
+    cancelAuthUser(row) {
+      const roleId = this.queryParams.roleId;
+      this.$modal.confirm('纭瑕佸彇娑堣鐢ㄦ埛"' + row.userName + '"瑙掕壊鍚楋紵').then(function() {
+        return authUserCancel({ userId: row.userId, roleId: roleId });
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍙栨秷鎺堟潈鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 鎵归噺鍙栨秷鎺堟潈鎸夐挳鎿嶄綔 */
+    cancelAuthUserAll(row) {
+      const roleId = this.queryParams.roleId;
+      const userIds = this.userIds.join(",");
+      this.$modal.confirm('鏄惁鍙栨秷閫変腑鐢ㄦ埛鎺堟潈鏁版嵁椤癸紵').then(function() {
+        return authUserCancelAll({ roleId: roleId, userIds: userIds });
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍙栨秷鎺堟潈鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/role/index.vue b/ruoyi-ui/src/views/system/role/index.vue
new file mode 100644
index 0000000..47419ba
--- /dev/null
+++ b/ruoyi-ui/src/views/system/role/index.vue
@@ -0,0 +1,605 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch">
+      <el-form-item label="瑙掕壊鍚嶇О" prop="roleName">
+        <el-input
+          v-model="queryParams.roleName"
+          placeholder="璇疯緭鍏ヨ鑹插悕绉�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鏉冮檺瀛楃" prop="roleKey">
+        <el-input
+          v-model="queryParams.roleKey"
+          placeholder="璇疯緭鍏ユ潈闄愬瓧绗�"
+          clearable
+          style="width: 240px"
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鐘舵��" prop="status">
+        <el-select
+          v-model="queryParams.status"
+          placeholder="瑙掕壊鐘舵��"
+          clearable
+          style="width: 240px"
+        >
+          <el-option
+            v-for="dict in dict.type.sys_normal_disable"
+            :key="dict.value"
+            :label="dict.label"
+            :value="dict.value"
+          />
+        </el-select>
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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="['system:role: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="['system:role: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="['system:role: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="['system:role:export']"
+        >瀵煎嚭</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="roleList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" width="55" align="center" />
+      <el-table-column label="瑙掕壊缂栧彿" prop="roleId" width="120" />
+      <el-table-column label="瑙掕壊鍚嶇О" prop="roleName" :show-overflow-tooltip="true" width="150" />
+      <el-table-column label="鏉冮檺瀛楃" prop="roleKey" :show-overflow-tooltip="true" width="150" />
+      <el-table-column label="鏄剧ず椤哄簭" prop="roleSort" width="100" />
+      <el-table-column label="鐘舵��" align="center" width="100">
+        <template slot-scope="scope">
+          <el-switch
+            v-model="scope.row.status"
+            active-value="0"
+            inactive-value="1"
+            @change="handleStatusChange(scope.row)"
+          ></el-switch>
+        </template>
+      </el-table-column>
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope" v-if="scope.row.roleId !== 1">
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-edit"
+            @click="handleUpdate(scope.row)"
+            v-hasPermi="['system:role:edit']"
+          >淇敼</el-button>
+          <el-button
+            size="mini"
+            type="text"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['system:role:remove']"
+          >鍒犻櫎</el-button>
+          <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:role:edit']">
+            <el-button size="mini" type="text" icon="el-icon-d-arrow-right">鏇村</el-button>
+            <el-dropdown-menu slot="dropdown">
+              <el-dropdown-item command="handleDataScope" icon="el-icon-circle-check"
+                v-hasPermi="['system:role:edit']">鏁版嵁鏉冮檺</el-dropdown-item>
+              <el-dropdown-item command="handleAuthUser" icon="el-icon-user"
+                v-hasPermi="['system:role:edit']">鍒嗛厤鐢ㄦ埛</el-dropdown-item>
+            </el-dropdown-menu>
+          </el-dropdown>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+
+    <!-- 娣诲姞鎴栦慨鏀硅鑹查厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="500px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="100px">
+        <el-form-item label="瑙掕壊鍚嶇О" prop="roleName">
+          <el-input v-model="form.roleName" placeholder="璇疯緭鍏ヨ鑹插悕绉�" />
+        </el-form-item>
+        <el-form-item prop="roleKey">
+          <span slot="label">
+            <el-tooltip content="鎺у埗鍣ㄤ腑瀹氫箟鐨勬潈闄愬瓧绗︼紝濡傦細@PreAuthorize(`@ss.hasRole('admin')`)" placement="top">
+              <i class="el-icon-question"></i>
+            </el-tooltip>
+            鏉冮檺瀛楃
+          </span>
+          <el-input v-model="form.roleKey" placeholder="璇疯緭鍏ユ潈闄愬瓧绗�" />
+        </el-form-item>
+        <el-form-item label="瑙掕壊椤哄簭" prop="roleSort">
+          <el-input-number v-model="form.roleSort" controls-position="right" :min="0" />
+        </el-form-item>
+        <el-form-item label="鐘舵��">
+          <el-radio-group v-model="form.status">
+            <el-radio
+              v-for="dict in dict.type.sys_normal_disable"
+              :key="dict.value"
+              :label="dict.value"
+            >{{dict.label}}</el-radio>
+          </el-radio-group>
+        </el-form-item>
+        <el-form-item label="鑿滃崟鏉冮檺">
+          <el-checkbox v-model="menuExpand" @change="handleCheckedTreeExpand($event, 'menu')">灞曞紑/鎶樺彔</el-checkbox>
+          <el-checkbox v-model="menuNodeAll" @change="handleCheckedTreeNodeAll($event, 'menu')">鍏ㄩ��/鍏ㄤ笉閫�</el-checkbox>
+          <el-checkbox v-model="form.menuCheckStrictly" @change="handleCheckedTreeConnect($event, 'menu')">鐖跺瓙鑱斿姩</el-checkbox>
+          <el-tree
+            class="tree-border"
+            :data="menuOptions"
+            show-checkbox
+            ref="menu"
+            node-key="id"
+            :check-strictly="!form.menuCheckStrictly"
+            empty-text="鍔犺浇涓紝璇风◢鍊�"
+            :props="defaultProps"
+          ></el-tree>
+        </el-form-item>
+        <el-form-item label="澶囨敞">
+          <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鍒嗛厤瑙掕壊鏁版嵁鏉冮檺瀵硅瘽妗� -->
+    <el-dialog :title="title" :visible.sync="openDataScope" width="500px" append-to-body>
+      <el-form :model="form" label-width="80px">
+        <el-form-item label="瑙掕壊鍚嶇О">
+          <el-input v-model="form.roleName" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏉冮檺瀛楃">
+          <el-input v-model="form.roleKey" :disabled="true" />
+        </el-form-item>
+        <el-form-item label="鏉冮檺鑼冨洿">
+          <el-select v-model="form.dataScope" @change="dataScopeSelectChange">
+            <el-option
+              v-for="item in dataScopeOptions"
+              :key="item.value"
+              :label="item.label"
+              :value="item.value"
+            ></el-option>
+          </el-select>
+        </el-form-item>
+        <el-form-item label="鏁版嵁鏉冮檺" v-show="form.dataScope == 2">
+          <el-checkbox v-model="deptExpand" @change="handleCheckedTreeExpand($event, 'dept')">灞曞紑/鎶樺彔</el-checkbox>
+          <el-checkbox v-model="deptNodeAll" @change="handleCheckedTreeNodeAll($event, 'dept')">鍏ㄩ��/鍏ㄤ笉閫�</el-checkbox>
+          <el-checkbox v-model="form.deptCheckStrictly" @change="handleCheckedTreeConnect($event, 'dept')">鐖跺瓙鑱斿姩</el-checkbox>
+          <el-tree
+            class="tree-border"
+            :data="deptOptions"
+            show-checkbox
+            default-expand-all
+            ref="dept"
+            node-key="id"
+            :check-strictly="!form.deptCheckStrictly"
+            empty-text="鍔犺浇涓紝璇风◢鍊�"
+            :props="defaultProps"
+          ></el-tree>
+        </el-form-item>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitDataScope">纭� 瀹�</el-button>
+        <el-button @click="cancelDataScope">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listRole, getRole, delRole, addRole, updateRole, dataScope, changeRoleStatus, deptTreeSelect } from "@/api/system/role";
+import { treeselect as menuTreeselect, roleMenuTreeselect } from "@/api/system/menu";
+
+export default {
+  name: "Role",
+  dicts: ['sys_normal_disable'],
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 瑙掕壊琛ㄦ牸鏁版嵁
+      roleList: [],
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁鏄剧ず寮瑰嚭灞傦紙鏁版嵁鏉冮檺锛�
+      openDataScope: false,
+      menuExpand: false,
+      menuNodeAll: false,
+      deptExpand: true,
+      deptNodeAll: false,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 鏁版嵁鑼冨洿閫夐」
+      dataScopeOptions: [
+        {
+          value: "1",
+          label: "鍏ㄩ儴鏁版嵁鏉冮檺"
+        },
+        {
+          value: "2",
+          label: "鑷畾鏁版嵁鏉冮檺"
+        },
+        {
+          value: "3",
+          label: "鏈儴闂ㄦ暟鎹潈闄�"
+        },
+        {
+          value: "4",
+          label: "鏈儴闂ㄥ強浠ヤ笅鏁版嵁鏉冮檺"
+        },
+        {
+          value: "5",
+          label: "浠呮湰浜烘暟鎹潈闄�"
+        }
+      ],
+      // 鑿滃崟鍒楄〃
+      menuOptions: [],
+      // 閮ㄩ棬鍒楄〃
+      deptOptions: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleName: undefined,
+        roleKey: undefined,
+        status: undefined
+      },
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      defaultProps: {
+        children: "children",
+        label: "label"
+      },
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        roleName: [
+          { required: true, message: "瑙掕壊鍚嶇О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        roleKey: [
+          { required: true, message: "鏉冮檺瀛楃涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        roleSort: [
+          { required: true, message: "瑙掕壊椤哄簭涓嶈兘涓虹┖", trigger: "blur" }
+        ]
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  methods: {
+    /** 鏌ヨ瑙掕壊鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listRole(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.roleList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鏌ヨ鑿滃崟鏍戠粨鏋� */
+    getMenuTreeselect() {
+      menuTreeselect().then(response => {
+        this.menuOptions = response.data;
+      });
+    },
+    // 鎵�鏈夎彍鍗曡妭鐐规暟鎹�
+    getMenuAllCheckedKeys() {
+      // 鐩墠琚�変腑鐨勮彍鍗曡妭鐐�
+      let checkedKeys = this.$refs.menu.getCheckedKeys();
+      // 鍗婇�変腑鐨勮彍鍗曡妭鐐�
+      let halfCheckedKeys = this.$refs.menu.getHalfCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      return checkedKeys;
+    },
+    // 鎵�鏈夐儴闂ㄨ妭鐐规暟鎹�
+    getDeptAllCheckedKeys() {
+      // 鐩墠琚�変腑鐨勯儴闂ㄨ妭鐐�
+      let checkedKeys = this.$refs.dept.getCheckedKeys();
+      // 鍗婇�変腑鐨勯儴闂ㄨ妭鐐�
+      let halfCheckedKeys = this.$refs.dept.getHalfCheckedKeys();
+      checkedKeys.unshift.apply(checkedKeys, halfCheckedKeys);
+      return checkedKeys;
+    },
+    /** 鏍规嵁瑙掕壊ID鏌ヨ鑿滃崟鏍戠粨鏋� */
+    getRoleMenuTreeselect(roleId) {
+      return roleMenuTreeselect(roleId).then(response => {
+        this.menuOptions = response.menus;
+        return response;
+      });
+    },
+    /** 鏍规嵁瑙掕壊ID鏌ヨ閮ㄩ棬鏍戠粨鏋� */
+    getDeptTree(roleId) {
+      return deptTreeSelect(roleId).then(response => {
+        this.deptOptions = response.depts;
+        return response;
+      });
+    },
+    // 瑙掕壊鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal.confirm('纭瑕�"' + text + '""' + row.roleName + '"瑙掕壊鍚楋紵').then(function() {
+        return changeRoleStatus(row.roleId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "鎴愬姛");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 鍙栨秷鎸夐挳锛堟暟鎹潈闄愶級
+    cancelDataScope() {
+      this.openDataScope = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      if (this.$refs.menu != undefined) {
+        this.$refs.menu.setCheckedKeys([]);
+      }
+      this.menuExpand = false,
+      this.menuNodeAll = false,
+      this.deptExpand = true,
+      this.deptNodeAll = false,
+      this.form = {
+        roleId: undefined,
+        roleName: undefined,
+        roleKey: undefined,
+        roleSort: 0,
+        status: "0",
+        menuIds: [],
+        deptIds: [],
+        menuCheckStrictly: true,
+        deptCheckStrictly: true,
+        remark: undefined
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.roleId)
+      this.single = selection.length!=1
+      this.multiple = !selection.length
+    },
+    // 鏇村鎿嶄綔瑙﹀彂
+    handleCommand(command, row) {
+      switch (command) {
+        case "handleDataScope":
+          this.handleDataScope(row);
+          break;
+        case "handleAuthUser":
+          this.handleAuthUser(row);
+          break;
+        default:
+          break;
+      }
+    },
+    // 鏍戞潈闄愶紙灞曞紑/鎶樺彔锛�
+    handleCheckedTreeExpand(value, type) {
+      if (type == 'menu') {
+        let treeList = this.menuOptions;
+        for (let i = 0; i < treeList.length; i++) {
+          this.$refs.menu.store.nodesMap[treeList[i].id].expanded = value;
+        }
+      } else if (type == 'dept') {
+        let treeList = this.deptOptions;
+        for (let i = 0; i < treeList.length; i++) {
+          this.$refs.dept.store.nodesMap[treeList[i].id].expanded = value;
+        }
+      }
+    },
+    // 鏍戞潈闄愶紙鍏ㄩ��/鍏ㄤ笉閫夛級
+    handleCheckedTreeNodeAll(value, type) {
+      if (type == 'menu') {
+        this.$refs.menu.setCheckedNodes(value ? this.menuOptions: []);
+      } else if (type == 'dept') {
+        this.$refs.dept.setCheckedNodes(value ? this.deptOptions: []);
+      }
+    },
+    // 鏍戞潈闄愶紙鐖跺瓙鑱斿姩锛�
+    handleCheckedTreeConnect(value, type) {
+      if (type == 'menu') {
+        this.form.menuCheckStrictly = value ? true: false;
+      } else if (type == 'dept') {
+        this.form.deptCheckStrictly = value ? true: false;
+      }
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      this.getMenuTreeselect();
+      this.open = true;
+      this.title = "娣诲姞瑙掕壊";
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const roleId = row.roleId || this.ids
+      const roleMenu = this.getRoleMenuTreeselect(roleId);
+      getRole(roleId).then(response => {
+        this.form = response.data;
+        this.open = true;
+        this.$nextTick(() => {
+          roleMenu.then(res => {
+            let checkedKeys = res.checkedKeys
+            checkedKeys.forEach((v) => {
+                this.$nextTick(()=>{
+                    this.$refs.menu.setChecked(v, true ,false);
+                })
+            })
+          });
+        });
+      });
+      this.title = "淇敼瑙掕壊";
+    },
+    /** 閫夋嫨瑙掕壊鏉冮檺鑼冨洿瑙﹀彂 */
+    dataScopeSelectChange(value) {
+      if(value !== '2') {
+        this.$refs.dept.setCheckedKeys([]);
+      }
+    },
+    /** 鍒嗛厤鏁版嵁鏉冮檺鎿嶄綔 */
+    handleDataScope(row) {
+      this.reset();
+      const deptTreeSelect = this.getDeptTree(row.roleId);
+      getRole(row.roleId).then(response => {
+        this.form = response.data;
+        this.openDataScope = true;
+        this.$nextTick(() => {
+          deptTreeSelect.then(res => {
+            this.$refs.dept.setCheckedKeys(res.checkedKeys);
+          });
+        });
+      });
+      this.title = "鍒嗛厤鏁版嵁鏉冮檺";
+    },
+    /** 鍒嗛厤鐢ㄦ埛鎿嶄綔 */
+    handleAuthUser: function(row) {
+      const roleId = row.roleId;
+      this.$router.push("/system/role-auth/user/" + roleId);
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.roleId != undefined) {
+            this.form.menuIds = this.getMenuAllCheckedKeys();
+            updateRole(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            this.form.menuIds = this.getMenuAllCheckedKeys();
+            addRole(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鎻愪氦鎸夐挳锛堟暟鎹潈闄愶級 */
+    submitDataScope: function() {
+      if (this.form.roleId != undefined) {
+        this.form.deptIds = this.getDeptAllCheckedKeys();
+        dataScope(this.form).then(response => {
+          this.$modal.msgSuccess("淇敼鎴愬姛");
+          this.openDataScope = false;
+          this.getList();
+        });
+      }
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const roleIds = row.roleId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎瑙掕壊缂栧彿涓�"' + roleIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delRole(roleIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/role/export', {
+        ...this.queryParams
+      }, `role_${new Date().getTime()}.xlsx`)
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/role/selectUser.vue b/ruoyi-ui/src/views/system/role/selectUser.vue
new file mode 100644
index 0000000..10a5365
--- /dev/null
+++ b/ruoyi-ui/src/views/system/role/selectUser.vue
@@ -0,0 +1,136 @@
+<template>
+  <!-- 鎺堟潈鐢ㄦ埛 -->
+  <el-dialog title="閫夋嫨鐢ㄦ埛" :visible.sync="visible" width="800px" top="5vh" append-to-body>
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
+      <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+        <el-input
+          v-model="queryParams.userName"
+          placeholder="璇疯緭鍏ョ敤鎴峰悕绉�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+        <el-input
+          v-model="queryParams.phonenumber"
+          placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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>
+      <el-table @row-click="clickRow" ref="table" :data="userList" @selection-change="handleSelectionChange" height="260px">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column label="鐢ㄦ埛鍚嶇О" prop="userName" :show-overflow-tooltip="true" />
+        <el-table-column label="鐢ㄦ埛鏄电О" prop="nickName" :show-overflow-tooltip="true" />
+        <el-table-column label="閭" prop="email" :show-overflow-tooltip="true" />
+        <el-table-column label="鎵嬫満" prop="phonenumber" :show-overflow-tooltip="true" />
+        <el-table-column label="鐘舵��" align="center" prop="status">
+          <template slot-scope="scope">
+            <dict-tag :options="dict.type.sys_normal_disable" :value="scope.row.status"/>
+          </template>
+        </el-table-column>
+        <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+          <template slot-scope="scope">
+            <span>{{ parseTime(scope.row.createTime) }}</span>
+          </template>
+        </el-table-column>
+      </el-table>
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="handleSelectUser">纭� 瀹�</el-button>
+      <el-button @click="visible = false">鍙� 娑�</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { unallocatedUserList, authUserSelectAll } from "@/api/system/role";
+export default {
+  dicts: ['sys_normal_disable'],
+  props: {
+    // 瑙掕壊缂栧彿
+    roleId: {
+      type: [Number, String]
+    }
+  },
+  data() {
+    return {
+      // 閬僵灞�
+      visible: false,
+      // 閫変腑鏁扮粍鍊�
+      userIds: [],
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鏈巿鏉冪敤鎴锋暟鎹�
+      userList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        roleId: undefined,
+        userName: undefined,
+        phonenumber: undefined
+      }
+    };
+  },
+  methods: {
+    // 鏄剧ず寮规
+    show() {
+      this.queryParams.roleId = this.roleId;
+      this.getList();
+      this.visible = true;
+    },
+    clickRow(row) {
+      this.$refs.table.toggleRowSelection(row);
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.userIds = selection.map(item => item.userId);
+    },
+    // 鏌ヨ琛ㄦ暟鎹�
+    getList() {
+      unallocatedUserList(this.queryParams).then(res => {
+        this.userList = res.rows;
+        this.total = res.total;
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 閫夋嫨鎺堟潈鐢ㄦ埛鎿嶄綔 */
+    handleSelectUser() {
+      const roleId = this.queryParams.roleId;
+      const userIds = this.userIds.join(",");
+      if (userIds == "") {
+        this.$modal.msgError("璇烽�夋嫨瑕佸垎閰嶇殑鐢ㄦ埛");
+        return;
+      }
+      authUserSelectAll({ roleId: roleId, userIds: userIds }).then(res => {
+        this.$modal.msgSuccess(res.msg);
+        this.visible = false;
+        this.$emit("ok");
+      }); 
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/user/authRole.vue b/ruoyi-ui/src/views/system/user/authRole.vue
new file mode 100644
index 0000000..943710e
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/authRole.vue
@@ -0,0 +1,117 @@
+<template>
+  <div class="app-container">
+    <h4 class="form-header h4">鍩烘湰淇℃伅</h4>
+    <el-form ref="form" :model="form" label-width="80px">
+      <el-row>
+        <el-col :span="8" :offset="2">
+          <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName">
+            <el-input v-model="form.nickName" disabled />
+          </el-form-item>
+        </el-col>
+        <el-col :span="8" :offset="2">
+          <el-form-item label="鐧诲綍璐﹀彿" prop="userName">
+            <el-input  v-model="form.userName" disabled />
+          </el-form-item>
+        </el-col>
+      </el-row>
+    </el-form>
+
+    <h4 class="form-header h4">瑙掕壊淇℃伅</h4>
+    <el-table v-loading="loading" :row-key="getRowKey" @row-click="clickRow" ref="table" @selection-change="handleSelectionChange" :data="roles.slice((pageNum-1)*pageSize,pageNum*pageSize)">
+      <el-table-column label="搴忓彿" type="index" align="center">
+        <template slot-scope="scope">
+          <span>{{(pageNum - 1) * pageSize + scope.$index + 1}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column type="selection" :reserve-selection="true" width="55"></el-table-column>
+      <el-table-column label="瑙掕壊缂栧彿" align="center" prop="roleId" />
+      <el-table-column label="瑙掕壊鍚嶇О" align="center" prop="roleName" />
+      <el-table-column label="鏉冮檺瀛楃" align="center" prop="roleKey" />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="180">
+        <template slot-scope="scope">
+          <span>{{ parseTime(scope.row.createTime) }}</span>
+        </template>
+      </el-table-column>
+    </el-table>
+
+    <pagination v-show="total>0" :total="total" :page.sync="pageNum" :limit.sync="pageSize" />
+
+    <el-form label-width="100px">
+      <el-form-item style="text-align: center;margin-left:-120px;margin-top:30px;">
+        <el-button type="primary" @click="submitForm()">鎻愪氦</el-button>
+        <el-button @click="close()">杩斿洖</el-button>
+      </el-form-item>
+    </el-form>
+  </div>
+</template>
+
+<script>
+import { getAuthRole, updateAuthRole } from "@/api/system/user";
+
+export default {
+  name: "AuthRole",
+  data() {
+    return {
+       // 閬僵灞�
+      loading: true,
+      // 鍒嗛〉淇℃伅
+      total: 0,
+      pageNum: 1,
+      pageSize: 10,
+      // 閫変腑瑙掕壊缂栧彿
+      roleIds:[],
+      // 瑙掕壊淇℃伅
+      roles: [],
+      // 鐢ㄦ埛淇℃伅
+      form: {}
+    };
+  },
+  created() {
+    const userId = this.$route.params && this.$route.params.userId;
+    if (userId) {
+      this.loading = true;
+      getAuthRole(userId).then((response) => {
+        this.form = response.user;
+        this.roles = response.roles;
+        this.total = this.roles.length;
+        this.$nextTick(() => {
+          this.roles.forEach((row) => {
+            if (row.flag) {
+              this.$refs.table.toggleRowSelection(row);
+            }
+          });
+        });
+        this.loading = false;
+      });
+    }
+  },
+  methods: {
+    /** 鍗曞嚮閫変腑琛屾暟鎹� */
+    clickRow(row) {
+      this.$refs.table.toggleRowSelection(row);
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.roleIds = selection.map((item) => item.roleId);
+    },
+    // 淇濆瓨閫変腑鐨勬暟鎹紪鍙�
+    getRowKey(row) {
+      return row.roleId;
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      const userId = this.form.userId;
+      const roleIds = this.roleIds.join(",");
+      updateAuthRole({ userId: userId, roleIds: roleIds }).then((response) => {
+        this.$modal.msgSuccess("鎺堟潈鎴愬姛");
+        this.close();
+      });
+    },
+    /** 鍏抽棴鎸夐挳 */
+    close() {
+      const obj = { path: "/system/user" };
+      this.$tab.closeOpenPage(obj);
+    },
+  },
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/index.vue b/ruoyi-ui/src/views/system/user/index.vue
new file mode 100644
index 0000000..1dbc2d1
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/index.vue
@@ -0,0 +1,553 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <splitpanes :horizontal="this.$store.getters.device === 'mobile'" class="default-theme">
+        <!--閮ㄩ棬鏁版嵁-->
+        <pane size="16">
+          <el-col>
+            <div class="head-container">
+              <el-input v-model="deptName" placeholder="璇疯緭鍏ラ儴闂ㄥ悕绉�" clearable size="small" prefix-icon="el-icon-search" style="margin-bottom: 20px" />
+            </div>
+            <div class="head-container">
+              <el-tree :data="deptOptions" :props="defaultProps" :expand-on-click-node="false" :filter-node-method="filterNode" ref="tree" node-key="id" default-expand-all highlight-current @node-click="handleNodeClick" />
+            </div>
+          </el-col>
+        </pane>
+        <!--鐢ㄦ埛鏁版嵁-->
+        <pane size="84">
+          <el-col>
+            <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+              <el-form-item label="鐢ㄦ埛鍚嶇О" prop="userName">
+                <el-input v-model="queryParams.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
+              </el-form-item>
+              <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+                <el-input v-model="queryParams.phonenumber" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" clearable style="width: 240px" @keyup.enter.native="handleQuery" />
+              </el-form-item>
+              <el-form-item label="鐘舵��" prop="status">
+                <el-select v-model="queryParams.status" placeholder="鐢ㄦ埛鐘舵��" clearable style="width: 240px">
+                  <el-option v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.label" :value="dict.value" />
+                </el-select>
+              </el-form-item>
+              <el-form-item label="鍒涘缓鏃堕棿">
+                <el-date-picker v-model="dateRange" style="width: 240px" value-format="yyyy-MM-dd" type="daterange" range-separator="-" start-placeholder="寮�濮嬫棩鏈�" end-placeholder="缁撴潫鏃ユ湡"></el-date-picker>
+              </el-form-item>
+              <el-form-item>
+                <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+                <el-button 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="['system:user: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="['system:user: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="['system:user:remove']">鍒犻櫎</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button type="info" plain icon="el-icon-upload2" size="mini" @click="handleImport" v-hasPermi="['system:user:import']">瀵煎叆</el-button>
+              </el-col>
+              <el-col :span="1.5">
+                <el-button type="warning" plain icon="el-icon-download" size="mini" @click="handleExport" v-hasPermi="['system:user:export']">瀵煎嚭</el-button>
+              </el-col>
+              <right-toolbar :showSearch.sync="showSearch" @queryTable="getList" :columns="columns"></right-toolbar>
+            </el-row>
+
+            <el-table v-loading="loading" :data="userList" @selection-change="handleSelectionChange">
+              <el-table-column type="selection" width="50" align="center" />
+              <el-table-column label="鐢ㄦ埛缂栧彿" align="center" key="userId" prop="userId" v-if="columns[0].visible" />
+              <el-table-column label="鐢ㄦ埛鍚嶇О" align="center" key="userName" prop="userName" v-if="columns[1].visible" :show-overflow-tooltip="true" />
+              <el-table-column label="鐢ㄦ埛鏄电О" align="center" key="nickName" prop="nickName" v-if="columns[2].visible" :show-overflow-tooltip="true" />
+              <el-table-column label="閮ㄩ棬" align="center" key="deptName" prop="dept.deptName" v-if="columns[3].visible" :show-overflow-tooltip="true" />
+              <el-table-column label="鎵嬫満鍙风爜" align="center" key="phonenumber" prop="phonenumber" v-if="columns[4].visible" width="120" />
+              <el-table-column label="鐘舵��" align="center" key="status" v-if="columns[5].visible">
+                <template slot-scope="scope">
+                  <el-switch v-model="scope.row.status" active-value="0" inactive-value="1" @change="handleStatusChange(scope.row)"></el-switch>
+                </template>
+              </el-table-column>
+              <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" v-if="columns[6].visible" width="160">
+                <template slot-scope="scope">
+                  <span>{{ parseTime(scope.row.createTime) }}</span>
+                </template>
+              </el-table-column>
+              <el-table-column label="鎿嶄綔" align="center" width="160" class-name="small-padding fixed-width">
+                <template slot-scope="scope" v-if="scope.row.userId !== 1">
+                  <el-button size="mini" type="text" icon="el-icon-edit" @click="handleUpdate(scope.row)" v-hasPermi="['system:user:edit']">淇敼</el-button>
+                  <el-button size="mini" type="text" icon="el-icon-delete" @click="handleDelete(scope.row)" v-hasPermi="['system:user:remove']">鍒犻櫎</el-button>
+                  <el-dropdown size="mini" @command="(command) => handleCommand(command, scope.row)" v-hasPermi="['system:user:resetPwd', 'system:user:edit']">
+                    <el-button size="mini" type="text" icon="el-icon-d-arrow-right">鏇村</el-button>
+                    <el-dropdown-menu slot="dropdown">
+                      <el-dropdown-item command="handleResetPwd" icon="el-icon-key" v-hasPermi="['system:user:resetPwd']">閲嶇疆瀵嗙爜</el-dropdown-item>
+                      <el-dropdown-item command="handleAuthRole" icon="el-icon-circle-check" v-hasPermi="['system:user:edit']">鍒嗛厤瑙掕壊</el-dropdown-item>
+                    </el-dropdown-menu>
+                  </el-dropdown>
+                </template>
+              </el-table-column>
+            </el-table>
+
+            <pagination v-show="total > 0" :total="total" :page.sync="queryParams.pageNum" :limit.sync="queryParams.pageSize" @pagination="getList" />
+          </el-col>
+        </pane>
+      </splitpanes>
+    </el-row>
+
+    <!-- 娣诲姞鎴栦慨鏀圭敤鎴烽厤缃璇濇 -->
+    <el-dialog :title="title" :visible.sync="open" width="600px" append-to-body>
+      <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName">
+              <el-input v-model="form.nickName" placeholder="璇疯緭鍏ョ敤鎴锋樀绉�" maxlength="30" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="褰掑睘閮ㄩ棬" prop="deptId">
+              <treeselect v-model="form.deptId" :options="enabledDeptOptions" :show-count="true" placeholder="璇烽�夋嫨褰掑睘閮ㄩ棬" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+              <el-input v-model="form.phonenumber" placeholder="璇疯緭鍏ユ墜鏈哄彿鐮�" maxlength="11" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="閭" prop="email">
+              <el-input v-model="form.email" placeholder="璇疯緭鍏ラ偖绠�" maxlength="50" />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item v-if="form.userId == undefined" label="鐢ㄦ埛鍚嶇О" prop="userName">
+              <el-input v-model="form.userName" placeholder="璇疯緭鍏ョ敤鎴峰悕绉�" maxlength="30" />
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item v-if="form.userId == undefined" label="鐢ㄦ埛瀵嗙爜" prop="password">
+              <el-input v-model="form.password" placeholder="璇疯緭鍏ョ敤鎴峰瘑鐮�" type="password" maxlength="20" show-password />
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="鐢ㄦ埛鎬у埆">
+              <el-select v-model="form.sex" placeholder="璇烽�夋嫨鎬у埆">
+                <el-option v-for="dict in dict.type.sys_user_sex" :key="dict.value" :label="dict.label" :value="dict.value"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="鐘舵��">
+              <el-radio-group v-model="form.status">
+                <el-radio v-for="dict in dict.type.sys_normal_disable" :key="dict.value" :label="dict.value">{{ dict.label }}</el-radio>
+              </el-radio-group>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="12">
+            <el-form-item label="宀椾綅">
+              <el-select v-model="form.postIds" multiple placeholder="璇烽�夋嫨宀椾綅">
+                <el-option v-for="item in postOptions" :key="item.postId" :label="item.postName" :value="item.postId" :disabled="item.status == 1" ></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+          <el-col :span="12">
+            <el-form-item label="瑙掕壊">
+              <el-select v-model="form.roleIds" multiple placeholder="璇烽�夋嫨瑙掕壊">
+                <el-option v-for="item in roleOptions" :key="item.roleId" :label="item.roleName" :value="item.roleId" :disabled="item.status == 1"></el-option>
+              </el-select>
+            </el-form-item>
+          </el-col>
+        </el-row>
+        <el-row>
+          <el-col :span="24">
+            <el-form-item label="澶囨敞">
+              <el-input v-model="form.remark" type="textarea" placeholder="璇疯緭鍏ュ唴瀹�"></el-input>
+            </el-form-item>
+          </el-col>
+        </el-row>
+      </el-form>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitForm">纭� 瀹�</el-button>
+        <el-button @click="cancel">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+
+    <!-- 鐢ㄦ埛瀵煎叆瀵硅瘽妗� -->
+    <el-dialog :title="upload.title" :visible.sync="upload.open" width="400px" append-to-body>
+      <el-upload ref="upload" :limit="1" accept=".xlsx, .xls" :headers="upload.headers" :action="upload.url + '?updateSupport=' + upload.updateSupport" :disabled="upload.isUploading" :on-progress="handleFileUploadProgress" :on-success="handleFileSuccess" :auto-upload="false" drag>
+        <i class="el-icon-upload"></i>
+        <div class="el-upload__text">灏嗘枃浠舵嫋鍒版澶勶紝鎴�<em>鐐瑰嚮涓婁紶</em></div>
+        <div class="el-upload__tip text-center" slot="tip">
+          <div class="el-upload__tip" slot="tip">
+            <el-checkbox v-model="upload.updateSupport" />鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
+          </div>
+          <span>浠呭厑璁稿鍏ls銆亁lsx鏍煎紡鏂囦欢銆�</span>
+          <el-link type="primary" :underline="false" style="font-size: 12px; vertical-align: baseline" @click="importTemplate">涓嬭浇妯℃澘</el-link>
+        </div>
+      </el-upload>
+      <div slot="footer" class="dialog-footer">
+        <el-button type="primary" @click="submitFileForm">纭� 瀹�</el-button>
+        <el-button @click="upload.open = false">鍙� 娑�</el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import { listUser, getUser, delUser, addUser, updateUser, resetUserPwd, changeUserStatus, deptTreeSelect } from "@/api/system/user";
+import { getToken } from "@/utils/auth";
+import Treeselect from "@riophae/vue-treeselect";
+import "@riophae/vue-treeselect/dist/vue-treeselect.css";
+import { Splitpanes, Pane } from "splitpanes";
+import "splitpanes/dist/splitpanes.css";
+
+export default {
+  name: "User",
+  dicts: ['sys_normal_disable', 'sys_user_sex'],
+  components: { Treeselect, Splitpanes, Pane },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 鐢ㄦ埛琛ㄦ牸鏁版嵁
+      userList: null,
+      // 寮瑰嚭灞傛爣棰�
+      title: "",
+      // 鎵�鏈夐儴闂ㄦ爲閫夐」
+      deptOptions: undefined,
+      // 杩囨护鎺夊凡绂佺敤閮ㄩ棬鏍戦�夐」
+      enabledDeptOptions: undefined,
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 閮ㄩ棬鍚嶇О
+      deptName: undefined,
+      // 榛樿瀵嗙爜
+      initPassword: undefined,
+      // 鏃ユ湡鑼冨洿
+      dateRange: [],
+      // 宀椾綅閫夐」
+      postOptions: [],
+      // 瑙掕壊閫夐」
+      roleOptions: [],
+      // 琛ㄥ崟鍙傛暟
+      form: {},
+      defaultProps: {
+        children: "children",
+        label: "label"
+      },
+      // 鐢ㄦ埛瀵煎叆鍙傛暟
+      upload: {
+        // 鏄惁鏄剧ず寮瑰嚭灞傦紙鐢ㄦ埛瀵煎叆锛�
+        open: false,
+        // 寮瑰嚭灞傛爣棰橈紙鐢ㄦ埛瀵煎叆锛�
+        title: "",
+        // 鏄惁绂佺敤涓婁紶
+        isUploading: false,
+        // 鏄惁鏇存柊宸茬粡瀛樺湪鐨勭敤鎴锋暟鎹�
+        updateSupport: 0,
+        // 璁剧疆涓婁紶鐨勮姹傚ご閮�
+        headers: { Authorization: "Bearer " + getToken() },
+        // 涓婁紶鐨勫湴鍧�
+        url: process.env.VUE_APP_BASE_API + "/system/user/importData"
+      },
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        userName: undefined,
+        phonenumber: undefined,
+        status: undefined,
+        deptId: undefined
+      },
+      // 鍒椾俊鎭�
+      columns: [
+        { key: 0, label: `鐢ㄦ埛缂栧彿`, visible: true },
+        { key: 1, label: `鐢ㄦ埛鍚嶇О`, visible: true },
+        { key: 2, label: `鐢ㄦ埛鏄电О`, visible: true },
+        { key: 3, label: `閮ㄩ棬`, visible: true },
+        { key: 4, label: `鎵嬫満鍙风爜`, visible: true },
+        { key: 5, label: `鐘舵�乣, visible: true },
+        { key: 6, label: `鍒涘缓鏃堕棿`, visible: true }
+      ],
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        userName: [
+          { required: true, message: "鐢ㄦ埛鍚嶇О涓嶈兘涓虹┖", trigger: "blur" },
+          { min: 2, max: 20, message: '鐢ㄦ埛鍚嶇О闀垮害蹇呴』浠嬩簬 2 鍜� 20 涔嬮棿', trigger: 'blur' }
+        ],
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        password: [
+          { required: true, message: "鐢ㄦ埛瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          { min: 5, max: 20, message: '鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿', trigger: 'blur' },
+          { pattern: /^[^<>"'|\\]+$/, message: "涓嶈兘鍖呭惈闈炴硶瀛楃锛�< > \" ' \\\ |", trigger: "blur" }
+        ],
+        email: [
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phonenumber: [
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  watch: {
+    // 鏍规嵁鍚嶇О绛涢�夐儴闂ㄦ爲
+    deptName(val) {
+      this.$refs.tree.filter(val);
+    }
+  },
+  created() {
+    this.getList();
+    this.getDeptTree();
+    this.getConfigKey("sys.user.initPassword").then(response => {
+      this.initPassword = response.msg;
+    });
+  },
+  methods: {
+    /** 鏌ヨ鐢ㄦ埛鍒楄〃 */
+    getList() {
+      this.loading = true;
+      listUser(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.userList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鏌ヨ閮ㄩ棬涓嬫媺鏍戠粨鏋� */
+    getDeptTree() {
+      deptTreeSelect().then(response => {
+        this.deptOptions = response.data;
+        this.enabledDeptOptions = this.filterDisabledDept(JSON.parse(JSON.stringify(response.data)));
+      });
+    },
+    // 杩囨护绂佺敤鐨勯儴闂�
+    filterDisabledDept(deptList) {
+      return deptList.filter(dept => {
+        if (dept.disabled) {
+          return false;
+        }
+        if (dept.children && dept.children.length) {
+          dept.children = this.filterDisabledDept(dept.children);
+        }
+        return true;
+      });
+    },
+    // 绛涢�夎妭鐐�
+    filterNode(value, data) {
+      if (!value) return true;
+      return data.label.indexOf(value) !== -1;
+    },
+    // 鑺傜偣鍗曞嚮浜嬩欢
+    handleNodeClick(data) {
+      this.queryParams.deptId = data.id;
+      this.handleQuery();
+    },
+    // 鐢ㄦ埛鐘舵�佷慨鏀�
+    handleStatusChange(row) {
+      let text = row.status === "0" ? "鍚敤" : "鍋滅敤";
+      this.$modal.confirm('纭瑕�"' + text + '""' + row.userName + '"鐢ㄦ埛鍚楋紵').then(function() {
+        return changeUserStatus(row.userId, row.status);
+      }).then(() => {
+        this.$modal.msgSuccess(text + "鎴愬姛");
+      }).catch(function() {
+        row.status = row.status === "0" ? "1" : "0";
+      });
+    },
+    // 鍙栨秷鎸夐挳
+    cancel() {
+      this.open = false;
+      this.reset();
+    },
+    // 琛ㄥ崟閲嶇疆
+    reset() {
+      this.form = {
+        userId: undefined,
+        deptId: undefined,
+        userName: undefined,
+        nickName: undefined,
+        password: undefined,
+        phonenumber: undefined,
+        email: undefined,
+        sex: undefined,
+        status: "0",
+        remark: undefined,
+        postIds: [],
+        roleIds: []
+      };
+      this.resetForm("form");
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.queryParams.deptId = undefined;
+      this.$refs.tree.setCurrentKey(null);
+      this.handleQuery();
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.userId);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    // 鏇村鎿嶄綔瑙﹀彂
+    handleCommand(command, row) {
+      switch (command) {
+        case "handleResetPwd":
+          this.handleResetPwd(row);
+          break;
+        case "handleAuthRole":
+          this.handleAuthRole(row);
+          break;
+        default:
+          break;
+      }
+    },
+    /** 鏂板鎸夐挳鎿嶄綔 */
+    handleAdd() {
+      this.reset();
+      getUser().then(response => {
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.open = true;
+        this.title = "娣诲姞鐢ㄦ埛";
+        this.form.password = this.initPassword;
+      });
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleUpdate(row) {
+      this.reset();
+      const userId = row.userId || this.ids;
+      getUser(userId).then(response => {
+        this.form = response.data;
+        this.postOptions = response.posts;
+        this.roleOptions = response.roles;
+        this.$set(this.form, "postIds", response.postIds);
+        this.$set(this.form, "roleIds", response.roleIds);
+        this.open = true;
+        this.title = "淇敼鐢ㄦ埛";
+        this.form.password = "";
+      });
+    },
+    /** 閲嶇疆瀵嗙爜鎸夐挳鎿嶄綔 */
+    handleResetPwd(row) {
+      this.$prompt('璇疯緭鍏�"' + row.userName + '"鐨勬柊瀵嗙爜', "鎻愮ず", {
+        confirmButtonText: "纭畾",
+        cancelButtonText: "鍙栨秷",
+        closeOnClickModal: false,
+        inputPattern: /^.{5,20}$/,
+        inputErrorMessage: "鐢ㄦ埛瀵嗙爜闀垮害蹇呴』浠嬩簬 5 鍜� 20 涔嬮棿",
+        inputValidator: (value) => {
+          if (/<|>|"|'|\||\\/.test(value)) {
+            return "涓嶈兘鍖呭惈闈炴硶瀛楃锛�< > \" ' \\\ |"
+          }
+        },
+      }).then(({ value }) => {
+          resetUserPwd(row.userId, value).then(response => {
+            this.$modal.msgSuccess("淇敼鎴愬姛锛屾柊瀵嗙爜鏄細" + value);
+          });
+        }).catch(() => {});
+    },
+    /** 鍒嗛厤瑙掕壊鎿嶄綔 */
+    handleAuthRole: function(row) {
+      const userId = row.userId;
+      this.$router.push("/system/user-auth/role/" + userId);
+    },
+    /** 鎻愪氦鎸夐挳 */
+    submitForm: function() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          if (this.form.userId != undefined) {
+            updateUser(this.form).then(response => {
+              this.$modal.msgSuccess("淇敼鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          } else {
+            addUser(this.form).then(response => {
+              this.$modal.msgSuccess("鏂板鎴愬姛");
+              this.open = false;
+              this.getList();
+            });
+          }
+        }
+      });
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const userIds = row.userId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎鐢ㄦ埛缂栧彿涓�"' + userIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delUser(userIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 瀵煎嚭鎸夐挳鎿嶄綔 */
+    handleExport() {
+      this.download('system/user/export', {
+        ...this.queryParams
+      }, `user_${new Date().getTime()}.xlsx`)
+    },
+    /** 瀵煎叆鎸夐挳鎿嶄綔 */
+    handleImport() {
+      this.upload.title = "鐢ㄦ埛瀵煎叆";
+      this.upload.open = true;
+    },
+    /** 涓嬭浇妯℃澘鎿嶄綔 */
+    importTemplate() {
+      this.download('system/user/importTemplate', {
+      }, `user_template_${new Date().getTime()}.xlsx`)
+    },
+    // 鏂囦欢涓婁紶涓鐞�
+    handleFileUploadProgress(event, file, fileList) {
+      this.upload.isUploading = true;
+    },
+    // 鏂囦欢涓婁紶鎴愬姛澶勭悊
+    handleFileSuccess(response, file, fileList) {
+      this.upload.open = false;
+      this.upload.isUploading = false;
+      this.$refs.upload.clearFiles();
+      this.$alert("<div style='overflow: auto;overflow-x: hidden;max-height: 70vh;padding: 10px 20px 0;'>" + response.msg + "</div>", "瀵煎叆缁撴灉", { dangerouslyUseHTMLString: true });
+      this.getList();
+    },
+    // 鎻愪氦涓婁紶鏂囦欢
+    submitFileForm() {
+      this.$refs.upload.submit();
+    }
+  }
+};
+</script>
\ No newline at end of file
diff --git a/ruoyi-ui/src/views/system/user/profile/index.vue b/ruoyi-ui/src/views/system/user/profile/index.vue
new file mode 100644
index 0000000..529c564
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/index.vue
@@ -0,0 +1,91 @@
+<template>
+  <div class="app-container">
+    <el-row :gutter="20">
+      <el-col :span="6" :xs="24">
+        <el-card class="box-card">
+          <div slot="header" class="clearfix">
+            <span>涓汉淇℃伅</span>
+          </div>
+          <div>
+            <div class="text-center">
+              <userAvatar />
+            </div>
+            <ul class="list-group list-group-striped">
+              <li class="list-group-item">
+                <svg-icon icon-class="user" />鐢ㄦ埛鍚嶇О
+                <div class="pull-right">{{ user.userName }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="phone" />鎵嬫満鍙风爜
+                <div class="pull-right">{{ user.phonenumber }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="email" />鐢ㄦ埛閭
+                <div class="pull-right">{{ user.email }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="tree" />鎵�灞為儴闂�
+                <div class="pull-right" v-if="user.dept">{{ user.dept.deptName }} / {{ postGroup }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="peoples" />鎵�灞炶鑹�
+                <div class="pull-right">{{ roleGroup }}</div>
+              </li>
+              <li class="list-group-item">
+                <svg-icon icon-class="date" />鍒涘缓鏃ユ湡
+                <div class="pull-right">{{ user.createTime }}</div>
+              </li>
+            </ul>
+          </div>
+        </el-card>
+      </el-col>
+      <el-col :span="18" :xs="24">
+        <el-card>
+          <div slot="header" class="clearfix">
+            <span>鍩烘湰璧勬枡</span>
+          </div>
+          <el-tabs v-model="activeTab">
+            <el-tab-pane label="鍩烘湰璧勬枡" name="userinfo">
+              <userInfo :user="user" />
+            </el-tab-pane>
+            <el-tab-pane label="淇敼瀵嗙爜" name="resetPwd">
+              <resetPwd />
+            </el-tab-pane>
+          </el-tabs>
+        </el-card>
+      </el-col>
+    </el-row>
+  </div>
+</template>
+
+<script>
+import userAvatar from "./userAvatar";
+import userInfo from "./userInfo";
+import resetPwd from "./resetPwd";
+import { getUserProfile } from "@/api/system/user";
+
+export default {
+  name: "Profile",
+  components: { userAvatar, userInfo, resetPwd },
+  data() {
+    return {
+      user: {},
+      roleGroup: {},
+      postGroup: {},
+      activeTab: "userinfo"
+    };
+  },
+  created() {
+    this.getUser();
+  },
+  methods: {
+    getUser() {
+      getUserProfile().then(response => {
+        this.user = response.data;
+        this.roleGroup = response.roleGroup;
+        this.postGroup = response.postGroup;
+      });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/resetPwd.vue b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
new file mode 100644
index 0000000..f329e6e
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/resetPwd.vue
@@ -0,0 +1,69 @@
+<template>
+  <el-form ref="form" :model="user" :rules="rules" label-width="80px">
+    <el-form-item label="鏃у瘑鐮�" prop="oldPassword">
+      <el-input v-model="user.oldPassword" placeholder="璇疯緭鍏ユ棫瀵嗙爜" type="password" show-password/>
+    </el-form-item>
+    <el-form-item label="鏂板瘑鐮�" prop="newPassword">
+      <el-input v-model="user.newPassword" placeholder="璇疯緭鍏ユ柊瀵嗙爜" type="password" show-password/>
+    </el-form-item>
+    <el-form-item label="纭瀵嗙爜" prop="confirmPassword">
+      <el-input v-model="user.confirmPassword" placeholder="璇风‘璁ゆ柊瀵嗙爜" type="password" show-password/>
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" size="mini" @click="submit">淇濆瓨</el-button>
+      <el-button type="danger" size="mini" @click="close">鍏抽棴</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import { updateUserPwd } from "@/api/system/user";
+
+export default {
+  data() {
+    const equalToPassword = (rule, value, callback) => {
+      if (this.user.newPassword !== value) {
+        callback(new Error("涓ゆ杈撳叆鐨勫瘑鐮佷笉涓�鑷�"));
+      } else {
+        callback();
+      }
+    };
+    return {
+      user: {
+        oldPassword: undefined,
+        newPassword: undefined,
+        confirmPassword: undefined
+      },
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        oldPassword: [
+          { required: true, message: "鏃у瘑鐮佷笉鑳戒负绌�", trigger: "blur" }
+        ],
+        newPassword: [
+          { required: true, message: "鏂板瘑鐮佷笉鑳戒负绌�", trigger: "blur" },
+          { min: 6, max: 20, message: "闀垮害鍦� 6 鍒� 20 涓瓧绗�", trigger: "blur" },
+          { pattern: /^[^<>"'|\\]+$/, message: "涓嶈兘鍖呭惈闈炴硶瀛楃锛�< > \" ' \\\ |", trigger: "blur" }
+        ],
+        confirmPassword: [
+          { required: true, message: "纭瀵嗙爜涓嶈兘涓虹┖", trigger: "blur" },
+          { required: true, validator: equalToPassword, trigger: "blur" }
+        ]
+      }
+    };
+  },
+  methods: {
+    submit() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          updateUserPwd(this.user.oldPassword, this.user.newPassword).then(response => {
+            this.$modal.msgSuccess("淇敼鎴愬姛");
+          });
+        }
+      });
+    },
+    close() {
+      this.$tab.closePage();
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/system/user/profile/userAvatar.vue b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
new file mode 100644
index 0000000..cbf3ca1
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/userAvatar.vue
@@ -0,0 +1,184 @@
+<template>
+  <div>
+    <div class="user-info-head" @click="editCropper()"><img v-bind:src="options.img" title="鐐瑰嚮涓婁紶澶村儚" class="img-circle img-lg" /></div>
+    <el-dialog :title="title" :visible.sync="open" width="800px" append-to-body @opened="modalOpened"  @close="closeDialog">
+      <el-row>
+        <el-col :xs="24" :md="12" :style="{height: '350px'}">
+          <vue-cropper
+            ref="cropper"
+            :img="options.img"
+            :info="true"
+            :autoCrop="options.autoCrop"
+            :autoCropWidth="options.autoCropWidth"
+            :autoCropHeight="options.autoCropHeight"
+            :fixedBox="options.fixedBox"
+            :outputType="options.outputType"
+            @realTime="realTime"
+            v-if="visible"
+          />
+        </el-col>
+        <el-col :xs="24" :md="12" :style="{height: '350px'}">
+          <div class="avatar-upload-preview">
+            <img :src="previews.url" :style="previews.img" />
+          </div>
+        </el-col>
+      </el-row>
+      <br />
+      <el-row>
+        <el-col :lg="2" :sm="3" :xs="3">
+          <el-upload action="#" :http-request="requestUpload" :show-file-list="false" :before-upload="beforeUpload">
+            <el-button size="small">
+              閫夋嫨
+              <i class="el-icon-upload el-icon--right"></i>
+            </el-button>
+          </el-upload>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 2}" :sm="2" :xs="2">
+          <el-button icon="el-icon-plus" size="small" @click="changeScale(1)"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+          <el-button icon="el-icon-minus" size="small" @click="changeScale(-1)"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+          <el-button icon="el-icon-refresh-left" size="small" @click="rotateLeft()"></el-button>
+        </el-col>
+        <el-col :lg="{span: 1, offset: 1}" :sm="2" :xs="2">
+          <el-button icon="el-icon-refresh-right" size="small" @click="rotateRight()"></el-button>
+        </el-col>
+        <el-col :lg="{span: 2, offset: 6}" :sm="2" :xs="2">
+          <el-button type="primary" size="small" @click="uploadImg()">鎻� 浜�</el-button>
+        </el-col>
+      </el-row>
+    </el-dialog>
+  </div>
+</template>
+
+<script>
+import store from "@/store";
+import { VueCropper } from "vue-cropper";
+import { uploadAvatar } from "@/api/system/user";
+import { debounce } from '@/utils'
+
+export default {
+  components: { VueCropper },
+  data() {
+    return {
+      // 鏄惁鏄剧ず寮瑰嚭灞�
+      open: false,
+      // 鏄惁鏄剧ずcropper
+      visible: false,
+      // 寮瑰嚭灞傛爣棰�
+      title: "淇敼澶村儚",
+      options: {
+        img: store.getters.avatar,  //瑁佸壀鍥剧墖鐨勫湴鍧�
+        autoCrop: true,             // 鏄惁榛樿鐢熸垚鎴浘妗�
+        autoCropWidth: 200,         // 榛樿鐢熸垚鎴浘妗嗗搴�
+        autoCropHeight: 200,        // 榛樿鐢熸垚鎴浘妗嗛珮搴�
+        fixedBox: true,             // 鍥哄畾鎴浘妗嗗ぇ灏� 涓嶅厑璁告敼鍙�
+        outputType:"png",           // 榛樿鐢熸垚鎴浘涓篜NG鏍煎紡
+        filename: 'avatar'          // 鏂囦欢鍚嶇О
+      },
+      previews: {},
+      resizeHandler: null
+    };
+  },
+  methods: {
+    // 缂栬緫澶村儚
+    editCropper() {
+      this.open = true;
+    },
+    // 鎵撳紑寮瑰嚭灞傜粨鏉熸椂鐨勫洖璋�
+    modalOpened() {
+      this.visible = true;
+      if (!this.resizeHandler) {
+        this.resizeHandler = debounce(() => {
+          this.refresh()
+        }, 100)
+      }
+      window.addEventListener("resize", this.resizeHandler)
+    },
+    // 鍒锋柊缁勪欢
+    refresh() {
+      this.$refs.cropper.refresh();
+    },
+    // 瑕嗙洊榛樿鐨勪笂浼犺涓�
+    requestUpload() {
+    },
+    // 鍚戝乏鏃嬭浆
+    rotateLeft() {
+      this.$refs.cropper.rotateLeft();
+    },
+    // 鍚戝彸鏃嬭浆
+    rotateRight() {
+      this.$refs.cropper.rotateRight();
+    },
+    // 鍥剧墖缂╂斁
+    changeScale(num) {
+      num = num || 1;
+      this.$refs.cropper.changeScale(num);
+    },
+    // 涓婁紶棰勫鐞�
+    beforeUpload(file) {
+      if (file.type.indexOf("image/") == -1) {
+        this.$modal.msgError("鏂囦欢鏍煎紡閿欒锛岃涓婁紶鍥剧墖绫诲瀷,濡傦細JPG锛孭NG鍚庣紑鐨勬枃浠躲��");
+      } else {
+        const reader = new FileReader();
+        reader.readAsDataURL(file);
+        reader.onload = () => {
+          this.options.img = reader.result;
+          this.options.filename = file.name;
+        };
+      }
+    },
+    // 涓婁紶鍥剧墖
+    uploadImg() {
+      this.$refs.cropper.getCropBlob(data => {
+        let formData = new FormData();
+        formData.append("avatarfile", data, this.options.filename);
+        uploadAvatar(formData).then(response => {
+          this.open = false;
+          this.options.img = process.env.VUE_APP_BASE_API + response.imgUrl;
+          store.commit('SET_AVATAR', this.options.img);
+          this.$modal.msgSuccess("淇敼鎴愬姛");
+          this.visible = false;
+        });
+      });
+    },
+    // 瀹炴椂棰勮
+    realTime(data) {
+      this.previews = data;
+    },
+    // 鍏抽棴绐楀彛
+    closeDialog() {
+      this.options.img = store.getters.avatar
+      this.visible = false;
+      window.removeEventListener("resize", this.resizeHandler)
+    }
+  }
+};
+</script>
+<style scoped lang="scss">
+.user-info-head {
+  position: relative;
+  display: inline-block;
+  height: 120px;
+}
+
+.user-info-head:hover:after {
+  content: '+';
+  position: absolute;
+  left: 0;
+  right: 0;
+  top: 0;
+  bottom: 0;
+  color: #eee;
+  background: rgba(0, 0, 0, 0.5);
+  font-size: 24px;
+  font-style: normal;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+  cursor: pointer;
+  line-height: 110px;
+  border-radius: 50%;
+}
+</style>
diff --git a/ruoyi-ui/src/views/system/user/profile/userInfo.vue b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
new file mode 100644
index 0000000..c970dc9
--- /dev/null
+++ b/ruoyi-ui/src/views/system/user/profile/userInfo.vue
@@ -0,0 +1,88 @@
+<template>
+  <el-form ref="form" :model="form" :rules="rules" label-width="80px">
+    <el-form-item label="鐢ㄦ埛鏄电О" prop="nickName">
+      <el-input v-model="form.nickName" maxlength="30" />
+    </el-form-item> 
+    <el-form-item label="鎵嬫満鍙风爜" prop="phonenumber">
+      <el-input v-model="form.phonenumber" maxlength="11" />
+    </el-form-item>
+    <el-form-item label="閭" prop="email">
+      <el-input v-model="form.email" maxlength="50" />
+    </el-form-item>
+    <el-form-item label="鎬у埆">
+      <el-radio-group v-model="form.sex">
+        <el-radio label="0">鐢�</el-radio>
+        <el-radio label="1">濂�</el-radio>
+      </el-radio-group>
+    </el-form-item>
+    <el-form-item>
+      <el-button type="primary" size="mini" @click="submit">淇濆瓨</el-button>
+      <el-button type="danger" size="mini" @click="close">鍏抽棴</el-button>
+    </el-form-item>
+  </el-form>
+</template>
+
+<script>
+import { updateUserProfile } from "@/api/system/user";
+
+export default {
+  props: {
+    user: {
+      type: Object
+    }
+  },
+  data() {
+    return {
+      form: {},
+      // 琛ㄥ崟鏍¢獙
+      rules: {
+        nickName: [
+          { required: true, message: "鐢ㄦ埛鏄电О涓嶈兘涓虹┖", trigger: "blur" }
+        ],
+        email: [
+          { required: true, message: "閭鍦板潃涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            type: "email",
+            message: "璇疯緭鍏ユ纭殑閭鍦板潃",
+            trigger: ["blur", "change"]
+          }
+        ],
+        phonenumber: [
+          { required: true, message: "鎵嬫満鍙风爜涓嶈兘涓虹┖", trigger: "blur" },
+          {
+            pattern: /^1[3|4|5|6|7|8|9][0-9]\d{8}$/,
+            message: "璇疯緭鍏ユ纭殑鎵嬫満鍙风爜",
+            trigger: "blur"
+          }
+        ]
+      }
+    };
+  },
+  watch: {
+    user: {
+      handler(user) {
+        if (user) {
+          this.form = { nickName: user.nickName, phonenumber: user.phonenumber, email: user.email, sex: user.sex };
+        }
+      },
+      immediate: true
+    }
+  },
+  methods: {
+    submit() {
+      this.$refs["form"].validate(valid => {
+        if (valid) {
+          updateUserProfile(this.form).then(response => {
+            this.$modal.msgSuccess("淇敼鎴愬姛");
+            this.user.phonenumber = this.form.phonenumber;
+            this.user.email = this.form.email;
+          });
+        }
+      });
+    },
+    close() {
+      this.$tab.closePage();
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
new file mode 100644
index 0000000..b5c2e2e
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/CodeTypeDialog.vue
@@ -0,0 +1,106 @@
+<template>
+  <div>
+    <el-dialog
+      v-bind="$attrs"
+      width="500px"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      v-on="$listeners"
+      @open="onOpen"
+      @close="onClose"
+    >
+      <el-row :gutter="15">
+        <el-form
+          ref="elForm"
+          :model="formData"
+          :rules="rules"
+          size="medium"
+          label-width="100px"
+        >
+          <el-col :span="24">
+            <el-form-item label="鐢熸垚绫诲瀷" prop="type">
+              <el-radio-group v-model="formData.type">
+                <el-radio-button
+                  v-for="(item, index) in typeOptions"
+                  :key="index"
+                  :label="item.value"
+                  :disabled="item.disabled"
+                >
+                  {{ item.label }}
+                </el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+            <el-form-item v-if="showFileName" label="鏂囦欢鍚�" prop="fileName">
+              <el-input v-model="formData.fileName" placeholder="璇疯緭鍏ユ枃浠跺悕" clearable />
+            </el-form-item>
+          </el-col>
+        </el-form>
+      </el-row>
+
+      <div slot="footer">
+        <el-button @click="close">
+          鍙栨秷
+        </el-button>
+        <el-button type="primary" @click="handleConfirm">
+          纭畾
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+export default {
+  inheritAttrs: false,
+  props: ['showFileName'],
+  data() {
+    return {
+      formData: {
+        fileName: undefined,
+        type: 'file'
+      },
+      rules: {
+        fileName: [{
+          required: true,
+          message: '璇疯緭鍏ユ枃浠跺悕',
+          trigger: 'blur'
+        }],
+        type: [{
+          required: true,
+          message: '鐢熸垚绫诲瀷涓嶈兘涓虹┖',
+          trigger: 'change'
+        }]
+      },
+      typeOptions: [{
+        label: '椤甸潰',
+        value: 'file'
+      }, {
+        label: '寮圭獥',
+        value: 'dialog'
+      }]
+    }
+  },
+  computed: {
+  },
+  watch: {},
+  mounted() {},
+  methods: {
+    onOpen() {
+      if (this.showFileName) {
+        this.formData.fileName = `${+new Date()}.vue`
+      }
+    },
+    onClose() {
+    },
+    close(e) {
+      this.$emit('update:visible', false)
+    },
+    handleConfirm() {
+      this.$refs.elForm.validate(valid => {
+        if (!valid) return
+        this.$emit('confirm', { ...this.formData })
+        this.close()
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/tool/build/DraggableItem.vue b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
new file mode 100644
index 0000000..e881778
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/DraggableItem.vue
@@ -0,0 +1,100 @@
+<script>
+import draggable from 'vuedraggable'
+import render from '@/utils/generator/render'
+
+const components = {
+  itemBtns(h, element, index, parent) {
+    const { copyItem, deleteItem } = this.$listeners
+    return [
+      <span class="drawing-item-copy" title="澶嶅埗" onClick={event => {
+        copyItem(element, parent); event.stopPropagation()
+      }}>
+        <i class="el-icon-copy-document" />
+      </span>,
+      <span class="drawing-item-delete" title="鍒犻櫎" onClick={event => {
+        deleteItem(index, parent); event.stopPropagation()
+      }}>
+        <i class="el-icon-delete" />
+      </span>
+    ]
+  }
+}
+const layouts = {
+  colFormItem(h, element, index, parent) {
+    const { activeItem } = this.$listeners
+    let className = this.activeId === element.formId ? 'drawing-item active-from-item' : 'drawing-item'
+    if (this.formConf.unFocusedComponentBorder) className += ' unfocus-bordered'
+    return (
+      <el-col span={element.span} class={className}
+        nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
+        <el-form-item label-width={element.labelWidth ? `${element.labelWidth}px` : null}
+          label={element.label} required={element.required}>
+          <render key={element.renderKey} conf={element} onInput={ event => {
+            this.$set(element, 'defaultValue', event)
+          }} />
+        </el-form-item>
+        {components.itemBtns.apply(this, arguments)}
+      </el-col>
+    )
+  },
+  rowFormItem(h, element, index, parent) {
+    const { activeItem } = this.$listeners
+    const className = this.activeId === element.formId ? 'drawing-row-item active-from-item' : 'drawing-row-item'
+    let child = renderChildren.apply(this, arguments)
+    if (element.type === 'flex') {
+      child = <el-row type={element.type} justify={element.justify} align={element.align}>
+              {child}
+            </el-row>
+    }
+    return (
+      <el-col span={element.span}>
+        <el-row gutter={element.gutter} class={className}
+          nativeOnClick={event => { activeItem(element); event.stopPropagation() }}>
+          <span class="component-name">{element.componentName}</span>
+          <draggable list={element.children} animation={340} group="componentsGroup" class="drag-wrapper">
+            {child}
+          </draggable>
+          {components.itemBtns.apply(this, arguments)}
+        </el-row>
+      </el-col>
+    )
+  }
+}
+
+function renderChildren(h, element, index, parent) {
+  if (!Array.isArray(element.children)) return null
+  return element.children.map((el, i) => {
+    const layout = layouts[el.layout]
+    if (layout) {
+      return layout.call(this, h, el, i, element.children)
+    }
+    return layoutIsNotFound()
+  })
+}
+
+function layoutIsNotFound() {
+  throw new Error(`娌℃湁涓�${this.element.layout}鍖归厤鐨刲ayout`)
+}
+
+export default {
+  components: {
+    render,
+    draggable
+  },
+  props: [
+    'element',
+    'index',
+    'drawingList',
+    'activeId',
+    'formConf'
+  ],
+  render(h) {
+    const layout = layouts[this.element.layout]
+
+    if (layout) {
+      return layout.call(this, h, this.element, this.index, this.drawingList)
+    }
+    return layoutIsNotFound()
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/tool/build/IconsDialog.vue b/ruoyi-ui/src/views/tool/build/IconsDialog.vue
new file mode 100644
index 0000000..958be50
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/IconsDialog.vue
@@ -0,0 +1,123 @@
+<template>
+  <div class="icon-dialog">
+    <el-dialog
+      v-bind="$attrs"
+      width="980px"
+      :modal-append-to-body="false"
+      v-on="$listeners"
+      @open="onOpen"
+      @close="onClose"
+    >
+      <div slot="title">
+        閫夋嫨鍥炬爣
+        <el-input
+          v-model="key"
+          size="mini"
+          :style="{width: '260px'}"
+          placeholder="璇疯緭鍏ュ浘鏍囧悕绉�"
+          prefix-icon="el-icon-search"
+          clearable
+        />
+      </div>
+      <ul class="icon-ul">
+        <li
+          v-for="icon in iconList"
+          :key="icon"
+          :class="active===icon?'active-item':''"
+          @click="onSelect(icon)"
+        >
+          <i :class="icon" />
+          <div>{{ icon }}</div>
+        </li>
+      </ul>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import iconList from '@/utils/generator/icon.json'
+
+const originList = iconList.map(name => `el-icon-${name}`)
+
+export default {
+  inheritAttrs: false,
+  props: ['current'],
+  data() {
+    return {
+      iconList: originList,
+      active: null,
+      key: ''
+    }
+  },
+  watch: {
+    key(val) {
+      if (val) {
+        this.iconList = originList.filter(name => name.indexOf(val) > -1)
+      } else {
+        this.iconList = originList
+      }
+    }
+  },
+  methods: {
+    onOpen() {
+      this.active = this.current
+      this.key = ''
+    },
+    onClose() {},
+    onSelect(icon) {
+      this.active = icon
+      this.$emit('select', icon)
+      this.$emit('update:visible', false)
+    }
+  }
+}
+</script>
+<style lang="scss" scoped>
+.icon-ul {
+  margin: 0;
+  padding: 0;
+  font-size: 0;
+  li {
+    list-style-type: none;
+    text-align: center;
+    font-size: 14px;
+    display: inline-block;
+    width: 16.66%;
+    box-sizing: border-box;
+    height: 108px;
+    padding: 15px 6px 6px 6px;
+    cursor: pointer;
+    overflow: hidden;
+    &:hover {
+      background: #f2f2f2;
+    }
+    &.active-item{
+      background: #e1f3fb;
+      color: #7a6df0
+    }
+    > i {
+      font-size: 30px;
+      line-height: 50px;
+    }
+  }
+}
+.icon-dialog {
+  ::v-deep .el-dialog {
+    border-radius: 8px;
+    margin-bottom: 0;
+    margin-top: 4vh !important;
+    display: flex;
+    flex-direction: column;
+    max-height: 92vh;
+    overflow: hidden;
+    box-sizing: border-box;
+    .el-dialog__header {
+      padding-top: 14px;
+    }
+    .el-dialog__body {
+      margin: 0 20px 20px 20px;
+      padding: 0;
+      overflow: auto;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/tool/build/RightPanel.vue b/ruoyi-ui/src/views/tool/build/RightPanel.vue
new file mode 100644
index 0000000..c2760eb
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/RightPanel.vue
@@ -0,0 +1,946 @@
+<template>
+  <div class="right-board">
+    <el-tabs v-model="currentTab" class="center-tabs">
+      <el-tab-pane label="缁勪欢灞炴��" name="field" />
+      <el-tab-pane label="琛ㄥ崟灞炴��" name="form" />
+    </el-tabs>
+    <div class="field-box">
+      <a class="document-link" target="_blank" :href="documentLink" title="鏌ョ湅缁勪欢鏂囨。">
+        <i class="el-icon-link" />
+      </a>
+      <el-scrollbar class="right-scrollbar">
+        <!-- 缁勪欢灞炴�� -->
+        <el-form v-show="currentTab==='field' && showField" size="small" label-width="90px">
+          <el-form-item v-if="activeData.changeTag" label="缁勪欢绫诲瀷">
+            <el-select
+              v-model="activeData.tagIcon"
+              placeholder="璇烽�夋嫨缁勪欢绫诲瀷"
+              :style="{width: '100%'}"
+              @change="tagChange"
+            >
+              <el-option-group v-for="group in tagList" :key="group.label" :label="group.label">
+                <el-option
+                  v-for="item in group.options"
+                  :key="item.label"
+                  :label="item.label"
+                  :value="item.tagIcon"
+                >
+                  <svg-icon class="node-icon" :icon-class="item.tagIcon" />
+                  <span> {{ item.label }}</span>
+                </el-option>
+              </el-option-group>
+            </el-select>
+          </el-form-item>
+          <el-form-item v-if="activeData.vModel!==undefined" label="瀛楁鍚�">
+            <el-input v-model="activeData.vModel" placeholder="璇疯緭鍏ュ瓧娈靛悕锛坴-model锛�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.componentName!==undefined" label="缁勪欢鍚�">
+            {{ activeData.componentName }}
+          </el-form-item>
+          <el-form-item v-if="activeData.label!==undefined" label="鏍囬">
+            <el-input v-model="activeData.label" placeholder="璇疯緭鍏ユ爣棰�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.placeholder!==undefined" label="鍗犱綅鎻愮ず">
+            <el-input v-model="activeData.placeholder" placeholder="璇疯緭鍏ュ崰浣嶆彁绀�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['start-placeholder']!==undefined" label="寮�濮嬪崰浣�">
+            <el-input v-model="activeData['start-placeholder']" placeholder="璇疯緭鍏ュ崰浣嶆彁绀�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['end-placeholder']!==undefined" label="缁撴潫鍗犱綅">
+            <el-input v-model="activeData['end-placeholder']" placeholder="璇疯緭鍏ュ崰浣嶆彁绀�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.span!==undefined" label="琛ㄥ崟鏍呮牸">
+            <el-slider v-model="activeData.span" :max="24" :min="1" :marks="{12:''}" @change="spanChange" />
+          </el-form-item>
+          <el-form-item v-if="activeData.layout==='rowFormItem'" label="鏍呮牸闂撮殧">
+            <el-input-number v-model="activeData.gutter" :min="0" placeholder="鏍呮牸闂撮殧" />
+          </el-form-item>
+          <el-form-item v-if="activeData.layout==='rowFormItem'" label="甯冨眬妯″紡">
+            <el-radio-group v-model="activeData.type">
+              <el-radio-button label="default" />
+              <el-radio-button label="flex" />
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="activeData.justify!==undefined&&activeData.type==='flex'" label="姘村钩鎺掑垪">
+            <el-select v-model="activeData.justify" placeholder="璇烽�夋嫨姘村钩鎺掑垪" :style="{width: '100%'}">
+              <el-option
+                v-for="(item, index) in justifyOptions"
+                :key="index"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item v-if="activeData.align!==undefined&&activeData.type==='flex'" label="鍨傜洿鎺掑垪">
+            <el-radio-group v-model="activeData.align">
+              <el-radio-button label="top" />
+              <el-radio-button label="middle" />
+              <el-radio-button label="bottom" />
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="activeData.labelWidth!==undefined" label="鏍囩瀹藉害">
+            <el-input v-model.number="activeData.labelWidth" type="number" placeholder="璇疯緭鍏ユ爣绛惧搴�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.style&&activeData.style.width!==undefined" label="缁勪欢瀹藉害">
+            <el-input v-model="activeData.style.width" placeholder="璇疯緭鍏ョ粍浠跺搴�" clearable />
+          </el-form-item>
+          <el-form-item v-if="activeData.vModel!==undefined" label="榛樿鍊�">
+            <el-input
+              :value="setDefaultValue(activeData.defaultValue)"
+              placeholder="璇疯緭鍏ラ粯璁ゅ��"
+              @input="onDefaultValueInput"
+            />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="鑷冲皯搴旈��">
+            <el-input-number
+              :value="activeData.min"
+              :min="0"
+              placeholder="鑷冲皯搴旈��"
+              @input="$set(activeData, 'min', $event?$event:undefined)"
+            />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag==='el-checkbox-group'" label="鏈�澶氬彲閫�">
+            <el-input-number
+              :value="activeData.max"
+              :min="0"
+              placeholder="鏈�澶氬彲閫�"
+              @input="$set(activeData, 'max', $event?$event:undefined)"
+            />
+          </el-form-item>
+          <el-form-item v-if="activeData.prepend!==undefined" label="鍓嶇紑">
+            <el-input v-model="activeData.prepend" placeholder="璇疯緭鍏ュ墠缂�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.append!==undefined" label="鍚庣紑">
+            <el-input v-model="activeData.append" placeholder="璇疯緭鍏ュ悗缂�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['prefix-icon']!==undefined" label="鍓嶅浘鏍�">
+            <el-input v-model="activeData['prefix-icon']" placeholder="璇疯緭鍏ュ墠鍥炬爣鍚嶇О">
+              <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('prefix-icon')">
+                閫夋嫨
+              </el-button>
+            </el-input>
+          </el-form-item>
+          <el-form-item v-if="activeData['suffix-icon'] !== undefined" label="鍚庡浘鏍�">
+            <el-input v-model="activeData['suffix-icon']" placeholder="璇疯緭鍏ュ悗鍥炬爣鍚嶇О">
+              <el-button slot="append" icon="el-icon-thumb" @click="openIconsDialog('suffix-icon')">
+                閫夋嫨
+              </el-button>
+            </el-input>
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-cascader'" label="閫夐」鍒嗛殧绗�">
+            <el-input v-model="activeData.separator" placeholder="璇疯緭鍏ラ�夐」鍒嗛殧绗�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.autosize !== undefined" label="鏈�灏忚鏁�">
+            <el-input-number v-model="activeData.autosize.minRows" :min="1" placeholder="鏈�灏忚鏁�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.autosize !== undefined" label="鏈�澶ц鏁�">
+            <el-input-number v-model="activeData.autosize.maxRows" :min="1" placeholder="鏈�澶ц鏁�" />
+          </el-form-item>
+          <el-form-item v-if="activeData.min !== undefined" label="鏈�灏忓��">
+            <el-input-number v-model="activeData.min" placeholder="鏈�灏忓��" />
+          </el-form-item>
+          <el-form-item v-if="activeData.max !== undefined" label="鏈�澶у��">
+            <el-input-number v-model="activeData.max" placeholder="鏈�澶у��" />
+          </el-form-item>
+          <el-form-item v-if="activeData.step !== undefined" label="姝ラ暱">
+            <el-input-number v-model="activeData.step" placeholder="姝ユ暟" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-input-number'" label="绮惧害">
+            <el-input-number v-model="activeData.precision" :min="0" placeholder="绮惧害" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-input-number'" label="鎸夐挳浣嶇疆">
+            <el-radio-group v-model="activeData['controls-position']">
+              <el-radio-button label="">
+                榛樿
+              </el-radio-button>
+              <el-radio-button label="right">
+                鍙充晶
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="activeData.maxlength !== undefined" label="鏈�澶氳緭鍏�">
+            <el-input v-model="activeData.maxlength" placeholder="璇疯緭鍏ュ瓧绗﹂暱搴�">
+              <template slot="append">
+                涓瓧绗�
+              </template>
+            </el-input>
+          </el-form-item>
+          <el-form-item v-if="activeData['active-text'] !== undefined" label="寮�鍚彁绀�">
+            <el-input v-model="activeData['active-text']" placeholder="璇疯緭鍏ュ紑鍚彁绀�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['inactive-text'] !== undefined" label="鍏抽棴鎻愮ず">
+            <el-input v-model="activeData['inactive-text']" placeholder="璇疯緭鍏ュ叧闂彁绀�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['active-value'] !== undefined" label="寮�鍚��">
+            <el-input
+              :value="setDefaultValue(activeData['active-value'])"
+              placeholder="璇疯緭鍏ュ紑鍚��"
+              @input="onSwitchValueInput($event, 'active-value')"
+            />
+          </el-form-item>
+          <el-form-item v-if="activeData['inactive-value'] !== undefined" label="鍏抽棴鍊�">
+            <el-input
+              :value="setDefaultValue(activeData['inactive-value'])"
+              placeholder="璇疯緭鍏ュ叧闂��"
+              @input="onSwitchValueInput($event, 'inactive-value')"
+            />
+          </el-form-item>
+          <el-form-item
+            v-if="activeData.type !== undefined && 'el-date-picker' === activeData.tag"
+            label="鏃堕棿绫诲瀷"
+          >
+            <el-select
+              v-model="activeData.type"
+              placeholder="璇烽�夋嫨鏃堕棿绫诲瀷"
+              :style="{ width: '100%' }"
+              @change="dateTypeChange"
+            >
+              <el-option
+                v-for="(item, index) in dateOptions"
+                :key="index"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item v-if="activeData.name !== undefined" label="鏂囦欢瀛楁鍚�">
+            <el-input v-model="activeData.name" placeholder="璇疯緭鍏ヤ笂浼犳枃浠跺瓧娈靛悕" />
+          </el-form-item>
+          <el-form-item v-if="activeData.accept !== undefined" label="鏂囦欢绫诲瀷">
+            <el-select
+              v-model="activeData.accept"
+              placeholder="璇烽�夋嫨鏂囦欢绫诲瀷"
+              :style="{ width: '100%' }"
+              clearable
+            >
+              <el-option label="鍥剧墖" value="image/*" />
+              <el-option label="瑙嗛" value="video/*" />
+              <el-option label="闊抽" value="audio/*" />
+              <el-option label="excel" value=".xls,.xlsx" />
+              <el-option label="word" value=".doc,.docx" />
+              <el-option label="pdf" value=".pdf" />
+              <el-option label="txt" value=".txt" />
+            </el-select>
+          </el-form-item>
+          <el-form-item v-if="activeData.fileSize !== undefined" label="鏂囦欢澶у皬">
+            <el-input v-model.number="activeData.fileSize" placeholder="璇疯緭鍏ユ枃浠跺ぇ灏�">
+              <el-select slot="append" v-model="activeData.sizeUnit" :style="{ width: '66px' }">
+                <el-option label="KB" value="KB" />
+                <el-option label="MB" value="MB" />
+                <el-option label="GB" value="GB" />
+              </el-select>
+            </el-input>
+          </el-form-item>
+          <el-form-item v-if="activeData.action !== undefined" label="涓婁紶鍦板潃">
+            <el-input v-model="activeData.action" placeholder="璇疯緭鍏ヤ笂浼犲湴鍧�" clearable />
+          </el-form-item>
+          <el-form-item v-if="activeData['list-type'] !== undefined" label="鍒楄〃绫诲瀷">
+            <el-radio-group v-model="activeData['list-type']" size="small">
+              <el-radio-button label="text">
+                text
+              </el-radio-button>
+              <el-radio-button label="picture">
+                picture
+              </el-radio-button>
+              <el-radio-button label="picture-card">
+                picture-card
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item
+            v-if="activeData.buttonText !== undefined"
+            v-show="'picture-card' !== activeData['list-type']"
+            label="鎸夐挳鏂囧瓧"
+          >
+            <el-input v-model="activeData.buttonText" placeholder="璇疯緭鍏ユ寜閽枃瀛�" />
+          </el-form-item>
+          <el-form-item v-if="activeData['range-separator'] !== undefined" label="鍒嗛殧绗�">
+            <el-input v-model="activeData['range-separator']" placeholder="璇疯緭鍏ュ垎闅旂" />
+          </el-form-item>
+          <el-form-item v-if="activeData['picker-options'] !== undefined" label="鏃堕棿娈�">
+            <el-input
+              v-model="activeData['picker-options'].selectableRange"
+              placeholder="璇疯緭鍏ユ椂闂存"
+            />
+          </el-form-item>
+          <el-form-item v-if="activeData.format !== undefined" label="鏃堕棿鏍煎紡">
+            <el-input
+              :value="activeData.format"
+              placeholder="璇疯緭鍏ユ椂闂存牸寮�"
+              @input="setTimeValue($event)"
+            />
+          </el-form-item>
+          <template v-if="['el-checkbox-group', 'el-radio-group', 'el-select'].indexOf(activeData.tag) > -1">
+            <el-divider>閫夐」</el-divider>
+            <draggable
+              :list="activeData.options"
+              :animation="340"
+              group="selectItem"
+              handle=".option-drag"
+            >
+              <div v-for="(item, index) in activeData.options" :key="index" class="select-item">
+                <div class="select-line-icon option-drag">
+                  <i class="el-icon-s-operation" />
+                </div>
+                <el-input v-model="item.label" placeholder="閫夐」鍚�" size="small" />
+                <el-input
+                  placeholder="閫夐」鍊�"
+                  size="small"
+                  :value="item.value"
+                  @input="setOptionValue(item, $event)"
+                />
+                <div class="close-btn select-line-icon" @click="activeData.options.splice(index, 1)">
+                  <i class="el-icon-remove-outline" />
+                </div>
+              </div>
+            </draggable>
+            <div style="margin-left: 20px;">
+              <el-button
+                style="padding-bottom: 0"
+                icon="el-icon-circle-plus-outline"
+                type="text"
+                @click="addSelectItem"
+              >
+                娣诲姞閫夐」
+              </el-button>
+            </div>
+            <el-divider />
+          </template>
+
+          <template v-if="['el-cascader'].indexOf(activeData.tag) > -1">
+            <el-divider>閫夐」</el-divider>
+            <el-form-item label="鏁版嵁绫诲瀷">
+              <el-radio-group v-model="activeData.dataType" size="small">
+                <el-radio-button label="dynamic">
+                  鍔ㄦ�佹暟鎹�
+                </el-radio-button>
+                <el-radio-button label="static">
+                  闈欐�佹暟鎹�
+                </el-radio-button>
+              </el-radio-group>
+            </el-form-item>
+
+            <template v-if="activeData.dataType === 'dynamic'">
+              <el-form-item label="鏍囩閿悕">
+                <el-input v-model="activeData.labelKey" placeholder="璇疯緭鍏ユ爣绛鹃敭鍚�" />
+              </el-form-item>
+              <el-form-item label="鍊奸敭鍚�">
+                <el-input v-model="activeData.valueKey" placeholder="璇疯緭鍏ュ�奸敭鍚�" />
+              </el-form-item>
+              <el-form-item label="瀛愮骇閿悕">
+                <el-input v-model="activeData.childrenKey" placeholder="璇疯緭鍏ュ瓙绾ч敭鍚�" />
+              </el-form-item>
+            </template>
+
+            <el-tree
+              v-if="activeData.dataType === 'static'"
+              draggable
+              :data="activeData.options"
+              node-key="id"
+              :expand-on-click-node="false"
+              :render-content="renderContent"
+            />
+            <div v-if="activeData.dataType === 'static'" style="margin-left: 20px">
+              <el-button
+                style="padding-bottom: 0"
+                icon="el-icon-circle-plus-outline"
+                type="text"
+                @click="addTreeItem"
+              >
+                娣诲姞鐖剁骇
+              </el-button>
+            </div>
+            <el-divider />
+          </template>
+
+          <el-form-item v-if="activeData.optionType !== undefined" label="閫夐」鏍峰紡">
+            <el-radio-group v-model="activeData.optionType">
+              <el-radio-button label="default">
+                榛樿
+              </el-radio-button>
+              <el-radio-button label="button">
+                鎸夐挳
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="activeData['active-color'] !== undefined" label="寮�鍚鑹�">
+            <el-color-picker v-model="activeData['active-color']" />
+          </el-form-item>
+          <el-form-item v-if="activeData['inactive-color'] !== undefined" label="鍏抽棴棰滆壊">
+            <el-color-picker v-model="activeData['inactive-color']" />
+          </el-form-item>
+
+          <el-form-item v-if="activeData['allow-half'] !== undefined" label="鍏佽鍗婇��">
+            <el-switch v-model="activeData['allow-half']" />
+          </el-form-item>
+          <el-form-item v-if="activeData['show-text'] !== undefined" label="杈呭姪鏂囧瓧">
+            <el-switch v-model="activeData['show-text']" @change="rateTextChange" />
+          </el-form-item>
+          <el-form-item v-if="activeData['show-score'] !== undefined" label="鏄剧ず鍒嗘暟">
+            <el-switch v-model="activeData['show-score']" @change="rateScoreChange" />
+          </el-form-item>
+          <el-form-item v-if="activeData['show-stops'] !== undefined" label="鏄剧ず闂存柇鐐�">
+            <el-switch v-model="activeData['show-stops']" />
+          </el-form-item>
+          <el-form-item v-if="activeData.range !== undefined" label="鑼冨洿閫夋嫨">
+            <el-switch v-model="activeData.range" @change="rangeChange" />
+          </el-form-item>
+          <el-form-item
+            v-if="activeData.border !== undefined && activeData.optionType === 'default'"
+            label="鏄惁甯﹁竟妗�"
+          >
+            <el-switch v-model="activeData.border" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-color-picker'" label="棰滆壊鏍煎紡">
+            <el-select
+              v-model="activeData['color-format']"
+              placeholder="璇烽�夋嫨棰滆壊鏍煎紡"
+              :style="{ width: '100%' }"
+              @change="colorFormatChange"
+            >
+              <el-option
+                v-for="(item, index) in colorFormatOptions"
+                :key="index"
+                :label="item.label"
+                :value="item.value"
+              />
+            </el-select>
+          </el-form-item>
+          <el-form-item
+            v-if="activeData.size !== undefined &&
+              (activeData.optionType === 'button' ||
+                activeData.border ||
+                activeData.tag === 'el-color-picker')"
+            label="閫夐」灏哄"
+          >
+            <el-radio-group v-model="activeData.size">
+              <el-radio-button label="medium">
+                涓瓑
+              </el-radio-button>
+              <el-radio-button label="small">
+                杈冨皬
+              </el-radio-button>
+              <el-radio-button label="mini">
+                杩蜂綘
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item v-if="activeData['show-word-limit'] !== undefined" label="杈撳叆缁熻">
+            <el-switch v-model="activeData['show-word-limit']" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-input-number'" label="涓ユ牸姝ユ暟">
+            <el-switch v-model="activeData['step-strictly']" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-cascader'" label="鏄惁澶氶��">
+            <el-switch v-model="activeData.props.props.multiple" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-cascader'" label="灞曠ず鍏ㄨ矾寰�">
+            <el-switch v-model="activeData['show-all-levels']" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-cascader'" label="鍙惁绛涢��">
+            <el-switch v-model="activeData.filterable" />
+          </el-form-item>
+          <el-form-item v-if="activeData.clearable !== undefined" label="鑳藉惁娓呯┖">
+            <el-switch v-model="activeData.clearable" />
+          </el-form-item>
+          <el-form-item v-if="activeData.showTip !== undefined" label="鏄剧ず鎻愮ず">
+            <el-switch v-model="activeData.showTip" />
+          </el-form-item>
+          <el-form-item v-if="activeData.multiple !== undefined" label="澶氶�夋枃浠�">
+            <el-switch v-model="activeData.multiple" />
+          </el-form-item>
+          <el-form-item v-if="activeData['auto-upload'] !== undefined" label="鑷姩涓婁紶">
+            <el-switch v-model="activeData['auto-upload']" />
+          </el-form-item>
+          <el-form-item v-if="activeData.readonly !== undefined" label="鏄惁鍙">
+            <el-switch v-model="activeData.readonly" />
+          </el-form-item>
+          <el-form-item v-if="activeData.disabled !== undefined" label="鏄惁绂佺敤">
+            <el-switch v-model="activeData.disabled" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-select'" label="鏄惁鍙悳绱�">
+            <el-switch v-model="activeData.filterable" />
+          </el-form-item>
+          <el-form-item v-if="activeData.tag === 'el-select'" label="鏄惁澶氶��">
+            <el-switch v-model="activeData.multiple" @change="multipleChange" />
+          </el-form-item>
+          <el-form-item v-if="activeData.required !== undefined" label="鏄惁蹇呭~">
+            <el-switch v-model="activeData.required" />
+          </el-form-item>
+
+          <template v-if="activeData.layoutTree">
+            <el-divider>甯冨眬缁撴瀯鏍�</el-divider>
+            <el-tree
+              :data="[activeData]"
+              :props="layoutTreeProps"
+              node-key="renderKey"
+              default-expand-all
+              draggable
+            >
+              <span slot-scope="{ node, data }">
+                <span class="node-label">
+                  <svg-icon class="node-icon" :icon-class="data.tagIcon" />
+                  {{ node.label }}
+                </span>
+              </span>
+            </el-tree>
+          </template>
+
+          <template v-if="activeData.layout === 'colFormItem' && activeData.tag !== 'el-button'">
+            <el-divider>姝e垯鏍¢獙</el-divider>
+            <div
+              v-for="(item, index) in activeData.regList"
+              :key="index"
+              class="reg-item"
+            >
+              <span class="close-btn" @click="activeData.regList.splice(index, 1)">
+                <i class="el-icon-close" />
+              </span>
+              <el-form-item label="琛ㄨ揪寮�">
+                <el-input v-model="item.pattern" placeholder="璇疯緭鍏ユ鍒�" />
+              </el-form-item>
+              <el-form-item label="閿欒鎻愮ず" style="margin-bottom:0">
+                <el-input v-model="item.message" placeholder="璇疯緭鍏ラ敊璇彁绀�" />
+              </el-form-item>
+            </div>
+            <div style="margin-left: 20px">
+              <el-button icon="el-icon-circle-plus-outline" type="text" @click="addReg">
+                娣诲姞瑙勫垯
+              </el-button>
+            </div>
+          </template>
+        </el-form>
+        <!-- 琛ㄥ崟灞炴�� -->
+        <el-form v-show="currentTab === 'form'" size="small" label-width="90px">
+          <el-form-item label="琛ㄥ崟鍚�">
+            <el-input v-model="formConf.formRef" placeholder="璇疯緭鍏ヨ〃鍗曞悕锛坮ef锛�" />
+          </el-form-item>
+          <el-form-item label="琛ㄥ崟妯″瀷">
+            <el-input v-model="formConf.formModel" placeholder="璇疯緭鍏ユ暟鎹ā鍨�" />
+          </el-form-item>
+          <el-form-item label="鏍¢獙妯″瀷">
+            <el-input v-model="formConf.formRules" placeholder="璇疯緭鍏ユ牎楠屾ā鍨�" />
+          </el-form-item>
+          <el-form-item label="琛ㄥ崟灏哄">
+            <el-radio-group v-model="formConf.size">
+              <el-radio-button label="medium">
+                涓瓑
+              </el-radio-button>
+              <el-radio-button label="small">
+                杈冨皬
+              </el-radio-button>
+              <el-radio-button label="mini">
+                杩蜂綘
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="鏍囩瀵归綈">
+            <el-radio-group v-model="formConf.labelPosition">
+              <el-radio-button label="left">
+                宸﹀榻�
+              </el-radio-button>
+              <el-radio-button label="right">
+                鍙冲榻�
+              </el-radio-button>
+              <el-radio-button label="top">
+                椤堕儴瀵归綈
+              </el-radio-button>
+            </el-radio-group>
+          </el-form-item>
+          <el-form-item label="鏍囩瀹藉害">
+            <el-input-number v-model="formConf.labelWidth" placeholder="鏍囩瀹藉害" />
+          </el-form-item>
+          <el-form-item label="鏍呮牸闂撮殧">
+            <el-input-number v-model="formConf.gutter" :min="0" placeholder="鏍呮牸闂撮殧" />
+          </el-form-item>
+          <el-form-item label="绂佺敤琛ㄥ崟">
+            <el-switch v-model="formConf.disabled" />
+          </el-form-item>
+          <el-form-item label="琛ㄥ崟鎸夐挳">
+            <el-switch v-model="formConf.formBtns" />
+          </el-form-item>
+          <el-form-item label="鏄剧ず鏈�変腑缁勪欢杈规">
+            <el-switch v-model="formConf.unFocusedComponentBorder" />
+          </el-form-item>
+        </el-form>
+      </el-scrollbar>
+    </div>
+
+    <treeNode-dialog :visible.sync="dialogVisible" title="娣诲姞閫夐」" @commit="addNode" />
+    <icons-dialog :visible.sync="iconsVisible" :current="activeData[currentIconModel]" @select="setIcon" />
+  </div>
+</template>
+
+<script>
+import { isArray } from 'util'
+import draggable from 'vuedraggable'
+import TreeNodeDialog from './TreeNodeDialog'
+import { isNumberStr } from '@/utils/index'
+import IconsDialog from './IconsDialog'
+import {
+  inputComponents,
+  selectComponents,
+  layoutComponents
+} from '@/utils/generator/config'
+
+const dateTimeFormat = {
+  date: 'yyyy-MM-dd',
+  week: 'yyyy 绗� WW 鍛�',
+  month: 'yyyy-MM',
+  year: 'yyyy',
+  datetime: 'yyyy-MM-dd HH:mm:ss',
+  daterange: 'yyyy-MM-dd',
+  monthrange: 'yyyy-MM',
+  datetimerange: 'yyyy-MM-dd HH:mm:ss'
+}
+
+export default {
+  components: {
+    draggable,
+    TreeNodeDialog,
+    IconsDialog
+  },
+  props: ['showField', 'activeData', 'formConf'],
+  data() {
+    return {
+      currentTab: 'field',
+      currentNode: null,
+      dialogVisible: false,
+      iconsVisible: false,
+      currentIconModel: null,
+      dateTypeOptions: [
+        {
+          label: '鏃�(date)',
+          value: 'date'
+        },
+        {
+          label: '鍛�(week)',
+          value: 'week'
+        },
+        {
+          label: '鏈�(month)',
+          value: 'month'
+        },
+        {
+          label: '骞�(year)',
+          value: 'year'
+        },
+        {
+          label: '鏃ユ湡鏃堕棿(datetime)',
+          value: 'datetime'
+        }
+      ],
+      dateRangeTypeOptions: [
+        {
+          label: '鏃ユ湡鑼冨洿(daterange)',
+          value: 'daterange'
+        },
+        {
+          label: '鏈堣寖鍥�(monthrange)',
+          value: 'monthrange'
+        },
+        {
+          label: '鏃ユ湡鏃堕棿鑼冨洿(datetimerange)',
+          value: 'datetimerange'
+        }
+      ],
+      colorFormatOptions: [
+        {
+          label: 'hex',
+          value: 'hex'
+        },
+        {
+          label: 'rgb',
+          value: 'rgb'
+        },
+        {
+          label: 'rgba',
+          value: 'rgba'
+        },
+        {
+          label: 'hsv',
+          value: 'hsv'
+        },
+        {
+          label: 'hsl',
+          value: 'hsl'
+        }
+      ],
+      justifyOptions: [
+        {
+          label: 'start',
+          value: 'start'
+        },
+        {
+          label: 'end',
+          value: 'end'
+        },
+        {
+          label: 'center',
+          value: 'center'
+        },
+        {
+          label: 'space-around',
+          value: 'space-around'
+        },
+        {
+          label: 'space-between',
+          value: 'space-between'
+        }
+      ],
+      layoutTreeProps: {
+        label(data, node) {
+          return data.componentName || `${data.label}: ${data.vModel}`
+        }
+      }
+    }
+  },
+  computed: {
+    documentLink() {
+      return (
+        this.activeData.document
+        || 'https://element.eleme.cn/#/zh-CN/component/installation'
+      )
+    },
+    dateOptions() {
+      if (
+        this.activeData.type !== undefined
+        && this.activeData.tag === 'el-date-picker'
+      ) {
+        if (this.activeData['start-placeholder'] === undefined) {
+          return this.dateTypeOptions
+        }
+        return this.dateRangeTypeOptions
+      }
+      return []
+    },
+    tagList() {
+      return [
+        {
+          label: '杈撳叆鍨嬬粍浠�',
+          options: inputComponents
+        },
+        {
+          label: '閫夋嫨鍨嬬粍浠�',
+          options: selectComponents
+        }
+      ]
+    }
+  },
+  methods: {
+    addReg() {
+      this.activeData.regList.push({
+        pattern: '',
+        message: ''
+      })
+    },
+    addSelectItem() {
+      this.activeData.options.push({
+        label: '',
+        value: ''
+      })
+    },
+    addTreeItem() {
+      ++this.idGlobal
+      this.dialogVisible = true
+      this.currentNode = this.activeData.options
+    },
+    renderContent(h, { node, data, store }) {
+      return (
+        <div class="custom-tree-node">
+          <span>{node.label}</span>
+          <span class="node-operation">
+            <i on-click={() => this.append(data)}
+              class="el-icon-plus"
+              title="娣诲姞"
+            ></i>
+            <i on-click={() => this.remove(node, data)}
+              class="el-icon-delete"
+              title="鍒犻櫎"
+            ></i>
+          </span>
+        </div>
+      )
+    },
+    append(data) {
+      if (!data.children) {
+        this.$set(data, 'children', [])
+      }
+      this.dialogVisible = true
+      this.currentNode = data.children
+    },
+    remove(node, data) {
+      const { parent } = node
+      const children = parent.data.children || parent.data
+      const index = children.findIndex(d => d.id === data.id)
+      children.splice(index, 1)
+    },
+    addNode(data) {
+      this.currentNode.push(data)
+    },
+    setOptionValue(item, val) {
+      item.value = isNumberStr(val) ? +val : val
+    },
+    setDefaultValue(val) {
+      if (Array.isArray(val)) {
+        return val.join(',')
+      }
+      if (['string', 'number'].indexOf(val) > -1) {
+        return val
+      }
+      if (typeof val === 'boolean') {
+        return `${val}`
+      }
+      return val
+    },
+    onDefaultValueInput(str) {
+      if (isArray(this.activeData.defaultValue)) {
+        // 鏁扮粍
+        this.$set(
+          this.activeData,
+          'defaultValue',
+          str.split(',').map(val => (isNumberStr(val) ? +val : val))
+        )
+      } else if (['true', 'false'].indexOf(str) > -1) {
+        // 甯冨皵
+        this.$set(this.activeData, 'defaultValue', JSON.parse(str))
+      } else {
+        // 瀛楃涓插拰鏁板瓧
+        this.$set(
+          this.activeData,
+          'defaultValue',
+          isNumberStr(str) ? +str : str
+        )
+      }
+    },
+    onSwitchValueInput(val, name) {
+      if (['true', 'false'].indexOf(val) > -1) {
+        this.$set(this.activeData, name, JSON.parse(val))
+      } else {
+        this.$set(this.activeData, name, isNumberStr(val) ? +val : val)
+      }
+    },
+    setTimeValue(val, type) {
+      const valueFormat = type === 'week' ? dateTimeFormat.date : val
+      this.$set(this.activeData, 'defaultValue', null)
+      this.$set(this.activeData, 'value-format', valueFormat)
+      this.$set(this.activeData, 'format', val)
+    },
+    spanChange(val) {
+      this.formConf.span = val
+    },
+    multipleChange(val) {
+      this.$set(this.activeData, 'defaultValue', val ? [] : '')
+    },
+    dateTypeChange(val) {
+      this.setTimeValue(dateTimeFormat[val], val)
+    },
+    rangeChange(val) {
+      this.$set(
+        this.activeData,
+        'defaultValue',
+        val ? [this.activeData.min, this.activeData.max] : this.activeData.min
+      )
+    },
+    rateTextChange(val) {
+      if (val) this.activeData['show-score'] = false
+    },
+    rateScoreChange(val) {
+      if (val) this.activeData['show-text'] = false
+    },
+    colorFormatChange(val) {
+      this.activeData.defaultValue = null
+      this.activeData['show-alpha'] = val.indexOf('a') > -1
+      this.activeData.renderKey = +new Date() // 鏇存柊renderKey,閲嶆柊娓叉煋璇ョ粍浠�
+    },
+    openIconsDialog(model) {
+      this.iconsVisible = true
+      this.currentIconModel = model
+    },
+    setIcon(val) {
+      this.activeData[this.currentIconModel] = val
+    },
+    tagChange(tagIcon) {
+      let target = inputComponents.find(item => item.tagIcon === tagIcon)
+      if (!target) target = selectComponents.find(item => item.tagIcon === tagIcon)
+      this.$emit('tag-change', target)
+    }
+  }
+}
+</script>
+
+<style lang="scss" scoped>
+.right-board {
+  width: 350px;
+  position: absolute;
+  right: 0;
+  top: 0;
+  padding-top: 3px;
+  .field-box {
+    position: relative;
+    height: calc(100vh - 42px);
+    box-sizing: border-box;
+    overflow: hidden;
+  }
+  .el-scrollbar {
+    height: 100%;
+  }
+}
+.select-item {
+  display: flex;
+  border: 1px dashed #fff;
+  box-sizing: border-box;
+  & .close-btn {
+    cursor: pointer;
+    color: #f56c6c;
+  }
+  & .el-input + .el-input {
+    margin-left: 4px;
+  }
+}
+.select-item + .select-item {
+  margin-top: 4px;
+}
+.select-item.sortable-chosen {
+  border: 1px dashed #409eff;
+}
+.select-line-icon {
+  line-height: 32px;
+  font-size: 22px;
+  padding: 0 4px;
+  color: #777;
+}
+.option-drag {
+  cursor: move;
+}
+.time-range {
+  .el-date-editor {
+    width: 227px;
+  }
+  ::v-deep .el-icon-time {
+    display: none;
+  }
+}
+.document-link {
+  position: absolute;
+  display: block;
+  width: 26px;
+  height: 26px;
+  top: 0;
+  left: 0;
+  cursor: pointer;
+  background: #409eff;
+  z-index: 1;
+  border-radius: 0 0 6px 0;
+  text-align: center;
+  line-height: 26px;
+  color: #fff;
+  font-size: 18px;
+}
+.node-label{
+  font-size: 14px;
+}
+.node-icon{
+  color: #bebfc3;
+}
+</style>
diff --git a/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
new file mode 100644
index 0000000..fa7f0b2
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/TreeNodeDialog.vue
@@ -0,0 +1,149 @@
+<template>
+  <div>
+    <el-dialog
+      v-bind="$attrs"
+      :close-on-click-modal="false"
+      :modal-append-to-body="false"
+      v-on="$listeners"
+      @open="onOpen"
+      @close="onClose"
+    >
+      <el-row :gutter="0">
+        <el-form
+          ref="elForm"
+          :model="formData"
+          :rules="rules"
+          size="small"
+          label-width="100px"
+        >
+          <el-col :span="24">
+            <el-form-item
+              label="閫夐」鍚�"
+              prop="label"
+            >
+              <el-input
+                v-model="formData.label"
+                placeholder="璇疯緭鍏ラ�夐」鍚�"
+                clearable
+              />
+            </el-form-item>
+          </el-col>
+          <el-col :span="24">
+            <el-form-item
+              label="閫夐」鍊�"
+              prop="value"
+            >
+              <el-input
+                v-model="formData.value"
+                placeholder="璇疯緭鍏ラ�夐」鍊�"
+                clearable
+              >
+                <el-select
+                  slot="append"
+                  v-model="dataType"
+                  :style="{width: '100px'}"
+                >
+                  <el-option
+                    v-for="(item, index) in dataTypeOptions"
+                    :key="index"
+                    :label="item.label"
+                    :value="item.value"
+                    :disabled="item.disabled"
+                  />
+                </el-select>
+              </el-input>
+            </el-form-item>
+          </el-col>
+        </el-form>
+      </el-row>
+      <div slot="footer">
+        <el-button
+          type="primary"
+          @click="handleConfirm"
+        >
+          纭畾
+        </el-button>
+        <el-button @click="close">
+          鍙栨秷
+        </el-button>
+      </div>
+    </el-dialog>
+  </div>
+</template>
+<script>
+import { isNumberStr } from '@/utils/index'
+
+export default {
+  components: {},
+  inheritAttrs: false,
+  props: [],
+  data() {
+    return {
+      id: 100,
+      formData: {
+        label: undefined,
+        value: undefined
+      },
+      rules: {
+        label: [
+          {
+            required: true,
+            message: '璇疯緭鍏ラ�夐」鍚�',
+            trigger: 'blur'
+          }
+        ],
+        value: [
+          {
+            required: true,
+            message: '璇疯緭鍏ラ�夐」鍊�',
+            trigger: 'blur'
+          }
+        ]
+      },
+      dataType: 'string',
+      dataTypeOptions: [
+        {
+          label: '瀛楃涓�',
+          value: 'string'
+        },
+        {
+          label: '鏁板瓧',
+          value: 'number'
+        }
+      ]
+    }
+  },
+  computed: {},
+  watch: {
+    // eslint-disable-next-line func-names
+    'formData.value': function (val) {
+      this.dataType = isNumberStr(val) ? 'number' : 'string'
+    }
+  },
+  created() {},
+  mounted() {},
+  methods: {
+    onOpen() {
+      this.formData = {
+        label: undefined,
+        value: undefined
+      }
+    },
+    onClose() {},
+    close() {
+      this.$emit('update:visible', false)
+    },
+    handleConfirm() {
+      this.$refs.elForm.validate(valid => {
+        if (!valid) return
+        if (this.dataType === 'number') {
+          this.formData.value = parseFloat(this.formData.value)
+        }
+        this.formData.id = this.id++
+        this.$emit('commit', this.formData)
+        this.close()
+      })
+    }
+  }
+}
+</script>
diff --git a/ruoyi-ui/src/views/tool/build/index.vue b/ruoyi-ui/src/views/tool/build/index.vue
new file mode 100644
index 0000000..2bd298b
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/build/index.vue
@@ -0,0 +1,768 @@
+<template>
+  <div class="container">
+    <div class="left-board">
+      <div class="logo-wrapper">
+        <div class="logo">
+          <img :src="logo" alt="logo"> Form Generator
+        </div>
+      </div>
+      <el-scrollbar class="left-scrollbar">
+        <div class="components-list">
+          <div class="components-title">
+            <svg-icon icon-class="component" />杈撳叆鍨嬬粍浠�
+          </div>
+          <draggable
+            class="components-draggable"
+            :list="inputComponents"
+            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+            :clone="cloneComponent"
+            draggable=".components-item"
+            :sort="false"
+            @end="onEnd"
+          >
+            <div
+              v-for="(element, index) in inputComponents" :key="index" class="components-item"
+              @click="addComponent(element)"
+            >
+              <div class="components-body">
+                <svg-icon :icon-class="element.tagIcon" />
+                {{ element.label }}
+              </div>
+            </div>
+          </draggable>
+          <div class="components-title">
+            <svg-icon icon-class="component" />閫夋嫨鍨嬬粍浠�
+          </div>
+          <draggable
+            class="components-draggable"
+            :list="selectComponents"
+            :group="{ name: 'componentsGroup', pull: 'clone', put: false }"
+            :clone="cloneComponent"
+            draggable=".components-item"
+            :sort="false"
+            @end="onEnd"
+          >
+            <div
+              v-for="(element, index) in selectComponents"
+              :key="index"
+              class="components-item"
+              @click="addComponent(element)"
+            >
+              <div class="components-body">
+                <svg-icon :icon-class="element.tagIcon" />
+                {{ element.label }}
+              </div>
+            </div>
+          </draggable>
+          <div class="components-title">
+            <svg-icon icon-class="component" /> 甯冨眬鍨嬬粍浠�
+          </div>
+          <draggable
+            class="components-draggable" :list="layoutComponents"
+            :group="{ name: 'componentsGroup', pull: 'clone', put: false }" :clone="cloneComponent"
+            draggable=".components-item" :sort="false" @end="onEnd"
+          >
+            <div
+              v-for="(element, index) in layoutComponents" :key="index" class="components-item"
+              @click="addComponent(element)"
+            >
+              <div class="components-body">
+                <svg-icon :icon-class="element.tagIcon" />
+                {{ element.label }}
+              </div>
+            </div>
+          </draggable>
+        </div>
+      </el-scrollbar>
+    </div>
+
+    <div class="center-board">
+      <div class="action-bar">
+        <el-button icon="el-icon-download" type="text" @click="download">
+          瀵煎嚭vue鏂囦欢
+        </el-button>
+        <el-button class="copy-btn-main" icon="el-icon-document-copy" type="text" @click="copy">
+          澶嶅埗浠g爜
+        </el-button>
+        <el-button class="delete-btn" icon="el-icon-delete" type="text" @click="empty">
+          娓呯┖
+        </el-button>
+      </div>
+      <el-scrollbar class="center-scrollbar">
+        <el-row class="center-board-row" :gutter="formConf.gutter">
+          <el-form
+            :size="formConf.size"
+            :label-position="formConf.labelPosition"
+            :disabled="formConf.disabled"
+            :label-width="formConf.labelWidth + 'px'"
+          >
+            <draggable class="drawing-board" :list="drawingList" :animation="340" group="componentsGroup">
+              <draggable-item
+                v-for="(element, index) in drawingList"
+                :key="element.renderKey"
+                :drawing-list="drawingList"
+                :element="element"
+                :index="index"
+                :active-id="activeId"
+                :form-conf="formConf"
+                @activeItem="activeFormItem"
+                @copyItem="drawingItemCopy"
+                @deleteItem="drawingItemDelete"
+              />
+            </draggable>
+            <div v-show="!drawingList.length" class="empty-info">
+              浠庡乏渚ф嫋鍏ユ垨鐐归�夌粍浠惰繘琛岃〃鍗曡璁�
+            </div>
+          </el-form>
+        </el-row>
+      </el-scrollbar>
+    </div>
+
+    <right-panel
+      :active-data="activeData"
+      :form-conf="formConf"
+      :show-field="!!drawingList.length"
+      @tag-change="tagChange"
+    />
+
+    <code-type-dialog
+      :visible.sync="dialogVisible"
+      title="閫夋嫨鐢熸垚绫诲瀷"
+      :show-file-name="showFileName"
+      @confirm="generate"
+    />
+    <input id="copyNode" type="hidden">
+  </div>
+</template>
+
+<script>
+import draggable from 'vuedraggable'
+import beautifier from 'js-beautify'
+import ClipboardJS from 'clipboard'
+import render from '@/utils/generator/render'
+import RightPanel from './RightPanel'
+import { inputComponents, selectComponents, layoutComponents, formConf } from '@/utils/generator/config'
+import { beautifierConf, titleCase } from '@/utils/index'
+import { makeUpHtml, vueTemplate, vueScript, cssStyle } from '@/utils/generator/html'
+import { makeUpJs } from '@/utils/generator/js'
+import { makeUpCss } from '@/utils/generator/css'
+import drawingDefault from '@/utils/generator/drawingDefault'
+import logo from '@/assets/logo/logo.png'
+import CodeTypeDialog from './CodeTypeDialog'
+import DraggableItem from './DraggableItem'
+
+let oldActiveId
+let tempActiveData
+
+export default {
+  components: {
+    draggable,
+    render,
+    RightPanel,
+    CodeTypeDialog,
+    DraggableItem
+  },
+  data() {
+    return {
+      logo,
+      idGlobal: 100,
+      formConf,
+      inputComponents,
+      selectComponents,
+      layoutComponents,
+      labelWidth: 100,
+      drawingList: drawingDefault,
+      drawingData: {},
+      activeId: drawingDefault[0].formId,
+      drawerVisible: false,
+      formData: {},
+      dialogVisible: false,
+      generateConf: null,
+      showFileName: false,
+      activeData: drawingDefault[0]
+    }
+  },
+  created() {
+    // 闃叉 firefox 涓� 鎷栨嫿 浼氭柊鎵撳崱涓�涓�夐」鍗�
+    document.body.ondrop = event => {
+      event.preventDefault()
+      event.stopPropagation()
+    }
+  },
+  watch: {
+    // eslint-disable-next-line func-names
+    'activeData.label': function (val, oldVal) {
+      if (
+        this.activeData.placeholder === undefined
+        || !this.activeData.tag
+        || oldActiveId !== this.activeId
+      ) {
+        return
+      }
+      this.activeData.placeholder = this.activeData.placeholder.replace(oldVal, '') + val
+    },
+    activeId: {
+      handler(val) {
+        oldActiveId = val
+      },
+      immediate: true
+    }
+  },
+  mounted() {
+    const clipboard = new ClipboardJS('#copyNode', {
+      text: trigger => {
+        const codeStr = this.generateCode()
+        this.$notify({
+          title: '鎴愬姛',
+          message: '浠g爜宸插鍒跺埌鍓垏鏉匡紝鍙矘璐淬��',
+          type: 'success'
+        })
+        return codeStr
+      }
+    })
+    clipboard.on('error', e => {
+      this.$message.error('浠g爜澶嶅埗澶辫触')
+    })
+  },
+  methods: {
+    activeFormItem(element) {
+      this.activeData = element
+      this.activeId = element.formId
+    },
+    onEnd(obj, a) {
+      if (obj.from !== obj.to) {
+        this.activeData = tempActiveData
+        this.activeId = this.idGlobal
+      }
+    },
+    addComponent(item) {
+      const clone = this.cloneComponent(item)
+      this.drawingList.push(clone)
+      this.activeFormItem(clone)
+    },
+    cloneComponent(origin) {
+      const clone = JSON.parse(JSON.stringify(origin))
+      clone.formId = ++this.idGlobal
+      clone.span = formConf.span
+      clone.renderKey = +new Date() // 鏀瑰彉renderKey鍚庡彲浠ュ疄鐜板己鍒舵洿鏂扮粍浠�
+      if (!clone.layout) clone.layout = 'colFormItem'
+      if (clone.layout === 'colFormItem') {
+        clone.vModel = `field${this.idGlobal}`
+        clone.placeholder !== undefined && (clone.placeholder += clone.label)
+        tempActiveData = clone
+      } else if (clone.layout === 'rowFormItem') {
+        delete clone.label
+        clone.componentName = `row${this.idGlobal}`
+        clone.gutter = this.formConf.gutter
+        tempActiveData = clone
+      }
+      return tempActiveData
+    },
+    AssembleFormData() {
+      this.formData = {
+        fields: JSON.parse(JSON.stringify(this.drawingList)),
+        ...this.formConf
+      }
+    },
+    generate(data) {
+      const func = this[`exec${titleCase(this.operationType)}`]
+      this.generateConf = data
+      func && func(data)
+    },
+    execRun(data) {
+      this.AssembleFormData()
+      this.drawerVisible = true
+    },
+    execDownload(data) {
+      const codeStr = this.generateCode()
+      const blob = new Blob([codeStr], { type: 'text/plain;charset=utf-8' })
+      this.$download.saveAs(blob, data.fileName)
+    },
+    execCopy(data) {
+      document.getElementById('copyNode').click()
+    },
+    empty() {
+      this.$confirm('纭畾瑕佹竻绌烘墍鏈夌粍浠跺悧锛�', '鎻愮ず', { type: 'warning' }).then(
+        () => {
+          this.drawingList = []
+        }
+      )
+    },
+    drawingItemCopy(item, parent) {
+      let clone = JSON.parse(JSON.stringify(item))
+      clone = this.createIdAndKey(clone)
+      parent.push(clone)
+      this.activeFormItem(clone)
+    },
+    createIdAndKey(item) {
+      item.formId = ++this.idGlobal
+      item.renderKey = +new Date()
+      if (item.layout === 'colFormItem') {
+        item.vModel = `field${this.idGlobal}`
+      } else if (item.layout === 'rowFormItem') {
+        item.componentName = `row${this.idGlobal}`
+      }
+      if (Array.isArray(item.children)) {
+        item.children = item.children.map(childItem => this.createIdAndKey(childItem))
+      }
+      return item
+    },
+    drawingItemDelete(index, parent) {
+      parent.splice(index, 1)
+      this.$nextTick(() => {
+        const len = this.drawingList.length
+        if (len) {
+          this.activeFormItem(this.drawingList[len - 1])
+        }
+      })
+    },
+    generateCode() {
+      const { type } = this.generateConf
+      this.AssembleFormData()
+      const script = vueScript(makeUpJs(this.formData, type))
+      const html = vueTemplate(makeUpHtml(this.formData, type))
+      const css = cssStyle(makeUpCss(this.formData))
+      return beautifier.html(html + script + css, beautifierConf.html)
+    },
+    download() {
+      this.dialogVisible = true
+      this.showFileName = true
+      this.operationType = 'download'
+    },
+    run() {
+      this.dialogVisible = true
+      this.showFileName = false
+      this.operationType = 'run'
+    },
+    copy() {
+      this.dialogVisible = true
+      this.showFileName = false
+      this.operationType = 'copy'
+    },
+    tagChange(newTag) {
+      newTag = this.cloneComponent(newTag)
+      newTag.vModel = this.activeData.vModel
+      newTag.formId = this.activeId
+      newTag.span = this.activeData.span
+      delete this.activeData.tag
+      delete this.activeData.tagIcon
+      delete this.activeData.document
+      Object.keys(newTag).forEach(key => {
+        if (this.activeData[key] !== undefined
+          && typeof this.activeData[key] === typeof newTag[key]) {
+          newTag[key] = this.activeData[key]
+        }
+      })
+      this.activeData = newTag
+      this.updateDrawingList(newTag, this.drawingList)
+    },
+    updateDrawingList(newTag, list) {
+      const index = list.findIndex(item => item.formId === this.activeId)
+      if (index > -1) {
+        list.splice(index, 1, newTag)
+      } else {
+        list.forEach(item => {
+          if (Array.isArray(item.children)) this.updateDrawingList(newTag, item.children)
+        })
+      }
+    }
+  }
+}
+</script>
+
+<style lang='scss'>
+.editor-tabs{
+  background: #121315;
+  .el-tabs__header{
+    margin: 0;
+    border-bottom-color: #121315;
+    .el-tabs__nav{
+      border-color: #121315;
+    }
+  }
+  .el-tabs__item{
+    height: 32px;
+    line-height: 32px;
+    color: #888a8e;
+    border-left: 1px solid #121315 !important;
+    background: #363636;
+    margin-right: 5px;
+    user-select: none;
+  }
+  .el-tabs__item.is-active{
+    background: #1e1e1e;
+    border-bottom-color: #1e1e1e!important;
+    color: #fff;
+  }
+  .el-icon-edit{
+    color: #f1fa8c;
+  }
+  .el-icon-document{
+    color: #a95812;
+  }
+}
+
+// home
+.right-scrollbar {
+  .el-scrollbar__view {
+    padding: 12px 18px 15px 15px;
+  }
+}
+.left-scrollbar .el-scrollbar__wrap {
+  box-sizing: border-box;
+  overflow-x: hidden !important;
+  margin-bottom: 0 !important;
+}
+.center-tabs{
+  .el-tabs__header{
+    margin-bottom: 0!important;
+  }
+  .el-tabs__item{
+    width: 50%;
+    text-align: center;
+  }
+  .el-tabs__nav{
+    width: 100%;
+  }
+}
+.reg-item{
+  padding: 12px 6px;
+  background: #f8f8f8;
+  position: relative;
+  border-radius: 4px;
+  .close-btn{
+    position: absolute;
+    right: -6px;
+    top: -6px;
+    display: block;
+    width: 16px;
+    height: 16px;
+    line-height: 16px;
+    background: rgba(0, 0, 0, 0.2);
+    border-radius: 50%;
+    color: #fff;
+    text-align: center;
+    z-index: 1;
+    cursor: pointer;
+    font-size: 12px;
+    &:hover{
+      background: rgba(210, 23, 23, 0.5)
+    }
+  }
+  & + .reg-item{
+    margin-top: 18px;
+  }
+}
+.action-bar{
+  & .el-button+.el-button {
+    margin-left: 15px;
+  }
+  & i {
+    font-size: 20px;
+    vertical-align: middle;
+    position: relative;
+    top: -1px;
+  }
+}
+
+.custom-tree-node{
+  width: 100%;
+  font-size: 14px;
+  .node-operation{
+    float: right;
+  }
+  i[class*="el-icon"] + i[class*="el-icon"]{
+    margin-left: 6px;
+  }
+  .el-icon-plus{
+    color: #409EFF;
+  }
+  .el-icon-delete{
+    color: #157a0c;
+  }
+}
+
+.left-scrollbar .el-scrollbar__view{
+  overflow-x: hidden;
+}
+
+.el-rate{
+  display: inline-block;
+  vertical-align: text-top;
+}
+.el-upload__tip{
+  line-height: 1.2;
+}
+
+$selectedColor: #f6f7ff;
+$lighterBlue: #409EFF;
+
+.container {
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+.components-list {
+  padding: 8px;
+  box-sizing: border-box;
+  height: 100%;
+  .components-item {
+    display: inline-block;
+    width: 48%;
+    margin: 1%;
+    transition: transform 0ms !important;
+  }
+}
+.components-draggable{
+  padding-bottom: 20px;
+}
+.components-title{
+  font-size: 14px;
+  color: #222;
+  margin: 6px 2px;
+  .svg-icon{
+    color: #666;
+    font-size: 18px;
+  }
+}
+
+.components-body {
+  padding: 8px 10px;
+  background: $selectedColor;
+  font-size: 12px;
+  cursor: move;
+  border: 1px dashed $selectedColor;
+  border-radius: 3px;
+  .svg-icon{
+    color: #777;
+    font-size: 15px;
+  }
+  &:hover {
+    border: 1px dashed #787be8;
+    color: #787be8;
+    .svg-icon {
+      color: #787be8;
+    }
+  }
+}
+
+.left-board {
+  width: 260px;
+  position: absolute;
+  left: 0;
+  top: 0;
+  height: 100vh;
+}
+.left-scrollbar{
+  height: calc(100vh - 42px);
+  overflow: hidden;
+}
+.center-scrollbar {
+  height: calc(100vh - 42px);
+  overflow: hidden;
+  border-left: 1px solid #f1e8e8;
+  border-right: 1px solid #f1e8e8;
+  box-sizing: border-box;
+}
+.center-board {
+  height: 100vh;
+  width: auto;
+  margin: 0 350px 0 260px;
+  box-sizing: border-box;
+}
+.empty-info{
+  position: absolute;
+  top: 46%;
+  left: 0;
+  right: 0;
+  text-align: center;
+  font-size: 18px;
+  color: #ccb1ea;
+  letter-spacing: 4px;
+}
+.action-bar{
+  position: relative;
+  height: 42px;
+  text-align: right;
+  padding: 0 15px;
+  box-sizing: border-box;;
+  border: 1px solid #f1e8e8;
+  border-top: none;
+  border-left: none;
+  .delete-btn{
+    color: #F56C6C;
+  }
+}
+.logo-wrapper{
+  position: relative;
+  height: 42px;
+  background: #fff;
+  border-bottom: 1px solid #f1e8e8;
+  box-sizing: border-box;
+}
+.logo{
+  position: absolute;
+  left: 12px;
+  top: 6px;
+  line-height: 30px;
+  color: #00afff;
+  font-weight: 600;
+  font-size: 17px;
+  white-space: nowrap;
+  > img{
+    width: 30px;
+    height: 30px;
+    vertical-align: top;
+  }
+  .github{
+    display: inline-block;
+    vertical-align: sub;
+    margin-left: 15px;
+    > img{
+      height: 22px;
+    }
+  }
+}
+
+.center-board-row {
+  padding: 12px 12px 15px 12px;
+  box-sizing: border-box;
+  & > .el-form {
+    // 69 = 12+15+42
+    height: calc(100vh - 69px);
+  }
+}
+.drawing-board {
+  height: 100%;
+  position: relative;
+  .components-body {
+    padding: 0;
+    margin: 0;
+    font-size: 0;
+  }
+  .sortable-ghost {
+    position: relative;
+    display: block;
+    overflow: hidden;
+    &::before {
+      content: " ";
+      position: absolute;
+      left: 0;
+      right: 0;
+      top: 0;
+      height: 3px;
+      background: rgb(89, 89, 223);
+      z-index: 2;
+    }
+  }
+  .components-item.sortable-ghost {
+    width: 100%;
+    height: 60px;
+    background-color: $selectedColor;
+  }
+  .active-from-item {
+    & > .el-form-item{
+      background: $selectedColor;
+      border-radius: 6px;
+    }
+    & > .drawing-item-copy, & > .drawing-item-delete{
+      display: initial;
+    }
+    & > .component-name{
+      color: $lighterBlue;
+    }
+  }
+  .el-form-item{
+    margin-bottom: 15px;
+  }
+}
+.drawing-item{
+  position: relative;
+  cursor: move;
+  &.unfocus-bordered:not(.activeFromItem) > div:first-child  {
+    border: 1px dashed #ccc;
+  }
+  .el-form-item{
+    padding: 12px 10px;
+  }
+}
+.drawing-row-item{
+  position: relative;
+  cursor: move;
+  box-sizing: border-box;
+  border: 1px dashed #ccc;
+  border-radius: 3px;
+  padding: 0 2px;
+  margin-bottom: 15px;
+  .drawing-row-item {
+    margin-bottom: 2px;
+  }
+  .el-col{
+    margin-top: 22px;
+  }
+  .el-form-item{
+    margin-bottom: 0;
+  }
+  .drag-wrapper{
+    min-height: 80px;
+  }
+  &.active-from-item{
+    border: 1px dashed $lighterBlue;
+  }
+  .component-name{
+    position: absolute;
+    top: 0;
+    left: 0;
+    font-size: 12px;
+    color: #bbb;
+    display: inline-block;
+    padding: 0 6px;
+  }
+}
+.drawing-item, .drawing-row-item{
+  &:hover {
+    & > .el-form-item{
+      background: $selectedColor;
+      border-radius: 6px;
+    }
+    & > .drawing-item-copy, & > .drawing-item-delete{
+      display: initial;
+    }
+  }
+  & > .drawing-item-copy, & > .drawing-item-delete{
+    display: none;
+    position: absolute;
+    top: -10px;
+    width: 22px;
+    height: 22px;
+    line-height: 22px;
+    text-align: center;
+    border-radius: 50%;
+    font-size: 12px;
+    border: 1px solid;
+    cursor: pointer;
+    z-index: 1;
+  }
+  & > .drawing-item-copy{
+    right: 56px;
+    border-color: $lighterBlue;
+    color: $lighterBlue;
+    background: #fff;
+    &:hover{
+      background: $lighterBlue;
+      color: #fff;
+    }
+  }
+  & > .drawing-item-delete{
+    right: 24px;
+    border-color: #F56C6C;
+    color: #F56C6C;
+    background: #fff;
+    &:hover{
+      background: #F56C6C;
+      color: #fff;
+    }
+  }
+}
+</style>
diff --git a/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
new file mode 100644
index 0000000..7029529
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/basicInfoForm.vue
@@ -0,0 +1,60 @@
+<template>
+  <el-form ref="basicInfoForm" :model="info" :rules="rules" label-width="150px">
+    <el-row>
+      <el-col :span="12">
+        <el-form-item label="琛ㄥ悕绉�" prop="tableName">
+          <el-input placeholder="璇疯緭鍏ヤ粨搴撳悕绉�" v-model="info.tableName" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="琛ㄦ弿杩�" prop="tableComment">
+          <el-input placeholder="璇疯緭鍏�" v-model="info.tableComment" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="瀹炰綋绫诲悕绉�" prop="className">
+          <el-input placeholder="璇疯緭鍏�" v-model="info.className" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="12">
+        <el-form-item label="浣滆��" prop="functionAuthor">
+          <el-input placeholder="璇疯緭鍏�" v-model="info.functionAuthor" />
+        </el-form-item>
+      </el-col>
+      <el-col :span="24">
+        <el-form-item label="澶囨敞" prop="remark">
+          <el-input type="textarea" :rows="3" v-model="info.remark"></el-input>
+        </el-form-item>
+      </el-col>
+    </el-row>
+  </el-form>
+</template>
+
+<script>
+export default {
+  props: {
+    info: {
+      type: Object,
+      default: null
+    }
+  },
+  data() {
+    return {
+      rules: {
+        tableName: [
+          { required: true, message: "璇疯緭鍏ヨ〃鍚嶇О", trigger: "blur" }
+        ],
+        tableComment: [
+          { required: true, message: "璇疯緭鍏ヨ〃鎻忚堪", trigger: "blur" }
+        ],
+        className: [
+          { required: true, message: "璇疯緭鍏ュ疄浣撶被鍚嶇О", trigger: "blur" }
+        ],
+        functionAuthor: [
+          { required: true, message: "璇疯緭鍏ヤ綔鑰�", trigger: "blur" }
+        ]
+      }
+    };
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/createTable.vue b/ruoyi-ui/src/views/tool/gen/createTable.vue
new file mode 100644
index 0000000..f914b5d
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/createTable.vue
@@ -0,0 +1,45 @@
+<template>
+  <!-- 鍒涘缓琛� -->
+  <el-dialog title="鍒涘缓琛�" :visible.sync="visible" width="800px" top="5vh" append-to-body>
+    <span>鍒涘缓琛ㄨ鍙�(鏀寔澶氫釜寤鸿〃璇彞)锛�</span>
+    <el-input type="textarea" :rows="10" placeholder="璇疯緭鍏ユ枃鏈�" v-model="content"></el-input>
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="handleCreateTable">纭� 瀹�</el-button>
+      <el-button @click="visible = false">鍙� 娑�</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { createTable } from "@/api/tool/gen";
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      visible: false,
+      // 鏂囨湰鍐呭
+      content: ""
+    };
+  },
+  methods: {
+    // 鏄剧ず寮规
+    show() {
+      this.visible = true;
+    },
+    /** 鍒涘缓鎸夐挳鎿嶄綔 */
+    handleCreateTable() {
+      if (this.content === "") {
+        this.$modal.msgError("璇疯緭鍏ュ缓琛ㄨ鍙�");
+        return;
+      }
+      createTable({ sql: this.content }).then(res => {
+        this.$modal.msgSuccess(res.msg);
+        if (res.code === 200) {
+          this.visible = false;
+          this.$emit("ok");
+        }
+      });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/editTable.vue b/ruoyi-ui/src/views/tool/gen/editTable.vue
new file mode 100644
index 0000000..951497a
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/editTable.vue
@@ -0,0 +1,234 @@
+<template>
+  <el-card>
+    <el-tabs v-model="activeName">
+      <el-tab-pane label="鍩烘湰淇℃伅" name="basic">
+        <basic-info-form ref="basicInfo" :info="info" />
+      </el-tab-pane>
+      <el-tab-pane label="瀛楁淇℃伅" name="columnInfo">
+        <el-table ref="dragTable" :data="columns" row-key="columnId" :max-height="tableHeight">
+          <el-table-column label="搴忓彿" type="index" min-width="5%" class-name="allowDrag" />
+          <el-table-column
+            label="瀛楁鍒楀悕"
+            prop="columnName"
+            min-width="10%"
+            :show-overflow-tooltip="true"
+          />
+          <el-table-column label="瀛楁鎻忚堪" min-width="10%">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.columnComment"></el-input>
+            </template>
+          </el-table-column>
+          <el-table-column
+            label="鐗╃悊绫诲瀷"
+            prop="columnType"
+            min-width="10%"
+            :show-overflow-tooltip="true"
+          />
+          <el-table-column label="Java绫诲瀷" min-width="11%">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.javaType">
+                <el-option label="Long" value="Long" />
+                <el-option label="String" value="String" />
+                <el-option label="Integer" value="Integer" />
+                <el-option label="Double" value="Double" />
+                <el-option label="BigDecimal" value="BigDecimal" />
+                <el-option label="Date" value="Date" />
+                <el-option label="Boolean" value="Boolean" />
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="java灞炴��" min-width="10%">
+            <template slot-scope="scope">
+              <el-input v-model="scope.row.javaField"></el-input>
+            </template>
+          </el-table-column>
+
+          <el-table-column label="鎻掑叆" min-width="5%">
+            <template slot-scope="scope">
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isInsert"></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column label="缂栬緫" min-width="5%">
+            <template slot-scope="scope">
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isEdit"></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column label="鍒楄〃" min-width="5%">
+            <template slot-scope="scope">
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isList"></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column label="鏌ヨ" min-width="5%">
+            <template slot-scope="scope">
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isQuery"></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column label="鏌ヨ鏂瑰紡" min-width="10%">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.queryType">
+                <el-option label="=" value="EQ" />
+                <el-option label="!=" value="NE" />
+                <el-option label=">" value="GT" />
+                <el-option label=">=" value="GTE" />
+                <el-option label="<" value="LT" />
+                <el-option label="<=" value="LTE" />
+                <el-option label="LIKE" value="LIKE" />
+                <el-option label="BETWEEN" value="BETWEEN" />
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="蹇呭~" min-width="5%">
+            <template slot-scope="scope">
+              <el-checkbox true-label="1" false-label="0" v-model="scope.row.isRequired"></el-checkbox>
+            </template>
+          </el-table-column>
+          <el-table-column label="鏄剧ず绫诲瀷" min-width="12%">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.htmlType">
+                <el-option label="鏂囨湰妗�" value="input" />
+                <el-option label="鏂囨湰鍩�" value="textarea" />
+                <el-option label="涓嬫媺妗�" value="select" />
+                <el-option label="鍗曢�夋" value="radio" />
+                <el-option label="澶嶉�夋" value="checkbox" />
+                <el-option label="鏃ユ湡鎺т欢" value="datetime" />
+                <el-option label="鍥剧墖涓婁紶" value="imageUpload" />
+                <el-option label="鏂囦欢涓婁紶" value="fileUpload" />
+                <el-option label="瀵屾枃鏈帶浠�" value="editor" />
+              </el-select>
+            </template>
+          </el-table-column>
+          <el-table-column label="瀛楀吀绫诲瀷" min-width="12%">
+            <template slot-scope="scope">
+              <el-select v-model="scope.row.dictType" clearable filterable placeholder="璇烽�夋嫨">
+                <el-option
+                  v-for="dict in dictOptions"
+                  :key="dict.dictType"
+                  :label="dict.dictName"
+                  :value="dict.dictType">
+                  <span style="float: left">{{ dict.dictName }}</span>
+                  <span style="float: right; color: #8492a6; font-size: 13px">{{ dict.dictType }}</span>
+              </el-option>
+              </el-select>
+            </template>
+          </el-table-column>
+        </el-table>
+      </el-tab-pane>
+      <el-tab-pane label="鐢熸垚淇℃伅" name="genInfo">
+        <gen-info-form ref="genInfo" :info="info" :tables="tables" :menus="menus"/>
+      </el-tab-pane>
+    </el-tabs>
+    <el-form label-width="100px">
+      <el-form-item style="text-align: center;margin-left:-100px;margin-top:10px;">
+        <el-button type="primary" @click="submitForm()">鎻愪氦</el-button>
+        <el-button @click="close()">杩斿洖</el-button>
+      </el-form-item>
+    </el-form>
+  </el-card>
+</template>
+
+<script>
+import { getGenTable, updateGenTable } from "@/api/tool/gen";
+import { optionselect as getDictOptionselect } from "@/api/system/dict/type";
+import { listMenu as getMenuTreeselect } from "@/api/system/menu";
+import basicInfoForm from "./basicInfoForm";
+import genInfoForm from "./genInfoForm";
+import Sortable from 'sortablejs'
+
+export default {
+  name: "GenEdit",
+  components: {
+    basicInfoForm,
+    genInfoForm
+  },
+  data() {
+    return {
+      // 閫変腑閫夐」鍗$殑 name
+      activeName: "columnInfo",
+      // 琛ㄦ牸鐨勯珮搴�
+      tableHeight: document.documentElement.scrollHeight - 245 + "px",
+      // 琛ㄤ俊鎭�
+      tables: [],
+      // 琛ㄥ垪淇℃伅
+      columns: [],
+      // 瀛楀吀淇℃伅
+      dictOptions: [],
+      // 鑿滃崟淇℃伅
+      menus: [],
+      // 琛ㄨ缁嗕俊鎭�
+      info: {}
+    };
+  },
+  created() {
+    const tableId = this.$route.params && this.$route.params.tableId;
+    if (tableId) {
+      // 鑾峰彇琛ㄨ缁嗕俊鎭�
+      getGenTable(tableId).then(res => {
+        this.columns = res.data.rows;
+        this.info = res.data.info;
+        this.tables = res.data.tables;
+      });
+      /** 鏌ヨ瀛楀吀涓嬫媺鍒楄〃 */
+      getDictOptionselect().then(response => {
+        this.dictOptions = response.data;
+      });
+      /** 鏌ヨ鑿滃崟涓嬫媺鍒楄〃 */
+      getMenuTreeselect().then(response => {
+        this.menus = this.handleTree(response.data, "menuId");
+      });
+    }
+  },
+  methods: {
+    /** 鎻愪氦鎸夐挳 */
+    submitForm() {
+      const basicForm = this.$refs.basicInfo.$refs.basicInfoForm;
+      const genForm = this.$refs.genInfo.$refs.genInfoForm;
+      Promise.all([basicForm, genForm].map(this.getFormPromise)).then(res => {
+        const validateResult = res.every(item => !!item);
+        if (validateResult) {
+          const genTable = Object.assign({}, basicForm.model, genForm.model);
+          genTable.columns = this.columns;
+          genTable.params = {
+            treeCode: genTable.treeCode,
+            treeName: genTable.treeName,
+            treeParentCode: genTable.treeParentCode,
+            parentMenuId: genTable.parentMenuId
+          };
+          updateGenTable(genTable).then(res => {
+            this.$modal.msgSuccess(res.msg);
+            if (res.code === 200) {
+              this.close();
+            }
+          });
+        } else {
+          this.$modal.msgError("琛ㄥ崟鏍¢獙鏈�氳繃锛岃閲嶆柊妫�鏌ユ彁浜ゅ唴瀹�");
+        }
+      });
+    },
+    getFormPromise(form) {
+      return new Promise(resolve => {
+        form.validate(res => {
+          resolve(res);
+        });
+      });
+    },
+    /** 鍏抽棴鎸夐挳 */
+    close() {
+      const obj = { path: "/tool/gen", query: { t: Date.now(), pageNum: this.$route.query.pageNum } };
+      this.$tab.closeOpenPage(obj);
+    }
+  },
+  mounted() {
+    const el = this.$refs.dragTable.$el.querySelectorAll(".el-table__body-wrapper > table > tbody")[0];
+    const sortable = Sortable.create(el, {
+      handle: ".allowDrag",
+      onEnd: evt => {
+        const targetRow = this.columns.splice(evt.oldIndex, 1)[0];
+        this.columns.splice(evt.newIndex, 0, targetRow);
+        for (let index in this.columns) {
+          this.columns[index].sort = parseInt(index) + 1;
+        }
+      }
+    });
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/genInfoForm.vue b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
new file mode 100644
index 0000000..98daf6d
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/genInfoForm.vue
@@ -0,0 +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="鐢熸垚鍦ㄥ摢涓猨ava鍖呬笅锛屼緥濡� 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="鍙悊瑙d负瀛愮郴缁熷悕锛屼緥濡� 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="鍙悊瑙d负鍔熻兘鑻辨枃鍚嶏紝渚嬪 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">
+            鐢熸垚浠g爜鏂瑰紡
+            <el-tooltip content="榛樿涓簔ip鍘嬬缉鍖呬笅杞斤紝涔熷彲浠ヨ嚜瀹氫箟鐢熸垚璺緞" 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/importTable.vue b/ruoyi-ui/src/views/tool/gen/importTable.vue
new file mode 100644
index 0000000..3ea9532
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/importTable.vue
@@ -0,0 +1,120 @@
+<template>
+  <!-- 瀵煎叆琛� -->
+  <el-dialog title="瀵煎叆琛�" :visible.sync="visible" width="800px" top="5vh" append-to-body>
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true">
+      <el-form-item label="琛ㄥ悕绉�" prop="tableName">
+        <el-input
+          v-model="queryParams.tableName"
+          placeholder="璇疯緭鍏ヨ〃鍚嶇О"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="琛ㄦ弿杩�" prop="tableComment">
+        <el-input
+          v-model="queryParams.tableComment"
+          placeholder="璇疯緭鍏ヨ〃鎻忚堪"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <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>
+      <el-table @row-click="clickRow" ref="table" :data="dbTableList" @selection-change="handleSelectionChange" height="260px">
+        <el-table-column type="selection" width="55"></el-table-column>
+        <el-table-column prop="tableName" label="琛ㄥ悕绉�" :show-overflow-tooltip="true"></el-table-column>
+        <el-table-column prop="tableComment" label="琛ㄦ弿杩�" :show-overflow-tooltip="true"></el-table-column>
+        <el-table-column prop="createTime" label="鍒涘缓鏃堕棿"></el-table-column>
+        <el-table-column prop="updateTime" label="鏇存柊鏃堕棿"></el-table-column>
+      </el-table>
+      <pagination
+        v-show="total>0"
+        :total="total"
+        :page.sync="queryParams.pageNum"
+        :limit.sync="queryParams.pageSize"
+        @pagination="getList"
+      />
+    </el-row>
+    <div slot="footer" class="dialog-footer">
+      <el-button type="primary" @click="handleImportTable">纭� 瀹�</el-button>
+      <el-button @click="visible = false">鍙� 娑�</el-button>
+    </div>
+  </el-dialog>
+</template>
+
+<script>
+import { listDbTable, importTable } from "@/api/tool/gen";
+export default {
+  data() {
+    return {
+      // 閬僵灞�
+      visible: false,
+      // 閫変腑鏁扮粍鍊�
+      tables: [],
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ暟鎹�
+      dbTableList: [],
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        tableName: undefined,
+        tableComment: undefined
+      }
+    };
+  },
+  methods: {
+    // 鏄剧ず寮规
+    show() {
+      this.getList();
+      this.visible = true;
+    },
+    clickRow(row) {
+      this.$refs.table.toggleRowSelection(row);
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.tables = selection.map(item => item.tableName);
+    },
+    // 鏌ヨ琛ㄦ暟鎹�
+    getList() {
+      listDbTable(this.queryParams).then(res => {
+        if (res.code === 200) {
+          this.dbTableList = res.rows;
+          this.total = res.total;
+        }
+      });
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 瀵煎叆鎸夐挳鎿嶄綔 */
+    handleImportTable() {
+      const tableNames = this.tables.join(",");
+      if (tableNames == "") {
+        this.$modal.msgError("璇烽�夋嫨瑕佸鍏ョ殑琛�");
+        return;
+      }
+      importTable({ tables: tableNames }).then(res => {
+        this.$modal.msgSuccess(res.msg);
+        if (res.code === 200) {
+          this.visible = false;
+          this.$emit("ok");
+        }
+      });
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/gen/index.vue b/ruoyi-ui/src/views/tool/gen/index.vue
new file mode 100644
index 0000000..9237c30
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/gen/index.vue
@@ -0,0 +1,354 @@
+<template>
+  <div class="app-container">
+    <el-form :model="queryParams" ref="queryForm" size="small" :inline="true" v-show="showSearch" label-width="68px">
+      <el-form-item label="琛ㄥ悕绉�" prop="tableName">
+        <el-input
+          v-model="queryParams.tableName"
+          placeholder="璇疯緭鍏ヨ〃鍚嶇О"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="琛ㄦ弿杩�" prop="tableComment">
+        <el-input
+          v-model="queryParams.tableComment"
+          placeholder="璇疯緭鍏ヨ〃鎻忚堪"
+          clearable
+          @keyup.enter.native="handleQuery"
+        />
+      </el-form-item>
+      <el-form-item label="鍒涘缓鏃堕棿">
+        <el-date-picker
+          v-model="dateRange"
+          style="width: 240px"
+          value-format="yyyy-MM-dd"
+          type="daterange"
+          range-separator="-"
+          start-placeholder="寮�濮嬫棩鏈�"
+          end-placeholder="缁撴潫鏃ユ湡"
+        ></el-date-picker>
+      </el-form-item>
+      <el-form-item>
+        <el-button type="primary" icon="el-icon-search" size="mini" @click="handleQuery">鎼滅储</el-button>
+        <el-button 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-download"
+          size="mini"
+          :disabled="multiple"
+          @click="handleGenTable"
+          v-hasPermi="['tool:gen:code']"
+        >鐢熸垚</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="primary"
+          plain
+          icon="el-icon-plus"
+          size="mini"
+          @click="openCreateTable"
+          v-hasRole="['admin']"
+        >鍒涘缓</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="info"
+          plain
+          icon="el-icon-upload"
+          size="mini"
+          @click="openImportTable"
+          v-hasPermi="['tool:gen:import']"
+        >瀵煎叆</el-button>
+      </el-col>
+      <el-col :span="1.5">
+        <el-button
+          type="success"
+          plain
+          icon="el-icon-edit"
+          size="mini"
+          :disabled="single"
+          @click="handleEditTable"
+          v-hasPermi="['tool:gen: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="['tool:gen:remove']"
+        >鍒犻櫎</el-button>
+      </el-col>
+      <right-toolbar :showSearch.sync="showSearch" @queryTable="getList"></right-toolbar>
+    </el-row>
+
+    <el-table v-loading="loading" :data="tableList" @selection-change="handleSelectionChange">
+      <el-table-column type="selection" align="center" width="55"></el-table-column>
+      <el-table-column label="搴忓彿" type="index" width="50" align="center">
+        <template slot-scope="scope">
+          <span>{{(queryParams.pageNum - 1) * queryParams.pageSize + scope.$index + 1}}</span>
+        </template>
+      </el-table-column>
+      <el-table-column
+        label="琛ㄥ悕绉�"
+        align="center"
+        prop="tableName"
+        :show-overflow-tooltip="true"
+        width="120"
+      />
+      <el-table-column
+        label="琛ㄦ弿杩�"
+        align="center"
+        prop="tableComment"
+        :show-overflow-tooltip="true"
+        width="120"
+      />
+      <el-table-column
+        label="瀹炰綋"
+        align="center"
+        prop="className"
+        :show-overflow-tooltip="true"
+        width="120"
+      />
+      <el-table-column label="鍒涘缓鏃堕棿" align="center" prop="createTime" width="160" />
+      <el-table-column label="鏇存柊鏃堕棿" align="center" prop="updateTime" width="160" />
+      <el-table-column label="鎿嶄綔" align="center" class-name="small-padding fixed-width">
+        <template slot-scope="scope">
+          <el-button
+            type="text"
+            size="small"
+            icon="el-icon-view"
+            @click="handlePreview(scope.row)"
+            v-hasPermi="['tool:gen:preview']"
+          >棰勮</el-button>
+          <el-button
+            type="text"
+            size="small"
+            icon="el-icon-edit"
+            @click="handleEditTable(scope.row)"
+            v-hasPermi="['tool:gen:edit']"
+          >缂栬緫</el-button>
+          <el-button
+            type="text"
+            size="small"
+            icon="el-icon-delete"
+            @click="handleDelete(scope.row)"
+            v-hasPermi="['tool:gen:remove']"
+          >鍒犻櫎</el-button>
+          <el-button
+            type="text"
+            size="small"
+            icon="el-icon-refresh"
+            @click="handleSynchDb(scope.row)"
+            v-hasPermi="['tool:gen:edit']"
+          >鍚屾</el-button>
+          <el-button
+            type="text"
+            size="small"
+            icon="el-icon-download"
+            @click="handleGenTable(scope.row)"
+            v-hasPermi="['tool:gen:code']"
+          >鐢熸垚浠g爜</el-button>
+        </template>
+      </el-table-column>
+    </el-table>
+    <pagination
+      v-show="total>0"
+      :total="total"
+      :page.sync="queryParams.pageNum"
+      :limit.sync="queryParams.pageSize"
+      @pagination="getList"
+    />
+    <!-- 棰勮鐣岄潰 -->
+    <el-dialog :title="preview.title" :visible.sync="preview.open" width="80%" top="5vh" append-to-body class="scrollbar">
+      <el-tabs v-model="preview.activeName">
+        <el-tab-pane
+          v-for="(value, key) in preview.data"
+          :label="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
+          :name="key.substring(key.lastIndexOf('/')+1,key.indexOf('.vm'))"
+          :key="key"
+        >
+          <el-link :underline="false" icon="el-icon-document-copy" v-clipboard:copy="value" v-clipboard:success="clipboardSuccess" style="float:right">澶嶅埗</el-link>
+          <pre><code class="hljs" v-html="highlightedCode(value, key)"></code></pre>
+        </el-tab-pane>
+      </el-tabs>
+    </el-dialog>
+    <import-table ref="import" @ok="handleQuery" />
+    <create-table ref="create" @ok="handleQuery" />
+  </div>
+</template>
+
+<script>
+import { listTable, previewTable, delTable, genCode, synchDb } from "@/api/tool/gen";
+import importTable from "./importTable";
+import createTable from "./createTable";
+import hljs from "highlight.js/lib/highlight";
+import "highlight.js/styles/github-gist.css";
+hljs.registerLanguage("java", require("highlight.js/lib/languages/java"));
+hljs.registerLanguage("xml", require("highlight.js/lib/languages/xml"));
+hljs.registerLanguage("html", require("highlight.js/lib/languages/xml"));
+hljs.registerLanguage("vue", require("highlight.js/lib/languages/xml"));
+hljs.registerLanguage("javascript", require("highlight.js/lib/languages/javascript"));
+hljs.registerLanguage("sql", require("highlight.js/lib/languages/sql"));
+
+export default {
+  name: "Gen",
+  components: { importTable, createTable },
+  data() {
+    return {
+      // 閬僵灞�
+      loading: true,
+      // 鍞竴鏍囪瘑绗�
+      uniqueId: "",
+      // 閫変腑鏁扮粍
+      ids: [],
+      // 閫変腑琛ㄦ暟缁�
+      tableNames: [],
+      // 闈炲崟涓鐢�
+      single: true,
+      // 闈炲涓鐢�
+      multiple: true,
+      // 鏄剧ず鎼滅储鏉′欢
+      showSearch: true,
+      // 鎬绘潯鏁�
+      total: 0,
+      // 琛ㄦ暟鎹�
+      tableList: [],
+      // 鏃ユ湡鑼冨洿
+      dateRange: "",
+      // 鏌ヨ鍙傛暟
+      queryParams: {
+        pageNum: 1,
+        pageSize: 10,
+        tableName: undefined,
+        tableComment: undefined
+      },
+      // 棰勮鍙傛暟
+      preview: {
+        open: false,
+        title: "浠g爜棰勮",
+        data: {},
+        activeName: "domain.java"
+      }
+    };
+  },
+  created() {
+    this.getList();
+  },
+  activated() {
+    const time = this.$route.query.t;
+    if (time != null && time != this.uniqueId) {
+      this.uniqueId = time;
+      this.queryParams.pageNum = Number(this.$route.query.pageNum);
+      this.getList();
+    }
+  },
+  methods: {
+    /** 鏌ヨ琛ㄩ泦鍚� */
+    getList() {
+      this.loading = true;
+      listTable(this.addDateRange(this.queryParams, this.dateRange)).then(response => {
+          this.tableList = response.rows;
+          this.total = response.total;
+          this.loading = false;
+        }
+      );
+    },
+    /** 鎼滅储鎸夐挳鎿嶄綔 */
+    handleQuery() {
+      this.queryParams.pageNum = 1;
+      this.getList();
+    },
+    /** 鐢熸垚浠g爜鎿嶄綔 */
+    handleGenTable(row) {
+      const tableNames = row.tableName || this.tableNames;
+      if (tableNames == "") {
+        this.$modal.msgError("璇烽�夋嫨瑕佺敓鎴愮殑鏁版嵁");
+        return;
+      }
+      if(row.genType === "1") {
+        genCode(row.tableName).then(response => {
+          this.$modal.msgSuccess("鎴愬姛鐢熸垚鍒拌嚜瀹氫箟璺緞锛�" + row.genPath);
+        });
+      } else {
+        this.$download.zip("/tool/gen/batchGenCode?tables=" + tableNames, "ruoyi.zip");
+      }
+    },
+    /** 鍚屾鏁版嵁搴撴搷浣� */
+    handleSynchDb(row) {
+      const tableName = row.tableName;
+      this.$modal.confirm('纭瑕佸己鍒跺悓姝�"' + tableName + '"琛ㄧ粨鏋勫悧锛�').then(function() {
+        return synchDb(tableName);
+      }).then(() => {
+        this.$modal.msgSuccess("鍚屾鎴愬姛");
+      }).catch(() => {});
+    },
+    /** 鎵撳紑瀵煎叆琛ㄥ脊绐� */
+    openImportTable() {
+      this.$refs.import.show();
+    },
+    /** 鎵撳紑鍒涘缓琛ㄥ脊绐� */
+    openCreateTable() {
+      this.$refs.create.show();
+    },
+    /** 閲嶇疆鎸夐挳鎿嶄綔 */
+    resetQuery() {
+      this.dateRange = [];
+      this.resetForm("queryForm");
+      this.handleQuery();
+    },
+    /** 棰勮鎸夐挳 */
+    handlePreview(row) {
+      previewTable(row.tableId).then(response => {
+        this.preview.data = response.data;
+        this.preview.open = true;
+        this.preview.activeName = "domain.java";
+      });
+    },
+    /** 楂樹寒鏄剧ず */
+    highlightedCode(code, key) {
+      const vmName = key.substring(key.lastIndexOf("/") + 1, key.indexOf(".vm"));
+      var language = vmName.substring(vmName.indexOf(".") + 1, vmName.length);
+      const result = hljs.highlight(language, code || "", true);
+      return result.value || '&nbsp;';
+    },
+    /** 澶嶅埗浠g爜鎴愬姛 */
+    clipboardSuccess() {
+      this.$modal.msgSuccess("澶嶅埗鎴愬姛");
+    },
+    // 澶氶�夋閫変腑鏁版嵁
+    handleSelectionChange(selection) {
+      this.ids = selection.map(item => item.tableId);
+      this.tableNames = selection.map(item => item.tableName);
+      this.single = selection.length != 1;
+      this.multiple = !selection.length;
+    },
+    /** 淇敼鎸夐挳鎿嶄綔 */
+    handleEditTable(row) {
+      const tableId = row.tableId || this.ids[0];
+      const tableName = row.tableName || this.tableNames[0];
+      const params = { pageNum: this.queryParams.pageNum };
+      this.$tab.openPage("淇敼[" + tableName + "]鐢熸垚閰嶇疆", '/tool/gen-edit/index/' + tableId, params);
+    },
+    /** 鍒犻櫎鎸夐挳鎿嶄綔 */
+    handleDelete(row) {
+      const tableIds = row.tableId || this.ids;
+      this.$modal.confirm('鏄惁纭鍒犻櫎琛ㄧ紪鍙蜂负"' + tableIds + '"鐨勬暟鎹」锛�').then(function() {
+        return delTable(tableIds);
+      }).then(() => {
+        this.getList();
+        this.$modal.msgSuccess("鍒犻櫎鎴愬姛");
+      }).catch(() => {});
+    }
+  }
+};
+</script>
diff --git a/ruoyi-ui/src/views/tool/swagger/index.vue b/ruoyi-ui/src/views/tool/swagger/index.vue
new file mode 100644
index 0000000..b8becc6
--- /dev/null
+++ b/ruoyi-ui/src/views/tool/swagger/index.vue
@@ -0,0 +1,15 @@
+<template>
+  <i-frame :src="url" />
+</template>
+<script>
+import iFrame from "@/components/iFrame/index";
+export default {
+  name: "Swagger",
+  components: { iFrame },
+  data() {
+    return {
+      url: process.env.VUE_APP_BASE_API + "/swagger-ui/index.html"
+    };
+  },
+};
+</script>
diff --git a/ruoyi-ui/vue.config.js b/ruoyi-ui/vue.config.js
new file mode 100644
index 0000000..8afb50b
--- /dev/null
+++ b/ruoyi-ui/vue.config.js
@@ -0,0 +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 = {
+  // 閮ㄧ讲鐢熶骇鐜鍜屽紑鍙戠幆澧冧笅鐨刄RL銆�
+  // 榛樿鎯呭喌涓嬶紝Vue CLI 浼氬亣璁句綘鐨勫簲鐢ㄦ槸琚儴缃插湪涓�涓煙鍚嶇殑鏍硅矾寰勪笂
+  // 渚嬪 https://www.ruoyi.vip/銆傚鏋滃簲鐢ㄨ閮ㄧ讲鍦ㄤ竴涓瓙璺緞涓婏紝浣犲氨闇�瑕佺敤杩欎釜閫夐」鎸囧畾杩欎釜瀛愯矾寰勩�備緥濡傦紝濡傛灉浣犵殑搴旂敤琚儴缃插湪 https://www.ruoyi.vip/admin/锛屽垯璁剧疆 baseUrl 涓� /admin/銆�
+  publicPath: process.env.NODE_ENV === "production" ? "/" : "/",
+  // 鍦╪pm run build 鎴� yarn build 鏃� 锛岀敓鎴愭枃浠剁殑鐩綍鍚嶇О锛堣鍜宐aseUrl鐨勭敓浜х幆澧冭矾寰勪竴鑷达級锛堥粯璁ist锛�
+  outputDir: 'dist',
+  // 鐢ㄤ簬鏀剧疆鐢熸垚鐨勯潤鎬佽祫婧� (js銆乧ss銆乮mg銆乫onts) 鐨勶紱锛堥」鐩墦鍖呬箣鍚庯紝闈欐�佽祫婧愪細鏀惧湪杩欎釜鏂囦欢澶逛笅锛�
+  assetsDir: 'static',
+  // 鏄惁寮�鍚痚slint淇濆瓨妫�娴嬶紝鏈夋晥鍊硷細ture | false | 'error'
+  lintOnSave: process.env.NODE_ENV === 'development',
+  // 濡傛灉浣犱笉闇�瑕佺敓浜х幆澧冪殑 source map锛屽彲浠ュ皢鍏惰缃负 false 浠ュ姞閫熺敓浜х幆澧冩瀯寤恒��
+  productionSourceMap: false,
+  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瑙e帇缂╅潤鎬佹枃浠�
+      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/sql/dameng/dameng.sql b/sql/dameng/dameng.sql
new file mode 100644
index 0000000..784302b
--- /dev/null
+++ b/sql/dameng/dameng.sql
@@ -0,0 +1,11 @@
+--windows
+create tablespace "TEST" datafile 'D:\dmdbms\data\TEST\TEST.DBF' size 128 ;
+
+create user "TEST" identified by "Test@123" hash with SHA512 salt
+encrypt by "123456"
+default tablespace "TEST"
+default index tablespace "TEST";
+
+grant "PUBLIC","SOI" to "TEST";
+
+grant "RESOURCE" to "TEST";
diff --git a/sql/dameng/quartz.sql b/sql/dameng/quartz.sql
new file mode 100644
index 0000000..7e7c34d
--- /dev/null
+++ b/sql/dameng/quartz.sql
@@ -0,0 +1,328 @@
+CREATE TABLE "QRTZ_BLOB_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "BLOB_DATA" BLOB NULL
+);
+CREATE TABLE "QRTZ_CALENDARS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "CALENDAR_NAME" VARCHAR(200 char) NOT NULL,
+ "CALENDAR" BLOB NOT NULL
+);
+CREATE TABLE "QRTZ_CRON_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "CRON_EXPRESSION" VARCHAR(200 char) NOT NULL,
+ "TIME_ZONE_ID" VARCHAR(80 char) NULL
+);
+CREATE TABLE "QRTZ_FIRED_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "ENTRY_ID" VARCHAR(95 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "INSTANCE_NAME" VARCHAR(200 char) NOT NULL,
+ "FIRED_TIME" BIGINT NOT NULL,
+ "SCHED_TIME" BIGINT NOT NULL,
+ "PRIORITY" INT NOT NULL,
+ "STATE" VARCHAR(16 char) NOT NULL,
+ "JOB_NAME" VARCHAR(200 char) NULL,
+ "JOB_GROUP" VARCHAR(200 char) NULL,
+ "IS_NONCONCURRENT" VARCHAR(1 char) NULL,
+ "REQUESTS_RECOVERY" VARCHAR(1 char) NULL
+);
+CREATE TABLE "QRTZ_JOB_DETAILS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "JOB_NAME" VARCHAR(200 char) NOT NULL,
+ "JOB_GROUP" VARCHAR(200 char) NOT NULL,
+ "DESCRIPTION" VARCHAR(250 char) NULL,
+ "JOB_CLASS_NAME" VARCHAR(250 char) NOT NULL,
+ "IS_DURABLE" VARCHAR(1 char) NOT NULL,
+ "IS_NONCONCURRENT" VARCHAR(1 char) NOT NULL,
+ "IS_UPDATE_DATA" VARCHAR(1 char) NOT NULL,
+ "REQUESTS_RECOVERY" VARCHAR(1 char) NOT NULL,
+ "JOB_DATA" BLOB NULL
+);
+CREATE TABLE "QRTZ_LOCKS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "LOCK_NAME" VARCHAR(40 char) NOT NULL
+);
+CREATE TABLE "QRTZ_PAUSED_TRIGGER_GRPS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL
+);
+CREATE TABLE "QRTZ_SCHEDULER_STATE"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "INSTANCE_NAME" VARCHAR(200 char) NOT NULL,
+ "LAST_CHECKIN_TIME" BIGINT NOT NULL,
+ "CHECKIN_INTERVAL" BIGINT NOT NULL
+);
+CREATE TABLE "QRTZ_SIMPLE_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "REPEAT_COUNT" BIGINT NOT NULL,
+ "REPEAT_INTERVAL" BIGINT NOT NULL,
+ "TIMES_TRIGGERED" BIGINT NOT NULL
+);
+CREATE TABLE "QRTZ_SIMPROP_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "STR_PROP_1" VARCHAR(512 char) NULL,
+ "STR_PROP_2" VARCHAR(512 char) NULL,
+ "STR_PROP_3" VARCHAR(512 char) NULL,
+ "INT_PROP_1" INT NULL,
+ "INT_PROP_2" INT NULL,
+ "LONG_PROP_1" BIGINT NULL,
+ "LONG_PROP_2" BIGINT NULL,
+ "DEC_PROP_1" DECIMAL(13,4) NULL,
+ "DEC_PROP_2" DECIMAL(13,4) NULL,
+ "BOOL_PROP_1" VARCHAR(1 char) NULL,
+ "BOOL_PROP_2" VARCHAR(1 char) NULL
+);
+CREATE TABLE "QRTZ_TRIGGERS"
+(
+    "SCHED_NAME" VARCHAR(120 char) NOT NULL,
+ "TRIGGER_NAME" VARCHAR(200 char) NOT NULL,
+ "TRIGGER_GROUP" VARCHAR(200 char) NOT NULL,
+ "JOB_NAME" VARCHAR(200 char) NOT NULL,
+ "JOB_GROUP" VARCHAR(200 char) NOT NULL,
+ "DESCRIPTION" VARCHAR(250 char) NULL,
+ "NEXT_FIRE_TIME" BIGINT NULL,
+ "PREV_FIRE_TIME" BIGINT NULL,
+ "PRIORITY" INT NULL,
+ "TRIGGER_STATE" VARCHAR(16 char) NOT NULL,
+ "TRIGGER_TYPE" VARCHAR(8 char) NOT NULL,
+ "START_TIME" BIGINT NOT NULL,
+ "END_TIME" BIGINT NULL,
+ "CALENDAR_NAME" VARCHAR(200 char) NULL,
+ "MISFIRE_INSTR" SMALLINT NULL,
+ "JOB_DATA" BLOB NULL
+);
+ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_CALENDARS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","CALENDAR_NAME") ;
+
+ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_FIRED_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","ENTRY_ID") ;
+
+ALTER TABLE "QRTZ_JOB_DETAILS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","JOB_NAME","JOB_GROUP") ;
+
+ALTER TABLE "QRTZ_LOCKS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","LOCK_NAME") ;
+
+ALTER TABLE "QRTZ_PAUSED_TRIGGER_GRPS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_SCHEDULER_STATE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","INSTANCE_NAME") ;
+
+ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") ;
+
+ALTER TABLE "QRTZ_BLOB_TRIGGERS" ADD CONSTRAINT "QRTZ_BLOB_TRIGGERS_IBFK_1" FOREIGN KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS"("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") with index ;
+
+ALTER TABLE "QRTZ_CRON_TRIGGERS" ADD CONSTRAINT "QRTZ_CRON_TRIGGERS_IBFK_1" FOREIGN KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS"("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") with index ;
+
+ALTER TABLE "QRTZ_SIMPLE_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPLE_TRIGGERS_IBFK_1" FOREIGN KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS"("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") with index ;
+
+ALTER TABLE "QRTZ_SIMPROP_TRIGGERS" ADD CONSTRAINT "QRTZ_SIMPROP_TRIGGERS_IBFK_1" FOREIGN KEY("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") REFERENCES "QRTZ_TRIGGERS"("SCHED_NAME","TRIGGER_NAME","TRIGGER_GROUP") with index ;
+
+ALTER TABLE "QRTZ_TRIGGERS" ADD CONSTRAINT "QRTZ_TRIGGERS_IBFK_1" FOREIGN KEY("SCHED_NAME","JOB_NAME","JOB_GROUP") REFERENCES "QRTZ_JOB_DETAILS"("SCHED_NAME","JOB_NAME","JOB_GROUP") with index ;
+
+CREATE INDEX "SCHED_NAME"
+    ON "QRTZ_TRIGGERS"("SCHED_NAME","JOB_NAME","JOB_GROUP");
+ALTER INDEX "SCHED_NAME" VISIBLE;
+
+COMMENT ON TABLE "QRTZ_BLOB_TRIGGERS" IS 'Blob绫诲瀷鐨勮Е鍙戝櫒琛�';
+
+COMMENT ON COLUMN "QRTZ_BLOB_TRIGGERS"."BLOB_DATA" IS '瀛樻斁鎸佷箙鍖朤rigger瀵硅薄';
+
+COMMENT ON COLUMN "QRTZ_BLOB_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_BLOB_TRIGGERS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_BLOB_TRIGGERS"."TRIGGER_NAME" IS 'qrtz_triggers琛╰rigger_name鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_CALENDARS" IS '鏃ュ巻淇℃伅琛�';
+
+COMMENT ON COLUMN "QRTZ_CALENDARS"."CALENDAR" IS '瀛樻斁鎸佷箙鍖朿alendar瀵硅薄';
+
+COMMENT ON COLUMN "QRTZ_CALENDARS"."CALENDAR_NAME" IS '鏃ュ巻鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_CALENDARS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON TABLE "QRTZ_CRON_TRIGGERS" IS 'Cron绫诲瀷鐨勮Е鍙戝櫒琛�';
+
+COMMENT ON COLUMN "QRTZ_CRON_TRIGGERS"."CRON_EXPRESSION" IS 'cron琛ㄨ揪寮�';
+
+COMMENT ON COLUMN "QRTZ_CRON_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_CRON_TRIGGERS"."TIME_ZONE_ID" IS '鏃跺尯';
+
+COMMENT ON COLUMN "QRTZ_CRON_TRIGGERS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_CRON_TRIGGERS"."TRIGGER_NAME" IS 'qrtz_triggers琛╰rigger_name鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_FIRED_TRIGGERS" IS '宸茶Е鍙戠殑瑙﹀彂鍣ㄨ〃';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."ENTRY_ID" IS '璋冨害鍣ㄥ疄渚媔d';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."FIRED_TIME" IS '瑙﹀彂鐨勬椂闂�';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."INSTANCE_NAME" IS '璋冨害鍣ㄥ疄渚嬪悕';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."IS_NONCONCURRENT" IS '鏄惁骞跺彂';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."JOB_GROUP" IS '浠诲姟缁勫悕';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."JOB_NAME" IS '浠诲姟鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."PRIORITY" IS '浼樺厛绾�';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."REQUESTS_RECOVERY" IS '鏄惁鎺ュ彈鎭㈠鎵ц';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."SCHED_TIME" IS '瀹氭椂鍣ㄥ埗瀹氱殑鏃堕棿';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."STATE" IS '鐘舵��';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_FIRED_TRIGGERS"."TRIGGER_NAME" IS 'qrtz_triggers琛╰rigger_name鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_JOB_DETAILS" IS '浠诲姟璇︾粏淇℃伅琛�';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."DESCRIPTION" IS '鐩稿叧浠嬬粛';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."IS_DURABLE" IS '鏄惁鎸佷箙鍖�';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."IS_NONCONCURRENT" IS '鏄惁骞跺彂';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."IS_UPDATE_DATA" IS '鏄惁鏇存柊鏁版嵁';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."JOB_CLASS_NAME" IS '鎵ц浠诲姟绫诲悕绉�';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."JOB_DATA" IS '瀛樻斁鎸佷箙鍖杍ob瀵硅薄';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."JOB_GROUP" IS '浠诲姟缁勫悕';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."JOB_NAME" IS '浠诲姟鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."REQUESTS_RECOVERY" IS '鏄惁鎺ュ彈鎭㈠鎵ц';
+
+COMMENT ON COLUMN "QRTZ_JOB_DETAILS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON TABLE "QRTZ_LOCKS" IS '瀛樺偍鐨勬偛瑙傞攣淇℃伅琛�';
+
+COMMENT ON COLUMN "QRTZ_LOCKS"."LOCK_NAME" IS '鎮茶閿佸悕绉�';
+
+COMMENT ON COLUMN "QRTZ_LOCKS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON TABLE "QRTZ_PAUSED_TRIGGER_GRPS" IS '鏆傚仠鐨勮Е鍙戝櫒琛�';
+
+COMMENT ON COLUMN "QRTZ_PAUSED_TRIGGER_GRPS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_PAUSED_TRIGGER_GRPS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_SCHEDULER_STATE" IS '璋冨害鍣ㄧ姸鎬佽〃';
+
+COMMENT ON COLUMN "QRTZ_SCHEDULER_STATE"."CHECKIN_INTERVAL" IS '妫�鏌ラ棿闅旀椂闂�';
+
+COMMENT ON COLUMN "QRTZ_SCHEDULER_STATE"."INSTANCE_NAME" IS '瀹炰緥鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_SCHEDULER_STATE"."LAST_CHECKIN_TIME" IS '涓婃妫�鏌ユ椂闂�';
+
+COMMENT ON COLUMN "QRTZ_SCHEDULER_STATE"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON TABLE "QRTZ_SIMPLE_TRIGGERS" IS '绠�鍗曡Е鍙戝櫒鐨勪俊鎭〃';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."REPEAT_COUNT" IS '閲嶅鐨勬鏁扮粺璁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."REPEAT_INTERVAL" IS '閲嶅鐨勯棿闅旀椂闂�';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."TIMES_TRIGGERED" IS '宸茬粡瑙﹀彂鐨勬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_SIMPLE_TRIGGERS"."TRIGGER_NAME" IS 'qrtz_triggers琛╰rigger_name鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_SIMPROP_TRIGGERS" IS '鍚屾鏈哄埗鐨勮閿佽〃';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."BOOL_PROP_1" IS 'Boolean绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."BOOL_PROP_2" IS 'Boolean绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."DEC_PROP_1" IS 'decimal绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."DEC_PROP_2" IS 'decimal绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."INT_PROP_1" IS 'int绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."INT_PROP_2" IS 'int绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."LONG_PROP_1" IS 'long绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."LONG_PROP_2" IS 'long绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."STR_PROP_1" IS 'String绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."STR_PROP_2" IS 'String绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."STR_PROP_3" IS 'String绫诲瀷鐨則rigger鐨勭涓変釜鍙傛暟';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."TRIGGER_GROUP" IS 'qrtz_triggers琛╰rigger_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_SIMPROP_TRIGGERS"."TRIGGER_NAME" IS 'qrtz_triggers琛╰rigger_name鐨勫閿�';
+
+COMMENT ON TABLE "QRTZ_TRIGGERS" IS '瑙﹀彂鍣ㄨ缁嗕俊鎭〃';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."CALENDAR_NAME" IS '鏃ョ▼琛ㄥ悕绉�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."DESCRIPTION" IS '鐩稿叧浠嬬粛';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."END_TIME" IS '缁撴潫鏃堕棿';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."JOB_DATA" IS '瀛樻斁鎸佷箙鍖杍ob瀵硅薄';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."JOB_GROUP" IS 'qrtz_job_details琛╦ob_group鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."JOB_NAME" IS 'qrtz_job_details琛╦ob_name鐨勫閿�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."MISFIRE_INSTR" IS '琛ュ伩鎵ц鐨勭瓥鐣�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."NEXT_FIRE_TIME" IS '涓婁竴娆¤Е鍙戞椂闂达紙姣锛�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."PREV_FIRE_TIME" IS '涓嬩竴娆¤Е鍙戞椂闂达紙榛樿涓�-1琛ㄧず涓嶈Е鍙戯級';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."PRIORITY" IS '浼樺厛绾�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."SCHED_NAME" IS '璋冨害鍚嶇О';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."START_TIME" IS '寮�濮嬫椂闂�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."TRIGGER_GROUP" IS '瑙﹀彂鍣ㄦ墍灞炵粍鐨勫悕瀛�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."TRIGGER_NAME" IS '瑙﹀彂鍣ㄧ殑鍚嶅瓧';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."TRIGGER_STATE" IS '瑙﹀彂鍣ㄧ姸鎬�';
+
+COMMENT ON COLUMN "QRTZ_TRIGGERS"."TRIGGER_TYPE" IS '瑙﹀彂鍣ㄧ殑绫诲瀷';
+
diff --git a/sql/dameng/ry_20240629.sql b/sql/dameng/ry_20240629.sql
new file mode 100644
index 0000000..9741c6b
--- /dev/null
+++ b/sql/dameng/ry_20240629.sql
@@ -0,0 +1,1201 @@
+CREATE TABLE "GEN_TABLE"
+(
+ "TABLE_ID" BIGINT IDENTITY(1000,1) NOT NULL,
+ "TABLE_NAME" VARCHAR(200 char) DEFAULT ''
+ NULL,
+ "TABLE_COMMENT" VARCHAR(500 char) DEFAULT ''
+ NULL,
+ "SUB_TABLE_NAME" VARCHAR(64 char) NULL,
+ "SUB_TABLE_FK_NAME" VARCHAR(64 char) NULL,
+ "CLASS_NAME" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "TPL_CATEGORY" VARCHAR(200 char) DEFAULT 'crud'
+ NULL,
+ "TPL_WEB_TYPE" VARCHAR(30 char) DEFAULT ''
+ NULL,
+ "PACKAGE_NAME" VARCHAR(100 char) NULL,
+ "MODULE_NAME" VARCHAR(30 char) NULL,
+ "BUSINESS_NAME" VARCHAR(30 char) NULL,
+ "FUNCTION_NAME" VARCHAR(50 char) NULL,
+ "FUNCTION_AUTHOR" VARCHAR(50 char) NULL,
+ "GEN_TYPE" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "GEN_PATH" VARCHAR(200 char) DEFAULT '/'
+ NULL,
+ "OPTIONS" VARCHAR(1000 char) NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "GEN_TABLE_COLUMN"
+(
+ "COLUMN_ID" BIGINT IDENTITY(2000,1) NOT NULL,
+ "TABLE_ID" BIGINT NULL,
+ "COLUMN_NAME" VARCHAR(200 char) NULL,
+ "COLUMN_COMMENT" VARCHAR(500 char) NULL,
+ "COLUMN_TYPE" VARCHAR(100 char) NULL,
+ "JAVA_TYPE" VARCHAR(500 char) NULL,
+ "JAVA_FIELD" VARCHAR(200 char) NULL,
+ "IS_PK" CHAR(1 char) NULL,
+ "IS_INCREMENT" CHAR(1 char) NULL,
+ "IS_REQUIRED" CHAR(1 char) NULL,
+ "IS_INSERT" CHAR(1 char) NULL,
+ "IS_EDIT" CHAR(1 char) NULL,
+ "IS_LIST" CHAR(1 char) NULL,
+ "IS_QUERY" CHAR(1 char) NULL,
+ "QUERY_TYPE" VARCHAR(200 char) DEFAULT 'EQ'
+ NULL,
+ "HTML_TYPE" VARCHAR(200 char) NULL,
+ "DICT_TYPE" VARCHAR(200 char) DEFAULT ''
+ NULL,
+ "SORT" INT NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL
+);
+CREATE TABLE "SYS_CONFIG"
+(
+ "CONFIG_ID" INT IDENTITY(3000,1) NOT NULL,
+ "CONFIG_NAME" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "CONFIG_KEY" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "CONFIG_VALUE" VARCHAR(500 char) DEFAULT ''
+ NULL,
+ "CONFIG_TYPE" CHAR(1 char) DEFAULT 'N'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_DEPT"
+(
+ "DEPT_ID" BIGINT IDENTITY(4000,1) NOT NULL,
+ "PARENT_ID" BIGINT DEFAULT 0
+ NULL,
+ "ANCESTORS" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "DEPT_NAME" VARCHAR(30 char) DEFAULT ''
+ NULL,
+ "ORDER_NUM" INT DEFAULT 0
+ NULL,
+ "LEADER" VARCHAR(20 char) NULL,
+ "PHONE" VARCHAR(11 char) NULL,
+ "EMAIL" VARCHAR(50 char) NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "DEL_FLAG" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL
+);
+CREATE TABLE "SYS_DICT_DATA"
+(
+ "DICT_CODE" BIGINT IDENTITY(5000,1) NOT NULL,
+ "DICT_SORT" INT DEFAULT 0
+ NULL,
+ "DICT_LABEL" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "DICT_VALUE" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "DICT_TYPE" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "CSS_CLASS" VARCHAR(100 char) NULL,
+ "LIST_CLASS" VARCHAR(100 char) NULL,
+ "IS_DEFAULT" CHAR(1 char) DEFAULT 'N'
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_DICT_TYPE"
+(
+ "DICT_ID" BIGINT IDENTITY(6000,1) NOT NULL,
+ "DICT_NAME" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "DICT_TYPE" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_JOB"
+(
+ "JOB_ID" BIGINT IDENTITY(7000,1) NOT NULL,
+ "JOB_NAME" VARCHAR(64 char) DEFAULT ''
+ NOT NULL,
+ "JOB_GROUP" VARCHAR(64 char) DEFAULT 'DEFAULT'
+ NOT NULL,
+ "INVOKE_TARGET" VARCHAR(500 char) NOT NULL,
+ "CRON_EXPRESSION" VARCHAR(255 char) DEFAULT ''
+ NULL,
+ "MISFIRE_POLICY" VARCHAR(20 char) DEFAULT '3'
+ NULL,
+ "CONCURRENT" CHAR(1 char) DEFAULT '1'
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) DEFAULT ''
+ NULL
+);
+CREATE TABLE "SYS_JOB_LOG"
+(
+ "JOB_LOG_ID" BIGINT IDENTITY(8000,1) NOT NULL,
+ "JOB_NAME" VARCHAR(64 char) NOT NULL,
+ "JOB_GROUP" VARCHAR(64 char) NOT NULL,
+ "INVOKE_TARGET" VARCHAR(500 char) NOT NULL,
+ "JOB_MESSAGE" VARCHAR(500 char) NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "EXCEPTION_INFO" VARCHAR(2000 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL
+);
+CREATE TABLE "SYS_LOGININFOR"
+(
+ "INFO_ID" BIGINT IDENTITY(9000,1) NOT NULL,
+ "USER_NAME" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "IPADDR" VARCHAR(128 char) DEFAULT ''
+ NULL,
+ "LOGIN_LOCATION" VARCHAR(255 char) DEFAULT ''
+ NULL,
+ "BROWSER" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "OS" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "MSG" VARCHAR(255 char) DEFAULT ''
+ NULL,
+ "LOGIN_TIME" TIMESTAMP(0) NULL
+);
+CREATE TABLE "SYS_MENU"
+(
+ "MENU_ID" BIGINT IDENTITY(10000,1) NOT NULL,
+ "MENU_NAME" VARCHAR(50 char) NOT NULL,
+ "PARENT_ID" BIGINT DEFAULT 0
+ NULL,
+ "ORDER_NUM" INT DEFAULT 0
+ NULL,
+ "PATH" VARCHAR(200 char) DEFAULT ''
+ NULL,
+ "COMPONENT" VARCHAR(255 char) NULL,
+ "QUERY" VARCHAR(255 char) NULL,
+ "ROUTE_NAME" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "IS_FRAME" INT DEFAULT 1
+ NULL,
+ "IS_CACHE" INT DEFAULT 0
+ NULL,
+ "MENU_TYPE" CHAR(1 char) DEFAULT ''
+ NULL,
+ "VISIBLE" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "PERMS" VARCHAR(100 char) NULL,
+ "ICON" VARCHAR(100 char) DEFAULT '#'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) DEFAULT ''
+ NULL
+);
+CREATE TABLE "SYS_NOTICE"
+(
+ "NOTICE_ID" INT IDENTITY(11000,1) NOT NULL,
+ "NOTICE_TITLE" VARCHAR(50 char) NOT NULL,
+ "NOTICE_TYPE" CHAR(1 char) NOT NULL,
+ "NOTICE_CONTENT" BLOB NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(255 char) NULL
+);
+CREATE TABLE "SYS_OPER_LOG"
+(
+ "OPER_ID" BIGINT IDENTITY(12000,1) NOT NULL,
+ "TITLE" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "BUSINESS_TYPE" INT DEFAULT 0
+ NULL,
+ "METHOD" VARCHAR(200 char) DEFAULT ''
+ NULL,
+ "REQUEST_METHOD" VARCHAR(10 char) DEFAULT ''
+ NULL,
+ "OPERATOR_TYPE" INT DEFAULT 0
+ NULL,
+ "OPER_NAME" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "DEPT_NAME" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "OPER_URL" VARCHAR(255 char) DEFAULT ''
+ NULL,
+ "OPER_IP" VARCHAR(128 char) DEFAULT ''
+ NULL,
+ "OPER_LOCATION" VARCHAR(255 char) DEFAULT ''
+ NULL,
+ "OPER_PARAM" VARCHAR(2000 char) DEFAULT ''
+ NULL,
+ "JSON_RESULT" VARCHAR(2000 char) DEFAULT ''
+ NULL,
+ "STATUS" INT DEFAULT 0
+ NULL,
+ "ERROR_MSG" VARCHAR(2000 char) DEFAULT ''
+ NULL,
+ "OPER_TIME" TIMESTAMP(0) NULL,
+ "COST_TIME" BIGINT DEFAULT 0
+ NULL
+);
+CREATE TABLE "SYS_POST"
+(
+ "POST_ID" BIGINT IDENTITY(13000,1) NOT NULL,
+ "POST_CODE" VARCHAR(64 char) NOT NULL,
+ "POST_NAME" VARCHAR(50 char) NOT NULL,
+ "POST_SORT" INT NOT NULL,
+ "STATUS" CHAR(1 char) NOT NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_ROLE"
+(
+ "ROLE_ID" BIGINT IDENTITY(14000,1) NOT NULL,
+ "ROLE_NAME" VARCHAR(30 char) NOT NULL,
+ "ROLE_KEY" VARCHAR(100 char) NOT NULL,
+ "ROLE_SORT" INT NOT NULL,
+ "DATA_SCOPE" CHAR(1 char) DEFAULT '1'
+ NULL,
+ "MENU_CHECK_STRICTLY" TINYINT DEFAULT 1
+ NULL,
+ "DEPT_CHECK_STRICTLY" TINYINT DEFAULT 1
+ NULL,
+ "STATUS" CHAR(1 char) NOT NULL,
+ "DEL_FLAG" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_ROLE_DEPT"
+(
+ "ROLE_ID" BIGINT NOT NULL,
+ "DEPT_ID" BIGINT NOT NULL
+);
+CREATE TABLE "SYS_ROLE_MENU"
+(
+ "ROLE_ID" BIGINT NOT NULL,
+ "MENU_ID" BIGINT NOT NULL
+);
+CREATE TABLE "SYS_USER"
+(
+ "USER_ID" BIGINT IDENTITY(17000,1) NOT NULL,
+ "DEPT_ID" BIGINT NULL,
+ "USER_NAME" VARCHAR(30 char) NOT NULL,
+ "NICK_NAME" VARCHAR(30 char) NOT NULL,
+ "USER_TYPE" VARCHAR(2 char) DEFAULT '00'
+ NULL,
+ "EMAIL" VARCHAR(50 char) DEFAULT ''
+ NULL,
+ "PHONENUMBER" VARCHAR(11 char) DEFAULT ''
+ NULL,
+ "SEX" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "AVATAR" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "PASSWORD" VARCHAR(100 char) DEFAULT ''
+ NULL,
+ "STATUS" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "DEL_FLAG" CHAR(1 char) DEFAULT '0'
+ NULL,
+ "LOGIN_IP" VARCHAR(128 char) DEFAULT ''
+ NULL,
+ "LOGIN_DATE" TIMESTAMP(0) NULL,
+ "CREATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "CREATE_TIME" TIMESTAMP(0) NULL,
+ "UPDATE_BY" VARCHAR(64 char) DEFAULT ''
+ NULL,
+ "UPDATE_TIME" TIMESTAMP(0) NULL,
+ "REMARK" VARCHAR(500 char) NULL
+);
+CREATE TABLE "SYS_USER_POST"
+(
+ "USER_ID" BIGINT NOT NULL,
+ "POST_ID" BIGINT NOT NULL
+);
+CREATE TABLE "SYS_USER_ROLE"
+(
+ "USER_ID" BIGINT NOT NULL,
+ "ROLE_ID" BIGINT NOT NULL
+);
+ALTER TABLE "GEN_TABLE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("TABLE_ID") ;
+
+ALTER TABLE "GEN_TABLE_COLUMN" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("COLUMN_ID") ;
+
+ALTER TABLE "SYS_CONFIG" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("CONFIG_ID") ;
+
+ALTER TABLE "SYS_DEPT" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("DEPT_ID") ;
+
+ALTER TABLE "SYS_DICT_DATA" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("DICT_CODE") ;
+
+ALTER TABLE "SYS_DICT_TYPE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("DICT_ID") ;
+
+ALTER TABLE "SYS_JOB" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("JOB_ID","JOB_NAME","JOB_GROUP") ;
+
+ALTER TABLE "SYS_JOB_LOG" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("JOB_LOG_ID") ;
+
+ALTER TABLE "SYS_LOGININFOR" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("INFO_ID") ;
+
+ALTER TABLE "SYS_MENU" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("MENU_ID") ;
+
+ALTER TABLE "SYS_NOTICE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("NOTICE_ID") ;
+
+ALTER TABLE "SYS_OPER_LOG" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("OPER_ID") ;
+
+ALTER TABLE "SYS_POST" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("POST_ID") ;
+
+ALTER TABLE "SYS_ROLE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("ROLE_ID") ;
+
+ALTER TABLE "SYS_ROLE_DEPT" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("ROLE_ID","DEPT_ID") ;
+
+ALTER TABLE "SYS_ROLE_MENU" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("ROLE_ID","MENU_ID") ;
+
+ALTER TABLE "SYS_USER" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("USER_ID") ;
+
+ALTER TABLE "SYS_USER_POST" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("USER_ID","POST_ID") ;
+
+ALTER TABLE "SYS_USER_ROLE" ADD CONSTRAINT  NOT CLUSTER  PRIMARY KEY("USER_ID","ROLE_ID") ;
+
+CREATE INDEX "IDX_SYS_LOGININFOR_LT"
+ON "SYS_LOGININFOR"("LOGIN_TIME");
+ALTER INDEX "IDX_SYS_LOGININFOR_LT" VISIBLE;
+
+CREATE INDEX "IDX_SYS_LOGININFOR_S"
+ON "SYS_LOGININFOR"("STATUS");
+ALTER INDEX "IDX_SYS_LOGININFOR_S" VISIBLE;
+
+CREATE INDEX "IDX_SYS_OPER_LOG_BT"
+ON "SYS_OPER_LOG"("BUSINESS_TYPE");
+ALTER INDEX "IDX_SYS_OPER_LOG_BT" VISIBLE;
+
+CREATE INDEX "IDX_SYS_OPER_LOG_OT"
+ON "SYS_OPER_LOG"("OPER_TIME");
+ALTER INDEX "IDX_SYS_OPER_LOG_OT" VISIBLE;
+
+CREATE INDEX "IDX_SYS_OPER_LOG_S"
+ON "SYS_OPER_LOG"("STATUS");
+ALTER INDEX "IDX_SYS_OPER_LOG_S" VISIBLE;
+
+ALTER TABLE "SYS_DICT_TYPE" ADD CONSTRAINT "DICT_TYPE" UNIQUE("DICT_TYPE") ;
+
+COMMENT ON TABLE "GEN_TABLE" IS '浠g爜鐢熸垚涓氬姟琛�';
+
+COMMENT ON COLUMN "GEN_TABLE"."BUSINESS_NAME" IS '鐢熸垚涓氬姟鍚�';
+
+COMMENT ON COLUMN "GEN_TABLE"."CLASS_NAME" IS '瀹炰綋绫诲悕绉�';
+
+COMMENT ON COLUMN "GEN_TABLE"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "GEN_TABLE"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "GEN_TABLE"."FUNCTION_AUTHOR" IS '鐢熸垚鍔熻兘浣滆��';
+
+COMMENT ON COLUMN "GEN_TABLE"."FUNCTION_NAME" IS '鐢熸垚鍔熻兘鍚�';
+
+COMMENT ON COLUMN "GEN_TABLE"."GEN_PATH" IS '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級';
+
+COMMENT ON COLUMN "GEN_TABLE"."GEN_TYPE" IS '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級';
+
+COMMENT ON COLUMN "GEN_TABLE"."MODULE_NAME" IS '鐢熸垚妯″潡鍚�';
+
+COMMENT ON COLUMN "GEN_TABLE"."OPTIONS" IS '鍏跺畠鐢熸垚閫夐」';
+
+COMMENT ON COLUMN "GEN_TABLE"."PACKAGE_NAME" IS '鐢熸垚鍖呰矾寰�';
+
+COMMENT ON COLUMN "GEN_TABLE"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "GEN_TABLE"."SUB_TABLE_FK_NAME" IS '瀛愯〃鍏宠仈鐨勫閿悕';
+
+COMMENT ON COLUMN "GEN_TABLE"."SUB_TABLE_NAME" IS '鍏宠仈瀛愯〃鐨勮〃鍚�';
+
+COMMENT ON COLUMN "GEN_TABLE"."TABLE_COMMENT" IS '琛ㄦ弿杩�';
+
+COMMENT ON COLUMN "GEN_TABLE"."TABLE_ID" IS '缂栧彿';
+
+COMMENT ON COLUMN "GEN_TABLE"."TABLE_NAME" IS '琛ㄥ悕绉�';
+
+COMMENT ON COLUMN "GEN_TABLE"."TPL_CATEGORY" IS '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�';
+
+COMMENT ON COLUMN "GEN_TABLE"."TPL_WEB_TYPE" IS '鍓嶇妯℃澘绫诲瀷锛坋lement-ui妯$増 element-plus妯$増锛�';
+
+COMMENT ON COLUMN "GEN_TABLE"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "GEN_TABLE"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "GEN_TABLE_COLUMN" IS '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."COLUMN_COMMENT" IS '鍒楁弿杩�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."COLUMN_ID" IS '缂栧彿';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."COLUMN_NAME" IS '鍒楀悕绉�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."COLUMN_TYPE" IS '鍒楃被鍨�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."DICT_TYPE" IS '瀛楀吀绫诲瀷';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."HTML_TYPE" IS '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_EDIT" IS '鏄惁缂栬緫瀛楁锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_INCREMENT" IS '鏄惁鑷锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_INSERT" IS '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_LIST" IS '鏄惁鍒楄〃瀛楁锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_PK" IS '鏄惁涓婚敭锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_QUERY" IS '鏄惁鏌ヨ瀛楁锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."IS_REQUIRED" IS '鏄惁蹇呭~锛�1鏄級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."JAVA_FIELD" IS 'JAVA瀛楁鍚�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."JAVA_TYPE" IS 'JAVA绫诲瀷';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."QUERY_TYPE" IS '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."SORT" IS '鎺掑簭';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."TABLE_ID" IS '褰掑睘琛ㄧ紪鍙�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "GEN_TABLE_COLUMN"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_CONFIG" IS '鍙傛暟閰嶇疆琛�';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CONFIG_ID" IS '鍙傛暟涓婚敭';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CONFIG_KEY" IS '鍙傛暟閿悕';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CONFIG_NAME" IS '鍙傛暟鍚嶇О';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CONFIG_TYPE" IS '绯荤粺鍐呯疆锛圷鏄� N鍚︼級';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CONFIG_VALUE" IS '鍙傛暟閿��';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_CONFIG"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_CONFIG"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_CONFIG"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_CONFIG"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_DEPT" IS '閮ㄩ棬琛�';
+
+COMMENT ON COLUMN "SYS_DEPT"."ANCESTORS" IS '绁栫骇鍒楄〃';
+
+COMMENT ON COLUMN "SYS_DEPT"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_DEPT"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_DEPT"."DEL_FLAG" IS '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+COMMENT ON COLUMN "SYS_DEPT"."DEPT_ID" IS '閮ㄩ棬id';
+
+COMMENT ON COLUMN "SYS_DEPT"."DEPT_NAME" IS '閮ㄩ棬鍚嶇О';
+
+COMMENT ON COLUMN "SYS_DEPT"."EMAIL" IS '閭';
+
+COMMENT ON COLUMN "SYS_DEPT"."LEADER" IS '璐熻矗浜�';
+
+COMMENT ON COLUMN "SYS_DEPT"."ORDER_NUM" IS '鏄剧ず椤哄簭';
+
+COMMENT ON COLUMN "SYS_DEPT"."PARENT_ID" IS '鐖堕儴闂╥d';
+
+COMMENT ON COLUMN "SYS_DEPT"."PHONE" IS '鑱旂郴鐢佃瘽';
+
+COMMENT ON COLUMN "SYS_DEPT"."STATUS" IS '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_DEPT"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_DEPT"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_DICT_DATA" IS '瀛楀吀鏁版嵁琛�';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."CSS_CLASS" IS '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."DICT_CODE" IS '瀛楀吀缂栫爜';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."DICT_LABEL" IS '瀛楀吀鏍囩';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."DICT_SORT" IS '瀛楀吀鎺掑簭';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."DICT_TYPE" IS '瀛楀吀绫诲瀷';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."DICT_VALUE" IS '瀛楀吀閿��';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."IS_DEFAULT" IS '鏄惁榛樿锛圷鏄� N鍚︼級';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."LIST_CLASS" IS '琛ㄦ牸鍥炴樉鏍峰紡';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."STATUS" IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_DICT_DATA"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_DICT_TYPE" IS '瀛楀吀绫诲瀷琛�';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."DICT_ID" IS '瀛楀吀涓婚敭';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."DICT_NAME" IS '瀛楀吀鍚嶇О';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."DICT_TYPE" IS '瀛楀吀绫诲瀷';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."STATUS" IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_DICT_TYPE"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_JOB" IS '瀹氭椂浠诲姟璋冨害琛�';
+
+COMMENT ON COLUMN "SYS_JOB"."CONCURRENT" IS '鏄惁骞跺彂鎵ц锛�0鍏佽 1绂佹锛�';
+
+COMMENT ON COLUMN "SYS_JOB"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_JOB"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_JOB"."CRON_EXPRESSION" IS 'cron鎵ц琛ㄨ揪寮�';
+
+COMMENT ON COLUMN "SYS_JOB"."INVOKE_TARGET" IS '璋冪敤鐩爣瀛楃涓�';
+
+COMMENT ON COLUMN "SYS_JOB"."JOB_GROUP" IS '浠诲姟缁勫悕';
+
+COMMENT ON COLUMN "SYS_JOB"."JOB_ID" IS '浠诲姟ID';
+
+COMMENT ON COLUMN "SYS_JOB"."JOB_NAME" IS '浠诲姟鍚嶇О';
+
+COMMENT ON COLUMN "SYS_JOB"."MISFIRE_POLICY" IS '璁″垝鎵ц閿欒绛栫暐锛�1绔嬪嵆鎵ц 2鎵ц涓�娆� 3鏀惧純鎵ц锛�';
+
+COMMENT ON COLUMN "SYS_JOB"."REMARK" IS '澶囨敞淇℃伅';
+
+COMMENT ON COLUMN "SYS_JOB"."STATUS" IS '鐘舵�侊紙0姝e父 1鏆傚仠锛�';
+
+COMMENT ON COLUMN "SYS_JOB"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_JOB"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_JOB_LOG" IS '瀹氭椂浠诲姟璋冨害鏃ュ織琛�';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."EXCEPTION_INFO" IS '寮傚父淇℃伅';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."INVOKE_TARGET" IS '璋冪敤鐩爣瀛楃涓�';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."JOB_GROUP" IS '浠诲姟缁勫悕';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."JOB_LOG_ID" IS '浠诲姟鏃ュ織ID';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."JOB_MESSAGE" IS '鏃ュ織淇℃伅';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."JOB_NAME" IS '浠诲姟鍚嶇О';
+
+COMMENT ON COLUMN "SYS_JOB_LOG"."STATUS" IS '鎵ц鐘舵�侊紙0姝e父 1澶辫触锛�';
+
+COMMENT ON TABLE "SYS_LOGININFOR" IS '绯荤粺璁块棶璁板綍';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."BROWSER" IS '娴忚鍣ㄧ被鍨�';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."INFO_ID" IS '璁块棶ID';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."IPADDR" IS '鐧诲綍IP鍦板潃';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."LOGIN_LOCATION" IS '鐧诲綍鍦扮偣';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."LOGIN_TIME" IS '璁块棶鏃堕棿';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."MSG" IS '鎻愮ず娑堟伅';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."OS" IS '鎿嶄綔绯荤粺';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."STATUS" IS '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�';
+
+COMMENT ON COLUMN "SYS_LOGININFOR"."USER_NAME" IS '鐢ㄦ埛璐﹀彿';
+
+COMMENT ON TABLE "SYS_MENU" IS '鑿滃崟鏉冮檺琛�';
+
+COMMENT ON COLUMN "SYS_MENU"."COMPONENT" IS '缁勪欢璺緞';
+
+COMMENT ON COLUMN "SYS_MENU"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_MENU"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_MENU"."ICON" IS '鑿滃崟鍥炬爣';
+
+COMMENT ON COLUMN "SYS_MENU"."IS_CACHE" IS '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級';
+
+COMMENT ON COLUMN "SYS_MENU"."IS_FRAME" IS '鏄惁涓哄閾撅紙0鏄� 1鍚︼級';
+
+COMMENT ON COLUMN "SYS_MENU"."MENU_ID" IS '鑿滃崟ID';
+
+COMMENT ON COLUMN "SYS_MENU"."MENU_NAME" IS '鑿滃崟鍚嶇О';
+
+COMMENT ON COLUMN "SYS_MENU"."MENU_TYPE" IS '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�';
+
+COMMENT ON COLUMN "SYS_MENU"."ORDER_NUM" IS '鏄剧ず椤哄簭';
+
+COMMENT ON COLUMN "SYS_MENU"."PARENT_ID" IS '鐖惰彍鍗旾D';
+
+COMMENT ON COLUMN "SYS_MENU"."PATH" IS '璺敱鍦板潃';
+
+COMMENT ON COLUMN "SYS_MENU"."PERMS" IS '鏉冮檺鏍囪瘑';
+
+COMMENT ON COLUMN "SYS_MENU"."QUERY" IS '璺敱鍙傛暟';
+
+COMMENT ON COLUMN "SYS_MENU"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_MENU"."ROUTE_NAME" IS '璺敱鍚嶇О';
+
+COMMENT ON COLUMN "SYS_MENU"."STATUS" IS '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_MENU"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_MENU"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON COLUMN "SYS_MENU"."VISIBLE" IS '鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛�';
+
+COMMENT ON TABLE "SYS_NOTICE" IS '閫氱煡鍏憡琛�';
+
+COMMENT ON COLUMN "SYS_NOTICE"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_NOTICE"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_NOTICE"."NOTICE_CONTENT" IS '鍏憡鍐呭';
+
+COMMENT ON COLUMN "SYS_NOTICE"."NOTICE_ID" IS '鍏憡ID';
+
+COMMENT ON COLUMN "SYS_NOTICE"."NOTICE_TITLE" IS '鍏憡鏍囬';
+
+COMMENT ON COLUMN "SYS_NOTICE"."NOTICE_TYPE" IS '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�';
+
+COMMENT ON COLUMN "SYS_NOTICE"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_NOTICE"."STATUS" IS '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�';
+
+COMMENT ON COLUMN "SYS_NOTICE"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_NOTICE"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_OPER_LOG" IS '鎿嶄綔鏃ュ織璁板綍';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."BUSINESS_TYPE" IS '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."COST_TIME" IS '娑堣�楁椂闂�';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."DEPT_NAME" IS '閮ㄩ棬鍚嶇О';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."ERROR_MSG" IS '閿欒娑堟伅';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."JSON_RESULT" IS '杩斿洖鍙傛暟';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."METHOD" IS '鏂规硶鍚嶇О';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPERATOR_TYPE" IS '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_ID" IS '鏃ュ織涓婚敭';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_IP" IS '涓绘満鍦板潃';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_LOCATION" IS '鎿嶄綔鍦扮偣';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_NAME" IS '鎿嶄綔浜哄憳';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_PARAM" IS '璇锋眰鍙傛暟';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_TIME" IS '鎿嶄綔鏃堕棿';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."OPER_URL" IS '璇锋眰URL';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."REQUEST_METHOD" IS '璇锋眰鏂瑰紡';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."STATUS" IS '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�';
+
+COMMENT ON COLUMN "SYS_OPER_LOG"."TITLE" IS '妯″潡鏍囬';
+
+COMMENT ON TABLE "SYS_POST" IS '宀椾綅淇℃伅琛�';
+
+COMMENT ON COLUMN "SYS_POST"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_POST"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_POST"."POST_CODE" IS '宀椾綅缂栫爜';
+
+COMMENT ON COLUMN "SYS_POST"."POST_ID" IS '宀椾綅ID';
+
+COMMENT ON COLUMN "SYS_POST"."POST_NAME" IS '宀椾綅鍚嶇О';
+
+COMMENT ON COLUMN "SYS_POST"."POST_SORT" IS '鏄剧ず椤哄簭';
+
+COMMENT ON COLUMN "SYS_POST"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_POST"."STATUS" IS '鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_POST"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_POST"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_ROLE" IS '瑙掕壊淇℃伅琛�';
+
+COMMENT ON COLUMN "SYS_ROLE"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_ROLE"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_ROLE"."DATA_SCOPE" IS '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級';
+
+COMMENT ON COLUMN "SYS_ROLE"."DEL_FLAG" IS '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+COMMENT ON COLUMN "SYS_ROLE"."DEPT_CHECK_STRICTLY" IS '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+
+COMMENT ON COLUMN "SYS_ROLE"."MENU_CHECK_STRICTLY" IS '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�';
+
+COMMENT ON COLUMN "SYS_ROLE"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_ROLE"."ROLE_ID" IS '瑙掕壊ID';
+
+COMMENT ON COLUMN "SYS_ROLE"."ROLE_KEY" IS '瑙掕壊鏉冮檺瀛楃涓�';
+
+COMMENT ON COLUMN "SYS_ROLE"."ROLE_NAME" IS '瑙掕壊鍚嶇О';
+
+COMMENT ON COLUMN "SYS_ROLE"."ROLE_SORT" IS '鏄剧ず椤哄簭';
+
+COMMENT ON COLUMN "SYS_ROLE"."STATUS" IS '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_ROLE"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_ROLE"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON TABLE "SYS_ROLE_DEPT" IS '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+
+COMMENT ON COLUMN "SYS_ROLE_DEPT"."DEPT_ID" IS '閮ㄩ棬ID';
+
+COMMENT ON COLUMN "SYS_ROLE_DEPT"."ROLE_ID" IS '瑙掕壊ID';
+
+COMMENT ON TABLE "SYS_ROLE_MENU" IS '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+COMMENT ON COLUMN "SYS_ROLE_MENU"."MENU_ID" IS '鑿滃崟ID';
+
+COMMENT ON COLUMN "SYS_ROLE_MENU"."ROLE_ID" IS '瑙掕壊ID';
+
+COMMENT ON TABLE "SYS_USER" IS '鐢ㄦ埛淇℃伅琛�';
+
+COMMENT ON COLUMN "SYS_USER"."AVATAR" IS '澶村儚鍦板潃';
+
+COMMENT ON COLUMN "SYS_USER"."CREATE_BY" IS '鍒涘缓鑰�';
+
+COMMENT ON COLUMN "SYS_USER"."CREATE_TIME" IS '鍒涘缓鏃堕棿';
+
+COMMENT ON COLUMN "SYS_USER"."DEL_FLAG" IS '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�';
+
+COMMENT ON COLUMN "SYS_USER"."DEPT_ID" IS '閮ㄩ棬ID';
+
+COMMENT ON COLUMN "SYS_USER"."EMAIL" IS '鐢ㄦ埛閭';
+
+COMMENT ON COLUMN "SYS_USER"."LOGIN_DATE" IS '鏈�鍚庣櫥褰曟椂闂�';
+
+COMMENT ON COLUMN "SYS_USER"."LOGIN_IP" IS '鏈�鍚庣櫥褰旾P';
+
+COMMENT ON COLUMN "SYS_USER"."NICK_NAME" IS '鐢ㄦ埛鏄电О';
+
+COMMENT ON COLUMN "SYS_USER"."PASSWORD" IS '瀵嗙爜';
+
+COMMENT ON COLUMN "SYS_USER"."PHONENUMBER" IS '鎵嬫満鍙风爜';
+
+COMMENT ON COLUMN "SYS_USER"."REMARK" IS '澶囨敞';
+
+COMMENT ON COLUMN "SYS_USER"."SEX" IS '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�';
+
+COMMENT ON COLUMN "SYS_USER"."STATUS" IS '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�';
+
+COMMENT ON COLUMN "SYS_USER"."UPDATE_BY" IS '鏇存柊鑰�';
+
+COMMENT ON COLUMN "SYS_USER"."UPDATE_TIME" IS '鏇存柊鏃堕棿';
+
+COMMENT ON COLUMN "SYS_USER"."USER_ID" IS '鐢ㄦ埛ID';
+
+COMMENT ON COLUMN "SYS_USER"."USER_NAME" IS '鐢ㄦ埛璐﹀彿';
+
+COMMENT ON COLUMN "SYS_USER"."USER_TYPE" IS '鐢ㄦ埛绫诲瀷锛�00绯荤粺鐢ㄦ埛锛�';
+
+COMMENT ON TABLE "SYS_USER_POST" IS '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+
+COMMENT ON COLUMN "SYS_USER_POST"."POST_ID" IS '宀椾綅ID';
+
+COMMENT ON COLUMN "SYS_USER_POST"."USER_ID" IS '鐢ㄦ埛ID';
+
+COMMENT ON TABLE "SYS_USER_ROLE" IS '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+COMMENT ON COLUMN "SYS_USER_ROLE"."ROLE_ID" IS '瑙掕壊ID';
+
+COMMENT ON COLUMN "SYS_USER_ROLE"."USER_ID" IS '鐢ㄦ埛ID';
+
+SET IDENTITY_INSERT "SYS_CONFIG" ON;
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О','sys.index.skinName','skin-blue','Y','admin','2025-02-16 16:24:25.000000000','',null,'钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow');
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜','sys.user.initPassword','123456','Y','admin','2025-02-16 16:24:25.000000000','',null,'鍒濆鍖栧瘑鐮� 123456');
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,'涓绘鏋堕〉-渚ц竟鏍忎富棰�','sys.index.sideTheme','theme-dark','Y','admin','2025-02-16 16:24:25.000000000','',null,'娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light');
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(4,'璐﹀彿鑷姪-楠岃瘉鐮佸紑鍏�','sys.account.captchaEnabled','true','Y','admin','2025-02-16 16:24:25.000000000','',null,'鏄惁寮�鍚獙璇佺爜鍔熻兘锛坱rue寮�鍚紝false鍏抽棴锛�');
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(5,'璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�','sys.account.registerUser','false','Y','admin','2025-02-16 16:24:25.000000000','',null,'鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
+INSERT INTO "SYS_CONFIG"("CONFIG_ID","CONFIG_NAME","CONFIG_KEY","CONFIG_VALUE","CONFIG_TYPE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(6,'鐢ㄦ埛鐧诲綍-榛戝悕鍗曞垪琛�','sys.login.blackIPList','','Y','admin','2025-02-16 16:24:25.000000000','',null,'璁剧疆鐧诲綍IP榛戝悕鍗曢檺鍒讹紝澶氫釜鍖归厤椤逛互;鍒嗛殧锛屾敮鎸佸尮閰嶏紙*閫氶厤銆佺綉娈碉級');
+SET IDENTITY_INSERT "SYS_CONFIG" OFF;
+
+SET IDENTITY_INSERT "SYS_DEPT" ON;
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(100,0,'0','鑻ヤ緷绉戞妧',0,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(101,100,'0,100','娣卞湷鎬诲叕鍙�',1,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(102,100,'0,100','闀挎矙鍒嗗叕鍙�',2,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(103,101,'0,100,101','鐮斿彂閮ㄩ棬',1,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(104,101,'0,100,101','甯傚満閮ㄩ棬',2,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(105,101,'0,100,101','娴嬭瘯閮ㄩ棬',3,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(106,101,'0,100,101','璐㈠姟閮ㄩ棬',4,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(107,101,'0,100,101','杩愮淮閮ㄩ棬',5,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(108,102,'0,100,102','甯傚満閮ㄩ棬',1,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+INSERT INTO "SYS_DEPT"("DEPT_ID","PARENT_ID","ANCESTORS","DEPT_NAME","ORDER_NUM","LEADER","PHONE","EMAIL","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME") VALUES(109,102,'0,100,102','璐㈠姟閮ㄩ棬',2,'鑻ヤ緷','15888888888','ry@qq.com','0','0','admin','2025-02-16 16:24:23.000000000','',null);
+SET IDENTITY_INSERT "SYS_DEPT" OFF;
+
+SET IDENTITY_INSERT "SYS_DICT_DATA" ON;
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,1,'鐢�','0','sys_user_sex','','','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'鎬у埆鐢�');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,2,'濂�','1','sys_user_sex','','','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鎬у埆濂�');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,3,'鏈煡','2','sys_user_sex','','','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鎬у埆鏈煡');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(4,1,'鏄剧ず','0','sys_show_hide','','primary','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'鏄剧ず鑿滃崟');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(5,2,'闅愯棌','1','sys_show_hide','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'闅愯棌鑿滃崟');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(6,1,'姝e父','0','sys_normal_disable','','primary','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'姝e父鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(7,2,'鍋滅敤','1','sys_normal_disable','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍋滅敤鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(8,1,'姝e父','0','sys_job_status','','primary','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'姝e父鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(9,2,'鏆傚仠','1','sys_job_status','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍋滅敤鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(10,1,'榛樿','DEFAULT','sys_job_group','','','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'榛樿鍒嗙粍');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(11,2,'绯荤粺','SYSTEM','sys_job_group','','','N','0','admin','2025-02-16 16:24:25.000000000','',null,'绯荤粺鍒嗙粍');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(12,1,'鏄�','Y','sys_yes_no','','primary','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'绯荤粺榛樿鏄�');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(13,2,'鍚�','N','sys_yes_no','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'绯荤粺榛樿鍚�');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(14,1,'閫氱煡','1','sys_notice_type','','warning','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'閫氱煡');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(15,2,'鍏憡','2','sys_notice_type','','success','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍏憡');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(16,1,'姝e父','0','sys_notice_status','','primary','Y','0','admin','2025-02-16 16:24:25.000000000','',null,'姝e父鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(17,2,'鍏抽棴','1','sys_notice_status','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍏抽棴鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(18,99,'鍏朵粬','0','sys_oper_type','','info','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍏朵粬鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(19,1,'鏂板','1','sys_oper_type','','info','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鏂板鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(20,2,'淇敼','2','sys_oper_type','','info','N','0','admin','2025-02-16 16:24:25.000000000','',null,'淇敼鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(21,3,'鍒犻櫎','3','sys_oper_type','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍒犻櫎鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(22,4,'鎺堟潈','4','sys_oper_type','','primary','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鎺堟潈鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(23,5,'瀵煎嚭','5','sys_oper_type','','warning','N','0','admin','2025-02-16 16:24:25.000000000','',null,'瀵煎嚭鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(24,6,'瀵煎叆','6','sys_oper_type','','warning','N','0','admin','2025-02-16 16:24:25.000000000','',null,'瀵煎叆鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(25,7,'寮洪��','7','sys_oper_type','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'寮洪��鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(26,8,'鐢熸垚浠g爜','8','sys_oper_type','','warning','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鐢熸垚鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(27,9,'娓呯┖鏁版嵁','9','sys_oper_type','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'娓呯┖鎿嶄綔');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(28,1,'鎴愬姛','0','sys_common_status','','primary','N','0','admin','2025-02-16 16:24:25.000000000','',null,'姝e父鐘舵��');
+INSERT INTO "SYS_DICT_DATA"("DICT_CODE","DICT_SORT","DICT_LABEL","DICT_VALUE","DICT_TYPE","CSS_CLASS","LIST_CLASS","IS_DEFAULT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(29,2,'澶辫触','1','sys_common_status','','danger','N','0','admin','2025-02-16 16:24:25.000000000','',null,'鍋滅敤鐘舵��');
+SET IDENTITY_INSERT "SYS_DICT_DATA" OFF;
+
+SET IDENTITY_INSERT "SYS_DICT_TYPE" ON;
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'鐢ㄦ埛鎬у埆','sys_user_sex','0','admin','2025-02-16 16:24:24.000000000','',null,'鐢ㄦ埛鎬у埆鍒楄〃');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'鑿滃崟鐘舵��','sys_show_hide','0','admin','2025-02-16 16:24:24.000000000','',null,'鑿滃崟鐘舵�佸垪琛�');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,'绯荤粺寮�鍏�','sys_normal_disable','0','admin','2025-02-16 16:24:24.000000000','',null,'绯荤粺寮�鍏冲垪琛�');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(4,'浠诲姟鐘舵��','sys_job_status','0','admin','2025-02-16 16:24:24.000000000','',null,'浠诲姟鐘舵�佸垪琛�');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(5,'浠诲姟鍒嗙粍','sys_job_group','0','admin','2025-02-16 16:24:24.000000000','',null,'浠诲姟鍒嗙粍鍒楄〃');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(6,'绯荤粺鏄惁','sys_yes_no','0','admin','2025-02-16 16:24:24.000000000','',null,'绯荤粺鏄惁鍒楄〃');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(7,'閫氱煡绫诲瀷','sys_notice_type','0','admin','2025-02-16 16:24:24.000000000','',null,'閫氱煡绫诲瀷鍒楄〃');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(8,'閫氱煡鐘舵��','sys_notice_status','0','admin','2025-02-16 16:24:24.000000000','',null,'閫氱煡鐘舵�佸垪琛�');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(9,'鎿嶄綔绫诲瀷','sys_oper_type','0','admin','2025-02-16 16:24:24.000000000','',null,'鎿嶄綔绫诲瀷鍒楄〃');
+INSERT INTO "SYS_DICT_TYPE"("DICT_ID","DICT_NAME","DICT_TYPE","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(10,'绯荤粺鐘舵��','sys_common_status','0','admin','2025-02-16 16:24:24.000000000','',null,'鐧诲綍鐘舵�佸垪琛�');
+SET IDENTITY_INSERT "SYS_DICT_TYPE" OFF;
+
+SET IDENTITY_INSERT "SYS_JOB" ON;
+INSERT INTO "SYS_JOB"("JOB_ID","JOB_NAME","JOB_GROUP","INVOKE_TARGET","CRON_EXPRESSION","MISFIRE_POLICY","CONCURRENT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'绯荤粺榛樿锛堟棤鍙傦級','DEFAULT','ryTask.ryNoParams','0/10 * * * * ?','3','1','1','admin','2025-02-16 16:24:25.000000000','',null,'');
+INSERT INTO "SYS_JOB"("JOB_ID","JOB_NAME","JOB_GROUP","INVOKE_TARGET","CRON_EXPRESSION","MISFIRE_POLICY","CONCURRENT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'绯荤粺榛樿锛堟湁鍙傦級','DEFAULT','ryTask.ryParams(''ry'')','0/15 * * * * ?','3','1','1','admin','2025-02-16 16:24:25.000000000','',null,'');
+INSERT INTO "SYS_JOB"("JOB_ID","JOB_NAME","JOB_GROUP","INVOKE_TARGET","CRON_EXPRESSION","MISFIRE_POLICY","CONCURRENT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,'绯荤粺榛樿锛堝鍙傦級','DEFAULT','ryTask.ryMultipleParams(''ry'', true, 2000L, 316.50D, 100)','0/20 * * * * ?','3','1','1','admin','2025-02-16 16:24:25.000000000','',null,'');
+SET IDENTITY_INSERT "SYS_JOB" OFF;
+
+SET IDENTITY_INSERT "SYS_MENU" ON;
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'绯荤粺绠$悊',0,1,'system',null,'','',1,0,'M','0','0','','system','admin','2025-02-16 16:24:23.000000000','',null,'绯荤粺绠$悊鐩綍');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'绯荤粺鐩戞帶',0,2,'monitor',null,'','',1,0,'M','0','0','','monitor','admin','2025-02-16 16:24:23.000000000','',null,'绯荤粺鐩戞帶鐩綍');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,'绯荤粺宸ュ叿',0,3,'tool',null,'','',1,0,'M','0','0','','tool','admin','2025-02-16 16:24:23.000000000','',null,'绯荤粺宸ュ叿鐩綍');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(4,'鑻ヤ緷瀹樼綉',0,4,'http://ruoyi.vip',null,'','',0,0,'M','0','0','','guide','admin','2025-02-16 16:24:23.000000000','',null,'鑻ヤ緷瀹樼綉鍦板潃');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(100,'鐢ㄦ埛绠$悊',1,1,'user','system/user/index','','',1,0,'C','0','0','system:user:list','user','admin','2025-02-16 16:24:23.000000000','',null,'鐢ㄦ埛绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(101,'瑙掕壊绠$悊',1,2,'role','system/role/index','','',1,0,'C','0','0','system:role:list','peoples','admin','2025-02-16 16:24:23.000000000','',null,'瑙掕壊绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(102,'鑿滃崟绠$悊',1,3,'menu','system/menu/index','','',1,0,'C','0','0','system:menu:list','tree-table','admin','2025-02-16 16:24:23.000000000','',null,'鑿滃崟绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(103,'閮ㄩ棬绠$悊',1,4,'dept','system/dept/index','','',1,0,'C','0','0','system:dept:list','tree','admin','2025-02-16 16:24:23.000000000','',null,'閮ㄩ棬绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(104,'宀椾綅绠$悊',1,5,'post','system/post/index','','',1,0,'C','0','0','system:post:list','post','admin','2025-02-16 16:24:23.000000000','',null,'宀椾綅绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(105,'瀛楀吀绠$悊',1,6,'dict','system/dict/index','','',1,0,'C','0','0','system:dict:list','dict','admin','2025-02-16 16:24:23.000000000','',null,'瀛楀吀绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(106,'鍙傛暟璁剧疆',1,7,'config','system/config/index','','',1,0,'C','0','0','system:config:list','edit','admin','2025-02-16 16:24:23.000000000','',null,'鍙傛暟璁剧疆鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(107,'閫氱煡鍏憡',1,8,'notice','system/notice/index','','',1,0,'C','0','0','system:notice:list','message','admin','2025-02-16 16:24:23.000000000','',null,'閫氱煡鍏憡鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(108,'鏃ュ織绠$悊',1,9,'log','','','',1,0,'M','0','0','','log','admin','2025-02-16 16:24:23.000000000','',null,'鏃ュ織绠$悊鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(109,'鍦ㄧ嚎鐢ㄦ埛',2,1,'online','monitor/online/index','','',1,0,'C','0','0','monitor:online:list','online','admin','2025-02-16 16:24:23.000000000','',null,'鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(110,'瀹氭椂浠诲姟',2,2,'job','monitor/job/index','','',1,0,'C','0','0','monitor:job:list','job','admin','2025-02-16 16:24:23.000000000','',null,'瀹氭椂浠诲姟鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(111,'鏁版嵁鐩戞帶',2,3,'druid','monitor/druid/index','','',1,0,'C','0','0','monitor:druid:list','druid','admin','2025-02-16 16:24:23.000000000','',null,'鏁版嵁鐩戞帶鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(112,'鏈嶅姟鐩戞帶',2,4,'server','monitor/server/index','','',1,0,'C','0','0','monitor:server:list','server','admin','2025-02-16 16:24:23.000000000','',null,'鏈嶅姟鐩戞帶鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(113,'缂撳瓨鐩戞帶',2,5,'cache','monitor/cache/index','','',1,0,'C','0','0','monitor:cache:list','redis','admin','2025-02-16 16:24:23.000000000','',null,'缂撳瓨鐩戞帶鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(114,'缂撳瓨鍒楄〃',2,6,'cacheList','monitor/cache/list','','',1,0,'C','0','0','monitor:cache:list','redis-list','admin','2025-02-16 16:24:23.000000000','',null,'缂撳瓨鍒楄〃鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(115,'琛ㄥ崟鏋勫缓',3,1,'build','tool/build/index','','',1,0,'C','0','0','tool:build:list','build','admin','2025-02-16 16:24:23.000000000','',null,'琛ㄥ崟鏋勫缓鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(116,'浠g爜鐢熸垚',3,2,'gen','tool/gen/index','','',1,0,'C','0','0','tool:gen:list','code','admin','2025-02-16 16:24:23.000000000','',null,'浠g爜鐢熸垚鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(117,'绯荤粺鎺ュ彛',3,3,'swagger','tool/swagger/index','','',1,0,'C','0','0','tool:swagger:list','swagger','admin','2025-02-16 16:24:23.000000000','',null,'绯荤粺鎺ュ彛鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(500,'鎿嶄綔鏃ュ織',108,1,'operlog','monitor/operlog/index','','',1,0,'C','0','0','monitor:operlog:list','form','admin','2025-02-16 16:24:23.000000000','',null,'鎿嶄綔鏃ュ織鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(501,'鐧诲綍鏃ュ織',108,2,'logininfor','monitor/logininfor/index','','',1,0,'C','0','0','monitor:logininfor:list','logininfor','admin','2025-02-16 16:24:23.000000000','',null,'鐧诲綍鏃ュ織鑿滃崟');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1000,'鐢ㄦ埛鏌ヨ',100,1,'','','','',1,0,'F','0','0','system:user:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1001,'鐢ㄦ埛鏂板',100,2,'','','','',1,0,'F','0','0','system:user:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1002,'鐢ㄦ埛淇敼',100,3,'','','','',1,0,'F','0','0','system:user:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1003,'鐢ㄦ埛鍒犻櫎',100,4,'','','','',1,0,'F','0','0','system:user:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1004,'鐢ㄦ埛瀵煎嚭',100,5,'','','','',1,0,'F','0','0','system:user:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1005,'鐢ㄦ埛瀵煎叆',100,6,'','','','',1,0,'F','0','0','system:user:import','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1006,'閲嶇疆瀵嗙爜',100,7,'','','','',1,0,'F','0','0','system:user:resetPwd','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1007,'瑙掕壊鏌ヨ',101,1,'','','','',1,0,'F','0','0','system:role:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1008,'瑙掕壊鏂板',101,2,'','','','',1,0,'F','0','0','system:role:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1009,'瑙掕壊淇敼',101,3,'','','','',1,0,'F','0','0','system:role:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1010,'瑙掕壊鍒犻櫎',101,4,'','','','',1,0,'F','0','0','system:role:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1011,'瑙掕壊瀵煎嚭',101,5,'','','','',1,0,'F','0','0','system:role:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1012,'鑿滃崟鏌ヨ',102,1,'','','','',1,0,'F','0','0','system:menu:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1013,'鑿滃崟鏂板',102,2,'','','','',1,0,'F','0','0','system:menu:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1014,'鑿滃崟淇敼',102,3,'','','','',1,0,'F','0','0','system:menu:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1015,'鑿滃崟鍒犻櫎',102,4,'','','','',1,0,'F','0','0','system:menu:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1016,'閮ㄩ棬鏌ヨ',103,1,'','','','',1,0,'F','0','0','system:dept:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1017,'閮ㄩ棬鏂板',103,2,'','','','',1,0,'F','0','0','system:dept:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1018,'閮ㄩ棬淇敼',103,3,'','','','',1,0,'F','0','0','system:dept:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1019,'閮ㄩ棬鍒犻櫎',103,4,'','','','',1,0,'F','0','0','system:dept:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1020,'宀椾綅鏌ヨ',104,1,'','','','',1,0,'F','0','0','system:post:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1021,'宀椾綅鏂板',104,2,'','','','',1,0,'F','0','0','system:post:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1022,'宀椾綅淇敼',104,3,'','','','',1,0,'F','0','0','system:post:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1023,'宀椾綅鍒犻櫎',104,4,'','','','',1,0,'F','0','0','system:post:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1024,'宀椾綅瀵煎嚭',104,5,'','','','',1,0,'F','0','0','system:post:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1025,'瀛楀吀鏌ヨ',105,1,'#','','','',1,0,'F','0','0','system:dict:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1026,'瀛楀吀鏂板',105,2,'#','','','',1,0,'F','0','0','system:dict:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1027,'瀛楀吀淇敼',105,3,'#','','','',1,0,'F','0','0','system:dict:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1028,'瀛楀吀鍒犻櫎',105,4,'#','','','',1,0,'F','0','0','system:dict:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1029,'瀛楀吀瀵煎嚭',105,5,'#','','','',1,0,'F','0','0','system:dict:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1030,'鍙傛暟鏌ヨ',106,1,'#','','','',1,0,'F','0','0','system:config:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1031,'鍙傛暟鏂板',106,2,'#','','','',1,0,'F','0','0','system:config:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1032,'鍙傛暟淇敼',106,3,'#','','','',1,0,'F','0','0','system:config:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1033,'鍙傛暟鍒犻櫎',106,4,'#','','','',1,0,'F','0','0','system:config:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1034,'鍙傛暟瀵煎嚭',106,5,'#','','','',1,0,'F','0','0','system:config:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1035,'鍏憡鏌ヨ',107,1,'#','','','',1,0,'F','0','0','system:notice:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1036,'鍏憡鏂板',107,2,'#','','','',1,0,'F','0','0','system:notice:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1037,'鍏憡淇敼',107,3,'#','','','',1,0,'F','0','0','system:notice:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1038,'鍏憡鍒犻櫎',107,4,'#','','','',1,0,'F','0','0','system:notice:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1039,'鎿嶄綔鏌ヨ',500,1,'#','','','',1,0,'F','0','0','monitor:operlog:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1040,'鎿嶄綔鍒犻櫎',500,2,'#','','','',1,0,'F','0','0','monitor:operlog:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1041,'鏃ュ織瀵煎嚭',500,3,'#','','','',1,0,'F','0','0','monitor:operlog:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1042,'鐧诲綍鏌ヨ',501,1,'#','','','',1,0,'F','0','0','monitor:logininfor:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1043,'鐧诲綍鍒犻櫎',501,2,'#','','','',1,0,'F','0','0','monitor:logininfor:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1044,'鏃ュ織瀵煎嚭',501,3,'#','','','',1,0,'F','0','0','monitor:logininfor:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1045,'璐︽埛瑙i攣',501,4,'#','','','',1,0,'F','0','0','monitor:logininfor:unlock','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1046,'鍦ㄧ嚎鏌ヨ',109,1,'#','','','',1,0,'F','0','0','monitor:online:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1047,'鎵归噺寮洪��',109,2,'#','','','',1,0,'F','0','0','monitor:online:batchLogout','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1048,'鍗曟潯寮洪��',109,3,'#','','','',1,0,'F','0','0','monitor:online:forceLogout','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1049,'浠诲姟鏌ヨ',110,1,'#','','','',1,0,'F','0','0','monitor:job:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1050,'浠诲姟鏂板',110,2,'#','','','',1,0,'F','0','0','monitor:job:add','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1051,'浠诲姟淇敼',110,3,'#','','','',1,0,'F','0','0','monitor:job:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1052,'浠诲姟鍒犻櫎',110,4,'#','','','',1,0,'F','0','0','monitor:job:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1053,'鐘舵�佷慨鏀�',110,5,'#','','','',1,0,'F','0','0','monitor:job:changeStatus','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1054,'浠诲姟瀵煎嚭',110,6,'#','','','',1,0,'F','0','0','monitor:job:export','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1055,'鐢熸垚鏌ヨ',116,1,'#','','','',1,0,'F','0','0','tool:gen:query','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1056,'鐢熸垚淇敼',116,2,'#','','','',1,0,'F','0','0','tool:gen:edit','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1057,'鐢熸垚鍒犻櫎',116,3,'#','','','',1,0,'F','0','0','tool:gen:remove','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1058,'瀵煎叆浠g爜',116,4,'#','','','',1,0,'F','0','0','tool:gen:import','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1059,'棰勮浠g爜',116,5,'#','','','',1,0,'F','0','0','tool:gen:preview','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_MENU"("MENU_ID","MENU_NAME","PARENT_ID","ORDER_NUM","PATH","COMPONENT","QUERY","ROUTE_NAME","IS_FRAME","IS_CACHE","MENU_TYPE","VISIBLE","STATUS","PERMS","ICON","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1060,'鐢熸垚浠g爜',116,6,'#','','','',1,0,'F','0','0','tool:gen:code','#','admin','2025-02-16 16:24:23.000000000','',null,'');
+SET IDENTITY_INSERT "SYS_MENU" OFF;
+
+SET IDENTITY_INSERT "SYS_NOTICE" ON;
+INSERT INTO "SYS_NOTICE"("NOTICE_ID","NOTICE_TITLE","NOTICE_TYPE","NOTICE_CONTENT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'娓╅Θ鎻愰啋锛�2018-07-01 鑻ヤ緷鏂扮増鏈彂甯冨暒','2',0xE696B0E78988E69CACE58685E5AEB9,'0','admin','2025-02-16 16:24:25.000000000','',null,'绠$悊鍛�');
+INSERT INTO "SYS_NOTICE"("NOTICE_ID","NOTICE_TITLE","NOTICE_TYPE","NOTICE_CONTENT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'缁存姢閫氱煡锛�2018-07-01 鑻ヤ緷绯荤粺鍑屾櫒缁存姢','1',0xE7BBB4E68AA4E58685E5AEB9,'0','admin','2025-02-16 16:24:25.000000000','',null,'绠$悊鍛�');
+SET IDENTITY_INSERT "SYS_NOTICE" OFF;
+
+SET IDENTITY_INSERT "SYS_POST" ON;
+INSERT INTO "SYS_POST"("POST_ID","POST_CODE","POST_NAME","POST_SORT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'ceo','钁d簨闀�',1,'0','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_POST"("POST_ID","POST_CODE","POST_NAME","POST_SORT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'se','椤圭洰缁忕悊',2,'0','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_POST"("POST_ID","POST_CODE","POST_NAME","POST_SORT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(3,'hr','浜哄姏璧勬簮',3,'0','admin','2025-02-16 16:24:23.000000000','',null,'');
+INSERT INTO "SYS_POST"("POST_ID","POST_CODE","POST_NAME","POST_SORT","STATUS","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(4,'user','鏅�氬憳宸�',4,'0','admin','2025-02-16 16:24:23.000000000','',null,'');
+SET IDENTITY_INSERT "SYS_POST" OFF;
+
+SET IDENTITY_INSERT "SYS_ROLE" ON;
+INSERT INTO "SYS_ROLE"("ROLE_ID","ROLE_NAME","ROLE_KEY","ROLE_SORT","DATA_SCOPE","MENU_CHECK_STRICTLY","DEPT_CHECK_STRICTLY","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,'瓒呯骇绠$悊鍛�','admin',1,'1',1,1,'0','0','admin','2025-02-16 16:24:23.000000000','',null,'瓒呯骇绠$悊鍛�');
+INSERT INTO "SYS_ROLE"("ROLE_ID","ROLE_NAME","ROLE_KEY","ROLE_SORT","DATA_SCOPE","MENU_CHECK_STRICTLY","DEPT_CHECK_STRICTLY","STATUS","DEL_FLAG","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,'鏅�氳鑹�','common',2,'2',1,1,'0','0','admin','2025-02-16 16:24:23.000000000','',null,'鏅�氳鑹�');
+SET IDENTITY_INSERT "SYS_ROLE" OFF;
+
+
+INSERT INTO "SYS_ROLE_DEPT"("ROLE_ID","DEPT_ID") VALUES(2,100);
+INSERT INTO "SYS_ROLE_DEPT"("ROLE_ID","DEPT_ID") VALUES(2,101);
+INSERT INTO "SYS_ROLE_DEPT"("ROLE_ID","DEPT_ID") VALUES(2,105);
+
+
+
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,2);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,3);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,4);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,100);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,101);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,102);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,103);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,104);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,105);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,106);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,107);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,108);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,109);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,110);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,111);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,112);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,113);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,114);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,115);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,116);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,117);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,500);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,501);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1000);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1001);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1002);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1003);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1004);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1005);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1006);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1007);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1008);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1009);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1010);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1011);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1012);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1013);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1014);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1015);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1016);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1017);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1018);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1019);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1020);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1021);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1022);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1023);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1024);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1025);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1026);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1027);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1028);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1029);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1030);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1031);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1032);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1033);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1034);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1035);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1036);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1037);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1038);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1039);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1040);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1041);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1042);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1043);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1044);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1045);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1046);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1047);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1048);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1049);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1050);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1051);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1052);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1053);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1054);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1055);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1056);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1057);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1058);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1059);
+INSERT INTO "SYS_ROLE_MENU"("ROLE_ID","MENU_ID") VALUES(2,1060);
+
+
+SET IDENTITY_INSERT "SYS_USER" ON;
+INSERT INTO "SYS_USER"("USER_ID","DEPT_ID","USER_NAME","NICK_NAME","USER_TYPE","EMAIL","PHONENUMBER","SEX","AVATAR","PASSWORD","STATUS","DEL_FLAG","LOGIN_IP","LOGIN_DATE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(1,103,'admin','鑻ヤ緷','00','ry@163.com','15888888888','1','','$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2','0','0','127.0.0.1','2025-02-16 16:24:23.000000000','admin','2025-02-16 16:24:23.000000000','',null,'绠$悊鍛�');
+INSERT INTO "SYS_USER"("USER_ID","DEPT_ID","USER_NAME","NICK_NAME","USER_TYPE","EMAIL","PHONENUMBER","SEX","AVATAR","PASSWORD","STATUS","DEL_FLAG","LOGIN_IP","LOGIN_DATE","CREATE_BY","CREATE_TIME","UPDATE_BY","UPDATE_TIME","REMARK") VALUES(2,105,'ry','鑻ヤ緷','00','ry@qq.com','15666666666','1','','$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2','0','0','127.0.0.1','2025-02-16 16:24:23.000000000','admin','2025-02-16 16:24:23.000000000','',null,'娴嬭瘯鍛�');
+SET IDENTITY_INSERT "SYS_USER" OFF;
+
+INSERT INTO "SYS_USER_POST"("USER_ID","POST_ID") VALUES(1,1);
+INSERT INTO "SYS_USER_POST"("USER_ID","POST_ID") VALUES(2,2);
+
+INSERT INTO "SYS_USER_ROLE"("USER_ID","ROLE_ID") VALUES(1,1);
+INSERT INTO "SYS_USER_ROLE"("USER_ID","ROLE_ID") VALUES(2,2);
+
+COMMIT;
diff --git a/sql/quartz.sql b/sql/quartz.sql
new file mode 100644
index 0000000..cee613b
--- /dev/null
+++ b/sql/quartz.sql
@@ -0,0 +1,174 @@
+DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
+DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
+DROP TABLE IF EXISTS QRTZ_LOCKS;
+DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_TRIGGERS;
+DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
+DROP TABLE IF EXISTS QRTZ_CALENDARS;
+
+-- ----------------------------
+-- 1銆佸瓨鍌ㄦ瘡涓�涓凡閰嶇疆鐨� jobDetail 鐨勮缁嗕俊鎭�
+-- ----------------------------
+create table QRTZ_JOB_DETAILS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    job_name             varchar(200)    not null            comment '浠诲姟鍚嶇О',
+    job_group            varchar(200)    not null            comment '浠诲姟缁勫悕',
+    description          varchar(250)    null                comment '鐩稿叧浠嬬粛',
+    job_class_name       varchar(250)    not null            comment '鎵ц浠诲姟绫诲悕绉�',
+    is_durable           varchar(1)      not null            comment '鏄惁鎸佷箙鍖�',
+    is_nonconcurrent     varchar(1)      not null            comment '鏄惁骞跺彂',
+    is_update_data       varchar(1)      not null            comment '鏄惁鏇存柊鏁版嵁',
+    requests_recovery    varchar(1)      not null            comment '鏄惁鎺ュ彈鎭㈠鎵ц',
+    job_data             blob            null                comment '瀛樻斁鎸佷箙鍖杍ob瀵硅薄',
+    primary key (sched_name, job_name, job_group)
+) engine=innodb comment = '浠诲姟璇︾粏淇℃伅琛�';
+
+-- ----------------------------
+-- 2銆� 瀛樺偍宸查厤缃殑 Trigger 鐨勪俊鎭�
+-- ----------------------------
+create table QRTZ_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_name         varchar(200)    not null            comment '瑙﹀彂鍣ㄧ殑鍚嶅瓧',
+    trigger_group        varchar(200)    not null            comment '瑙﹀彂鍣ㄦ墍灞炵粍鐨勫悕瀛�',
+    job_name             varchar(200)    not null            comment 'qrtz_job_details琛╦ob_name鐨勫閿�',
+    job_group            varchar(200)    not null            comment 'qrtz_job_details琛╦ob_group鐨勫閿�',
+    description          varchar(250)    null                comment '鐩稿叧浠嬬粛',
+    next_fire_time       bigint(13)      null                comment '涓婁竴娆¤Е鍙戞椂闂达紙姣锛�',
+    prev_fire_time       bigint(13)      null                comment '涓嬩竴娆¤Е鍙戞椂闂达紙榛樿涓�-1琛ㄧず涓嶈Е鍙戯級',
+    priority             integer         null                comment '浼樺厛绾�',
+    trigger_state        varchar(16)     not null            comment '瑙﹀彂鍣ㄧ姸鎬�',
+    trigger_type         varchar(8)      not null            comment '瑙﹀彂鍣ㄧ殑绫诲瀷',
+    start_time           bigint(13)      not null            comment '寮�濮嬫椂闂�',
+    end_time             bigint(13)      null                comment '缁撴潫鏃堕棿',
+    calendar_name        varchar(200)    null                comment '鏃ョ▼琛ㄥ悕绉�',
+    misfire_instr        smallint(2)     null                comment '琛ュ伩鎵ц鐨勭瓥鐣�',
+    job_data             blob            null                comment '瀛樻斁鎸佷箙鍖杍ob瀵硅薄',
+    primary key (sched_name, trigger_name, trigger_group),
+    foreign key (sched_name, job_name, job_group) references QRTZ_JOB_DETAILS(sched_name, job_name, job_group)
+) engine=innodb comment = '瑙﹀彂鍣ㄨ缁嗕俊鎭〃';
+
+-- ----------------------------
+-- 3銆� 瀛樺偍绠�鍗曠殑 Trigger锛屽寘鎷噸澶嶆鏁帮紝闂撮殧锛屼互鍙婂凡瑙﹀彂鐨勬鏁�
+-- ----------------------------
+create table QRTZ_SIMPLE_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_name         varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_name鐨勫閿�',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    repeat_count         bigint(7)       not null            comment '閲嶅鐨勬鏁扮粺璁�',
+    repeat_interval      bigint(12)      not null            comment '閲嶅鐨勯棿闅旀椂闂�',
+    times_triggered      bigint(10)      not null            comment '宸茬粡瑙﹀彂鐨勬鏁�',
+    primary key (sched_name, trigger_name, trigger_group),
+    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
+) engine=innodb comment = '绠�鍗曡Е鍙戝櫒鐨勪俊鎭〃';
+
+-- ----------------------------
+-- 4銆� 瀛樺偍 Cron Trigger锛屽寘鎷� Cron 琛ㄨ揪寮忓拰鏃跺尯淇℃伅
+-- ---------------------------- 
+create table QRTZ_CRON_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_name         varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_name鐨勫閿�',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    cron_expression      varchar(200)    not null            comment 'cron琛ㄨ揪寮�',
+    time_zone_id         varchar(80)                         comment '鏃跺尯',
+    primary key (sched_name, trigger_name, trigger_group),
+    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
+) engine=innodb comment = 'Cron绫诲瀷鐨勮Е鍙戝櫒琛�';
+
+-- ----------------------------
+-- 5銆� Trigger 浣滀负 Blob 绫诲瀷瀛樺偍(鐢ㄤ簬 Quartz 鐢ㄦ埛鐢� JDBC 鍒涘缓浠栦滑鑷繁瀹氬埗鐨� Trigger 绫诲瀷锛孞obStore 骞朵笉鐭ラ亾濡備綍瀛樺偍瀹炰緥鐨勬椂鍊�)
+-- ---------------------------- 
+create table QRTZ_BLOB_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_name         varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_name鐨勫閿�',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    blob_data            blob            null                comment '瀛樻斁鎸佷箙鍖朤rigger瀵硅薄',
+    primary key (sched_name, trigger_name, trigger_group),
+    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
+) engine=innodb comment = 'Blob绫诲瀷鐨勮Е鍙戝櫒琛�';
+
+-- ----------------------------
+-- 6銆� 浠� Blob 绫诲瀷瀛樺偍瀛樻斁鏃ュ巻淇℃伅锛� quartz鍙厤缃竴涓棩鍘嗘潵鎸囧畾涓�涓椂闂磋寖鍥�
+-- ---------------------------- 
+create table QRTZ_CALENDARS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    calendar_name        varchar(200)    not null            comment '鏃ュ巻鍚嶇О',
+    calendar             blob            not null            comment '瀛樻斁鎸佷箙鍖朿alendar瀵硅薄',
+    primary key (sched_name, calendar_name)
+) engine=innodb comment = '鏃ュ巻淇℃伅琛�';
+
+-- ----------------------------
+-- 7銆� 瀛樺偍宸叉殏鍋滅殑 Trigger 缁勭殑淇℃伅
+-- ---------------------------- 
+create table QRTZ_PAUSED_TRIGGER_GRPS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    primary key (sched_name, trigger_group)
+) engine=innodb comment = '鏆傚仠鐨勮Е鍙戝櫒琛�';
+
+-- ----------------------------
+-- 8銆� 瀛樺偍涓庡凡瑙﹀彂鐨� Trigger 鐩稿叧鐨勭姸鎬佷俊鎭紝浠ュ強鐩歌仈 Job 鐨勬墽琛屼俊鎭�
+-- ---------------------------- 
+create table QRTZ_FIRED_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    entry_id             varchar(95)     not null            comment '璋冨害鍣ㄥ疄渚媔d',
+    trigger_name         varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_name鐨勫閿�',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    instance_name        varchar(200)    not null            comment '璋冨害鍣ㄥ疄渚嬪悕',
+    fired_time           bigint(13)      not null            comment '瑙﹀彂鐨勬椂闂�',
+    sched_time           bigint(13)      not null            comment '瀹氭椂鍣ㄥ埗瀹氱殑鏃堕棿',
+    priority             integer         not null            comment '浼樺厛绾�',
+    state                varchar(16)     not null            comment '鐘舵��',
+    job_name             varchar(200)    null                comment '浠诲姟鍚嶇О',
+    job_group            varchar(200)    null                comment '浠诲姟缁勫悕',
+    is_nonconcurrent     varchar(1)      null                comment '鏄惁骞跺彂',
+    requests_recovery    varchar(1)      null                comment '鏄惁鎺ュ彈鎭㈠鎵ц',
+    primary key (sched_name, entry_id)
+) engine=innodb comment = '宸茶Е鍙戠殑瑙﹀彂鍣ㄨ〃';
+
+-- ----------------------------
+-- 9銆� 瀛樺偍灏戦噺鐨勬湁鍏� Scheduler 鐨勭姸鎬佷俊鎭紝鍋囧鏄敤浜庨泦缇や腑锛屽彲浠ョ湅鍒板叾浠栫殑 Scheduler 瀹炰緥
+-- ---------------------------- 
+create table QRTZ_SCHEDULER_STATE (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    instance_name        varchar(200)    not null            comment '瀹炰緥鍚嶇О',
+    last_checkin_time    bigint(13)      not null            comment '涓婃妫�鏌ユ椂闂�',
+    checkin_interval     bigint(13)      not null            comment '妫�鏌ラ棿闅旀椂闂�',
+    primary key (sched_name, instance_name)
+) engine=innodb comment = '璋冨害鍣ㄧ姸鎬佽〃';
+
+-- ----------------------------
+-- 10銆� 瀛樺偍绋嬪簭鐨勬偛瑙傞攣鐨勪俊鎭�(鍋囧浣跨敤浜嗘偛瑙傞攣)
+-- ---------------------------- 
+create table QRTZ_LOCKS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    lock_name            varchar(40)     not null            comment '鎮茶閿佸悕绉�',
+    primary key (sched_name, lock_name)
+) engine=innodb comment = '瀛樺偍鐨勬偛瑙傞攣淇℃伅琛�';
+
+-- ----------------------------
+-- 11銆� Quartz闆嗙兢瀹炵幇鍚屾鏈哄埗鐨勮閿佽〃
+-- ---------------------------- 
+create table QRTZ_SIMPROP_TRIGGERS (
+    sched_name           varchar(120)    not null            comment '璋冨害鍚嶇О',
+    trigger_name         varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_name鐨勫閿�',
+    trigger_group        varchar(200)    not null            comment 'qrtz_triggers琛╰rigger_group鐨勫閿�',
+    str_prop_1           varchar(512)    null                comment 'String绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
+    str_prop_2           varchar(512)    null                comment 'String绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
+    str_prop_3           varchar(512)    null                comment 'String绫诲瀷鐨則rigger鐨勭涓変釜鍙傛暟',
+    int_prop_1           int             null                comment 'int绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
+    int_prop_2           int             null                comment 'int绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
+    long_prop_1          bigint          null                comment 'long绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
+    long_prop_2          bigint          null                comment 'long绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
+    dec_prop_1           numeric(13,4)   null                comment 'decimal绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
+    dec_prop_2           numeric(13,4)   null                comment 'decimal绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
+    bool_prop_1          varchar(1)      null                comment 'Boolean绫诲瀷鐨則rigger鐨勭涓�涓弬鏁�',
+    bool_prop_2          varchar(1)      null                comment 'Boolean绫诲瀷鐨則rigger鐨勭浜屼釜鍙傛暟',
+    primary key (sched_name, trigger_name, trigger_group),
+    foreign key (sched_name, trigger_name, trigger_group) references QRTZ_TRIGGERS(sched_name, trigger_name, trigger_group)
+) engine=innodb comment = '鍚屾鏈哄埗鐨勮閿佽〃';
+
+commit;
\ No newline at end of file
diff --git a/sql/ry_20240629.sql b/sql/ry_20240629.sql
new file mode 100644
index 0000000..a8647d2
--- /dev/null
+++ b/sql/ry_20240629.sql
@@ -0,0 +1,701 @@
+-- ----------------------------
+-- 1銆侀儴闂ㄨ〃
+-- ----------------------------
+drop table if exists sys_dept;
+create table sys_dept (
+  dept_id           bigint(20)      not null auto_increment    comment '閮ㄩ棬id',
+  parent_id         bigint(20)      default 0                  comment '鐖堕儴闂╥d',
+  ancestors         varchar(50)     default ''                 comment '绁栫骇鍒楄〃',
+  dept_name         varchar(30)     default ''                 comment '閮ㄩ棬鍚嶇О',
+  order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+  leader            varchar(20)     default null               comment '璐熻矗浜�',
+  phone             varchar(11)     default null               comment '鑱旂郴鐢佃瘽',
+  email             varchar(50)     default null               comment '閭',
+  status            char(1)         default '0'                comment '閮ㄩ棬鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  primary key (dept_id)
+) engine=innodb auto_increment=200 comment = '閮ㄩ棬琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-閮ㄩ棬琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_dept values(100,  0,   '0',          '鑻ヤ緷绉戞妧',   0, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(101,  100, '0,100',      '娣卞湷鎬诲叕鍙�', 1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(102,  100, '0,100',      '闀挎矙鍒嗗叕鍙�', 2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(103,  101, '0,100,101',  '鐮斿彂閮ㄩ棬',   1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(104,  101, '0,100,101',  '甯傚満閮ㄩ棬',   2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(105,  101, '0,100,101',  '娴嬭瘯閮ㄩ棬',   3, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(106,  101, '0,100,101',  '璐㈠姟閮ㄩ棬',   4, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(107,  101, '0,100,101',  '杩愮淮閮ㄩ棬',   5, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(108,  102, '0,100,102',  '甯傚満閮ㄩ棬',   1, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+insert into sys_dept values(109,  102, '0,100,102',  '璐㈠姟閮ㄩ棬',   2, '鑻ヤ緷', '15888888888', 'ry@qq.com', '0', '0', 'admin', sysdate(), '', null);
+
+
+-- ----------------------------
+-- 2銆佺敤鎴蜂俊鎭〃
+-- ----------------------------
+drop table if exists sys_user;
+create table sys_user (
+  user_id           bigint(20)      not null auto_increment    comment '鐢ㄦ埛ID',
+  dept_id           bigint(20)      default null               comment '閮ㄩ棬ID',
+  user_name         varchar(30)     not null                   comment '鐢ㄦ埛璐﹀彿',
+  nick_name         varchar(30)     not null                   comment '鐢ㄦ埛鏄电О',
+  user_type         varchar(2)      default '00'               comment '鐢ㄦ埛绫诲瀷锛�00绯荤粺鐢ㄦ埛锛�',
+  email             varchar(50)     default ''                 comment '鐢ㄦ埛閭',
+  phonenumber       varchar(11)     default ''                 comment '鎵嬫満鍙风爜',
+  sex               char(1)         default '0'                comment '鐢ㄦ埛鎬у埆锛�0鐢� 1濂� 2鏈煡锛�',
+  avatar            varchar(100)    default ''                 comment '澶村儚鍦板潃',
+  password          varchar(100)    default ''                 comment '瀵嗙爜',
+  status            char(1)         default '0'                comment '甯愬彿鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag          char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  login_ip          varchar(128)    default ''                 comment '鏈�鍚庣櫥褰旾P',
+  login_date        datetime                                   comment '鏈�鍚庣櫥褰曟椂闂�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (user_id)
+) engine=innodb auto_increment=100 comment = '鐢ㄦ埛淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_user values(1,  103, 'admin', '鑻ヤ緷', '00', 'ry@163.com', '15888888888', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '绠$悊鍛�');
+insert into sys_user values(2,  105, 'ry',    '鑻ヤ緷', '00', 'ry@qq.com',  '15666666666', '1', '', '$2a$10$7JB720yubVSZvUI0rEqK/.VqGOZTH.ulu33dHOiBE8ByOhJIrdAu2', '0', '0', '127.0.0.1', sysdate(), 'admin', sysdate(), '', null, '娴嬭瘯鍛�');
+
+
+-- ----------------------------
+-- 3銆佸矖浣嶄俊鎭〃
+-- ----------------------------
+drop table if exists sys_post;
+create table sys_post
+(
+  post_id       bigint(20)      not null auto_increment    comment '宀椾綅ID',
+  post_code     varchar(64)     not null                   comment '宀椾綅缂栫爜',
+  post_name     varchar(50)     not null                   comment '宀椾綅鍚嶇О',
+  post_sort     int(4)          not null                   comment '鏄剧ず椤哄簭',
+  status        char(1)         not null                   comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by     varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time   datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by     varchar(64)     default ''			       comment '鏇存柊鑰�',
+  update_time   datetime                                   comment '鏇存柊鏃堕棿',
+  remark        varchar(500)    default null               comment '澶囨敞',
+  primary key (post_id)
+) engine=innodb comment = '宀椾綅淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-宀椾綅淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_post values(1, 'ceo',  '钁d簨闀�',    1, '0', 'admin', sysdate(), '', null, '');
+insert into sys_post values(2, 'se',   '椤圭洰缁忕悊',  2, '0', 'admin', sysdate(), '', null, '');
+insert into sys_post values(3, 'hr',   '浜哄姏璧勬簮',  3, '0', 'admin', sysdate(), '', null, '');
+insert into sys_post values(4, 'user', '鏅�氬憳宸�',  4, '0', 'admin', sysdate(), '', null, '');
+
+
+-- ----------------------------
+-- 4銆佽鑹蹭俊鎭〃
+-- ----------------------------
+drop table if exists sys_role;
+create table sys_role (
+  role_id              bigint(20)      not null auto_increment    comment '瑙掕壊ID',
+  role_name            varchar(30)     not null                   comment '瑙掕壊鍚嶇О',
+  role_key             varchar(100)    not null                   comment '瑙掕壊鏉冮檺瀛楃涓�',
+  role_sort            int(4)          not null                   comment '鏄剧ず椤哄簭',
+  data_scope           char(1)         default '1'                comment '鏁版嵁鑼冨洿锛�1锛氬叏閮ㄦ暟鎹潈闄� 2锛氳嚜瀹氭暟鎹潈闄� 3锛氭湰閮ㄩ棬鏁版嵁鏉冮檺 4锛氭湰閮ㄩ棬鍙婁互涓嬫暟鎹潈闄愶級',
+  menu_check_strictly  tinyint(1)      default 1                  comment '鑿滃崟鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
+  dept_check_strictly  tinyint(1)      default 1                  comment '閮ㄩ棬鏍戦�夋嫨椤规槸鍚﹀叧鑱旀樉绀�',
+  status               char(1)         not null                   comment '瑙掕壊鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  del_flag             char(1)         default '0'                comment '鍒犻櫎鏍囧織锛�0浠h〃瀛樺湪 2浠h〃鍒犻櫎锛�',
+  create_by            varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time          datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by            varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time          datetime                                   comment '鏇存柊鏃堕棿',
+  remark               varchar(500)    default null               comment '澶囨敞',
+  primary key (role_id)
+) engine=innodb auto_increment=100 comment = '瑙掕壊淇℃伅琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_role values('1', '瓒呯骇绠$悊鍛�',  'admin',  1, 1, 1, 1, '0', '0', 'admin', sysdate(), '', null, '瓒呯骇绠$悊鍛�');
+insert into sys_role values('2', '鏅�氳鑹�',    'common', 2, 2, 1, 1, '0', '0', 'admin', sysdate(), '', null, '鏅�氳鑹�');
+
+
+-- ----------------------------
+-- 5銆佽彍鍗曟潈闄愯〃
+-- ----------------------------
+drop table if exists sys_menu;
+create table sys_menu (
+  menu_id           bigint(20)      not null auto_increment    comment '鑿滃崟ID',
+  menu_name         varchar(50)     not null                   comment '鑿滃崟鍚嶇О',
+  parent_id         bigint(20)      default 0                  comment '鐖惰彍鍗旾D',
+  order_num         int(4)          default 0                  comment '鏄剧ず椤哄簭',
+  path              varchar(200)    default ''                 comment '璺敱鍦板潃',
+  component         varchar(255)    default null               comment '缁勪欢璺緞',
+  query             varchar(255)    default null               comment '璺敱鍙傛暟',
+  route_name        varchar(50)     default ''                 comment '璺敱鍚嶇О',
+  is_frame          int(1)          default 1                  comment '鏄惁涓哄閾撅紙0鏄� 1鍚︼級',
+  is_cache          int(1)          default 0                  comment '鏄惁缂撳瓨锛�0缂撳瓨 1涓嶇紦瀛橈級',
+  menu_type         char(1)         default ''                 comment '鑿滃崟绫诲瀷锛圡鐩綍 C鑿滃崟 F鎸夐挳锛�',
+  visible           char(1)         default 0                  comment '鑿滃崟鐘舵�侊紙0鏄剧ず 1闅愯棌锛�',
+  status            char(1)         default 0                  comment '鑿滃崟鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  perms             varchar(100)    default null               comment '鏉冮檺鏍囪瘑',
+  icon              varchar(100)    default '#'                comment '鑿滃崟鍥炬爣',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default ''                 comment '澶囨敞',
+  primary key (menu_id)
+) engine=innodb auto_increment=2000 comment = '鑿滃崟鏉冮檺琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鑿滃崟淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+-- 涓�绾ц彍鍗�
+insert into sys_menu values('1', '绯荤粺绠$悊', '0', '1', 'system',           null, '', '', 1, 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('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, '瑙掕壊绠$悊鑿滃崟');
+insert into sys_menu values('102',  '鑿滃崟绠$悊', '1',   '3', 'menu',       'system/menu/index',        '', '', 1, 0, 'C', '0', '0', 'system:menu:list',        'tree-table',    'admin', sysdate(), '', null, '鑿滃崟绠$悊鑿滃崟');
+insert into sys_menu values('103',  '閮ㄩ棬绠$悊', '1',   '4', 'dept',       'system/dept/index',        '', '', 1, 0, 'C', '0', '0', 'system:dept:list',        'tree',          'admin', sysdate(), '', null, '閮ㄩ棬绠$悊鑿滃崟');
+insert into sys_menu values('104',  '宀椾綅绠$悊', '1',   '5', 'post',       'system/post/index',        '', '', 1, 0, 'C', '0', '0', 'system:post:list',        'post',          'admin', sysdate(), '', null, '宀椾綅绠$悊鑿滃崟');
+insert into sys_menu values('105',  '瀛楀吀绠$悊', '1',   '6', 'dict',       'system/dict/index',        '', '', 1, 0, 'C', '0', '0', 'system:dict:list',        'dict',          'admin', sysdate(), '', null, '瀛楀吀绠$悊鑿滃崟');
+insert into sys_menu values('106',  '鍙傛暟璁剧疆', '1',   '7', 'config',     'system/config/index',      '', '', 1, 0, 'C', '0', '0', 'system:config:list',      'edit',          'admin', sysdate(), '', null, '鍙傛暟璁剧疆鑿滃崟');
+insert into sys_menu values('107',  '閫氱煡鍏憡', '1',   '8', 'notice',     'system/notice/index',      '', '', 1, 0, 'C', '0', '0', 'system:notice:list',      'message',       'admin', sysdate(), '', null, '閫氱煡鍏憡鑿滃崟');
+insert into sys_menu values('108',  '鏃ュ織绠$悊', '1',   '9', 'log',        '',                         '', '', 1, 0, 'M', '0', '0', '',                        'log',           'admin', sysdate(), '', null, '鏃ュ織绠$悊鑿滃崟');
+insert into sys_menu values('109',  '鍦ㄧ嚎鐢ㄦ埛', '2',   '1', 'online',     'monitor/online/index',     '', '', 1, 0, 'C', '0', '0', 'monitor:online:list',     'online',        'admin', sysdate(), '', null, '鍦ㄧ嚎鐢ㄦ埛鑿滃崟');
+insert into sys_menu values('110',  '瀹氭椂浠诲姟', '2',   '2', 'job',        'monitor/job/index',        '', '', 1, 0, 'C', '0', '0', 'monitor:job:list',        'job',           'admin', sysdate(), '', null, '瀹氭椂浠诲姟鑿滃崟');
+insert into sys_menu values('111',  '鏁版嵁鐩戞帶', '2',   '3', 'druid',      'monitor/druid/index',      '', '', 1, 0, 'C', '0', '0', 'monitor:druid:list',      'druid',         'admin', sysdate(), '', null, '鏁版嵁鐩戞帶鑿滃崟');
+insert into sys_menu values('112',  '鏈嶅姟鐩戞帶', '2',   '4', 'server',     'monitor/server/index',     '', '', 1, 0, 'C', '0', '0', 'monitor:server:list',     'server',        'admin', sysdate(), '', null, '鏈嶅姟鐩戞帶鑿滃崟');
+insert into sys_menu values('113',  '缂撳瓨鐩戞帶', '2',   '5', 'cache',      'monitor/cache/index',      '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list',      'redis',         'admin', sysdate(), '', null, '缂撳瓨鐩戞帶鑿滃崟');
+insert into sys_menu values('114',  '缂撳瓨鍒楄〃', '2',   '6', 'cacheList',  'monitor/cache/list',       '', '', 1, 0, 'C', '0', '0', 'monitor:cache:list',      'redis-list',    'admin', sysdate(), '', null, '缂撳瓨鍒楄〃鑿滃崟');
+insert into sys_menu values('115',  '琛ㄥ崟鏋勫缓', '3',   '1', 'build',      'tool/build/index',         '', '', 1, 0, 'C', '0', '0', 'tool:build:list',         'build',         'admin', sysdate(), '', null, '琛ㄥ崟鏋勫缓鑿滃崟');
+insert into sys_menu values('116',  '浠g爜鐢熸垚', '3',   '2', 'gen',        'tool/gen/index',           '', '', 1, 0, 'C', '0', '0', 'tool:gen:list',           'code',          'admin', sysdate(), '', null, '浠g爜鐢熸垚鑿滃崟');
+insert into sys_menu values('117',  '绯荤粺鎺ュ彛', '3',   '3', 'swagger',    'tool/swagger/index',       '', '', 1, 0, 'C', '0', '0', 'tool:swagger:list',       'swagger',       'admin', sysdate(), '', null, '绯荤粺鎺ュ彛鑿滃崟');
+-- 涓夌骇鑿滃崟
+insert into sys_menu values('500',  '鎿嶄綔鏃ュ織', '108', '1', 'operlog',    'monitor/operlog/index',    '', '', 1, 0, 'C', '0', '0', 'monitor:operlog:list',    'form',          'admin', sysdate(), '', null, '鎿嶄綔鏃ュ織鑿滃崟');
+insert into sys_menu values('501',  '鐧诲綍鏃ュ織', '108', '2', 'logininfor', 'monitor/logininfor/index', '', '', 1, 0, 'C', '0', '0', 'monitor:logininfor:list', 'logininfor',    'admin', sysdate(), '', null, '鐧诲綍鏃ュ織鑿滃崟');
+-- 鐢ㄦ埛绠$悊鎸夐挳
+insert into sys_menu values('1000', '鐢ㄦ埛鏌ヨ', '100', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1001', '鐢ㄦ埛鏂板', '100', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1002', '鐢ㄦ埛淇敼', '100', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1003', '鐢ㄦ埛鍒犻櫎', '100', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:remove',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1004', '鐢ㄦ埛瀵煎嚭', '100', '5',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:export',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1005', '鐢ㄦ埛瀵煎叆', '100', '6',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:import',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1006', '閲嶇疆瀵嗙爜', '100', '7',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:user:resetPwd',       '#', 'admin', sysdate(), '', null, '');
+-- 瑙掕壊绠$悊鎸夐挳
+insert into sys_menu values('1007', '瑙掕壊鏌ヨ', '101', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1008', '瑙掕壊鏂板', '101', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1009', '瑙掕壊淇敼', '101', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1010', '瑙掕壊鍒犻櫎', '101', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:remove',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1011', '瑙掕壊瀵煎嚭', '101', '5',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:role:export',         '#', 'admin', sysdate(), '', null, '');
+-- 鑿滃崟绠$悊鎸夐挳
+insert into sys_menu values('1012', '鑿滃崟鏌ヨ', '102', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1013', '鑿滃崟鏂板', '102', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1014', '鑿滃崟淇敼', '102', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1015', '鑿滃崟鍒犻櫎', '102', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:menu:remove',         '#', 'admin', sysdate(), '', null, '');
+-- 閮ㄩ棬绠$悊鎸夐挳
+insert into sys_menu values('1016', '閮ㄩ棬鏌ヨ', '103', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1017', '閮ㄩ棬鏂板', '103', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1018', '閮ㄩ棬淇敼', '103', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1019', '閮ㄩ棬鍒犻櫎', '103', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:dept:remove',         '#', 'admin', sysdate(), '', null, '');
+-- 宀椾綅绠$悊鎸夐挳
+insert into sys_menu values('1020', '宀椾綅鏌ヨ', '104', '1',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1021', '宀椾綅鏂板', '104', '2',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1022', '宀椾綅淇敼', '104', '3',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1023', '宀椾綅鍒犻櫎', '104', '4',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:remove',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1024', '宀椾綅瀵煎嚭', '104', '5',  '', '', '', '', 1, 0, 'F', '0', '0', 'system:post:export',         '#', 'admin', sysdate(), '', null, '');
+-- 瀛楀吀绠$悊鎸夐挳
+insert into sys_menu values('1025', '瀛楀吀鏌ヨ', '105', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1026', '瀛楀吀鏂板', '105', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1027', '瀛楀吀淇敼', '105', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1028', '瀛楀吀鍒犻櫎', '105', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:remove',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1029', '瀛楀吀瀵煎嚭', '105', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:dict:export',         '#', 'admin', sysdate(), '', null, '');
+-- 鍙傛暟璁剧疆鎸夐挳
+insert into sys_menu values('1030', '鍙傛暟鏌ヨ', '106', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:query',        '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1031', '鍙傛暟鏂板', '106', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:add',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1032', '鍙傛暟淇敼', '106', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:edit',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1033', '鍙傛暟鍒犻櫎', '106', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:remove',       '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1034', '鍙傛暟瀵煎嚭', '106', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:config:export',       '#', 'admin', sysdate(), '', null, '');
+-- 閫氱煡鍏憡鎸夐挳
+insert into sys_menu values('1035', '鍏憡鏌ヨ', '107', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:query',        '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1036', '鍏憡鏂板', '107', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:add',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1037', '鍏憡淇敼', '107', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:edit',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1038', '鍏憡鍒犻櫎', '107', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'system:notice:remove',       '#', 'admin', sysdate(), '', null, '');
+-- 鎿嶄綔鏃ュ織鎸夐挳
+insert into sys_menu values('1039', '鎿嶄綔鏌ヨ', '500', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:query',      '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1040', '鎿嶄綔鍒犻櫎', '500', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:remove',     '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1041', '鏃ュ織瀵煎嚭', '500', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:operlog:export',     '#', 'admin', sysdate(), '', null, '');
+-- 鐧诲綍鏃ュ織鎸夐挳
+insert into sys_menu values('1042', '鐧诲綍鏌ヨ', '501', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:query',   '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1043', '鐧诲綍鍒犻櫎', '501', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:remove',  '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1044', '鏃ュ織瀵煎嚭', '501', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:export',  '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1045', '璐︽埛瑙i攣', '501', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:logininfor:unlock',  '#', 'admin', sysdate(), '', null, '');
+-- 鍦ㄧ嚎鐢ㄦ埛鎸夐挳
+insert into sys_menu values('1046', '鍦ㄧ嚎鏌ヨ', '109', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:query',       '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1047', '鎵归噺寮洪��', '109', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:batchLogout', '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1048', '鍗曟潯寮洪��', '109', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:online:forceLogout', '#', 'admin', sysdate(), '', null, '');
+-- 瀹氭椂浠诲姟鎸夐挳
+insert into sys_menu values('1049', '浠诲姟鏌ヨ', '110', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:query',          '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1050', '浠诲姟鏂板', '110', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:add',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1051', '浠诲姟淇敼', '110', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:edit',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1052', '浠诲姟鍒犻櫎', '110', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:remove',         '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1053', '鐘舵�佷慨鏀�', '110', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:changeStatus',   '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1054', '浠诲姟瀵煎嚭', '110', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'monitor:job:export',         '#', 'admin', sysdate(), '', null, '');
+-- 浠g爜鐢熸垚鎸夐挳
+insert into sys_menu values('1055', '鐢熸垚鏌ヨ', '116', '1', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:query',             '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1056', '鐢熸垚淇敼', '116', '2', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:edit',              '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1057', '鐢熸垚鍒犻櫎', '116', '3', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:remove',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1058', '瀵煎叆浠g爜', '116', '4', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:import',            '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1059', '棰勮浠g爜', '116', '5', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:preview',           '#', 'admin', sysdate(), '', null, '');
+insert into sys_menu values('1060', '鐢熸垚浠g爜', '116', '6', '#', '', '', '', 1, 0, 'F', '0', '0', 'tool:gen:code',              '#', 'admin', sysdate(), '', null, '');
+
+
+-- ----------------------------
+-- 6銆佺敤鎴峰拰瑙掕壊鍏宠仈琛�  鐢ㄦ埛N-1瑙掕壊
+-- ----------------------------
+drop table if exists sys_user_role;
+create table sys_user_role (
+  user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  primary key(user_id, role_id)
+) engine=innodb comment = '鐢ㄦ埛鍜岃鑹插叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛鍜岃鑹插叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_role values ('1', '1');
+insert into sys_user_role values ('2', '2');
+
+
+-- ----------------------------
+-- 7銆佽鑹插拰鑿滃崟鍏宠仈琛�  瑙掕壊1-N鑿滃崟
+-- ----------------------------
+drop table if exists sys_role_menu;
+create table sys_role_menu (
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  menu_id   bigint(20) not null comment '鑿滃崟ID',
+  primary key(role_id, menu_id)
+) engine=innodb comment = '瑙掕壊鍜岃彍鍗曞叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岃彍鍗曞叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_menu values ('2', '1');
+insert into sys_role_menu values ('2', '2');
+insert into sys_role_menu values ('2', '3');
+insert into sys_role_menu values ('2', '4');
+insert into sys_role_menu values ('2', '100');
+insert into sys_role_menu values ('2', '101');
+insert into sys_role_menu values ('2', '102');
+insert into sys_role_menu values ('2', '103');
+insert into sys_role_menu values ('2', '104');
+insert into sys_role_menu values ('2', '105');
+insert into sys_role_menu values ('2', '106');
+insert into sys_role_menu values ('2', '107');
+insert into sys_role_menu values ('2', '108');
+insert into sys_role_menu values ('2', '109');
+insert into sys_role_menu values ('2', '110');
+insert into sys_role_menu values ('2', '111');
+insert into sys_role_menu values ('2', '112');
+insert into sys_role_menu values ('2', '113');
+insert into sys_role_menu values ('2', '114');
+insert into sys_role_menu values ('2', '115');
+insert into sys_role_menu values ('2', '116');
+insert into sys_role_menu values ('2', '117');
+insert into sys_role_menu values ('2', '500');
+insert into sys_role_menu values ('2', '501');
+insert into sys_role_menu values ('2', '1000');
+insert into sys_role_menu values ('2', '1001');
+insert into sys_role_menu values ('2', '1002');
+insert into sys_role_menu values ('2', '1003');
+insert into sys_role_menu values ('2', '1004');
+insert into sys_role_menu values ('2', '1005');
+insert into sys_role_menu values ('2', '1006');
+insert into sys_role_menu values ('2', '1007');
+insert into sys_role_menu values ('2', '1008');
+insert into sys_role_menu values ('2', '1009');
+insert into sys_role_menu values ('2', '1010');
+insert into sys_role_menu values ('2', '1011');
+insert into sys_role_menu values ('2', '1012');
+insert into sys_role_menu values ('2', '1013');
+insert into sys_role_menu values ('2', '1014');
+insert into sys_role_menu values ('2', '1015');
+insert into sys_role_menu values ('2', '1016');
+insert into sys_role_menu values ('2', '1017');
+insert into sys_role_menu values ('2', '1018');
+insert into sys_role_menu values ('2', '1019');
+insert into sys_role_menu values ('2', '1020');
+insert into sys_role_menu values ('2', '1021');
+insert into sys_role_menu values ('2', '1022');
+insert into sys_role_menu values ('2', '1023');
+insert into sys_role_menu values ('2', '1024');
+insert into sys_role_menu values ('2', '1025');
+insert into sys_role_menu values ('2', '1026');
+insert into sys_role_menu values ('2', '1027');
+insert into sys_role_menu values ('2', '1028');
+insert into sys_role_menu values ('2', '1029');
+insert into sys_role_menu values ('2', '1030');
+insert into sys_role_menu values ('2', '1031');
+insert into sys_role_menu values ('2', '1032');
+insert into sys_role_menu values ('2', '1033');
+insert into sys_role_menu values ('2', '1034');
+insert into sys_role_menu values ('2', '1035');
+insert into sys_role_menu values ('2', '1036');
+insert into sys_role_menu values ('2', '1037');
+insert into sys_role_menu values ('2', '1038');
+insert into sys_role_menu values ('2', '1039');
+insert into sys_role_menu values ('2', '1040');
+insert into sys_role_menu values ('2', '1041');
+insert into sys_role_menu values ('2', '1042');
+insert into sys_role_menu values ('2', '1043');
+insert into sys_role_menu values ('2', '1044');
+insert into sys_role_menu values ('2', '1045');
+insert into sys_role_menu values ('2', '1046');
+insert into sys_role_menu values ('2', '1047');
+insert into sys_role_menu values ('2', '1048');
+insert into sys_role_menu values ('2', '1049');
+insert into sys_role_menu values ('2', '1050');
+insert into sys_role_menu values ('2', '1051');
+insert into sys_role_menu values ('2', '1052');
+insert into sys_role_menu values ('2', '1053');
+insert into sys_role_menu values ('2', '1054');
+insert into sys_role_menu values ('2', '1055');
+insert into sys_role_menu values ('2', '1056');
+insert into sys_role_menu values ('2', '1057');
+insert into sys_role_menu values ('2', '1058');
+insert into sys_role_menu values ('2', '1059');
+insert into sys_role_menu values ('2', '1060');
+
+-- ----------------------------
+-- 8銆佽鑹插拰閮ㄩ棬鍏宠仈琛�  瑙掕壊1-N閮ㄩ棬
+-- ----------------------------
+drop table if exists sys_role_dept;
+create table sys_role_dept (
+  role_id   bigint(20) not null comment '瑙掕壊ID',
+  dept_id   bigint(20) not null comment '閮ㄩ棬ID',
+  primary key(role_id, dept_id)
+) engine=innodb comment = '瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-瑙掕壊鍜岄儴闂ㄥ叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_role_dept values ('2', '100');
+insert into sys_role_dept values ('2', '101');
+insert into sys_role_dept values ('2', '105');
+
+
+-- ----------------------------
+-- 9銆佺敤鎴蜂笌宀椾綅鍏宠仈琛�  鐢ㄦ埛1-N宀椾綅
+-- ----------------------------
+drop table if exists sys_user_post;
+create table sys_user_post
+(
+  user_id   bigint(20) not null comment '鐢ㄦ埛ID',
+  post_id   bigint(20) not null comment '宀椾綅ID',
+  primary key (user_id, post_id)
+) engine=innodb comment = '鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃';
+
+-- ----------------------------
+-- 鍒濆鍖�-鐢ㄦ埛涓庡矖浣嶅叧鑱旇〃鏁版嵁
+-- ----------------------------
+insert into sys_user_post values ('1', '1');
+insert into sys_user_post values ('2', '2');
+
+
+-- ----------------------------
+-- 10銆佹搷浣滄棩蹇楄褰�
+-- ----------------------------
+drop table if exists sys_oper_log;
+create table sys_oper_log (
+  oper_id           bigint(20)      not null auto_increment    comment '鏃ュ織涓婚敭',
+  title             varchar(50)     default ''                 comment '妯″潡鏍囬',
+  business_type     int(2)          default 0                  comment '涓氬姟绫诲瀷锛�0鍏跺畠 1鏂板 2淇敼 3鍒犻櫎锛�',
+  method            varchar(200)    default ''                 comment '鏂规硶鍚嶇О',
+  request_method    varchar(10)     default ''                 comment '璇锋眰鏂瑰紡',
+  operator_type     int(1)          default 0                  comment '鎿嶄綔绫诲埆锛�0鍏跺畠 1鍚庡彴鐢ㄦ埛 2鎵嬫満绔敤鎴凤級',
+  oper_name         varchar(50)     default ''                 comment '鎿嶄綔浜哄憳',
+  dept_name         varchar(50)     default ''                 comment '閮ㄩ棬鍚嶇О',
+  oper_url          varchar(255)    default ''                 comment '璇锋眰URL',
+  oper_ip           varchar(128)    default ''                 comment '涓绘満鍦板潃',
+  oper_location     varchar(255)    default ''                 comment '鎿嶄綔鍦扮偣',
+  oper_param        varchar(2000)   default ''                 comment '璇锋眰鍙傛暟',
+  json_result       varchar(2000)   default ''                 comment '杩斿洖鍙傛暟',
+  status            int(1)          default 0                  comment '鎿嶄綔鐘舵�侊紙0姝e父 1寮傚父锛�',
+  error_msg         varchar(2000)   default ''                 comment '閿欒娑堟伅',
+  oper_time         datetime                                   comment '鎿嶄綔鏃堕棿',
+  cost_time         bigint(20)      default 0                  comment '娑堣�楁椂闂�',
+  primary key (oper_id),
+  key idx_sys_oper_log_bt (business_type),
+  key idx_sys_oper_log_s  (status),
+  key idx_sys_oper_log_ot (oper_time)
+) engine=innodb auto_increment=100 comment = '鎿嶄綔鏃ュ織璁板綍';
+
+
+-- ----------------------------
+-- 11銆佸瓧鍏哥被鍨嬭〃
+-- ----------------------------
+drop table if exists sys_dict_type;
+create table sys_dict_type
+(
+  dict_id          bigint(20)      not null auto_increment    comment '瀛楀吀涓婚敭',
+  dict_name        varchar(100)    default ''                 comment '瀛楀吀鍚嶇О',
+  dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+  status           char(1)         default '0'                comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by        varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by        varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time      datetime                                   comment '鏇存柊鏃堕棿',
+  remark           varchar(500)    default null               comment '澶囨敞',
+  primary key (dict_id),
+  unique (dict_type)
+) engine=innodb auto_increment=100 comment = '瀛楀吀绫诲瀷琛�';
+
+insert into sys_dict_type values(1,  '鐢ㄦ埛鎬у埆', 'sys_user_sex',        '0', 'admin', sysdate(), '', null, '鐢ㄦ埛鎬у埆鍒楄〃');
+insert into sys_dict_type values(2,  '鑿滃崟鐘舵��', 'sys_show_hide',       '0', 'admin', sysdate(), '', null, '鑿滃崟鐘舵�佸垪琛�');
+insert into sys_dict_type values(3,  '绯荤粺寮�鍏�', 'sys_normal_disable',  '0', 'admin', sysdate(), '', null, '绯荤粺寮�鍏冲垪琛�');
+insert into sys_dict_type values(4,  '浠诲姟鐘舵��', 'sys_job_status',      '0', 'admin', sysdate(), '', null, '浠诲姟鐘舵�佸垪琛�');
+insert into sys_dict_type values(5,  '浠诲姟鍒嗙粍', 'sys_job_group',       '0', 'admin', sysdate(), '', null, '浠诲姟鍒嗙粍鍒楄〃');
+insert into sys_dict_type values(6,  '绯荤粺鏄惁', 'sys_yes_no',          '0', 'admin', sysdate(), '', null, '绯荤粺鏄惁鍒楄〃');
+insert into sys_dict_type values(7,  '閫氱煡绫诲瀷', 'sys_notice_type',     '0', 'admin', sysdate(), '', null, '閫氱煡绫诲瀷鍒楄〃');
+insert into sys_dict_type values(8,  '閫氱煡鐘舵��', 'sys_notice_status',   '0', 'admin', sysdate(), '', null, '閫氱煡鐘舵�佸垪琛�');
+insert into sys_dict_type values(9,  '鎿嶄綔绫诲瀷', 'sys_oper_type',       '0', 'admin', sysdate(), '', null, '鎿嶄綔绫诲瀷鍒楄〃');
+insert into sys_dict_type values(10, '绯荤粺鐘舵��', 'sys_common_status',   '0', 'admin', sysdate(), '', null, '鐧诲綍鐘舵�佸垪琛�');
+
+
+-- ----------------------------
+-- 12銆佸瓧鍏告暟鎹〃
+-- ----------------------------
+drop table if exists sys_dict_data;
+create table sys_dict_data
+(
+  dict_code        bigint(20)      not null auto_increment    comment '瀛楀吀缂栫爜',
+  dict_sort        int(4)          default 0                  comment '瀛楀吀鎺掑簭',
+  dict_label       varchar(100)    default ''                 comment '瀛楀吀鏍囩',
+  dict_value       varchar(100)    default ''                 comment '瀛楀吀閿��',
+  dict_type        varchar(100)    default ''                 comment '瀛楀吀绫诲瀷',
+  css_class        varchar(100)    default null               comment '鏍峰紡灞炴�э紙鍏朵粬鏍峰紡鎵╁睍锛�',
+  list_class       varchar(100)    default null               comment '琛ㄦ牸鍥炴樉鏍峰紡',
+  is_default       char(1)         default 'N'                comment '鏄惁榛樿锛圷鏄� N鍚︼級',
+  status           char(1)         default '0'                comment '鐘舵�侊紙0姝e父 1鍋滅敤锛�',
+  create_by        varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time      datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by        varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time      datetime                                   comment '鏇存柊鏃堕棿',
+  remark           varchar(500)    default null               comment '澶囨敞',
+  primary key (dict_code)
+) engine=innodb auto_increment=100 comment = '瀛楀吀鏁版嵁琛�';
+
+insert into sys_dict_data values(1,  1,  '鐢�',       '0',       'sys_user_sex',        '',   '',        'Y', '0', 'admin', sysdate(), '', null, '鎬у埆鐢�');
+insert into sys_dict_data values(2,  2,  '濂�',       '1',       'sys_user_sex',        '',   '',        'N', '0', 'admin', sysdate(), '', null, '鎬у埆濂�');
+insert into sys_dict_data values(3,  3,  '鏈煡',     '2',       'sys_user_sex',        '',   '',        'N', '0', 'admin', sysdate(), '', null, '鎬у埆鏈煡');
+insert into sys_dict_data values(4,  1,  '鏄剧ず',     '0',       'sys_show_hide',       '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '鏄剧ず鑿滃崟');
+insert into sys_dict_data values(5,  2,  '闅愯棌',     '1',       'sys_show_hide',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '闅愯棌鑿滃崟');
+insert into sys_dict_data values(6,  1,  '姝e父',     '0',       'sys_normal_disable',  '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '姝e父鐘舵��');
+insert into sys_dict_data values(7,  2,  '鍋滅敤',     '1',       'sys_normal_disable',  '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(8,  1,  '姝e父',     '0',       'sys_job_status',      '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '姝e父鐘舵��');
+insert into sys_dict_data values(9,  2,  '鏆傚仠',     '1',       'sys_job_status',      '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '鍋滅敤鐘舵��');
+insert into sys_dict_data values(10, 1,  '榛樿',     'DEFAULT', 'sys_job_group',       '',   '',        'Y', '0', 'admin', sysdate(), '', null, '榛樿鍒嗙粍');
+insert into sys_dict_data values(11, 2,  '绯荤粺',     'SYSTEM',  'sys_job_group',       '',   '',        'N', '0', 'admin', sysdate(), '', null, '绯荤粺鍒嗙粍');
+insert into sys_dict_data values(12, 1,  '鏄�',       'Y',       'sys_yes_no',          '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '绯荤粺榛樿鏄�');
+insert into sys_dict_data values(13, 2,  '鍚�',       'N',       'sys_yes_no',          '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '绯荤粺榛樿鍚�');
+insert into sys_dict_data values(14, 1,  '閫氱煡',     '1',       'sys_notice_type',     '',   'warning', 'Y', '0', 'admin', sysdate(), '', null, '閫氱煡');
+insert into sys_dict_data values(15, 2,  '鍏憡',     '2',       'sys_notice_type',     '',   'success', 'N', '0', 'admin', sysdate(), '', null, '鍏憡');
+insert into sys_dict_data values(16, 1,  '姝e父',     '0',       'sys_notice_status',   '',   'primary', 'Y', '0', 'admin', sysdate(), '', null, '姝e父鐘舵��');
+insert into sys_dict_data values(17, 2,  '鍏抽棴',     '1',       'sys_notice_status',   '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '鍏抽棴鐘舵��');
+insert into sys_dict_data values(18, 99, '鍏朵粬',     '0',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '鍏朵粬鎿嶄綔');
+insert into sys_dict_data values(19, 1,  '鏂板',     '1',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '鏂板鎿嶄綔');
+insert into sys_dict_data values(20, 2,  '淇敼',     '2',       'sys_oper_type',       '',   'info',    'N', '0', 'admin', sysdate(), '', null, '淇敼鎿嶄綔');
+insert into sys_dict_data values(21, 3,  '鍒犻櫎',     '3',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '鍒犻櫎鎿嶄綔');
+insert into sys_dict_data values(22, 4,  '鎺堟潈',     '4',       'sys_oper_type',       '',   'primary', 'N', '0', 'admin', sysdate(), '', null, '鎺堟潈鎿嶄綔');
+insert into sys_dict_data values(23, 5,  '瀵煎嚭',     '5',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '瀵煎嚭鎿嶄綔');
+insert into sys_dict_data values(24, 6,  '瀵煎叆',     '6',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '瀵煎叆鎿嶄綔');
+insert into sys_dict_data values(25, 7,  '寮洪��',     '7',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '寮洪��鎿嶄綔');
+insert into sys_dict_data values(26, 8,  '鐢熸垚浠g爜', '8',       'sys_oper_type',       '',   'warning', 'N', '0', 'admin', sysdate(), '', null, '鐢熸垚鎿嶄綔');
+insert into sys_dict_data values(27, 9,  '娓呯┖鏁版嵁', '9',       'sys_oper_type',       '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '娓呯┖鎿嶄綔');
+insert into sys_dict_data values(28, 1,  '鎴愬姛',     '0',       'sys_common_status',   '',   'primary', 'N', '0', 'admin', sysdate(), '', null, '姝e父鐘舵��');
+insert into sys_dict_data values(29, 2,  '澶辫触',     '1',       'sys_common_status',   '',   'danger',  'N', '0', 'admin', sysdate(), '', null, '鍋滅敤鐘舵��');
+
+
+-- ----------------------------
+-- 13銆佸弬鏁伴厤缃〃
+-- ----------------------------
+drop table if exists sys_config;
+create table sys_config (
+  config_id         int(5)          not null auto_increment    comment '鍙傛暟涓婚敭',
+  config_name       varchar(100)    default ''                 comment '鍙傛暟鍚嶇О',
+  config_key        varchar(100)    default ''                 comment '鍙傛暟閿悕',
+  config_value      varchar(500)    default ''                 comment '鍙傛暟閿��',
+  config_type       char(1)         default 'N'                comment '绯荤粺鍐呯疆锛圷鏄� N鍚︼級',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (config_id)
+) engine=innodb auto_increment=100 comment = '鍙傛暟閰嶇疆琛�';
+
+insert into sys_config values(1, '涓绘鏋堕〉-榛樿鐨偆鏍峰紡鍚嶇О',     'sys.index.skinName',            'skin-blue',     'Y', 'admin', sysdate(), '', null, '钃濊壊 skin-blue銆佺豢鑹� skin-green銆佺传鑹� skin-purple銆佺孩鑹� skin-red銆侀粍鑹� skin-yellow' );
+insert into sys_config values(2, '鐢ㄦ埛绠$悊-璐﹀彿鍒濆瀵嗙爜',         'sys.user.initPassword',         '123456',        'Y', 'admin', sysdate(), '', null, '鍒濆鍖栧瘑鐮� 123456' );
+insert into sys_config values(3, '涓绘鏋堕〉-渚ц竟鏍忎富棰�',           'sys.index.sideTheme',           'theme-dark',    'Y', 'admin', sysdate(), '', null, '娣辫壊涓婚theme-dark锛屾祬鑹蹭富棰榯heme-light' );
+insert into sys_config values(4, '璐﹀彿鑷姪-楠岃瘉鐮佸紑鍏�',           'sys.account.captchaEnabled',    'true',          'Y', 'admin', sysdate(), '', null, '鏄惁寮�鍚獙璇佺爜鍔熻兘锛坱rue寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(5, '璐﹀彿鑷姪-鏄惁寮�鍚敤鎴锋敞鍐屽姛鑳�', 'sys.account.registerUser',      'false',         'Y', 'admin', sysdate(), '', null, '鏄惁寮�鍚敞鍐岀敤鎴峰姛鑳斤紙true寮�鍚紝false鍏抽棴锛�');
+insert into sys_config values(6, '鐢ㄦ埛鐧诲綍-榛戝悕鍗曞垪琛�',           'sys.login.blackIPList',         '',              'Y', 'admin', sysdate(), '', null, '璁剧疆鐧诲綍IP榛戝悕鍗曢檺鍒讹紝澶氫釜鍖归厤椤逛互;鍒嗛殧锛屾敮鎸佸尮閰嶏紙*閫氶厤銆佺綉娈碉級');
+
+
+-- ----------------------------
+-- 14銆佺郴缁熻闂褰�
+-- ----------------------------
+drop table if exists sys_logininfor;
+create table sys_logininfor (
+  info_id        bigint(20)     not null auto_increment   comment '璁块棶ID',
+  user_name      varchar(50)    default ''                comment '鐢ㄦ埛璐﹀彿',
+  ipaddr         varchar(128)   default ''                comment '鐧诲綍IP鍦板潃',
+  login_location varchar(255)   default ''                comment '鐧诲綍鍦扮偣',
+  browser        varchar(50)    default ''                comment '娴忚鍣ㄧ被鍨�',
+  os             varchar(50)    default ''                comment '鎿嶄綔绯荤粺',
+  status         char(1)        default '0'               comment '鐧诲綍鐘舵�侊紙0鎴愬姛 1澶辫触锛�',
+  msg            varchar(255)   default ''                comment '鎻愮ず娑堟伅',
+  login_time     datetime                                 comment '璁块棶鏃堕棿',
+  primary key (info_id),
+  key idx_sys_logininfor_s  (status),
+  key idx_sys_logininfor_lt (login_time)
+) engine=innodb auto_increment=100 comment = '绯荤粺璁块棶璁板綍';
+
+
+-- ----------------------------
+-- 15銆佸畾鏃朵换鍔¤皟搴﹁〃
+-- ----------------------------
+drop table if exists sys_job;
+create table sys_job (
+  job_id              bigint(20)    not null auto_increment    comment '浠诲姟ID',
+  job_name            varchar(64)   default ''                 comment '浠诲姟鍚嶇О',
+  job_group           varchar(64)   default 'DEFAULT'          comment '浠诲姟缁勫悕',
+  invoke_target       varchar(500)  not null                   comment '璋冪敤鐩爣瀛楃涓�',
+  cron_expression     varchar(255)  default ''                 comment 'cron鎵ц琛ㄨ揪寮�',
+  misfire_policy      varchar(20)   default '3'                comment '璁″垝鎵ц閿欒绛栫暐锛�1绔嬪嵆鎵ц 2鎵ц涓�娆� 3鏀惧純鎵ц锛�',
+  concurrent          char(1)       default '1'                comment '鏄惁骞跺彂鎵ц锛�0鍏佽 1绂佹锛�',
+  status              char(1)       default '0'                comment '鐘舵�侊紙0姝e父 1鏆傚仠锛�',
+  create_by           varchar(64)   default ''                 comment '鍒涘缓鑰�',
+  create_time         datetime                                 comment '鍒涘缓鏃堕棿',
+  update_by           varchar(64)   default ''                 comment '鏇存柊鑰�',
+  update_time         datetime                                 comment '鏇存柊鏃堕棿',
+  remark              varchar(500)  default ''                 comment '澶囨敞淇℃伅',
+  primary key (job_id, job_name, job_group)
+) engine=innodb auto_increment=100 comment = '瀹氭椂浠诲姟璋冨害琛�';
+
+insert into sys_job values(1, '绯荤粺榛樿锛堟棤鍙傦級', 'DEFAULT', 'ryTask.ryNoParams',        '0/10 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
+insert into sys_job values(2, '绯荤粺榛樿锛堟湁鍙傦級', 'DEFAULT', 'ryTask.ryParams(\'ry\')',  '0/15 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
+insert into sys_job values(3, '绯荤粺榛樿锛堝鍙傦級', 'DEFAULT', 'ryTask.ryMultipleParams(\'ry\', true, 2000L, 316.50D, 100)',  '0/20 * * * * ?', '3', '1', '1', 'admin', sysdate(), '', null, '');
+
+
+-- ----------------------------
+-- 16銆佸畾鏃朵换鍔¤皟搴︽棩蹇楄〃
+-- ----------------------------
+drop table if exists sys_job_log;
+create table sys_job_log (
+  job_log_id          bigint(20)     not null auto_increment    comment '浠诲姟鏃ュ織ID',
+  job_name            varchar(64)    not null                   comment '浠诲姟鍚嶇О',
+  job_group           varchar(64)    not null                   comment '浠诲姟缁勫悕',
+  invoke_target       varchar(500)   not null                   comment '璋冪敤鐩爣瀛楃涓�',
+  job_message         varchar(500)                              comment '鏃ュ織淇℃伅',
+  status              char(1)        default '0'                comment '鎵ц鐘舵�侊紙0姝e父 1澶辫触锛�',
+  exception_info      varchar(2000)  default ''                 comment '寮傚父淇℃伅',
+  create_time         datetime                                  comment '鍒涘缓鏃堕棿',
+  primary key (job_log_id)
+) engine=innodb comment = '瀹氭椂浠诲姟璋冨害鏃ュ織琛�';
+
+
+-- ----------------------------
+-- 17銆侀�氱煡鍏憡琛�
+-- ----------------------------
+drop table if exists sys_notice;
+create table sys_notice (
+  notice_id         int(4)          not null auto_increment    comment '鍏憡ID',
+  notice_title      varchar(50)     not null                   comment '鍏憡鏍囬',
+  notice_type       char(1)         not null                   comment '鍏憡绫诲瀷锛�1閫氱煡 2鍏憡锛�',
+  notice_content    longblob        default null               comment '鍏憡鍐呭',
+  status            char(1)         default '0'                comment '鍏憡鐘舵�侊紙0姝e父 1鍏抽棴锛�',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time       datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(255)    default null               comment '澶囨敞',
+  primary key (notice_id)
+) engine=innodb auto_increment=10 comment = '閫氱煡鍏憡琛�';
+
+-- ----------------------------
+-- 鍒濆鍖�-鍏憡淇℃伅琛ㄦ暟鎹�
+-- ----------------------------
+insert into sys_notice values('1', '娓╅Θ鎻愰啋锛�2018-07-01 鑻ヤ緷鏂扮増鏈彂甯冨暒', '2', '鏂扮増鏈唴瀹�', '0', 'admin', sysdate(), '', null, '绠$悊鍛�');
+insert into sys_notice values('2', '缁存姢閫氱煡锛�2018-07-01 鑻ヤ緷绯荤粺鍑屾櫒缁存姢', '1', '缁存姢鍐呭',   '0', 'admin', sysdate(), '', null, '绠$悊鍛�');
+
+
+-- ----------------------------
+-- 18銆佷唬鐮佺敓鎴愪笟鍔¤〃
+-- ----------------------------
+drop table if exists gen_table;
+create table gen_table (
+  table_id          bigint(20)      not null auto_increment    comment '缂栧彿',
+  table_name        varchar(200)    default ''                 comment '琛ㄥ悕绉�',
+  table_comment     varchar(500)    default ''                 comment '琛ㄦ弿杩�',
+  sub_table_name    varchar(64)     default null               comment '鍏宠仈瀛愯〃鐨勮〃鍚�',
+  sub_table_fk_name varchar(64)     default null               comment '瀛愯〃鍏宠仈鐨勫閿悕',
+  class_name        varchar(100)    default ''                 comment '瀹炰綋绫诲悕绉�',
+  tpl_category      varchar(200)    default 'crud'             comment '浣跨敤鐨勬ā鏉匡紙crud鍗曡〃鎿嶄綔 tree鏍戣〃鎿嶄綔锛�',
+  tpl_web_type      varchar(30)     default ''                 comment '鍓嶇妯℃澘绫诲瀷锛坋lement-ui妯$増 element-plus妯$増锛�',
+  package_name      varchar(100)                               comment '鐢熸垚鍖呰矾寰�',
+  module_name       varchar(30)                                comment '鐢熸垚妯″潡鍚�',
+  business_name     varchar(30)                                comment '鐢熸垚涓氬姟鍚�',
+  function_name     varchar(50)                                comment '鐢熸垚鍔熻兘鍚�',
+  function_author   varchar(50)                                comment '鐢熸垚鍔熻兘浣滆��',
+  gen_type          char(1)         default '0'                comment '鐢熸垚浠g爜鏂瑰紡锛�0zip鍘嬬缉鍖� 1鑷畾涔夎矾寰勶級',
+  gen_path          varchar(200)    default '/'                comment '鐢熸垚璺緞锛堜笉濉粯璁ら」鐩矾寰勶級',
+  options           varchar(1000)                              comment '鍏跺畠鐢熸垚閫夐」',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  remark            varchar(500)    default null               comment '澶囨敞',
+  primary key (table_id)
+) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛�';
+
+
+-- ----------------------------
+-- 19銆佷唬鐮佺敓鎴愪笟鍔¤〃瀛楁
+-- ----------------------------
+drop table if exists gen_table_column;
+create table gen_table_column (
+  column_id         bigint(20)      not null auto_increment    comment '缂栧彿',
+  table_id          bigint(20)                                 comment '褰掑睘琛ㄧ紪鍙�',
+  column_name       varchar(200)                               comment '鍒楀悕绉�',
+  column_comment    varchar(500)                               comment '鍒楁弿杩�',
+  column_type       varchar(100)                               comment '鍒楃被鍨�',
+  java_type         varchar(500)                               comment 'JAVA绫诲瀷',
+  java_field        varchar(200)                               comment 'JAVA瀛楁鍚�',
+  is_pk             char(1)                                    comment '鏄惁涓婚敭锛�1鏄級',
+  is_increment      char(1)                                    comment '鏄惁鑷锛�1鏄級',
+  is_required       char(1)                                    comment '鏄惁蹇呭~锛�1鏄級',
+  is_insert         char(1)                                    comment '鏄惁涓烘彃鍏ュ瓧娈碉紙1鏄級',
+  is_edit           char(1)                                    comment '鏄惁缂栬緫瀛楁锛�1鏄級',
+  is_list           char(1)                                    comment '鏄惁鍒楄〃瀛楁锛�1鏄級',
+  is_query          char(1)                                    comment '鏄惁鏌ヨ瀛楁锛�1鏄級',
+  query_type        varchar(200)    default 'EQ'               comment '鏌ヨ鏂瑰紡锛堢瓑浜庛�佷笉绛変簬銆佸ぇ浜庛�佸皬浜庛�佽寖鍥达級',
+  html_type         varchar(200)                               comment '鏄剧ず绫诲瀷锛堟枃鏈銆佹枃鏈煙銆佷笅鎷夋銆佸閫夋銆佸崟閫夋銆佹棩鏈熸帶浠讹級',
+  dict_type         varchar(200)    default ''                 comment '瀛楀吀绫诲瀷',
+  sort              int                                        comment '鎺掑簭',
+  create_by         varchar(64)     default ''                 comment '鍒涘缓鑰�',
+  create_time 	    datetime                                   comment '鍒涘缓鏃堕棿',
+  update_by         varchar(64)     default ''                 comment '鏇存柊鑰�',
+  update_time       datetime                                   comment '鏇存柊鏃堕棿',
+  primary key (column_id)
+) engine=innodb auto_increment=1 comment = '浠g爜鐢熸垚涓氬姟琛ㄥ瓧娈�';
\ No newline at end of file
diff --git a/ts.txt b/ts.txt
new file mode 100644
index 0000000..0534403
--- /dev/null
+++ b/ts.txt
@@ -0,0 +1,29 @@
+select count(*) from DP_EQUIPMENT where EQUIPMENT_TYPE_ID = 3;
+select id, equ_name from DP_EQUIPMENT where EQUIPMENT_TYPE_ID = 3;
+
+select a.*,b.HARBOR_NAME as whName ,b.pkId as whId,c.NAME as beName,c.pkId as beId,
+        d.ID as equipmentTypeId,d.TYPE_NAME as equtype,d.DESCRIPTION as description,d.FILE_PATH as filepath,d.ICON as icon,
+        b.HARBOR_NAME as whName, c.NAME as beName from DP_EQUIPMENT a
+        left join DM_BERTH c on c.pkId = a.BE_ID
+        left join dm_harbor b on c.HARBOR_ID = b.pkId
+        left join DP_EQUIPMENT_TYPE d on d.ID = a.EQUIPMENT_TYPE_ID
+        where d.TYPE_NAME='鏅鸿兘鐢佃〃'
+        order by a.id
+
+select id, equ_name from DP_EQUIPMENT where EQUIPMENT_TYPE_ID = 3 limit 1;
+
+select * from DP_EQUIPMENT where id in (394, 395, 105);
+select * from SYSDBA.RECEIVE_MODULE_INFO order by id desc;
+select * from SYSDBA.RECEIVE_OIL_INFO where DEVICE_NAME in ('394','105');
+
+鐢靛帇鍛婅
+ryTask.dbGaoJing(370,450,211,250)
+* 0/15 * * * ?
+-----------------------------------------------------------
+code=500锛宨d=101 涓嶅瓨鍦�
+getYdkfm锛歴tatus=true 寮�鍚紝    status=false 鍏抽棴锛宻tatus=null && error!=null 鍑洪敊
+
+code=500锛宨d=101 涓嶅瓨鍦�
+ctrlYdkfm锛歴tatus=true 鎿嶄綔鎴愬姛锛宻tatus=null && error!=null 鍑洪敊
+-----------------------------------------------------------
+

--
Gitblit v1.9.3