lipenghui 4 mesiacov pred
commit
30cfb05858
100 zmenil súbory, kde vykonal 10879 pridanie a 0 odobranie
  1. 47 0
      .gitignore
  2. 20 0
      LICENSE
  3. 97 0
      README.md
  4. 12 0
      bin/clean.bat
  5. 86 0
      bin/clear-data.sql
  6. 12 0
      bin/package.bat
  7. 14 0
      bin/run.bat
  8. 788 0
      pom.xml
  9. 256 0
      yanfan-admin/pom.xml
  10. 20 0
      yanfan-admin/src/main/java/com/yanfan/YanfanApplication.java
  11. 16 0
      yanfan-admin/src/main/java/com/yanfan/YanfanServletInitializer.java
  12. 91 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/common/CaptchaController.java
  13. 148 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/common/CommonController.java
  14. 113 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/CacheController.java
  15. 29 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/ServerController.java
  16. 80 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysLogininforController.java
  17. 67 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysOperlogController.java
  18. 80 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysUserOnlineController.java
  19. 100 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysClientController.java
  20. 128 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysConfigController.java
  21. 275 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDeptController.java
  22. 106 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDictDataController.java
  23. 128 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDictTypeController.java
  24. 30 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysIndexController.java
  25. 105 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysLoginController.java
  26. 150 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysMenuController.java
  27. 87 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysNoticeController.java
  28. 122 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysPostController.java
  29. 149 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysProfileController.java
  30. 97 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysRegisterController.java
  31. 274 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysRoleController.java
  32. 78 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysTranslateController.java
  33. 281 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysUserController.java
  34. 22 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/tool/SwaggerController.java
  35. 217 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/tool/TestController2.java
  36. 116 0
      yanfan-admin/src/main/java/com/yanfan/web/controller/tool/TestUserController.java
  37. 120 0
      yanfan-admin/src/main/java/com/yanfan/web/core/config/SwaggerConfig.java
  38. 1 0
      yanfan-admin/src/main/resources/META-INF/spring-devtools.properties
  39. 195 0
      yanfan-admin/src/main/resources/application-dev.yml
  40. 160 0
      yanfan-admin/src/main/resources/application-local.yml
  41. 187 0
      yanfan-admin/src/main/resources/application-prod.yml
  42. 165 0
      yanfan-admin/src/main/resources/application.yml
  43. 2 0
      yanfan-admin/src/main/resources/banner.txt
  44. 192 0
      yanfan-admin/src/main/resources/i18n/messages.properties
  45. 193 0
      yanfan-admin/src/main/resources/i18n/messages_en_US.properties
  46. 193 0
      yanfan-admin/src/main/resources/i18n/messages_zh_CN.properties
  47. 150 0
      yanfan-admin/src/main/resources/logback.xml
  48. 20 0
      yanfan-admin/src/main/resources/mybatis/mybatis-config.xml
  49. BIN
      yanfan-admin/src/main/resources/static/jmreport/desreport_/corelib/logo.png
  50. BIN
      yanfan-admin/src/main/resources/static/jmreport/desreport_/logoimage/jim_logo_20200814094127.png
  51. 213 0
      yanfan-common/pom.xml
  52. 14 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/Anonymous.java
  53. 16 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/CacheBatch.java
  54. 27 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/CacheBatchEvict.java
  55. 28 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/DataScope.java
  56. 23 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/DataSource.java
  57. 22 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/DictFormat.java
  58. 181 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/Excel.java
  59. 17 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/Excels.java
  60. 41 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/Log.java
  61. 36 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/RateLimiter.java
  62. 24 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/RepeatSubmit.java
  63. 24 0
      yanfan-common/src/main/java/com/yanfan/common/annotation/SysProtocol.java
  64. 114 0
      yanfan-common/src/main/java/com/yanfan/common/config/DeviceTask.java
  65. 126 0
      yanfan-common/src/main/java/com/yanfan/common/config/RuoYiConfig.java
  66. 63 0
      yanfan-common/src/main/java/com/yanfan/common/constant/CacheConstants.java
  67. 156 0
      yanfan-common/src/main/java/com/yanfan/common/constant/Constants.java
  68. 183 0
      yanfan-common/src/main/java/com/yanfan/common/constant/GenConstants.java
  69. 104 0
      yanfan-common/src/main/java/com/yanfan/common/constant/HttpStatus.java
  70. 20 0
      yanfan-common/src/main/java/com/yanfan/common/constant/MagicValueConstants.java
  71. 40 0
      yanfan-common/src/main/java/com/yanfan/common/constant/ProductAuthConstant.java
  72. 14 0
      yanfan-common/src/main/java/com/yanfan/common/constant/ScadaConstant.java
  73. 47 0
      yanfan-common/src/main/java/com/yanfan/common/constant/SceneModelConstants.java
  74. 56 0
      yanfan-common/src/main/java/com/yanfan/common/constant/ScheduleConstants.java
  75. 9 0
      yanfan-common/src/main/java/com/yanfan/common/constant/SipConstants.java
  76. 111 0
      yanfan-common/src/main/java/com/yanfan/common/constant/UserConstants.java
  77. 356 0
      yanfan-common/src/main/java/com/yanfan/common/constant/YanfanConstant.java
  78. 195 0
      yanfan-common/src/main/java/com/yanfan/common/core/controller/BaseController.java
  79. 66 0
      yanfan-common/src/main/java/com/yanfan/common/core/device/DeviceAndProtocol.java
  80. 199 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/AjaxResult.java
  81. 54 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/BaseDO.java
  82. 127 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/BaseEntity.java
  83. 112 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/CommonResult.java
  84. 36 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/ImportExcelVO.java
  85. 25 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/OutputExcelVO.java
  86. 25 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/PageParam.java
  87. 42 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/PageResult.java
  88. 99 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/R.java
  89. 56 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/SortingField.java
  90. 20 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/TenantBaseDO.java
  91. 78 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/TreeEntity.java
  92. 74 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/TreeSelect.java
  93. 334 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDept.java
  94. 212 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDictData.java
  95. 117 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDictType.java
  96. 305 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysMenu.java
  97. 317 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysRole.java
  98. 41 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysTranslate.java
  99. 251 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysUser.java
  100. 10 0
      yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/vo/SysMenuVo.java

+ 47 - 0
.gitignore

@@ -0,0 +1,47 @@
+######################################################################
+# Build Tools
+.gradle
+/build/
+!gradle/wrapper/gradle-wrapper.jar
+
+target/
+!.mvn/wrapper/maven-wrapper.jar
+
+######################################################################
+# IDE
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+../.idea
+
+### NetBeans ###
+nbproject/private/
+build/*
+nbbuild/
+dist/
+nbdist/
+.nb-gradle/
+
+######################################################################
+# Others
+*.log
+*.xml.versionsBackup
+*.swp
+
+own-*
+
+!*/build/*.java
+!*/build/*.html
+!*/build/*.xml
+rebel.xml

+ 20 - 0
LICENSE

@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2018 RuoYi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 97 - 0
README.md

@@ -0,0 +1,97 @@
+## 平台简介
+
+若依是一套全部开源的快速开发平台,毫无保留给个人及企业免费使用。
+
+* 前端采用Vue、Element UI。
+* 后端采用Spring Boot、Spring Security、Redis & Jwt。
+* 权限认证使用Jwt,支持多终端认证系统。
+* 支持加载动态权限菜单,多方式轻松权限控制。
+* 高效率开发,使用代码生成器可以一键生成前后端代码。
+*
+
+提供了技术栈([Vue3](https://v3.cn.vuejs.org) [Element Plus](https://element-plus.org/zh-CN) [Vite](https://cn.vitejs.dev)
+)版本[RuoYi-Vue3](https://github.com/yangzongzhuan/RuoYi-Vue3),保持同步更新。
+
+* 提供了单应用版本[RuoYi-Vue-fast](https://github.com/yangzongzhuan/RuoYi-Vue-fast)
+  ,Oracle版本[RuoYi-Vue-Oracle](https://github.com/yangzongzhuan/RuoYi-Vue-Oracle),保持同步更新。
+* 不分离版本,请移步[RuoYi](https://gitee.com/y_project/RuoYi)
+  ,微服务版本,请移步[RuoYi-Cloud](https://gitee.com/y_project/RuoYi-Cloud)
+*
+
+特别鸣谢:[element](https://github.com/ElemeFE/element),[vue-element-admin](https://github.com/PanJiaChen/vue-element-admin),[eladmin-web](https://github.com/elunez/eladmin-web)。
+
+* 阿里云折扣场:[点我进入](http://aly.ruoyi.vip),腾讯云秒杀场:[点我进入](http://txy.ruoyi.vip)  
+* 阿里云优惠券:[点我领取](https://www.aliyun.com/minisite/goods?userCode=brki8iof&share_source=copy_link)
+  ,腾讯云优惠券:[点我领取](https://cloud.tencent.com/redirect.php?redirect=1025&cps_key=198c8df2ed259157187173bc7f4f32fd&from=console)
+    
+
+## 内置功能
+
+1. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。
+2. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。
+3. 岗位管理:配置系统用户所属担任职务。
+4. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。
+5. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。
+6. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。
+7. 参数管理:对系统动态配置常用参数。
+8. 通知公告:系统通知公告信息发布维护。
+9. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。
+10. 登录日志:系统登录日志记录查询包含登录异常。
+11. 在线用户:当前系统中活跃用户状态监控。
+12. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。
+13. 代码生成:前后端代码的生成(java、html、xml、sql)支持CRUD下载 。
+14. 系统接口:根据业务代码自动生成相关的api接口文档。
+15. 服务监控:监视当前系统CPU、内存、磁盘、堆栈等相关信息。
+16. 缓存监控:对系统的缓存信息查询,命令统计等。
+17. 在线构建器:拖动表单元素生成相应的HTML代码。
+18. 连接池监视:监视当前系统数据库连接池状态,可进行分析SQL找出系统性能瓶颈。
+
+## 在线体验
+
+- admin/admin123
+- 陆陆续续收到一些打赏,为了更好的体验已用于演示服务器升级。谢谢各位小伙伴。
+
+演示地址:http://vue.ruoyi.vip  
+文档地址:http://doc.ruoyi.vip
+
+## 演示图
+
+<table>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/cd1f90be5f2684f4560c9519c0f2a232ee8.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/1cbcf0e6f257c7d3a063c0e3f2ff989e4b3.jpg"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-8074972883b5ba0622e13246738ebba237a.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-9f88719cdfca9af2e58b352a20e23d43b12.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-39bf2584ec3a529b0d5a3b70d15c9b37646.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-936ec82d1f4872e1bc980927654b6007307.png"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-b2d62ceb95d2dd9b3fbe157bb70d26001e9.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-d67451d308b7a79ad6819723396f7c3d77a.png"/></td>
+    </tr>	 
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/5e8c387724954459291aafd5eb52b456f53.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/644e78da53c2e92a95dfda4f76e6d117c4b.jpg"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-8370a0d02977eebf6dbf854c8450293c937.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-49003ed83f60f633e7153609a53a2b644f7.png"/></td>
+    </tr>
+	<tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-d4fe726319ece268d4746602c39cffc0621.png"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-c195234bbcd30be6927f037a6755e6ab69c.png"/></td>
+    </tr>
+    <tr>
+        <td><img src="https://oscimg.oschina.net/oscnet/b6115bc8c31de52951982e509930b20684a.jpg"/></td>
+        <td><img src="https://oscimg.oschina.net/oscnet/up-5e4daac0bb59612c5038448acbcef235e3a.png"/></td>
+    </tr>
+</table>
+
+## 若依前后端分离交流群
+
+QQ群: [![加入QQ群](https://img.shields.io/badge/已满-937441-blue.svg)](https://jq.qq.com/?_wv=1027&k=5bVB1og) [![加入QQ群](https://img.shields.io/badge/已满-887144332-blue.svg)](https://jq.qq.com/?_wv=1027&k=5eiA4DH) [![加入QQ群](https://img.shields.io/badge/已满-180251782-blue.svg)](https://jq.qq.com/?_wv=1027&k=5AxMKlC) [![加入QQ群](https://img.shields.io/badge/已满-104180207-blue.svg)](https://jq.qq.com/?_wv=1027&k=51G72yr) [![加入QQ群](https://img.shields.io/badge/已满-186866453-blue.svg)](https://jq.qq.com/?_wv=1027&k=VvjN2nvu) [![加入QQ群](https://img.shields.io/badge/已满-201396349-blue.svg)](https://jq.qq.com/?_wv=1027&k=5vYAqA05) [![加入QQ群](https://img.shields.io/badge/已满-101456076-blue.svg)](https://jq.qq.com/?_wv=1027&k=kOIINEb5) [![加入QQ群](https://img.shields.io/badge/101539465-blue.svg)](https://jq.qq.com/?_wv=1027&k=UKtX5jhs)
+点击按钮入群。

+ 12 - 0
bin/clean.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 清理工程target生成路径。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean
+
+pause

+ 86 - 0
bin/clear-data.sql

@@ -0,0 +1,86 @@
+-- ----------------------------
+-- 清空日志表中数据
+-- ----------------------------
+truncate table `iot_alert_log`;
+truncate table `iot_device_log`;
+truncate table `iot_event_log`;
+truncate table `iot_function_log`;
+truncate table `iot_simulate_log`;
+truncate table `notify_log`;
+truncate table `sys_job_log`;
+truncate table `sys_logininfor`;
+truncate table `sys_oper_log`;
+
+
+truncate table iot_alert;
+truncate table iot_alert_log;
+truncate table iot_alert_notify_template;
+truncate table iot_alert_scene;
+truncate table iot_alert_trigger;
+truncate table iot_category;
+truncate table iot_device;
+truncate table iot_device_abnormal;
+truncate table iot_device_alert;
+truncate table iot_device_alert_user;
+truncate table iot_device_detail;
+truncate table iot_device_group;
+truncate table iot_device_history;
+truncate table iot_device_imgs;
+truncate table iot_device_inspection;
+truncate table iot_device_job;
+truncate table iot_device_lifecyle;
+truncate table iot_device_log;
+truncate table iot_device_log_buck;
+truncate table iot_device_maintain;
+truncate table iot_device_record;
+truncate table iot_device_share;
+truncate table iot_device_spare_part;
+truncate table iot_device_template;
+truncate table iot_device_user;
+truncate table iot_event_log;
+truncate table iot_firmware;
+truncate table iot_firmware_task;
+truncate table iot_firmware_task_detail;
+truncate table iot_function_log;
+truncate table iot_goview_project;
+truncate table iot_goview_project_data;
+truncate table iot_group;
+truncate table iot_group_user;
+truncate table iot_modbus_config;
+truncate table iot_modbus_job;
+truncate table iot_modbus_params;
+truncate table iot_product;
+truncate table iot_product_authorize;
+truncate table iot_product_copy1;
+truncate table iot_product_user;
+truncate table iot_scene;
+truncate table iot_scene_device;
+truncate table iot_scene_eneregy;
+truncate table iot_scene_maintainuser;
+truncate table iot_scene_operation;
+truncate table iot_scene_rule;
+truncate table iot_scene_rule_value;
+truncate table iot_scene_script;
+truncate table iot_scene_trigger;
+truncate table iot_script;
+truncate table iot_script_bridge;
+truncate table iot_script_user;
+truncate table iot_simulate_log;
+truncate table iot_sip_relation;
+truncate table iot_social_platform;
+truncate table iot_social_user;
+truncate table iot_sub_gateway;
+truncate table iot_things_model;
+truncate table iot_things_model_template;
+truncate table iot_things_model_template_translate;
+truncate table iot_things_model_translate;
+truncate table iot_var_temp;
+truncate table iot_var_temp_salve;
+
+
+delete from sys_role where role_id not in (1,2,3,4,5);
+delete from sys_user where user_id not in (1);
+delete from sys_role_dept where role_id not in (1,2,3,4,5);
+delete from sys_user_role where role_id not in (1,2,3,4,5);
+delete from sys_user_role where user_id not in (1);
+delete from sys_dept where dept_id not in (100, 101, 102);

+ 12 - 0
bin/package.bat

@@ -0,0 +1,12 @@
+@echo off
+echo.
+echo [信息] 打包Web工程,生成war/jar包文件。
+echo.
+
+%~d0
+cd %~dp0
+
+cd ..
+call mvn clean package -Dmaven.test.skip=true
+
+pause

+ 14 - 0
bin/run.bat

@@ -0,0 +1,14 @@
+@echo off
+echo.
+echo [��Ϣ] ʹ��Jar��������Web���̡�
+echo.
+
+cd %~dp0
+cd ../yanfan-admin/target
+
+set JAVA_OPTS=-Xms256m -Xmx1024m -XX:MetaspaceSize=128m -XX:MaxMetaspaceSize=512m
+
+java -jar %JAVA_OPTS% yanfan-admin.jar
+
+cd bin
+pause

+ 788 - 0
pom.xml

@@ -0,0 +1,788 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.yanfan</groupId>
+    <artifactId>yanfan</artifactId>
+    <version>3.8.5</version>
+
+    <name>yanfan</name>
+    <url>http://yanfan.cn</url>
+    <description>千丝物芯物联网平台</description>
+    <packaging>pom</packaging>
+
+    <properties>
+        <yanfan.version>3.8.5</yanfan.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <java.version>1.8</java.version>
+        <maven-jar-plugin.version>3.1.1</maven-jar-plugin.version>
+        <druid.version>1.2.15</druid.version>
+        <bitwalker.version>1.21</bitwalker.version>
+        <swagger.version>3.0.0</swagger.version>
+        <kaptcha.version>2.3.3</kaptcha.version>
+        <mybatis-spring-boot.version>2.2.0</mybatis-spring-boot.version>
+        <pagehelper.boot.version>1.4.6</pagehelper.boot.version>
+        <fastjson.version>2.0.20</fastjson.version>
+        <oshi.version>6.1.6</oshi.version>
+        <jna.version>5.9.0</jna.version>
+        <commons.io.version>2.11.0</commons.io.version>
+        <commons.fileupload.version>1.4</commons.fileupload.version>
+        <commons.collections.version>3.2.2</commons.collections.version>
+        <poi.version>4.1.2</poi.version>
+        <velocity.version>2.3</velocity.version>
+        <jwt.version>0.9.1</jwt.version>
+        <justAuth.version>1.16.5</justAuth.version>
+        <forest.version>1.5.36</forest.version>
+        <lombok.version>1.18.22</lombok.version>
+        <rocketmq.version>2.2.1</rocketmq.version>
+        <hutool.version>5.8.20</hutool.version>
+        <mapstruct.version>1.5.5.Final</mapstruct.version>
+        <mybatis-plus.version>3.5.3.1</mybatis-plus.version>
+        <mybatis-plus-generator.version>3.5.3.1</mybatis-plus-generator.version>
+        <guava.version>32.0.1-jre</guava.version>
+        <easyexcel.version>3.3.1</easyexcel.version>
+        <liteflow.version>2.12.2</liteflow.version>
+        <redisson.version>3.23.1</redisson.version>
+<!--    <taos.version>2.0.38</taos.version>-->
+        <taos.version>3.2.11</taos.version>
+        <lock4j.version>2.2.7</lock4j.version>
+        <okhttp.version>4.10.0</okhttp.version>
+        <jimureport.version>1.7.6</jimureport.version>
+    </properties>
+
+    <modules>
+        <module>yanfan-admin</module>
+        <module>yanfan-framework</module>
+        <module>yanfan-plugs</module>
+        <module>yanfan-common</module>
+        <module>yanfan-gateway</module>
+        <module>yanfan-server</module>
+        <module>yanfan-protocol</module>
+        <module>yanfan-open-api</module>
+        <module>yanfan-service</module>
+        <!-- <module>yanfan-record</module> -->
+        <module>yanfan-pay</module>
+        <module>yanfan-notify</module>
+    </modules>
+
+    <!-- 依赖声明 -->
+    <dependencyManagement>
+        <dependencies>
+
+            <!-- SpringBoot的依赖配置-->
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>2.5.14</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <!-- 阿里数据库连接池 -->
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>druid-spring-boot-starter</artifactId>
+                <version>${druid.version}</version>
+            </dependency>
+
+            <!-- 解析客户端操作系统、浏览器等 -->
+            <dependency>
+                <groupId>eu.bitwalker</groupId>
+                <artifactId>UserAgentUtils</artifactId>
+                <version>${bitwalker.version}</version>
+            </dependency>
+
+            <!-- SpringBoot集成mybatis框架 -->
+            <!--            <dependency>-->
+            <!--                <groupId>org.mybatis.spring.boot</groupId>-->
+            <!--                <artifactId>mybatis-spring-boot-starter</artifactId>-->
+            <!--                <version>${mybatis-spring-boot.version}</version>-->
+            <!--            </dependency>-->
+
+            <!-- mybatis plus -->
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-boot-starter</artifactId>
+                <version>${mybatis-plus.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>mybatis-plus-generator</artifactId>
+                <version>${mybatis-plus-generator.version}</version>
+            </dependency>
+
+            <!-- pagehelper 分页插件 -->
+            <dependency>
+                <groupId>com.github.pagehelper</groupId>
+                <artifactId>pagehelper-spring-boot-starter</artifactId>
+                <version>${pagehelper.boot.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>org.mybatis</groupId>
+                        <artifactId>mybatis</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!-- 获取系统信息 -->
+            <dependency>
+                <groupId>com.github.oshi</groupId>
+                <artifactId>oshi-core</artifactId>
+                <version>${oshi.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>net.java.dev.jna</groupId>
+                <artifactId>jna</artifactId>
+                <version>${jna.version}</version>
+            </dependency>
+
+            <!-- Swagger3依赖 -->
+            <dependency>
+                <groupId>io.springfox</groupId>
+                <artifactId>springfox-boot-starter</artifactId>
+                <version>${swagger.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <groupId>io.swagger</groupId>
+                        <artifactId>swagger-models</artifactId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <!-- io常用工具类 -->
+            <dependency>
+                <groupId>commons-io</groupId>
+                <artifactId>commons-io</artifactId>
+                <version>${commons.io.version}</version>
+            </dependency>
+
+            <!-- 文件上传工具类 -->
+            <dependency>
+                <groupId>commons-fileupload</groupId>
+                <artifactId>commons-fileupload</artifactId>
+                <version>${commons.fileupload.version}</version>
+            </dependency>
+
+            <!-- excel工具 -->
+            <dependency>
+                <groupId>org.apache.poi</groupId>
+                <artifactId>poi-ooxml</artifactId>
+                <version>${poi.version}</version>
+            </dependency>
+
+            <!-- velocity代码生成使用模板 -->
+            <dependency>
+                <groupId>org.apache.velocity</groupId>
+                <artifactId>velocity-engine-core</artifactId>
+                <version>${velocity.version}</version>
+            </dependency>
+
+            <!-- collections工具类 -->
+            <dependency>
+                <groupId>commons-collections</groupId>
+                <artifactId>commons-collections</artifactId>
+                <version>${commons.collections.version}</version>
+            </dependency>
+
+            <!--lombok-->
+            <dependency>
+                <groupId>org.projectlombok</groupId>
+                <artifactId>lombok</artifactId>
+                <version>${lombok.version}</version>
+            </dependency>
+
+            <!-- 阿里JSON解析器 -->
+            <dependency>
+                <groupId>com.alibaba.fastjson2</groupId>
+                <artifactId>fastjson2</artifactId>
+                <version>${fastjson.version}</version>
+            </dependency>
+            <!--<dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>fastjson</artifactId>
+                <version>1.2.83</version>
+                <scope>compile</scope>
+            </dependency>-->
+
+            <!-- Token生成与解析-->
+            <dependency>
+                <groupId>io.jsonwebtoken</groupId>
+                <artifactId>jjwt</artifactId>
+                <version>${jwt.version}</version>
+            </dependency>
+
+            <!-- 验证码 -->
+            <dependency>
+                <groupId>pro.fessional</groupId>
+                <artifactId>kaptcha</artifactId>
+                <version>${kaptcha.version}</version>
+            </dependency>
+
+            <!--rocket-mq-->
+            <dependency>
+                <groupId>org.apache.rocketmq</groupId>
+                <artifactId>rocketmq-spring-boot-starter</artifactId>
+                <version>${rocketmq.version}</version>
+            </dependency>
+
+            <!--Hutool Java工具包-->
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-all</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-core</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-crypto</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-http</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-json</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>cn.hutool</groupId>
+                <artifactId>hutool-cron</artifactId>
+                <version>${hutool.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>dysmsapi20170525</artifactId>
+                <version>2.0.24</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>dyvmsapi20170525</artifactId>
+                <version>2.1.4</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>tea</artifactId>
+                <version>1.2.0</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>tea-openapi</artifactId>
+                <version>0.2.8</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>tea-util</artifactId>
+                <version>0.2.18</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.code.gson</groupId>
+                <artifactId>gson</artifactId>
+                <version>2.8.9</version>
+            </dependency>
+            <dependency>
+                <groupId>com.google.code.findbugs</groupId>
+                <artifactId>jsr305</artifactId>
+                <version>3.0.2</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-digester</groupId>
+                <artifactId>commons-digester</artifactId>
+                <version>2.1</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-logging</groupId>
+                <artifactId>commons-logging</artifactId>
+                <version>1.2</version>
+            </dependency>
+            <dependency>
+                <groupId>commons-validator</groupId>
+                <artifactId>commons-validator</artifactId>
+                <version>1.7</version>
+            </dependency>
+            <dependency>
+                <groupId>io.github.classgraph</groupId>
+                <artifactId>classgraph</artifactId>
+                <version>4.8.149</version>
+            </dependency>
+            <dependency>
+                <groupId>io.lettuce</groupId>
+                <artifactId>lettuce-core</artifactId>
+                <version>6.1.8.RELEASE</version>
+            </dependency>
+            <dependency>
+                <groupId>io.swagger.core.v3</groupId>
+                <artifactId>swagger-annotations</artifactId>
+                <version>2.2.2</version>
+            </dependency>
+            <dependency>
+                <groupId>io.swagger.core.v3</groupId>
+                <artifactId>swagger-models</artifactId>
+                <version>2.2.2</version>
+            </dependency>
+            <dependency>
+                <groupId>org.bouncycastle</groupId>
+                <artifactId>bcpkix-jdk15on</artifactId>
+                <version>1.70</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>credentials-java</artifactId>
+                <version>0.2.4</version>
+            </dependency>
+            <dependency>
+                <groupId>com.aliyun</groupId>
+                <artifactId>openapiutil</artifactId>
+                <version>0.2.1</version>
+            </dependency>
+            <dependency>
+                <groupId>javax.activation</groupId>
+                <artifactId>activation</artifactId>
+                <version>1.1.1</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>transmittable-thread-local</artifactId>
+                <version>2.14.0</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.dtflys.forest</groupId>
+                <artifactId>forest-spring-boot-starter</artifactId>
+                <version>${forest.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dtflys.forest</groupId>
+                <artifactId>forest-jaxb</artifactId>
+                <version>${forest.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.dtflys.forest</groupId>
+                <artifactId>forest-core</artifactId>
+                <version>${forest.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.taosdata.jdbc</groupId>
+                <artifactId>taos-jdbcdriver</artifactId>
+                <version>${taos.version}</version>
+            </dependency>
+            <!--<dependency>
+                <groupId>com.fasterxml.jackson.dataformat</groupId>
+                <artifactId>jackson-dataformat-yaml</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-annotations</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-databind</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.core</groupId>
+                <artifactId>jackson-core</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.module</groupId>
+                <artifactId>jackson-module-parameter-names</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.datatype</groupId>
+                <artifactId>jackson-datatype-jsr310</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.datatype</groupId>
+                <artifactId>jackson-datatype-jdk8</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.dataformat</groupId>
+                <artifactId>jackson-dataformat-cbor</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.fasterxml.jackson.dataformat</groupId>
+                <artifactId>jackson-dataformat-xml</artifactId>
+                <version>${jackson.version}</version>
+            </dependency>-->
+
+            <dependency>
+                <groupId>com.yomahub</groupId>
+                <artifactId>liteflow-core</artifactId>
+                <version>${liteflow.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yomahub</groupId>
+                <artifactId>liteflow-spring</artifactId>
+                <version>${liteflow.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yomahub</groupId>
+                <artifactId>liteflow-spring-boot-starter</artifactId>
+                <version>${liteflow.version}</version>
+            </dependency>
+            <!--数据库规则配置源插件-->
+            <dependency>
+                <groupId>com.yomahub</groupId>
+                <artifactId>liteflow-rule-sql</artifactId>
+                <version>${liteflow.version}</version>
+            </dependency>
+            <!--groovy脚本插件-->
+            <dependency>
+                <groupId>com.yomahub</groupId>
+                <artifactId>liteflow-script-groovy</artifactId>
+                <version>${liteflow.version}</version>
+            </dependency>
+
+            <!-- 核心模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-framework</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!-- 通用工具-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-common</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--网关模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-gateway</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-message-bus</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--服务层模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-server</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--工具插件管理类-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-plugs</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-iot-service</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-system-service</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--定时模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-quartz</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--代码生成模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-generator</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-oss</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--基于netty的MqttBroker-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>mqtt-broker</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>http-server</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>coap-server</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>sip-server</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--协议层模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-protocol</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--controller层模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-open-api</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--modbus协议模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-protocol-collect</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--服务核心模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>iot-server-core</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--服务基础模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>base-server</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--mq模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-mq</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--服务启动模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>boot-strap</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--协议解析基础模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-protocol-base</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--网关启动模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>gateway-boot</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-http</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-mqtt-client</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.mapstruct</groupId>
+                <artifactId>mapstruct</artifactId> <!-- use mapstruct-jdk8 for Java 8 or higher -->
+                <version>${mapstruct.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.mapstruct</groupId>
+                <artifactId>mapstruct-jdk8</artifactId>
+                <version>${mapstruct.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>org.mapstruct</groupId>
+                <artifactId>mapstruct-processor</artifactId>
+                <version>${mapstruct.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.google.guava</groupId>
+                <artifactId>guava</artifactId>
+                <version>${guava.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.redisson</groupId>
+                <artifactId>redisson-spring-boot-starter</artifactId>
+                <version>${redisson.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>com.baomidou</groupId>
+                <artifactId>lock4j-redisson-spring-boot-starter</artifactId>
+                <version>${lock4j.version}</version>
+                <exclusions>
+                    <exclusion>
+                        <artifactId>redisson-spring-boot-starter</artifactId>
+                        <groupId>org.redisson</groupId>
+                    </exclusion>
+                </exclusions>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba</groupId>
+                <artifactId>easyexcel-core</artifactId>
+                <version>${easyexcel.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>org.jeecgframework.jimureport</groupId>
+                <artifactId>jimureport-spring-boot-starter</artifactId>
+                <version>${jimureport.version}</version>
+            </dependency>
+
+
+            <!-- 通知模块 -->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-notify</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!-- 通知配置模块 -->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-notify-web</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-notify-core</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!-- 工具插件模块:oauth2.0 -->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-oauth</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--            &lt;!&ndash; 音箱接入模块 &ndash;&gt;-->
+            <!--            <dependency>-->
+            <!--                <groupId>com.yanfan</groupId>-->
+            <!--                <artifactId>yanfan-speaker</artifactId>-->
+            <!--                <version>${yanfan.version}</version>-->
+            <!--            </dependency>-->
+
+            <!--            &lt;!&ndash; 小度音箱模块 &ndash;&gt;-->
+            <!--            <dependency>-->
+            <!--                <groupId>com.yanfan</groupId>-->
+            <!--                <artifactId>yanfan-link-dueros</artifactId>-->
+            <!--                <version>${yanfan.version}</version>-->
+            <!--            </dependency>-->
+
+            <!--            &lt;!&ndash; 组态模块 &ndash;&gt;-->
+            <!--            <dependency>-->
+            <!--                <groupId>com.yanfan</groupId>-->
+            <!--                <artifactId>yanfan-scada</artifactId>-->
+            <!--                <version>${yanfan.version}</version>-->
+            <!--            </dependency>-->
+
+            <!-- 组态模块 -->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-scada</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--设备附加模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-attach</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+            <!--个推-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-getui</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+
+            <!--测试模块-->
+            <dependency>
+                <groupId>com.yanfan</groupId>
+                <artifactId>yanfan-test</artifactId>
+                <version>${yanfan.version}</version>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <version>3.1</version>
+                <configuration>
+                    <source>${java.version}</source>
+                    <target>${java.version}</target>
+                    <encoding>${project.build.sourceEncoding}</encoding>
+                </configuration>
+            </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>

+ 256 - 0
yanfan-admin/pom.xml

@@ -0,0 +1,256 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yanfan</artifactId>
+        <groupId>com.yanfan</groupId>
+        <version>3.8.5</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+    <packaging>jar</packaging>
+    <artifactId>yanfan-admin</artifactId>
+
+    <description>
+        web服务入口
+    </description>
+
+    <properties>
+        <service.path>${project.build.directory}/${project.artifactId}</service.path>
+        <maven.plugin.version>3.3.0</maven.plugin.version>
+    </properties>
+    <dependencies>
+
+        <!--瀚高 6 JDBC 驱动依赖 -->
+        <!-- https://mvnrepository.com/artifact/com.highgo/HgdbJdbc -->
+        <dependency>
+            <groupId>com.highgo</groupId>
+            <artifactId>HgdbJdbc</artifactId>
+            <version>6.0.4.jre8</version>
+        </dependency>
+
+        <!-- spring-boot-devtools -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-devtools</artifactId>
+            <optional>true</optional> <!-- 表示依赖不会传递 -->
+        </dependency>
+
+        <!-- swagger3-->
+        <dependency>
+            <groupId>io.springfox</groupId>
+            <artifactId>springfox-boot-starter</artifactId>
+        </dependency>
+
+        <!-- 防止进入swagger页面报类型转换错误,排除3.0.0中的引用,手动增加1.6.2版本 -->
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-models</artifactId>
+            <version>1.6.2</version>
+        </dependency>
+
+        <!-- Mysql驱动包 -->
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.ben-manes.caffeine</groupId>
+            <artifactId>caffeine</artifactId>
+        </dependency>
+
+        <!-- 核心模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-framework</artifactId>
+        </dependency>
+
+        <!-- 定时任务-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-quartz</artifactId>
+        </dependency>
+
+        <!-- 代码生成-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-generator</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-oss</artifactId>
+        </dependency>
+
+        <!-- controller API模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-open-api</artifactId>
+        </dependency>
+        <!--服务集成启动模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>boot-strap</artifactId>
+        </dependency>
+        <!--网关集成启动模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>gateway-boot</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>http-server</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>sip-server</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-http</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.yomahub</groupId>
+            <artifactId>liteflow-core</artifactId>
+        </dependency>
+
+        <!-- 通知配置模块 -->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-notify-web</artifactId>
+        </dependency>
+        <!-- 通知api模块 -->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-notify-core</artifactId>
+        </dependency>
+
+        <!-- oauth2.0 -->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-oauth</artifactId>
+        </dependency>
+        <!--测试模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-attach</artifactId>
+        </dependency>
+        <!--测试模块-->
+        <dependency>
+            <groupId>com.yanfan</groupId>
+            <artifactId>yanfan-test</artifactId>
+        </dependency>
+
+        <!--        &lt;!&ndash; 小度音箱 &ndash;&gt;-->
+        <!--        <dependency>-->
+        <!--            <groupId>com.yanfan</groupId>-->
+        <!--            <artifactId>yanfan-link-dueros</artifactId>-->
+        <!--        </dependency>-->
+
+        <!-- 组态模块 -->
+        <!--        <dependency>-->
+        <!--            <groupId>com.yanfan</groupId>-->
+        <!--            <artifactId>yanfan-scada</artifactId>-->
+        <!--        </dependency>-->
+
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-dependency-plugin</artifactId>
+                <version>${maven.plugin.version}</version>
+                <executions>
+                    <execution>
+                        <id>copy-lib</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-dependencies</goal>
+                        </goals>
+                        <configuration>
+                            <outputDirectory>${service.path}/lib</outputDirectory>
+                            <excludeTransitive>false</excludeTransitive>
+                            <stripVersion>false</stripVersion>
+                            <includeScope>runtime</includeScope>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <!--拷贝资源文件 copy-resources-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-resources-plugin</artifactId>
+                <version>${maven.plugin.version}</version>
+                <executions>
+                    <execution>
+                        <id>copy-resources</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/resources</directory>
+                                    <filtering>true</filtering>
+                                    <excludes>
+                                        <exclude>mapper/**/*.xml</exclude>
+                                        <exclude>config/**</exclude>
+                                    </excludes>
+                                </resource>
+                            </resources>
+                            <outputDirectory>${service.path}/resources</outputDirectory>
+                        </configuration>
+                    </execution>
+                    <execution>
+                        <id>copy-script</id>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>copy-resources</goal>
+                        </goals>
+                        <configuration>
+                            <resources>
+                                <resource>
+                                    <directory>src/main/script</directory>
+                                </resource>
+                            </resources>
+                            <outputDirectory>${service.path}</outputDirectory>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-jar-plugin</artifactId>
+                <version>${maven.plugin.version}</version>
+                <configuration>
+                    <archive>
+                        <manifest>
+                            <addClasspath>true</addClasspath>
+                            <classpathPrefix>lib/</classpathPrefix>
+                            <mainClass>com.yanfan.YanfanApplication</mainClass>
+                        </manifest>
+                        <manifestEntries>
+                            <Class-Path>./resources/</Class-Path>
+                        </manifestEntries>
+                    </archive>
+                    <!-- 排除配置文件 -->
+                    <excludes>
+                        <exclude>*.**</exclude>
+                    </excludes>
+                    <outputDirectory>${service.path}</outputDirectory>
+                </configuration>
+            </plugin>
+        </plugins>
+        <finalName>${project.artifactId}</finalName>
+    </build>
+
+</project>

+ 20 - 0
yanfan-admin/src/main/java/com/yanfan/YanfanApplication.java

@@ -0,0 +1,20 @@
+package com.yanfan;
+
+import com.dtflys.forest.springboot.annotation.ForestScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+
+/**
+ * 启动程序
+ *
+ * @author ruoyi
+ */
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@ForestScan(basePackages = "com.yanfan.http.client")
+public class YanfanApplication {
+    public static void main(String[] args) {
+        // System.setProperty("spring.devtools.restart.enabled", "false");
+        SpringApplication.run(YanfanApplication.class, args);
+    }
+}

+ 16 - 0
yanfan-admin/src/main/java/com/yanfan/YanfanServletInitializer.java

@@ -0,0 +1,16 @@
+package com.yanfan;
+
+import org.springframework.boot.builder.SpringApplicationBuilder;
+import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
+
+/**
+ * web容器中进行部署
+ *
+ * @author ruoyi
+ */
+public class YanfanServletInitializer extends SpringBootServletInitializer {
+    @Override
+    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
+        return application.sources(YanfanApplication.class);
+    }
+}

+ 91 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/common/CaptchaController.java

@@ -0,0 +1,91 @@
+package com.yanfan.web.controller.common;
+
+import com.yanfan.common.config.RuoYiConfig;
+import com.yanfan.common.constant.CacheConstants;
+import com.yanfan.common.constant.Constants;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.redis.RedisCache;
+import com.yanfan.common.utils.sign.Base64;
+import com.yanfan.common.utils.uuid.IdUtils;
+import com.yanfan.system.service.ISysConfigService;
+import com.google.code.kaptcha.Producer;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.annotation.Resource;
+import javax.imageio.ImageIO;
+import javax.servlet.http.HttpServletResponse;
+import java.awt.image.BufferedImage;
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 验证码操作处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "验证码操作")
+@RestController
+public class CaptchaController {
+    @Resource(name = "captchaProducer")
+    private Producer captchaProducer;
+
+    @Resource(name = "captchaProducerMath")
+    private Producer captchaProducerMath;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 生成验证码
+     */
+    @ApiOperation("获取验证码")
+    @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;
+    }
+}

+ 148 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/common/CommonController.java

@@ -0,0 +1,148 @@
+package com.yanfan.web.controller.common;
+
+import com.yanfan.common.config.RuoYiConfig;
+import com.yanfan.common.constant.Constants;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.file.FileUploadUtils;
+import com.yanfan.common.utils.file.FileUtils;
+import com.yanfan.framework.config.ServerConfig;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 通用请求处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "通用请求处理")
+@RestController
+@RequestMapping("/common")
+public class CommonController {
+    private static final Logger log = LoggerFactory.getLogger(CommonController.class);
+    private static final String FILE_DELIMETER = ",";
+    @Autowired
+    private ServerConfig serverConfig;
+
+    /**
+     * 通用下载请求
+     *
+     * @param fileName 文件名称
+     * @param delete   是否删除
+     */
+    @ApiOperation("文件下载")
+    @GetMapping("/download")
+    public void fileDownload(String fileName, Boolean delete, HttpServletResponse response, HttpServletRequest request) {
+        try {
+            if (!FileUtils.checkAllowDownload(fileName)) {
+                throw new Exception(StringUtils.format(MessageUtils.message("download.filename.not.valid"), 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);
+        }
+    }
+
+    /**
+     * 通用上传请求(单个)
+     */
+    @ApiOperation("单个文件上传")
+    @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());
+        }
+    }
+
+    /**
+     * 通用上传请求(多个)
+     */
+    @ApiOperation("多个文件上传")
+    @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")
+    @ApiOperation("本地资源通用下载")
+    public void resourceDownload(String resource, HttpServletRequest request, HttpServletResponse response) throws Exception {
+        try {
+            if (!FileUtils.checkAllowDownload(resource)) {
+                throw new Exception(StringUtils.format(MessageUtils.message("download.resource.not.valid"), 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);
+        }
+    }
+}

+ 113 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/CacheController.java

@@ -0,0 +1,113 @@
+package com.yanfan.web.controller.monitor;
+
+import com.yanfan.common.constant.CacheConstants;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.system.domain.SysCache;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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.*;
+
+import java.util.*;
+
+/**
+ * 缓存监控
+ *
+ * @author ruoyi
+ */
+@Api(tags = "缓存监控")
+@RestController
+@RequestMapping("/monitor/cache")
+public class CacheController {
+    private final static List<SysCache> caches = new ArrayList<SysCache>();
+    @Autowired
+    private RedisTemplate<String, String> redisTemplate;
+
+    {
+        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, "密码错误次数"));
+    }
+
+    @ApiOperation("获取缓存信息")
+    //@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);
+    }
+
+    @ApiOperation("缓存列表")
+    //@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getNames")
+    public AjaxResult cache() {
+        return AjaxResult.success(caches);
+    }
+
+    @ApiOperation("键名列表")
+    //@PreAuthorize("@ss.hasPermi('monitor:cache:list')")
+    @GetMapping("/getKeys/{cacheName}")
+    public AjaxResult getCacheKeys(@PathVariable String cacheName) {
+        Set<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        return AjaxResult.success(cacheKeys);
+    }
+
+    @ApiOperation("缓存内容")
+    //@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);
+    }
+
+    @ApiOperation("清理缓存名称")
+    //@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
+    @DeleteMapping("/clearCacheName/{cacheName}")
+    public AjaxResult clearCacheName(@PathVariable String cacheName) {
+        Collection<String> cacheKeys = redisTemplate.keys(cacheName + "*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("清理缓存键名")
+    //@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
+    @DeleteMapping("/clearCacheKey/{cacheKey}")
+    public AjaxResult clearCacheKey(@PathVariable String cacheKey) {
+        redisTemplate.delete(cacheKey);
+        return AjaxResult.success();
+    }
+
+    @ApiOperation("清理所有缓存内容")
+    //@PreAuthorize("@ss.hasPermi('monitor:cache:remove')")
+    @DeleteMapping("/clearCacheAll")
+    public AjaxResult clearCacheAll() {
+        Collection<String> cacheKeys = redisTemplate.keys("*");
+        redisTemplate.delete(cacheKeys);
+        return AjaxResult.success();
+    }
+}

+ 29 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/ServerController.java

@@ -0,0 +1,29 @@
+package com.yanfan.web.controller.monitor;
+
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.framework.web.domain.Server;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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;
+
+/**
+ * 服务器监控
+ *
+ * @author ruoyi
+ */
+@Api(tags = "服务器监控")
+@RestController
+@RequestMapping("/monitor/server")
+public class ServerController {
+    @ApiOperation("获取服务器信息")
+    //@PreAuthorize("@ss.hasPermi('monitor:server:list')")
+    @GetMapping()
+    public AjaxResult getInfo() throws Exception {
+        Server server = new Server();
+        server.copyTo();
+        return AjaxResult.success(server);
+    }
+}

+ 80 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysLogininforController.java

@@ -0,0 +1,80 @@
+package com.yanfan.web.controller.monitor;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.framework.web.service.SysPasswordService;
+import com.yanfan.system.domain.SysLogininfor;
+import com.yanfan.system.service.ISysLogininforService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 系统访问记录
+ *
+ * @author ruoyi
+ */
+@Api(tags = "日志管理:登录日志")
+@RestController
+@RequestMapping("/monitor/logininfor")
+public class SysLogininforController extends BaseController {
+    @Autowired
+    private ISysLogininforService logininforService;
+
+    @Autowired
+    private SysPasswordService passwordService;
+
+    @ApiOperation("获取列表登录信息")
+    //@PreAuthorize("@ss.hasPermi('monitor:logininfor:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysLogininfor logininfor) {
+        startPage();
+        List<SysLogininfor> list = logininforService.selectLogininforList(logininfor);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出登录日志列表")
+    @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, "登录日志");
+    }
+
+    @ApiOperation("批量删除登录日志")
+    //@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{infoIds}")
+    public AjaxResult remove(@PathVariable Long[] infoIds) {
+        return toAjax(logininforService.deleteLogininforByIds(infoIds));
+    }
+
+    @ApiOperation("清空登录日志信息")
+    //@PreAuthorize("@ss.hasPermi('monitor:logininfor:remove')")
+    @Log(title = "登录日志", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/clean")
+    public AjaxResult clean() {
+        logininforService.cleanLogininfor();
+        return success();
+    }
+
+    @ApiOperation("账户解锁")
+    //@PreAuthorize("@ss.hasPermi('monitor:logininfor:unlock')")
+    @Log(title = "账户解锁", businessType = BusinessType.OTHER)
+    @GetMapping("/unlock/{userName}")
+    public AjaxResult unlock(@PathVariable("userName") String userName) {
+        passwordService.clearLoginRecordCache(userName);
+        return success();
+    }
+}

+ 67 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysOperlogController.java

@@ -0,0 +1,67 @@
+package com.yanfan.web.controller.monitor;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.domain.SysOperLog;
+import com.yanfan.system.service.ISysOperLogService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 操作日志记录
+ *
+ * @author ruoyi
+ */
+@Api(tags = "日志管理:操作日志")
+@RestController
+@RequestMapping("/monitor/operlog")
+public class SysOperlogController extends BaseController {
+    @Autowired
+    private ISysOperLogService operLogService;
+
+    @ApiOperation("获取操作日志列表")
+    //@PreAuthorize("@ss.hasPermi('monitor:operlog:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysOperLog operLog) {
+        startPage();
+        List<SysOperLog> list = operLogService.selectOperLogList(operLog);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出操作日志")
+    @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, "操作日志");
+    }
+
+    @ApiOperation("批量删除操作日志")
+    @Log(title = "操作日志", businessType = BusinessType.DELETE)
+    //@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/{operIds}")
+    public AjaxResult remove(@PathVariable Long[] operIds) {
+        return toAjax(operLogService.deleteOperLogByIds(operIds));
+    }
+
+    @ApiOperation("清空操作日志")
+    @Log(title = "操作日志", businessType = BusinessType.CLEAN)
+    //@PreAuthorize("@ss.hasPermi('monitor:operlog:remove')")
+    @DeleteMapping("/clean")
+    public AjaxResult clean() {
+        operLogService.cleanOperLog();
+        return success();
+    }
+}

+ 80 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/monitor/SysUserOnlineController.java

@@ -0,0 +1,80 @@
+package com.yanfan.web.controller.monitor;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.CacheConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.model.LoginUser;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.core.redis.RedisCache;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.system.domain.SysUserOnline;
+import com.yanfan.system.service.ISysUserOnlineService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * 在线用户监控
+ *
+ * @author ruoyi
+ */
+@Api(tags = "在线用户监控")
+@RestController
+@RequestMapping("/monitor/online")
+public class SysUserOnlineController extends BaseController {
+    @Autowired
+    private ISysUserOnlineService userOnlineService;
+
+    @Autowired
+    private RedisCache redisCache;
+
+    @ApiOperation("获取在线用户列表")
+    //@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)) {
+                if (StringUtils.equals(ipaddr, user.getIpaddr()) && StringUtils.equals(userName, user.getUsername())) {
+                    userOnlineList.add(userOnlineService.selectOnlineByInfo(ipaddr, userName, user));
+                }
+            } else if (StringUtils.isNotEmpty(ipaddr)) {
+                if (StringUtils.equals(ipaddr, user.getIpaddr())) {
+                    userOnlineList.add(userOnlineService.selectOnlineByIpaddr(ipaddr, user));
+                }
+            } else if (StringUtils.isNotEmpty(userName) && StringUtils.isNotNull(user.getUser())) {
+                if (StringUtils.equals(userName, user.getUsername())) {
+                    userOnlineList.add(userOnlineService.selectOnlineByUserName(userName, user));
+                }
+            } else {
+                userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
+            }
+        }
+        Collections.reverse(userOnlineList);
+        userOnlineList.removeAll(Collections.singleton(null));
+        return getDataTable(userOnlineList);
+    }
+
+    /**
+     * 强退用户
+     */
+    @ApiOperation("强制退出在线用户")
+    //@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();
+    }
+}

+ 100 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysClientController.java

@@ -0,0 +1,100 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.framework.web.service.TokenService;
+import com.yanfan.system.domain.SysClient;
+import com.yanfan.system.service.ISysClientService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 系统授权Controller
+ *
+ * @author zhuangpeng.li
+ * @date 2024-07-26
+ */
+@RestController
+@RequestMapping("/system/sysclient")
+@Api(tags = "系统授权")
+public class SysClientController extends BaseController {
+    @Autowired
+    private ISysClientService sysClientService;
+    @Autowired
+    private TokenService tokenService;
+
+    /**
+     * 查询系统授权列表
+     */
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:list')")
+    @GetMapping("/list")
+    @ApiOperation("查询系统授权列表")
+    public TableDataInfo list(SysClient sysClient) {
+        startPage();
+        List<SysClient> list = sysClientService.selectSysClientList(sysClient);
+        return getDataTable(list);
+    }
+
+    /**
+     * 导出系统授权列表
+     */
+    @ApiOperation("导出系统授权列表")
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysClient sysClient) {
+        List<SysClient> list = sysClientService.selectSysClientList(sysClient);
+        ExcelUtil<SysClient> util = new ExcelUtil<SysClient>(SysClient.class);
+        util.exportExcel(response, list, "系统授权数据");
+    }
+
+    /**
+     * 获取系统授权详细信息
+     */
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:query')")
+    @GetMapping(value = "/{id}")
+    @ApiOperation("获取系统授权详细信息")
+    public AjaxResult getInfo(@PathVariable("id") Long id) {
+        return success(sysClientService.selectSysClientById(id));
+    }
+
+    /**
+     * 新增系统授权
+     */
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:add')")
+    @PostMapping
+    @ApiOperation("新增系统授权")
+    public AjaxResult add(@RequestBody SysClient sysClient) {
+        SysUser user = getLoginUser().getUser();
+        return toAjax(tokenService.addToken(user, sysClient));
+    }
+
+    /**
+     * 修改系统授权
+     */
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:edit')")
+    @PutMapping
+    @ApiOperation("修改系统授权")
+    public AjaxResult edit(@RequestBody SysClient sysClient) {
+        SysUser user = getLoginUser().getUser();
+        return toAjax(tokenService.updateToken(user, sysClient));
+    }
+
+    /**
+     * 删除系统授权
+     */
+    //@PreAuthorize("@ss.hasPermi('system:sysclient:remove')")
+    @DeleteMapping("/{ids}")
+    @ApiOperation("删除系统授权")
+    public AjaxResult remove(@PathVariable Long[] ids) {
+        return toAjax(sysClientService.deleteSysClientByIds(ids));
+    }
+}

+ 128 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysConfigController.java

@@ -0,0 +1,128 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.domain.SysConfig;
+import com.yanfan.system.service.ISysConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 参数配置 信息操作处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "参数设置")
+@RestController
+@RequestMapping("/system/config")
+public class SysConfigController extends BaseController {
+    @Autowired
+    private ISysConfigService configService;
+
+    /**
+     * 获取参数配置列表
+     */
+    @ApiOperation("获取参数配置列表")
+    //@PreAuthorize("@ss.hasPermi('system:config:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysConfig config) {
+        startPage();
+        List<SysConfig> list = configService.selectConfigList(config);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出参数配置列表")
+    @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, "参数数据");
+    }
+
+    /**
+     * 根据参数编号获取详细信息
+     */
+    @ApiOperation("根据参数编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:config:query')")
+    @GetMapping(value = "/{configId}")
+    public AjaxResult getInfo(@PathVariable Long configId) {
+        return success(configService.selectConfigById(configId));
+    }
+
+    /**
+     * 根据参数键名查询参数值
+     */
+    @ApiOperation("根据参数键名查询参数值")
+    @GetMapping(value = "/configKey/{configKey}")
+    public AjaxResult getConfigKey(@PathVariable String configKey) {
+        return success(configService.selectConfigByKey(configKey));
+    }
+
+    /**
+     * 新增参数配置
+     */
+    @ApiOperation("新增参数配置")
+    //@PreAuthorize("@ss.hasPermi('system:config:add')")
+    @Log(title = "参数管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
+            return error("新增参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setCreateBy(getUsername());
+        return toAjax(configService.insertConfig(config));
+    }
+
+    /**
+     * 修改参数配置
+     */
+    @ApiOperation("修改参数配置")
+    //@PreAuthorize("@ss.hasPermi('system:config:edit')")
+    @Log(title = "参数管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysConfig config) {
+        if (UserConstants.NOT_UNIQUE.equals(configService.checkConfigKeyUnique(config))) {
+            return error("修改参数'" + config.getConfigName() + "'失败,参数键名已存在");
+        }
+        config.setUpdateBy(getUsername());
+        return toAjax(configService.updateConfig(config));
+    }
+
+    /**
+     * 删除参数配置
+     */
+    @ApiOperation("批量删除参数配置")
+    //@PreAuthorize("@ss.hasPermi('system:config:remove')")
+    @Log(title = "参数管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{configIds}")
+    public AjaxResult remove(@PathVariable Long[] configIds) {
+        configService.deleteConfigByIds(configIds);
+        return success();
+    }
+
+    /**
+     * 刷新参数缓存
+     */
+    @ApiOperation("刷新参数缓存")
+    //@PreAuthorize("@ss.hasPermi('system:config:refresh')")
+    @Log(title = "参数管理", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache() {
+        configService.resetConfigCache();
+        return success();
+    }
+}

+ 275 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDeptController.java

@@ -0,0 +1,275 @@
+package com.yanfan.web.controller.system;
+
+import cn.hutool.core.util.ObjectUtil;
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.*;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.exception.ServiceException;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.iot.model.RegisterUserInput;
+import com.yanfan.iot.model.RegisterUserOutput;
+import com.yanfan.iot.service.IToolService;
+import com.yanfan.system.domain.vo.SysDeptTypeVO;
+import com.yanfan.system.mapper.SysRoleDeptMapper;
+import com.yanfan.system.service.*;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.validation.annotation.Validated;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 机构信息
+ *
+ * @author ruoyi
+ */
+@Api(tags = "机构管理")
+@RestController
+@RequestMapping("/system/dept")
+public class SysDeptController extends BaseController {
+    @Autowired
+    private ISysDeptService deptService;
+
+    @Resource
+    private IToolService toolService;
+
+    @Resource
+    private ISysUserService sysUserService;
+
+    @Resource
+    private SysRoleDeptMapper sysRoleDeptMapper;
+
+    @Resource
+    private ISysDictDataService sysDictDataService;
+
+    @Resource
+    private ISysRoleService sysRoleService;
+
+    @Resource
+    private ISysMenuService sysMenuService;
+
+    /**
+     * 获取机构列表
+     */
+    @ApiOperation("获取机构列表")
+    //@PreAuthorize("@ss.hasPermi('system:dept:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysDept dept) {
+        List<SysDept> depts = deptService.selectDeptList(dept);
+        return success(depts);
+    }
+
+    /**
+     * 查询机构列表(排除节点)
+     */
+    @ApiOperation("查询机构列表(排除节点)")
+    //@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);
+    }
+
+    /**
+     * 根据机构编号获取详细信息
+     */
+    @ApiOperation("根据机构编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:dept:query')")
+    @Transactional(rollbackFor = Exception.class)
+    @GetMapping(value = "/{deptId}")
+    public AjaxResult getInfo(@PathVariable Long deptId) {
+        deptService.checkDeptDataScope(deptId);
+        SysDept sysDept = deptService.selectDeptById(deptId);
+        if (null != sysDept && null != sysDept.getDeptUserId()) {
+            SysUser sysUser = sysUserService.selectUserById(sysDept.getDeptUserId());
+            sysDept.setUserName(sysUser.getUserName());
+            sysDept.setPhone(sysUser.getPhonenumber());
+        }
+        return success(sysDept);
+    }
+
+    /**
+     * 新增机构
+     */
+    @ApiOperation("新增机构")
+    //@PreAuthorize("@ss.hasPermi('system:dept:add')")
+    @Log(title = "机构管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(HttpServletRequest request, @Validated @RequestBody SysDept dept) {
+        if (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {
+            return error(StringUtils.format(MessageUtils.message("dept.add.failed.name.exists"), dept.getDeptName()));
+        }
+        dept.setCreateBy(getUsername());
+        // 校验系统账号信息
+        if (StringUtils.isNotEmpty(dept.getUserName())) {
+            SysUser sysUser = sysUserService.selectUserByUserName(dept.getUserName());
+            if (ObjectUtil.isNotNull(sysUser)) {
+                throw new ServiceException(MessageUtils.message("user.username.exists"));
+            }
+            if (!dept.getPassword().equals(dept.getConfirmPassword())) {
+                throw new ServiceException(MessageUtils.message("user.password.differ"));
+            }
+        }
+        int result = deptService.insertDept(dept);
+        // 新增机构关联系统账号
+        if (result > 0) {
+            // 添加管理员角色,给所有权限
+            // 查询所有权限
+//            List<SysMenu> sysMenuList = sysMenuService.selectMenuList(new SysMenu(), 1L, request.getHeader(LANGUAGE));
+            SysDept sysDept = deptService.selectDeptById(dept.getParentId());
+            List<SysMenu> sysMenuList = sysMenuService.selectMenuList(new SysMenu(), sysDept.getDeptUserId());
+            Long[] menuIdList = sysMenuList.stream().map(SysMenu::getMenuId).toArray(Long[]::new);
+            SysRole sysRole = new SysRole();
+            sysRole.setRoleName("管理员");
+            sysRole.setRoleKey("manager");
+            sysRole.setRoleSort(1);
+            sysRole.setStatus("0");
+            sysRole.setDeptId(dept.getDeptId());
+            sysRole.setMenuIds(menuIdList);
+            sysRoleService.insertRole(sysRole);
+
+            // 注册机构管理员用户
+            RegisterUserInput registerUserInput = new RegisterUserInput();
+            registerUserInput.setUsername(dept.getUserName());
+            registerUserInput.setPassword(dept.getPassword());
+            registerUserInput.setPhonenumber(dept.getPhone());
+            registerUserInput.setDeptId(dept.getDeptId());
+            registerUserInput.setRoleIds(new Long[]{sysRole.getRoleId()});
+            RegisterUserOutput registerUserOutput = toolService.registerNoCaptcha(registerUserInput);
+            if (StringUtils.isNotEmpty(registerUserOutput.getMsg())) {
+                deptService.deleteDeptById(dept.getDeptId());
+                sysRoleService.deleteRoleById(sysRole.getRoleId());
+                return AjaxResult.error(registerUserOutput.getMsg());
+            }
+            // 更新机构管理员角色绑定信息
+            deptService.updateDeptUserId(dept.getDeptId(), registerUserOutput.getSysUserId());
+        }
+        return toAjax(result);
+    }
+
+    /**
+     * 修改机构
+     */
+    @ApiOperation("修改机构")
+    //@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 (UserConstants.NOT_UNIQUE.equals(deptService.checkDeptNameUnique(dept))) {
+            return error(StringUtils.format(MessageUtils.message("dept.update.failed.name.exists"), dept.getDeptName()));
+        } else if (dept.getParentId().equals(deptId)) {
+            return error(StringUtils.format(MessageUtils.message("dept.update.failed.parent.not.valid"), dept.getDeptName()));
+        } else if (StringUtils.equals(UserConstants.DEPT_DISABLE, dept.getStatus()) && deptService.selectNormalChildrenDeptById(deptId) > 0) {
+            return error(MessageUtils.message("dept.update.failed.child.not.valid"));
+        }
+        dept.setUpdateBy(getUsername());
+        return toAjax(deptService.updateDept(dept));
+    }
+
+    /**
+     * 删除机构
+     */
+    @ApiOperation("根据机构编号删除机构")
+    //@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(MessageUtils.message("dept.delete.failed.child.exists"));
+        }
+//        if (deptService.checkDeptExistUser(deptId))
+//        {
+//            return warn(MessageUtils.message("dept.delete.failed.user.exists"));
+//        }
+        deptService.checkDeptDataScope(deptId);
+        // 删除机构绑定角色和用户
+        List<Long> roleIdList = sysRoleDeptMapper.selectByDeptId(deptId);
+        if (!org.springframework.util.CollectionUtils.isEmpty(roleIdList)) {
+            sysRoleService.deleteRoleByIds(roleIdList.toArray(new Long[roleIdList.size()]));
+            sysUserService.deleteUserByDeptID(deptId);
+        }
+        return toAjax(deptService.deleteDeptById(deptId));
+    }
+
+    /**
+     * 获取机构类型
+     *
+     * @param deptType 父级类型
+     * @return com.yanfan.common.core.domain.AjaxResult
+     */
+    @GetMapping("/getDeptType")
+    public AjaxResult getDeptType(HttpServletRequest request, Integer deptType, Boolean showOwner) {
+        SysDictData sysDictData = new SysDictData();
+        sysDictData.setDictType("department_type");
+        List<SysDictData> sysDictDataList = sysDictDataService.selectDictDataList(sysDictData);
+        if (CollectionUtils.isEmpty(sysDictDataList)) {
+            return success();
+        }
+        List<SysDeptTypeVO> result = new ArrayList<>();
+        for (SysDictData dictData : sysDictDataList) {
+            SysDeptTypeVO sysDeptTypeVO = new SysDeptTypeVO();
+            sysDeptTypeVO.setDeptType(Integer.valueOf(dictData.getDictValue()));
+            sysDeptTypeVO.setDeptTypeName(dictData.getDictLabel());
+            sysDeptTypeVO.setAncestors(dictData.getRemark());
+            result.add(sysDeptTypeVO);
+        }
+        if (null == deptType) {
+            return success(result);
+        }
+        SysDeptTypeVO sysDeptTypeVO = result
+                .stream()
+                .filter(d -> deptType.equals(d.getDeptType()))
+                .findFirst()
+                .orElse(null);
+        if (ObjectUtil.isNull(sysDeptTypeVO)) {
+            return success(new ArrayList<>());
+        }
+        String ancestors = sysDeptTypeVO.getAncestors();
+        result = result
+                .stream()
+                .filter(d -> ancestors.contains(d.getDeptType().toString()))
+                .collect(Collectors.toList());
+        if (showOwner) {
+            List<SysDeptTypeVO> newResult = new ArrayList<>();
+            newResult.add(sysDeptTypeVO);
+            newResult.addAll(result);
+            return success(newResult);
+        }
+        return success(result);
+    }
+
+    /**
+     * 获取机构角色
+     *
+     * @param deptId 机构id
+     * @return com.yanfan.common.core.domain.AjaxResult
+     */
+    @GetMapping("/getRole")
+    public AjaxResult getRole(Long deptId) {
+        AjaxResult success = AjaxResult.success();
+        List<SysRole> sysRoleList = deptService.getRole(deptId);
+        success.put("roles", sysRoleList);
+        success.put("roleIds", sysRoleList.stream().map(SysRole::getRoleId).collect(Collectors.toList()));
+        return success;
+    }
+
+}

+ 106 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDictDataController.java

@@ -0,0 +1,106 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysDictData;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.service.ISysDictDataService;
+import com.yanfan.system.service.ISysDictTypeService;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 数据字典信息
+ *
+ * @author ruoyi
+ */
+@RestController
+@RequestMapping("/system/dict/data")
+public class SysDictDataController extends BaseController {
+    @Autowired
+    private ISysDictDataService dictDataService;
+
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    //@PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictData dictData) {
+        startPage();
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        return getDataTable(list);
+    }
+
+    @Log(title = "字典数据", businessType = BusinessType.EXPORT)
+    //@PreAuthorize("@ss.hasPermi('system:dict:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysDictData dictData) {
+        List<SysDictData> list = dictDataService.selectDictDataList(dictData);
+        ExcelUtil<SysDictData> util = new ExcelUtil<SysDictData>(SysDictData.class);
+        util.exportExcel(response, list, "字典数据");
+    }
+
+    /**
+     * 查询字典数据详细
+     */
+    //@PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictCode}")
+    public AjaxResult getInfo(@PathVariable Long dictCode) {
+        return success(dictDataService.selectDictDataById(dictCode));
+    }
+
+    /**
+     * 根据字典类型查询字典数据信息
+     */
+    @GetMapping(value = "/type/{dictType}")
+    public AjaxResult dictType(@PathVariable String dictType) {
+        List<SysDictData> data = dictTypeService.selectDictDataByType(dictType);
+        if (StringUtils.isNull(data)) {
+            data = new ArrayList<SysDictData>();
+        }
+        return success(data);
+    }
+
+    /**
+     * 新增字典类型
+     */
+    //@PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典数据", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictData dict) {
+        dict.setCreateBy(getUsername());
+        return toAjax(dictDataService.insertDictData(dict));
+    }
+
+    /**
+     * 修改保存字典类型
+     */
+    //@PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典数据", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictData dict) {
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictDataService.updateDictData(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    //@PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictCodes}")
+    public AjaxResult remove(@PathVariable Long[] dictCodes) {
+        dictDataService.deleteDictDataByIds(dictCodes);
+        return success();
+    }
+}

+ 128 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysDictTypeController.java

@@ -0,0 +1,128 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysDictType;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.service.ISysDictTypeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 数据字典信息
+ *
+ * @author ruoyi
+ */
+@Api(tags = "字典管理")
+@RestController
+@RequestMapping("/system/dict/type")
+public class SysDictTypeController extends BaseController {
+    @Autowired
+    private ISysDictTypeService dictTypeService;
+
+    @ApiOperation("获取字典分页列表")
+    //@PreAuthorize("@ss.hasPermi('system:dict:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysDictType dictType) {
+        startPage();
+        List<SysDictType> list = dictTypeService.selectDictTypeList(dictType);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出字典列表")
+    @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, "字典类型");
+    }
+
+    /**
+     * 查询字典类型详细
+     */
+    @ApiOperation("查询字典类型详细")
+    //@PreAuthorize("@ss.hasPermi('system:dict:query')")
+    @GetMapping(value = "/{dictId}")
+    public AjaxResult getInfo(@PathVariable Long dictId) {
+        return success(dictTypeService.selectDictTypeById(dictId));
+    }
+
+    /**
+     * 新增字典类型
+     */
+    @ApiOperation("新增字典类型")
+    //@PreAuthorize("@ss.hasPermi('system:dict:add')")
+    @Log(title = "字典类型", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysDictType dict) {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) {
+            return error(StringUtils.format(MessageUtils.message("dict.add.failed.type.exists"), dict.getDictName()));
+        }
+        dict.setCreateBy(getUsername());
+        return toAjax(dictTypeService.insertDictType(dict));
+    }
+
+    /**
+     * 修改字典类型
+     */
+    @ApiOperation("新增字典类型")
+    //@PreAuthorize("@ss.hasPermi('system:dict:edit')")
+    @Log(title = "字典类型", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysDictType dict) {
+        if (UserConstants.NOT_UNIQUE.equals(dictTypeService.checkDictTypeUnique(dict))) {
+            return error(StringUtils.format(MessageUtils.message("dict.update.failed.type.exists"), dict.getDictName()));
+        }
+        dict.setUpdateBy(getUsername());
+        return toAjax(dictTypeService.updateDictType(dict));
+    }
+
+    /**
+     * 删除字典类型
+     */
+    @ApiOperation("删除字典类型")
+    //@PreAuthorize("@ss.hasPermi('system:dict:remove')")
+    @Log(title = "字典类型", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{dictIds}")
+    public AjaxResult remove(@PathVariable Long[] dictIds) {
+        dictTypeService.deleteDictTypeByIds(dictIds);
+        return success();
+    }
+
+    /**
+     * 刷新字典缓存
+     */
+    @ApiOperation("刷新字典缓存")
+    //@PreAuthorize("@ss.hasPermi('system:dict:refresh')")
+    @Log(title = "字典类型", businessType = BusinessType.CLEAN)
+    @DeleteMapping("/refreshCache")
+    public AjaxResult refreshCache() {
+        dictTypeService.resetDictCache();
+        return success();
+    }
+
+    /**
+     * 获取字典选择框列表
+     */
+    @ApiOperation("获取字典选择框列表")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect() {
+        List<SysDictType> dictTypes = dictTypeService.selectDictTypeAll();
+        return success(dictTypes);
+    }
+}

+ 30 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysIndexController.java

@@ -0,0 +1,30 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.config.RuoYiConfig;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 首页
+ *
+ * @author ruoyi
+ */
+@RestController
+public class SysIndexController {
+    /**
+     * 系统基础配置
+     */
+    @Autowired
+    private RuoYiConfig ruoyiConfig;
+
+    /**
+     * 访问首页,提示语
+     */
+    @RequestMapping("/")
+    public String index() {
+        return StringUtils.format(MessageUtils.message("index.welcome.message"), ruoyiConfig.getName(), ruoyiConfig.getVersion());
+    }
+}

+ 105 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysLoginController.java

@@ -0,0 +1,105 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.constant.Constants;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysMenu;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.domain.model.LoginBody;
+import com.yanfan.common.utils.SecurityUtils;
+import com.yanfan.framework.web.service.SysLoginService;
+import com.yanfan.framework.web.service.SysPermissionService;
+import com.yanfan.system.domain.AppPreferences;
+import com.yanfan.system.service.IAppPreferencesService;
+import com.yanfan.system.service.ISysMenuService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+import java.util.Set;
+
+import static com.yanfan.common.constant.Constants.LANGUAGE;
+
+/**
+ * 登录验证
+ *
+ * @author ruoyi
+ */
+@Api(tags = "登录验证")
+@RestController
+public class SysLoginController {
+    @Autowired
+    private SysLoginService loginService;
+
+    @Autowired
+    private ISysMenuService menuService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+    @Value("${server.broker.enabled}")
+    private Boolean enabled;
+    @Autowired
+    private IAppPreferencesService appPreferencesService;
+
+
+    /**
+     * 登录方法
+     *
+     * @param loginBody 登录信息
+     * @return 结果
+     */
+    @ApiOperation("用户登录")
+    @PostMapping("/login")
+    public AjaxResult login(HttpServletRequest request, @RequestBody LoginBody loginBody) {
+        AjaxResult ajax = AjaxResult.success();
+        // 生成令牌
+        String token = loginService.login(loginBody.getUsername(), loginBody.getPassword(), loginBody.getCode(), loginBody.getUuid(), loginBody.getSourceType(), request.getHeader(LANGUAGE));
+        ajax.put(Constants.TOKEN, token);
+        return ajax;
+    }
+
+    /**
+     * 获取用户信息
+     *
+     * @return 用户信息
+     */
+    @ApiOperation("获取用户信息")
+    @GetMapping("getInfo")
+    public AjaxResult getInfo() {
+        SysUser user = SecurityUtils.getLoginUser().getUser();
+        // 角色集合
+        Set<String> roles = permissionService.getRolePermission(user);
+        // 权限集合
+        Set<String> permissions = permissionService.getMenuPermission(user);
+        AppPreferences appPreferences = appPreferencesService.selectAppPreferencesByUserId(user.getUserId());
+        //部门的菜单
+        Set<String> deptMenu = permissionService.getDeptMenu(user);
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("user", user);
+        ajax.put("deptMenu", deptMenu);
+        ajax.put("roles", roles);
+        ajax.put("permissions", permissions);
+        ajax.put("mqtt", enabled);
+        ajax.put("language", appPreferences.getLanguage());
+        return ajax;
+    }
+
+    /**
+     * 获取路由信息
+     *
+     * @return 路由信息
+     */
+    @ApiOperation("获取路由信息")
+    @GetMapping("getRouters")
+    public AjaxResult getRouters(HttpServletRequest request) {
+        Long userId = SecurityUtils.getUserId();
+        List<SysMenu> menus = menuService.selectMenuTreeByUserId(userId, request.getHeader(LANGUAGE));
+        return AjaxResult.success(menuService.buildMenus(menus));
+    }
+}

+ 150 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysMenuController.java

@@ -0,0 +1,150 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysMenu;
+import com.yanfan.common.core.domain.entity.vo.SysMenuVo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.system.service.ISysMenuService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 java.util.List;
+
+/**
+ * 菜单信息
+ *
+ * @author ruoyi
+ */
+@Api(tags = "菜单管理")
+@RestController
+@RequestMapping("/system/menu")
+public class SysMenuController extends BaseController {
+    @Autowired
+    private ISysMenuService menuService;
+
+    /**
+     * 获取菜单列表
+     */
+    @ApiOperation("获取菜单列表")
+    //@PreAuthorize("@ss.hasPermi('system:menu:list')")
+    @GetMapping("/list")
+    public AjaxResult list(SysMenu menu) {
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
+        return success(menus);
+    }
+
+    /**
+     * 获取菜单列表
+     */
+    @GetMapping("/listmenu")
+    public AjaxResult listmenu() {
+        List<SysMenuVo> sysMenuVos = menuService.selectSysMenuVo();
+        return success(sysMenuVos);
+    }
+
+    /**
+     * 根据菜单编号获取详细信息
+     */
+    @ApiOperation("根据菜单编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:menu:query')")
+    @GetMapping(value = "/{menuId}")
+    public AjaxResult getInfo(@PathVariable Long menuId) {
+        return success(menuService.selectMenuById(menuId));
+    }
+
+    /**
+     * 获取菜单下拉树列表
+     */
+    @ApiOperation("获取菜单下拉树列表")
+    @GetMapping("/treeselect")
+    public AjaxResult treeselect(SysMenu menu) {
+        List<SysMenu> menus = menuService.selectMenuList(menu, getUserId());
+        return success(menuService.buildMenuTreeSelect(menus));
+    }
+
+    /**
+     * 加载对应角色菜单列表树
+     */
+    @ApiOperation("加载对应角色菜单列表树")
+    @GetMapping(value = "/roleMenuTreeselect")
+    public AjaxResult roleMenuTreeselect(@RequestParam Long roleId, @RequestParam Long deptId) {
+        List<SysMenu> menus = menuService.deptRoleMenuTreeselect(deptId, roleId);
+//        List<SysMenu> menus = menuService.selectMenuList(getUserId(), request.getHeader(LANGUAGE));
+        AjaxResult ajax = AjaxResult.success();
+        ajax.put("checkedKeys", menuService.selectMenuListByRoleId(roleId));
+        ajax.put("menus", menuService.buildMenuTreeSelect(menus));
+        return ajax;
+    }
+
+    /**
+     * 新增菜单
+     */
+    @ApiOperation("新增菜单")
+    //@PreAuthorize("@ss.hasPermi('system:menu:add')")
+    @Log(title = "菜单管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysMenu menu) {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
+            return error(StringUtils.format(MessageUtils.message("menu.add.failed.name.exists"), menu.getMenuName()));
+        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+            return error(StringUtils.format(MessageUtils.message("menu.add.failed.path.not.valid"), menu.getMenuName()));
+        }
+        menu.setCreateBy(getUsername());
+        return toAjax(menuService.insertMenu(menu));
+    }
+
+    /**
+     * 修改菜单
+     */
+    @ApiOperation("修改菜单")
+    //@PreAuthorize("@ss.hasPermi('system:menu:edit')")
+    @Log(title = "菜单管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysMenu menu) {
+        if (UserConstants.NOT_UNIQUE.equals(menuService.checkMenuNameUnique(menu))) {
+            return error(StringUtils.format(MessageUtils.message("menu.update.failed.name.exists"), menu.getMenuName()));
+        } else if (UserConstants.YES_FRAME.equals(menu.getIsFrame()) && !StringUtils.ishttp(menu.getPath())) {
+            return error(StringUtils.format(MessageUtils.message("menu.update.failed.path.not.valid"), menu.getMenuName()));
+        } else if (menu.getMenuId().equals(menu.getParentId())) {
+            return error(StringUtils.format(MessageUtils.message("menu.update.failed.parent.not.valid"), menu.getMenuName()));
+        }
+        menu.setUpdateBy(getUsername());
+        return toAjax(menuService.updateMenu(menu));
+    }
+
+    /**
+     * 删除菜单
+     */
+    @ApiOperation("删除菜单")
+    //@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(MessageUtils.message("menu.delete.failed.child.exists"));
+        }
+        if (menuService.checkMenuExistRole(menuId)) {
+            return warn(MessageUtils.message("menu.delete.failed.role.exists"));
+        }
+        return toAjax(menuService.deleteMenuById(menuId));
+    }
+
+    /**
+     * 加载对应部门菜单列表树
+     */
+    @ApiOperation("加载对应部门菜单列表树")
+    @GetMapping(value = "/deptMenuTreeselect/{deptId}")
+    public AjaxResult deptMenuTreeselect(@PathVariable("deptId") Long deptId) {
+        List<SysMenu> menus = menuService.deptMenuTreeselect(deptId);
+        return success(menuService.buildMenuTreeSelect(menus));
+    }
+}

+ 87 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysNoticeController.java

@@ -0,0 +1,87 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.system.domain.SysNotice;
+import com.yanfan.system.service.ISysNoticeService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 java.util.List;
+
+/**
+ * 公告 信息操作处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "通知公告")
+@RestController
+@RequestMapping("/system/notice")
+public class SysNoticeController extends BaseController {
+    @Autowired
+    private ISysNoticeService noticeService;
+
+    /**
+     * 获取通知公告列表
+     */
+    @ApiOperation("获取通知公告列表")
+    // //@PreAuthorize("@ss.hasPermi('system:notice:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysNotice notice) {
+        startPage();
+        List<SysNotice> list = noticeService.selectNoticeList(notice);
+        return getDataTable(list);
+    }
+
+    /**
+     * 根据通知公告编号获取详细信息
+     */
+    @ApiOperation("根据通知公告编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:notice:query')")
+    @GetMapping(value = "/{noticeId}")
+    public AjaxResult getInfo(@PathVariable Long noticeId) {
+        return success(noticeService.selectNoticeById(noticeId));
+    }
+
+    /**
+     * 新增通知公告
+     */
+    @ApiOperation("新增通知公告")
+    //@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));
+    }
+
+    /**
+     * 修改通知公告
+     */
+    @ApiOperation("修改通知公告")
+    //@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));
+    }
+
+    /**
+     * 删除通知公告
+     */
+    @ApiOperation("删除通知公告")
+    //@PreAuthorize("@ss.hasPermi('system:notice:remove')")
+    @Log(title = "通知公告", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{noticeIds}")
+    public AjaxResult remove(@PathVariable Long[] noticeIds) {
+        return toAjax(noticeService.deleteNoticeByIds(noticeIds));
+    }
+}

+ 122 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysPostController.java

@@ -0,0 +1,122 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.domain.SysPost;
+import com.yanfan.system.service.ISysPostService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 岗位信息操作处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "岗位管理")
+@RestController
+@RequestMapping("/system/post")
+public class SysPostController extends BaseController {
+    @Autowired
+    private ISysPostService postService;
+
+    /**
+     * 获取岗位列表
+     */
+    @ApiOperation("获取岗位列表")
+    //@PreAuthorize("@ss.hasPermi('system:post:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysPost post) {
+        startPage();
+        List<SysPost> list = postService.selectPostList(post);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出岗位列表")
+    @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, "岗位数据");
+    }
+
+    /**
+     * 根据岗位编号获取详细信息
+     */
+    @ApiOperation("根据岗位编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:post:query')")
+    @GetMapping(value = "/{postId}")
+    public AjaxResult getInfo(@PathVariable Long postId) {
+        return success(postService.selectPostById(postId));
+    }
+
+    /**
+     * 新增岗位
+     */
+    @ApiOperation("新增岗位")
+    //@PreAuthorize("@ss.hasPermi('system:post:add')")
+    @Log(title = "岗位管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysPost post) {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) {
+            return error(StringUtils.format(MessageUtils.message("post.add.failed.name.exists"), post.getPostName()));
+        } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) {
+            return error(StringUtils.format(MessageUtils.message("post.add.failed.code.exists"), post.getPostName()));
+        }
+        post.setCreateBy(getUsername());
+        return toAjax(postService.insertPost(post));
+    }
+
+    /**
+     * 修改岗位
+     */
+    @ApiOperation("修改岗位")
+    //@PreAuthorize("@ss.hasPermi('system:post:edit')")
+    @Log(title = "岗位管理", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult edit(@Validated @RequestBody SysPost post) {
+        if (UserConstants.NOT_UNIQUE.equals(postService.checkPostNameUnique(post))) {
+            return error(StringUtils.format(MessageUtils.message("post.update.failed.name.exists"), post.getPostName()));
+        } else if (UserConstants.NOT_UNIQUE.equals(postService.checkPostCodeUnique(post))) {
+            return error(StringUtils.format(MessageUtils.message("post.update.failed.code.exists"), post.getPostName()));
+        }
+        post.setUpdateBy(getUsername());
+        return toAjax(postService.updatePost(post));
+    }
+
+    /**
+     * 删除岗位
+     */
+    @ApiOperation("删除岗位")
+    //@PreAuthorize("@ss.hasPermi('system:post:remove')")
+    @Log(title = "岗位管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{postIds}")
+    public AjaxResult remove(@PathVariable Long[] postIds) {
+        return toAjax(postService.deletePostByIds(postIds));
+    }
+
+    /**
+     * 获取岗位选择框列表
+     */
+    @ApiOperation("获取岗位选择框列表")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect() {
+        List<SysPost> posts = postService.selectPostAll();
+        return success(posts);
+    }
+}

+ 149 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysProfileController.java

@@ -0,0 +1,149 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.config.RuoYiConfig;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.domain.model.LoginUser;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.enums.SocialPlatformType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.SecurityUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.file.FileUploadUtils;
+import com.yanfan.common.utils.file.MimeTypeUtils;
+import com.yanfan.framework.web.service.TokenService;
+import com.yanfan.iot.domain.UserSocialProfile;
+import com.yanfan.iot.service.IUserSocialProfileService;
+import com.yanfan.system.service.ISysUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.util.List;
+
+/**
+ * 个人信息 业务处理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "个人中心")
+@RestController
+@RequestMapping("/system/user/profile")
+public class SysProfileController extends BaseController {
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private IUserSocialProfileService iUserSocialProfileService;
+
+    /**
+     * 个人信息
+     */
+    @ApiOperation("获取个人信息")
+    @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()));
+        List<UserSocialProfile> socialProfileList = iUserSocialProfileService.selectUserSocialProfile(loginUser.getUserId());
+        UserSocialProfile userSocialProfile = socialProfileList
+                .stream()
+                .filter(s -> SocialPlatformType.listWechatPlatform.contains(s.getSourceClient()) && "1".equals(s.getStatus()))
+                .findFirst()
+                .orElse(null);
+        ajax.put("socialGroup", socialProfileList);
+        ajax.put("wxBind", userSocialProfile != null);
+        return ajax;
+    }
+
+    /**
+     * 修改用户
+     */
+    @ApiOperation("修改个人信息")
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping
+    public AjaxResult updateProfile(@RequestBody SysUser user) {
+        LoginUser loginUser = getLoginUser();
+        SysUser sysUser = loginUser.getUser();
+        user.setUserName(sysUser.getUserName());
+        if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.update.failed.phone.exists"), user.getUserName()));
+        }
+        if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.update.failed.email.exists"), user.getUserName()));
+        }
+        user.setUserId(sysUser.getUserId());
+        user.setPassword(null);
+        user.setAvatar(null);
+        user.setDeptId(sysUser.getDeptId());
+        if (userService.updateUserProfile(user) > 0) {
+            // 更新缓存用户信息
+            sysUser.setNickName(user.getNickName());
+            sysUser.setPhonenumber(user.getPhonenumber());
+            sysUser.setEmail(user.getEmail());
+            sysUser.setSex(user.getSex());
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error(MessageUtils.message("user.update.failed"));
+    }
+
+    /**
+     * 重置密码
+     */
+    @ApiOperation("重置密码")
+    //@PreAuthorize("@ss.hasPermi('systerm:user:updatePwd')")
+    @Log(title = "个人信息", businessType = BusinessType.UPDATE)
+    @PutMapping("/updatePwd")
+    public AjaxResult updatePwd(String oldPassword, String newPassword) {
+        LoginUser loginUser = getLoginUser();
+        String userName = loginUser.getUsername();
+        String password = loginUser.getPassword();
+        if (!SecurityUtils.matchesPassword(oldPassword, password)) {
+            return error(MessageUtils.message("user.update.failed.password.wrong"));
+        }
+        if (SecurityUtils.matchesPassword(newPassword, password)) {
+            return error(MessageUtils.message("user.update.failed.password.same"));
+        }
+        if (userService.resetUserPwd(userName, SecurityUtils.encryptPassword(newPassword)) > 0) {
+            // 更新缓存用户密码
+            loginUser.getUser().setPassword(SecurityUtils.encryptPassword(newPassword));
+            tokenService.setLoginUser(loginUser);
+            return success();
+        }
+        return error(MessageUtils.message("user.update.password.failed"));
+    }
+
+    /**
+     * 头像上传
+     */
+    @ApiOperation("头像上传")
+    @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(MessageUtils.message("user.upload.avatar.failed"));
+    }
+}

+ 97 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysRegisterController.java

@@ -0,0 +1,97 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.domain.model.RegisterBody;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.framework.web.service.SysRegisterService;
+import com.yanfan.iot.domain.Device;
+import com.yanfan.iot.domain.DeviceShare;
+import com.yanfan.iot.domain.Product;
+import com.yanfan.iot.mapper.DeviceMapper;
+import com.yanfan.iot.mapper.ProductMapper;
+import com.yanfan.iot.model.ThingsModelPerm;
+import com.yanfan.iot.service.IDeviceShareService;
+import com.yanfan.iot.service.IThingsModelService;
+import com.yanfan.system.service.ISysConfigService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 注册验证
+ *
+ * @author ruoyi
+ */
+@Api(tags = "注册账号")
+@RestController
+public class SysRegisterController extends BaseController {
+    @Autowired
+    private SysRegisterService registerService;
+
+    @Autowired
+    private ISysConfigService configService;
+
+    @Autowired
+    private DeviceMapper deviceMapper;
+
+    @Autowired
+    private ProductMapper productMapper;
+
+    @Autowired
+    private IThingsModelService thingsModelService;
+
+    @Autowired
+    private IDeviceShareService deviceShareService;
+
+    @ApiOperation("注册账号")
+    @PostMapping("/register")
+    public AjaxResult register(@RequestBody RegisterBody user) {
+        if (!("true".equals(configService.selectConfigByKey("sys.account.registerUser")))) {
+            return error("当前系统没有开启注册功能!");
+        }
+        //完成用户注册
+        String msg = registerService.register(user);
+        //当sys.device.sbfx为false时,走用户注册后完成设备的分配
+        if (!("true".equals(configService.selectConfigByKey("sys.device.sbfx")))) {
+            //需要的结构
+            DeviceShare deviceShare = new DeviceShare();
+            deviceShare.setPhonenumber(user.getPhonenumber());
+            deviceShare.setDelFlag("0");
+            SysUser users = registerService.getuser(user.getPhonenumber());
+            deviceShare.setUserId(users.getUserId());
+            //获取客户测试下面的所有机构
+            Device device = new Device();
+            device.setTenantId(9L);
+            List<Device> deviceslist = deviceMapper.selectDeviceList(device);
+            for (Device devices : deviceslist) {
+                //获取对应的产品类型
+                Product product = productMapper.selectProductByProductId(devices.getProductId());
+                if (product == null) {
+                    continue;
+                }
+                deviceShare.setDeviceId(devices.getDeviceId());
+                List<ThingsModelPerm> list = thingsModelService.selectThingsModelPermList(product.getProductId());
+                String substrings = "ota,timer,log,monitor,statistic";
+                if (list != null && list.size() > 0) {
+                    String identifiers = list
+                            .stream()
+                            .filter(item -> item.getIdentifier() != null)
+                            .map(ThingsModelPerm::getIdentifier)
+                            .collect(Collectors.joining(","));
+                    substrings = substrings + "," + identifiers;
+                }
+                deviceShare.setPerms(substrings);
+                deviceShareService.insertDeviceShare(deviceShare);
+            }
+        }
+        return StringUtils.isEmpty(msg) ? success() : error(msg);
+    }
+}

+ 274 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysRoleController.java

@@ -0,0 +1,274 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.HttpStatus;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysDept;
+import com.yanfan.common.core.domain.entity.SysRole;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.domain.model.LoginUser;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.collection.CollectionUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.framework.web.service.SysPermissionService;
+import com.yanfan.framework.web.service.TokenService;
+import com.yanfan.system.domain.SysUserRole;
+import com.yanfan.system.service.ISysDeptService;
+import com.yanfan.system.service.ISysRoleService;
+import com.yanfan.system.service.ISysUserService;
+import com.github.pagehelper.PageInfo;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 角色信息
+ *
+ * @author ruoyi
+ */
+@Api(tags = "角色管理")
+@RestController
+@RequestMapping("/system/role")
+public class SysRoleController extends BaseController {
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private TokenService tokenService;
+
+    @Autowired
+    private SysPermissionService permissionService;
+
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @ApiOperation("获取角色分页列表")
+    ////@PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysRole role, Integer pageNum, Integer pageSize) {
+//        startPage();
+        List<SysRole> list = roleService.selectRoleList(role);
+        TableDataInfo tableDataInfo = new TableDataInfo();
+        tableDataInfo.setCode(HttpStatus.SUCCESS);
+        tableDataInfo.setMsg(MessageUtils.message("query.success"));
+        if (org.apache.commons.collections4.CollectionUtils.isEmpty(list)) {
+            tableDataInfo.setRows(list);
+            tableDataInfo.setTotal(0);
+        } else {
+            List list1 = CollectionUtils.startPage(list, pageNum, pageSize);
+            tableDataInfo.setRows(list1);
+            tableDataInfo.setTotal(new PageInfo(list).getTotal());
+        }
+        return tableDataInfo;
+    }
+
+    @ApiOperation("导出角色列表")
+    @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, "角色数据");
+    }
+
+    /**
+     * 根据角色编号获取详细信息
+     */
+    @ApiOperation("根据角色编号获取详细信息")
+    ////@PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping(value = "/{roleId}")
+    public AjaxResult getInfo(@PathVariable Long roleId) {
+        roleService.checkRoleDataScope(roleId);
+        return success(roleService.selectRoleById(roleId));
+    }
+
+    /**
+     * 新增角色
+     */
+    @ApiOperation("新增角色")
+    ////@PreAuthorize("@ss.hasPermi('system:role:add')")
+    @Log(title = "角色管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysRole role) {
+//        if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+//        {
+//            return error(StringUtils.format(MessageUtils.message("role.add.failed.name.exists"), role.getRoleName()));
+//        }
+//        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+//        {
+//            return error(StringUtils.format(MessageUtils.message("role.add.failed.key.exists"), role.getRoleName()));
+//        }
+        if ("manager".equals(role.getRoleKey())) {
+            return error(MessageUtils.message("role.add.manager.failed"));
+        }
+        role.setCreateBy(getUsername());
+        return toAjax(roleService.insertRole(role));
+
+    }
+
+    /**
+     * 修改保存角色
+     */
+    @ApiOperation("修改角色")
+    ////@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 (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleNameUnique(role)))
+//        {
+//            return error(StringUtils.format(MessageUtils.message("role.update.failed.name.exists"), role.getRoleName()));
+//        }
+//        else if (UserConstants.NOT_UNIQUE.equals(roleService.checkRoleKeyUnique(role)))
+//        {
+//            return error(StringUtils.format(MessageUtils.message("role.update.failed.key.exists"), role.getRoleName()));
+//        }
+        role.setUpdateBy(getUsername());
+
+        if (roleService.updateRole(role) > 0) {
+            // 更新缓存用户权限
+            LoginUser loginUser = getLoginUser();
+            if (StringUtils.isNotNull(loginUser.getUser()) && !loginUser.getUser().isAdmin()) {
+                loginUser.setPermissions(permissionService.getMenuPermission(loginUser.getUser()));
+                loginUser.setUser(userService.selectUserByUserName(loginUser.getUser().getUserName()));
+                tokenService.setLoginUser(loginUser);
+            }
+            return success();
+        }
+        return error(StringUtils.format(MessageUtils.message("role.update.failed"), role.getRoleName()));
+    }
+
+    /**
+     * 修改保存数据权限
+     */
+    @ApiOperation("修改保存数据权限")
+    ////@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));
+    }
+
+    /**
+     * 状态修改
+     */
+    @ApiOperation("修改角色状态")
+    ////@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));
+    }
+
+    /**
+     * 删除角色
+     */
+    @ApiOperation("删除角色")
+    ////@PreAuthorize("@ss.hasPermi('system:role:remove')")
+    @Log(title = "角色管理", businessType = BusinessType.DELETE)
+    @DeleteMapping("/{roleIds}")
+    public AjaxResult remove(@PathVariable Long[] roleIds) {
+        return toAjax(roleService.deleteRoleByIds(roleIds));
+    }
+
+    /**
+     * 获取角色选择框列表
+     */
+    @ApiOperation("获取角色选择框列表")
+    //@PreAuthorize("@ss.hasPermi('system:role:query')")
+    @GetMapping("/optionselect")
+    public AjaxResult optionselect() {
+        return success(roleService.selectRoleAll());
+    }
+
+    /**
+     * 查询已分配用户角色列表
+     */
+    @ApiOperation("查询已分配用户角色列表")
+    //@PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/allocatedList")
+    public TableDataInfo allocatedList(SysUser user) {
+        startPage();
+        List<SysUser> list = userService.selectAllocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 查询未分配用户角色列表
+     */
+    @ApiOperation("查询未分配用户角色列表")
+    //@PreAuthorize("@ss.hasPermi('system:role:list')")
+    @GetMapping("/authUser/unallocatedList")
+    public TableDataInfo unallocatedList(SysUser user) {
+        startPage();
+        List<SysUser> list = userService.selectUnallocatedList(user);
+        return getDataTable(list);
+    }
+
+    /**
+     * 取消授权用户
+     */
+    @ApiOperation("取消授权用户")
+    //@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));
+    }
+
+    /**
+     * 批量取消授权用户
+     */
+    @ApiOperation("批量取消授权用户")
+    //@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));
+    }
+
+    /**
+     * 批量选择用户授权
+     */
+    @ApiOperation("批量选择用户授权")
+    //@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));
+    }
+
+    /**
+     * 获取对应角色部门树列表
+     */
+    @ApiOperation("获取对应角色部门树列表")
+    //@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;
+    }
+}

+ 78 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysTranslateController.java

@@ -0,0 +1,78 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysTranslate;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.service.ISysTranslateService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.PostMapping;
+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 javax.servlet.http.HttpServletResponse;
+import java.util.List;
+
+/**
+ * 翻译表管理
+ *
+ * @author ruoyi
+ */
+@Api(tags = "翻译表管理")
+@RestController
+@RequestMapping("/system/translate")
+public class SysTranslateController extends BaseController {
+    @Autowired
+    private ISysTranslateService sysTranslateService;
+
+    /**
+     * 导入翻译列表
+     */
+    @ApiOperation("导入翻译列表")
+    //@PreAuthorize("@ss.hasPermi('system:translate:import')")
+    @PostMapping("/import")
+    public AjaxResult importSysTranslate(MultipartFile file, String type, Long productId) throws Exception {
+        if (null == file) {
+            return error(MessageUtils.message("import.failed.file.null"));
+        }
+        if (StringUtils.isEmpty(type)) {
+            return error();
+        }
+        ExcelUtil<SysTranslate> util = new ExcelUtil<>(SysTranslate.class);
+        List<SysTranslate> list = util.importExcel(file.getInputStream());
+        if (CollectionUtils.isEmpty(list)) {
+            return error(MessageUtils.message("import.failed.data.null"));
+        }
+        sysTranslateService.importSysTranslate(list, type, productId);
+        return success(MessageUtils.message("import.success"));
+    }
+
+    /**
+     * 导出翻译列表
+     */
+    @ApiOperation("导出翻译列表")
+    //@PreAuthorize("@ss.hasPermi('system:translate:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysTranslate sysTranslate, String type, @RequestParam(name = "isSource", required = false, defaultValue = "0") Boolean isSource) {
+        if (StringUtils.isEmpty(type)) {
+            return;
+        }
+        List<SysTranslate> list;
+        if (isSource) {
+            list = sysTranslateService.selectSourceList(type, sysTranslate.getProductId());
+        } else {
+            list = sysTranslateService.selectSysTranslateList(sysTranslate, type);
+        }
+        ExcelUtil<SysTranslate> util = new ExcelUtil<>(SysTranslate.class);
+        util.exportExcel(response, list, "翻译列表");
+    }
+
+}

+ 281 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/system/SysUserController.java

@@ -0,0 +1,281 @@
+package com.yanfan.web.controller.system;
+
+import com.yanfan.common.annotation.Log;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.entity.SysDept;
+import com.yanfan.common.core.domain.entity.SysRole;
+import com.yanfan.common.core.domain.entity.SysUser;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.utils.MessageUtils;
+import com.yanfan.common.utils.SecurityUtils;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.system.service.ISysDeptService;
+import com.yanfan.system.service.ISysPostService;
+import com.yanfan.system.service.ISysRoleService;
+import com.yanfan.system.service.ISysUserService;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+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.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletResponse;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * 用户信息
+ *
+ * @author ruoyi
+ */
+@Api(tags = "用户管理")
+@RestController
+@RequestMapping("/system/user")
+public class SysUserController extends BaseController {
+    @Autowired
+    private ISysUserService userService;
+
+    @Autowired
+    private ISysRoleService roleService;
+
+    @Autowired
+    private ISysDeptService deptService;
+
+    @Autowired
+    private ISysPostService postService;
+
+    /**
+     * 获取用户列表
+     */
+    @ApiOperation("获取用户分页列表")
+    //@PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/list")
+    public TableDataInfo list(SysUser user) {
+        startPage();
+        if (null == user.getDeptId()) {
+            user.setDeptId(getLoginUser().getDeptId());
+        }
+        List<SysUser> list = userService.selectUserList(user);
+        return getDataTable(list);
+    }
+
+    @ApiOperation("导出用户列表")
+    @Log(title = "用户管理", businessType = BusinessType.EXPORT)
+    //@PreAuthorize("@ss.hasPermi('system:user:export')")
+    @PostMapping("/export")
+    public void export(HttpServletResponse response, SysUser user) {
+        if (null == user.getDeptId()) {
+            user.setDeptId(getLoginUser().getDeptId());
+        }
+        List<SysUser> list = userService.selectUserList(user);
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.exportExcel(response, list, "用户数据");
+    }
+
+    @ApiOperation("批量导入用户")
+    @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);
+    }
+
+
+    @ApiOperation("下载用户导入模板")
+    @PostMapping("/importTemplate")
+    public void importTemplate(HttpServletResponse response) {
+        ExcelUtil<SysUser> util = new ExcelUtil<SysUser>(SysUser.class);
+        util.importTemplateExcel(response, "用户数据");
+    }
+
+    /**
+     * 根据用户编号获取详细信息
+     */
+    @ApiOperation("根据用户编号获取详细信息")
+    //@PreAuthorize("@ss.hasPermi('system:user:query')")
+    @GetMapping(value = {"/", "/{userId}"})
+    public AjaxResult getInfo(@PathVariable(value = "userId", required = false) Long userId) {
+        userService.checkUserDataScope(userId);
+        AjaxResult ajax = AjaxResult.success();
+//        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());
+        if (StringUtils.isNotNull(userId)) {
+            SysUser sysUser = userService.selectUserById(userId);
+            ajax.put(AjaxResult.DATA_TAG, sysUser);
+            ajax.put("postIds", postService.selectPostListByUserId(userId));
+            SysRole sysRole = new SysRole();
+            sysRole.setDeptId(sysUser.getDeptId());
+            sysRole.setShowChild(false);
+            List<SysRole> sysRoleList = roleService.selectRoleList(sysRole);
+            ajax.put("roles", sysRoleList);
+            ajax.put("roleIds", sysUser.getRoles().stream().map(SysRole::getRoleId).collect(Collectors.toList()));
+        }
+        return ajax;
+    }
+
+    /**
+     * 新增用户
+     */
+    @ApiOperation("新增用户")
+    //@PreAuthorize("@ss.hasPermi('system:user:add')")
+    @Log(title = "用户管理", businessType = BusinessType.INSERT)
+    @PostMapping
+    public AjaxResult add(@Validated @RequestBody SysUser user) {
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.add.failed.name.exists"), user.getUserName()));
+        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.add.failed.phone.exists"), user.getUserName()));
+        } else if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.add.failed.email.exists"), user.getUserName()));
+        }
+        user.setCreateBy(getUsername());
+        user.setPassword(SecurityUtils.encryptPassword(user.getPassword()));
+        return toAjax(userService.insertUser(user));
+    }
+
+    /**
+     * 修改用户
+     */
+    @ApiOperation("修改用户")
+    //@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());
+        if (UserConstants.NOT_UNIQUE.equals(userService.checkUserNameUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.update.failed.name.exists"), user.getUserName()));
+        } else if (StringUtils.isNotEmpty(user.getPhonenumber()) && UserConstants.NOT_UNIQUE.equals(userService.checkPhoneUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.update.failed.phone.exists"), user.getUserName()));
+        } else if (StringUtils.isNotEmpty(user.getEmail()) && UserConstants.NOT_UNIQUE.equals(userService.checkEmailUnique(user))) {
+            return error(StringUtils.format(MessageUtils.message("user.update.failed.email.exists"), user.getUserName()));
+        }
+        user.setUpdateBy(getUsername());
+        return toAjax(userService.updateUser(user));
+    }
+
+    /**
+     * 删除用户
+     */
+    @ApiOperation("删除用户")
+    //@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(MessageUtils.message("user.delete.failed"));
+        }
+        return toAjax(userService.deleteUserByIds(userIds));
+    }
+
+    /**
+     * 重置密码
+     */
+    @ApiOperation("重置用户密码")
+    //@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));
+    }
+
+    /**
+     * 状态修改
+     */
+    @ApiOperation("修改用户状态")
+    //@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));
+    }
+
+    /**
+     * 根据用户编号获取授权角色
+     */
+    @ApiOperation("根据用户编号获取授权角色")
+    //@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;
+    }
+
+    /**
+     * 用户授权角色
+     */
+    @ApiOperation("为用户授权角色")
+    //@PreAuthorize("@ss.hasPermi('system:user:edit')")
+    @Log(title = "用户管理", businessType = BusinessType.GRANT)
+    @PutMapping("/authRole")
+    public AjaxResult insertAuthRole(Long userId, Long[] roleIds) {
+        userService.checkUserDataScope(userId);
+        userService.insertUserAuth(userId, roleIds);
+        return success();
+    }
+
+    /**
+     * 获取部门树列表
+     */
+    @ApiOperation("获取部门树列表")
+    // //@PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/deptTree")
+    public AjaxResult deptTree(SysDept dept) {
+        return success(deptService.selectDeptTreeList(dept));
+    }
+
+    /**
+     * 获取终端用户列表
+     *
+     * @param user 用户信息
+     * @return com.yanfan.common.core.page.TableDataInfo
+     */
+    @ApiOperation("获取用户分页列表")
+    //@PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/listTerminal")
+    public TableDataInfo listTerminal(SysUser user) {
+        startPage();
+        List<SysUser> list = userService.listTerminal(user);
+        return getDataTable(list);
+    }
+
+
+    /**
+     * 根据机构id获取当前用户列表
+     */
+    @ApiOperation("根据机构id获取当前用户列表")
+    //@PreAuthorize("@ss.hasPermi('system:user:list')")
+    @GetMapping("/getByDeptId")
+    public TableDataInfo getByDeptId() {
+        startPage();
+        List<SysUser> list = userService.selectByDeptId();
+        return getDataTable(list);
+    }
+
+}

+ 22 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/tool/SwaggerController.java

@@ -0,0 +1,22 @@
+package com.yanfan.web.controller.tool;
+
+import com.yanfan.common.core.controller.BaseController;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * swagger 接口
+ *
+ * @author ruoyi
+ */
+@Controller
+@RequestMapping("/tool/swagger")
+public class SwaggerController extends BaseController {
+    //@PreAuthorize("@ss.hasPermi('tool:swagger:view')")
+    @GetMapping()
+    public String index() {
+        return redirect("/swagger-ui.html");
+    }
+}

+ 217 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/tool/TestController2.java

@@ -0,0 +1,217 @@
+package com.yanfan.web.controller.tool;
+
+import com.alibaba.fastjson2.JSON;
+import com.yanfan.common.annotation.Anonymous;
+import com.yanfan.common.core.domain.ImportExcelVO;
+import com.yanfan.common.core.domain.OutputExcelVO;
+import com.yanfan.common.utils.StringUtils;
+import com.yanfan.common.utils.poi.ExcelUtil;
+import com.yanfan.iot.domain.AlertLog;
+import com.yanfan.iot.domain.DeviceJob;
+import com.yanfan.iot.domain.DeviceLog;
+import com.yanfan.iot.mapper.AlertLogMapper;
+import com.yanfan.iot.mapper.DeviceJobMapper;
+import com.yanfan.iot.mapper.DeviceLogMapper;
+import com.yanfan.iot.mapper.DeviceMapper;
+import com.yanfan.iot.model.DeviceRelateAlertLogVO;
+import org.apache.commons.collections4.CollectionUtils;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.annotation.Resource;
+import java.util.*;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+
+
+/**
+ * 测试类
+ *
+ * @author fastb
+ * @date 2023-09-13 11:42
+ */
+@Anonymous
+@RestController
+@RequestMapping("/test2")
+public class TestController2 {
+
+    @Resource
+    private AlertLogMapper alertLogMapper;
+    @Resource
+    private DeviceMapper deviceMapper;
+
+    @Resource
+    private DeviceJobMapper deviceJobMapper;
+    @Resource
+    private DeviceLogMapper deviceLogMapper;
+
+    @GetMapping("/add")
+    public void add() {
+        Set<String> deviceNumbers = new HashSet<>();
+        deviceNumbers.add("D1PGLPG58K88");
+        deviceNumbers.add("D1F0L7P84D8Z");
+        deviceNumbers.add("D1F0L7P84D8Z_2");
+        List<DeviceRelateAlertLogVO> deviceRelateAlertLogVOList = deviceMapper.selectDeviceBySerialNumbers(deviceNumbers);
+        Map<String, DeviceRelateAlertLogVO> deviceRelateAlertLogVOMap = deviceRelateAlertLogVOList
+                .stream()
+                .collect(Collectors.toMap(DeviceRelateAlertLogVO::getSerialNumber, Function.identity()));
+
+        ArrayList<AlertLog> alertLogList = new ArrayList<>();
+        for (String deviceNumber : deviceNumbers) {
+            AlertLog alertLog = new AlertLog();
+            alertLog.setSerialNumber(deviceNumber);
+            alertLog.setAlertName("温度告警测试");
+            alertLog.setAlertLevel(1L);
+            alertLog.setStatus(1);
+            alertLog.setProductId(1L);
+            alertLog.setDetail("111");
+            alertLog.setCreateTime(new Date());
+            // 添加设备关联信息
+            if (deviceRelateAlertLogVOMap.containsKey(deviceNumber)) {
+                DeviceRelateAlertLogVO deviceRelateAlertLogVO = deviceRelateAlertLogVOMap.get(deviceNumber);
+                alertLog.setDeviceName(deviceRelateAlertLogVO.getDeviceName());
+                alertLog.setUserId(deviceRelateAlertLogVO.getUserId());
+            }
+            alertLogList.add(alertLog);
+        }
+
+        // 批量插入告警日志
+        alertLogMapper.insertAlertLogBatch(alertLogList);
+    }
+
+    @PostMapping("/handleExcel")
+    public String handleExcel(@RequestParam("file") MultipartFile file) throws Exception {
+        if (null == file) {
+            return "导入失败,请先上传文件!";
+        }
+        ExcelUtil<ImportExcelVO> util = new ExcelUtil<>(ImportExcelVO.class);
+        List<ImportExcelVO> importExcelVOList = util.importExcel(file.getInputStream());
+        if (CollectionUtils.isEmpty(importExcelVOList)) {
+            return "导入失败,模板数据不能为空!";
+        }
+        System.out.println(importExcelVOList.size());
+        List<String> oneCityName = new ArrayList<>();
+        List<String> twoCityName = new ArrayList<>();
+        List<String> threeCityName = new ArrayList<>();
+
+        List<OutputExcelVO> oneCityList = new ArrayList<>();
+        Map<String, List<OutputExcelVO>> twoCityMap = new HashMap<>(2);
+        Map<String, List<OutputExcelVO>> threeCityMap = new HashMap<>(2);
+
+        for (ImportExcelVO vo : importExcelVOList) {
+            String city = vo.getCity();
+            List<String> cityNameList = StringUtils.str2List(city, "/", true, true);
+            int size = cityNameList.size();
+            if (1 == size) {
+                String name = cityNameList.get(0);
+                if (!oneCityName.contains(name)) {
+                    oneCityName.add(name);
+                    OutputExcelVO outputExcelVO = new OutputExcelVO();
+                    outputExcelVO.setName(name);
+                    outputExcelVO.setCode(vo.getCode());
+                    outputExcelVO.setLat(vo.getLat());
+                    outputExcelVO.setLon(vo.getLon());
+                    oneCityList.add(outputExcelVO);
+                    twoCityMap.put(name, new ArrayList<>());
+                }
+            } else if (2 == size) {
+                String oneName = cityNameList.get(0);
+                if (!oneCityName.contains(oneName)) {
+                    oneCityName.add(oneName);
+                    OutputExcelVO outputExcelVO = new OutputExcelVO();
+                    outputExcelVO.setName(oneName);
+                    oneCityList.add(outputExcelVO);
+                    twoCityMap.put(oneName, new ArrayList<>());
+                }
+                String twoName = cityNameList.get(1);
+                OutputExcelVO outputExcelVO = new OutputExcelVO();
+                outputExcelVO.setName(twoName);
+                outputExcelVO.setCode(vo.getCode());
+                outputExcelVO.setLat(vo.getLat());
+                outputExcelVO.setLon(vo.getLon());
+                if (!twoCityName.contains(twoName)) {
+                    twoCityName.add(twoName);
+                    List<OutputExcelVO> twoList = twoCityMap.get(oneName);
+                    twoList.add(outputExcelVO);
+                    twoCityMap.put(oneName, twoList);
+                    threeCityMap.put(twoName, new ArrayList<>());
+                }
+            } else if (3 == size) {
+                String oneName = cityNameList.get(0);
+                if (!oneCityName.contains(oneName)) {
+                    oneCityName.add(oneName);
+                    OutputExcelVO outputExcelVO = new OutputExcelVO();
+                    outputExcelVO.setName(oneName);
+                    oneCityList.add(outputExcelVO);
+                    twoCityMap.put(oneName, new ArrayList<>());
+                }
+                String twoName = cityNameList.get(1);
+                if (!twoCityName.contains(twoName)) {
+                    twoCityName.add(twoName);
+                    OutputExcelVO outputExcelVO = new OutputExcelVO();
+                    outputExcelVO.setName(twoName);
+                    List<OutputExcelVO> twoList = twoCityMap.get(oneName);
+                    twoList.add(outputExcelVO);
+                    twoCityMap.put(oneName, twoList);
+                    threeCityMap.put(twoName, new ArrayList<>());
+                }
+                String threeName = cityNameList.get(2);
+                if (!threeCityName.contains(threeName)) {
+                    threeCityName.add(threeName);
+                    OutputExcelVO outputExcelVO = new OutputExcelVO();
+                    outputExcelVO.setName(threeName);
+                    outputExcelVO.setCode(vo.getCode());
+                    outputExcelVO.setLat(vo.getLat());
+                    outputExcelVO.setLon(vo.getLon());
+                    List<OutputExcelVO> twoList = threeCityMap.get(twoName);
+                    twoList.add(outputExcelVO);
+                    threeCityMap.put(twoName, twoList);
+                }
+            }
+        }
+        int total = 0;
+        total = total + oneCityList.size();
+        for (OutputExcelVO outputExcelVO : oneCityList) {
+            List<OutputExcelVO> voList = twoCityMap.get(outputExcelVO.getName());
+            if (CollectionUtils.isNotEmpty(voList)) {
+                total = total + voList.size();
+                outputExcelVO.setChildren(voList);
+                for (OutputExcelVO excelVO : voList) {
+                    List<OutputExcelVO> voList1 = threeCityMap.get(excelVO.getName());
+                    if (CollectionUtils.isNotEmpty(voList1)) {
+                        total = total + voList1.size();
+                        excelVO.setChildren(voList1);
+                    }
+                }
+            }
+        }
+        System.out.println(total);
+        return JSON.toJSONString(oneCityList);
+    }
+
+    /**
+     * 计算场景运算型变量的值
+     *
+     * @return java.lang.String
+     */
+    @GetMapping("/getJobList")
+    public String getJobList() {
+        Long[] ids = {1L, 2L};
+        List<DeviceJob> deviceJobList = deviceJobMapper.selectListByJobTypeAndDatasourceIds(ids, 3);
+        return JSON.toJSONString(deviceJobList);
+    }
+
+    @GetMapping("/getStatsValue")
+    public String getStatsValue() {
+        DeviceLog deviceLog = new DeviceLog();
+        deviceLog.setLogType(1);
+        deviceLog.setIdentity("k1");
+        deviceLog.setSerialNumber("D10I741UL2P3_1");
+        deviceLog.setBeginTime("2024-05-17 00:00:00");
+        deviceLog.setEndTime("2024-05-17 23:59:59");
+//        deviceLog.setOperation(5);
+        List<String> list = deviceLogMapper.selectStatsValue(deviceLog);
+        return JSON.toJSONString(list);
+    }
+
+}

+ 116 - 0
yanfan-admin/src/main/java/com/yanfan/web/controller/tool/TestUserController.java

@@ -0,0 +1,116 @@
+package com.yanfan.web.controller.tool;
+
+import com.yanfan.common.core.controller.BaseController;
+import com.yanfan.common.core.domain.R;
+import com.yanfan.common.utils.StringUtils;
+import io.swagger.annotations.*;
+import lombok.Getter;
+import lombok.Setter;
+import org.springframework.web.bind.annotation.*;
+
+import java.util.ArrayList;
+import java.util.LinkedHashMap;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * swagger 用户测试方法
+ *
+ * @author ruoyi
+ */
+@Api("swagger 用户测试方法")
+@RestController
+@RequestMapping("/test/user")
+public class TestUserController extends BaseController {
+    private final static Map<Integer, UserEntity> users = new LinkedHashMap<Integer, UserEntity>();
+
+    {
+        users.put(1, new UserEntity(1, "admin", "admin123", "15888888888"));
+        users.put(2, new UserEntity(2, "ry", "admin123", "15666666666"));
+    }
+
+    @ApiOperation("获取用户列表")
+    @GetMapping("/list")
+    public R<List<UserEntity>> userList() {
+        List<UserEntity> userList = new ArrayList<UserEntity>(users.values());
+        return R.ok(userList);
+    }
+
+    @ApiOperation("获取用户详细")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
+    @GetMapping("/{userId}")
+    public R<UserEntity> getUser(@PathVariable Integer userId) {
+        if (!users.isEmpty() && users.containsKey(userId)) {
+            return R.ok(users.get(userId));
+        } else {
+            return R.fail("用户不存在");
+        }
+    }
+
+    @ApiOperation("新增用户")
+    @ApiImplicitParams({@ApiImplicitParam(name = "userId", value = "用户id", dataType = "Integer", dataTypeClass = Integer.class), @ApiImplicitParam(name = "username", value = "用户名称", dataType = "String", dataTypeClass = String.class), @ApiImplicitParam(name = "password", value = "用户密码", dataType = "String", dataTypeClass = String.class), @ApiImplicitParam(name = "mobile", value = "用户手机", dataType = "String", dataTypeClass = String.class)})
+    @PostMapping("/save")
+    public R<String> save(UserEntity user) {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) {
+            return R.fail("用户ID不能为空");
+        }
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+
+    @ApiOperation("更新用户")
+    @PutMapping("/update")
+    public R<String> update(@RequestBody UserEntity user) {
+        if (StringUtils.isNull(user) || StringUtils.isNull(user.getUserId())) {
+            return R.fail("用户ID不能为空");
+        }
+        if (users.isEmpty() || !users.containsKey(user.getUserId())) {
+            return R.fail("用户不存在");
+        }
+        users.remove(user.getUserId());
+        users.put(user.getUserId(), user);
+        return R.ok();
+    }
+
+    @ApiOperation("删除用户信息")
+    @ApiImplicitParam(name = "userId", value = "用户ID", required = true, dataType = "int", paramType = "path", dataTypeClass = Integer.class)
+    @DeleteMapping("/{userId}")
+    public R<String> delete(@PathVariable Integer userId) {
+        if (!users.isEmpty() && users.containsKey(userId)) {
+            users.remove(userId);
+            return R.ok();
+        } else {
+            return R.fail("用户不存在");
+        }
+    }
+
+    @Setter
+    @Getter
+    @ApiModel(value = "UserEntity", description = "用户实体")
+    static class UserEntity {
+        @ApiModelProperty("用户ID")
+        private Integer userId;
+
+        @ApiModelProperty("用户名称")
+        private String username;
+
+        @ApiModelProperty("用户密码")
+        private String password;
+
+        @ApiModelProperty("用户手机")
+        private String mobile;
+
+        public UserEntity() {
+
+        }
+
+        public UserEntity(Integer userId, String username, String password, String mobile) {
+            this.userId = userId;
+            this.username = username;
+            this.password = password;
+            this.mobile = mobile;
+        }
+
+    }
+
+}

+ 120 - 0
yanfan-admin/src/main/java/com/yanfan/web/core/config/SwaggerConfig.java

@@ -0,0 +1,120 @@
+package com.yanfan.web.core.config;
+
+import com.yanfan.common.config.RuoYiConfig;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.models.auth.In;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.service.*;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spi.service.contexts.SecurityContext;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Swagger2的接口配置
+ *
+ * @author ruoyi
+ */
+@Configuration
+public class SwaggerConfig {
+    /**
+     * 系统基础配置
+     */
+    @Autowired
+    private RuoYiConfig ruoyiConfig;
+
+    /**
+     * 是否开启swagger
+     */
+    @Value("${swagger.enabled}")
+    private boolean enabled;
+
+    /**
+     * 设置请求的统一前缀
+     */
+    @Value("${swagger.pathMapping}")
+    private String pathMapping;
+
+    /**
+     * 创建API
+     */
+    @Bean
+    public Docket createRestApi() {
+        return new Docket(DocumentationType.OAS_30)
+                // 是否启用Swagger
+                .enable(enabled)
+                // 用来创建该API的基本信息,展示在文档的页面中(自定义展示的信息)
+                .apiInfo(apiInfo())
+                // 设置哪些接口暴露给Swagger展示
+                .select()
+                // 扫描所有有注解的api,用这种方式更灵活
+                .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
+                // 扫描指定包中的swagger注解
+                // .apis(RequestHandlerSelectors.basePackage("com.yanfan.project.tool.swagger"))
+                // 扫描所有 .apis(RequestHandlerSelectors.any())
+                .paths(PathSelectors.any())
+                .build()
+                /* 设置安全模式,swagger可以设置访问token */
+                .securitySchemes(securitySchemes())
+                .securityContexts(securityContexts())
+                .pathMapping(pathMapping);
+    }
+
+    /**
+     * 安全模式,这里指定token通过Authorization头请求头传递
+     */
+    private List<SecurityScheme> securitySchemes() {
+        List<SecurityScheme> apiKeyList = new ArrayList<SecurityScheme>();
+        apiKeyList.add(new ApiKey("Authorization", "Authorization", In.HEADER.toValue()));
+        return apiKeyList;
+    }
+
+    /**
+     * 安全上下文
+     */
+    private List<SecurityContext> securityContexts() {
+        List<SecurityContext> securityContexts = new ArrayList<>();
+        securityContexts.add(SecurityContext
+                                     .builder()
+                                     .securityReferences(defaultAuth())
+                                     .operationSelector(o -> o.requestMappingPattern().matches("/.*"))
+                                     .build());
+        return securityContexts;
+    }
+
+    /**
+     * 默认的安全上引用
+     */
+    private List<SecurityReference> defaultAuth() {
+        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
+        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
+        authorizationScopes[0] = authorizationScope;
+        List<SecurityReference> securityReferences = new ArrayList<>();
+        securityReferences.add(new SecurityReference("Authorization", authorizationScopes));
+        return securityReferences;
+    }
+
+    /**
+     * 添加摘要信息
+     */
+    private ApiInfo apiInfo() {
+        // 用ApiInfoBuilder进行定制
+        return new ApiInfoBuilder()
+                // 设置标题
+                .title("千丝物芯物联网平台接口文档")
+                // 描述
+                .description("描述:千丝物芯物联网平台")
+                // 作者信息
+                .contact(new Contact(ruoyiConfig.getName(), null, null))
+                // 版本
+                .version("版本号:" + ruoyiConfig.getVersion()).build();
+    }
+}

+ 1 - 0
yanfan-admin/src/main/resources/META-INF/spring-devtools.properties

@@ -0,0 +1 @@
+restart.include.json=/com.alibaba.fastjson2.*.jar

+ 195 - 0
yanfan-admin/src/main/resources/application-dev.yml

@@ -0,0 +1,195 @@
+# 数据源配置
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://172.16.101.77:3306/yanfan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: 123456
+      # 从库数据源
+      slave:
+        enabled: false      # 从数据源开关/默认关闭
+        url:
+        username:
+        password:
+      # TDengine数据库
+      tdengine-server:
+        enabled: true      # 默认不启用TDengine,true=启用,false=不启用
+        driverClassName: com.taosdata.jdbc.TSDBDriver
+        url: jdbc:TAOS://127.0.0.1:6030/yanfan_log?timezone=Asia/Shanghai&charset=utf-8
+        username: root
+        password: taosdata
+        dbName: yanfan_log
+        precision: ns     # 精度,ms毫秒 us微秒 ns纳秒
+        keep: 3650        # 天,数据保留 3650 天
+        duration: 1       # 天,文件切割间隔 1天
+        buffer: 256        # MB,内存池大小 256MB
+
+      # 瀚高数据库
+      hgdb-server:
+        driverClassName: com.highgo.jdbc.Driver
+        # jdbc:highgo://ip:端口号/数据库名?currentSchema=模式名
+        url: jdbc:highgo://localhost:5866/highgo?currentSchema=test
+        username: highgo
+        password: P@ssw0rd
+
+      initialSize: 5                        # 初始连接数
+      minIdle: 10                           # 最小连接池数量
+      maxActive: 20                         # 最大连接池数量
+      maxWait: 60000                        # 配置获取连接等待超时的时间
+      timeBetweenEvictionRunsMillis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      minEvictableIdleTimeMillis: 300000    # 配置一个连接在池中最小生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000    # 配置一个连接在池中最大生存的时间,单位是毫秒
+      validationQuery: SELECT 1 FROM DUAL   # 配置检测连接是否有效
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: yanfan
+        login-password: yanfan
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # redis 配置
+  redis:
+    host: localhost                         # 地址
+    port: 6379                              # 端口,默认为6379
+    database: 1                             # 数据库索引
+    password: 123456                       # 密码
+    timeout: 10s                            # 连接超时时间
+    lettuce:
+      pool:
+        min-idle: 0                         # 连接池中的最小空闲连接
+        max-idle: 8                         # 连接池中的最大空闲连接
+        max-active: 8                       # 连接池的最大数据库连接数
+        max-wait: -1ms                      # 连接池最大阻塞等待时间(使用负值表示没有限制)
+  # mqtt 配置
+  mqtt:
+    username: yanfan                       # 账号
+    password: yanfan                       # 密码
+    host-url: tcp://localhost:1883          # mqtt连接tcp地址
+    client-id: ${random.int}                # 客户端Id,不能相同,采用随机数 ${random.value}
+    default-topic: test                     # 默认主题
+    timeout: 30                             # 超时时间
+    keepalive: 30                           # 保持连接
+    clearSession: true                      # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+    prod-def-user: yanfan                   # mqtt产品管理的默认账号
+    maxInflight: 1000                       # mqtt产品管理的默认账号
+
+# redisson 配置
+redisson:
+  # redis key前缀
+  keyPrefix:
+  # 线程池数量
+  threads: 4
+  # Netty线程池数量
+  nettyThreads: 8
+  # 单节点配置
+  singleServerConfig:
+    # 客户端名称
+    clientName: ${yanfan.name}
+    # 最小空闲连接数
+    connectionMinimumIdleSize: 8
+    # 连接池大小
+    connectionPoolSize: 32
+    # 连接空闲超时,单位:毫秒
+    idleConnectionTimeout: 10000
+    # 命令等待超时,单位:毫秒
+    timeout: 3000
+    # 发布和订阅连接池大小
+    subscriptionConnectionPoolSize: 50
+
+# sip 配置
+sip:
+  enabled: false                            # 是否启用视频监控SIP,true为启用
+  ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
+  ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
+  ip: localhost
+  port: 5061                                # SIP端口(保持默认)
+  domain: 3402000000                        # 由省级、市级、区级、基层编号组成
+  id: 34020000002000000001                  # 同上,另外增加编号,(可保持默认)
+  password: 12345678                        # 监控设备接入的密码
+
+# 日志配置
+logging:
+  level:
+    com.yanfan: debug
+    com.yomahub: debug
+    org.dromara: warn
+    org.springframework: warn
+
+# Swagger配置
+swagger:
+  enabled: true                             # 是否开启swagger
+  pathMapping: /dev-api                     # 请求前缀
+
+jeecg :
+  jmreport:
+    #自定义项目前缀,必须与前端 process.env.VUE_APP_BASE_API 的值一致
+    customPrePath: /dev-api
+
+liteflow:
+  #FlowExecutor的execute2Future的线程数,默认为64
+  main-executor-works: 64
+  #FlowExecutor的execute2Future的自定义线程池Builder
+  main-executor-class: com.yanfan.ruleEngine.config.MainExecutorBuilder
+  #并行节点的线程池Builder
+  thread-executor-class: com.yanfan.ruleEngine.config.WhenExecutorBuilder
+  rule-source-ext-data-map:
+    # 应用名称,规则链和脚本组件名称需要一致,不要修改
+    applicationName: yanfan
+    #是否开启SQL日志
+    sqlLogEnabled: true
+    # 规则多时,启用快速加载模式
+    fast-load: false
+    #是否开启SQL数据轮询自动刷新机制 默认不开启
+    pollingEnabled: false
+    pollingIntervalSeconds: 60
+    pollingStartSeconds: 60
+    #以下是chain表的配置
+    chainTableName: iot_scene
+    chainApplicationNameField: application_name
+    chainNameField: chain_name
+    elDataField: el_data
+    chainEnableField: enable
+    #以下是script表的配置
+    scriptTableName: iot_script
+    scriptApplicationNameField: application_name
+    scriptIdField: script_id
+    scriptNameField: script_name
+    scriptDataField: script_data
+    scriptTypeField: script_type
+    scriptLanguageField: script_language
+    scriptEnableField: enable
+
+
+#uniapp的个推
+uniPush:
+  enabled: false
+  appId: 12154545
+  appKey: 45454545
+  masterSecret: 4545454
+
+rc.pay:
+  order-no-prefix: P
+  refund-no-prefix: R
+  order-notify-url: http://localhost:8080/pay/notify/order/
+  refund-notify-url: http://localhost:8080/pay/notify/refund/
+

+ 160 - 0
yanfan-admin/src/main/resources/application-local.yml

@@ -0,0 +1,160 @@
+# 数据源配置
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://111.231.1.12:3306/yanfan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: yanfan
+      # 从库数据源
+      slave:
+        enabled: false      # 从数据源开关/默认关闭
+        url:
+        username:
+        password:
+      # TDengine数据库
+      tdengine-server:
+        enabled: true       # 默认不启用TDengine,true=启用,false=不启用
+        driverClassName: com.taosdata.jdbc.TSDBDriver
+        url: jdbc:TAOS://111.231.1.12:6030/yanfan_log?timezone=UTC-8&charset=utf-8
+        username: root
+        password: taosdata
+        dbName: yanfan_log
+        precision: ns     # 精度,ms毫秒 us微秒 ns纳秒
+        keep: 3650        # 天,数据保留 3650 天
+        duration: 1       # 天,文件切割间隔 1天
+        buffer: 256        # MB,内存池大小 32MB
+
+      initialSize: 5                        # 初始连接数
+      minIdle: 10                           # 最小连接池数量
+      maxActive: 20                         # 最大连接池数量
+      maxWait: 60000                        # 配置获取连接等待超时的时间
+      timeBetweenEvictionRunsMillis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      minEvictableIdleTimeMillis: 300000    # 配置一个连接在池中最小生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000    # 配置一个连接在池中最大生存的时间,单位是毫秒
+      validationQuery: SELECT 1 FROM DUAL   # 配置检测连接是否有效
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: yanfan
+        login-password: yanfan
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # redis 配置
+  redis:
+    host: 111.231.1.12                        # 地址
+    port: 6379                              # 端口,默认为6379
+    database: 0                             # 数据库索引
+    password: yanfan                       # 密码
+    timeout: 10s                            # 连接超时时间
+    lettuce:
+      pool:
+        min-idle: 0                         # 连接池中的最小空闲连接
+        max-idle: 8                         # 连接池中的最大空闲连接
+        max-active: 8                       # 连接池的最大数据库连接数
+        max-wait: -1ms                      # 连接池最大阻塞等待时间(使用负值表示没有限制)
+  # mqtt 配置
+  mqtt:
+    username: yanfan                       # 账号(仅用于后端自认证)
+    password: yanfan                       # 密码(仅用于后端自认证)
+    #    host-url: tcp://emqx:1883         # 连接 Emqx 消息服务器地址
+    host-url: tcp://localhost:1883       # 内置netty mqtt broker地址
+    client-id: ${random.int}                # 客户端Id,不能相同,采用随机数 ${random.value}
+    default-topic: test                     # 默认主题
+    timeout: 30                             # 超时时间
+    keepalive: 30                           # 保持连接
+    clearSession: true                      # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+    prod-def-user: yanfan                   # mqtt产品管理的默认账号
+    maxInflight: 1000                       # mqtt产品管理的默认账号
+
+# sip 配置
+sip:
+  enabled: false                             # 是否启用视频监控SIP,true为启用
+  ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
+  ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
+  ip: 111.231.1.12
+  port: 5061                                # SIP端口(保持默认)
+  domain: 3402000000                        # 由省级、市级、区级、基层编号组成
+  id: 34020000002000000001                  # 同上,另外增加编号,(可保持默认)
+  password: 12345678                        # 监控设备接入的密码
+
+# 日志配置
+logging:
+  level:
+    com.yanfan: error
+    com.yomahub: warn
+    org.dromara: warn
+    org.springframework: warn
+
+# Swagger配置
+swagger:
+  enabled: true                             # 是否开启swagger
+  pathMapping: /prod-api                    # 请求前缀
+
+
+liteflow:
+  #FlowExecutor的execute2Future的线程数
+  main-executor-works: 128
+  #FlowExecutor的execute2Future的自定义线程池Builder
+  main-executor-class: com.yanfan.mq.ruleEngine.MainExecutorBuilder
+  #并行节点的线程池Builder
+  thread-executor-class: com.yanfan.mq.ruleEngine.WhenExecutorBuilder
+  rule-source-ext-data-map:
+    # 应用名称,规则链和脚本组件名称需要一致,不要修改
+    applicationName: yanfan
+    #是否开启SQL日志
+    sqlLogEnabled: true
+    # 规则多时,启用快速加载模式
+    fast-load: false
+    #是否开启SQL数据轮询自动刷新机制 默认不开启
+    pollingEnabled: false
+    pollingIntervalSeconds: 60
+    pollingStartSeconds: 60
+    #以下是chain表的配置
+    chainTableName: iot_scene
+    chainApplicationNameField: application_name
+    chainNameField: chain_name
+    elDataField: el_data
+    chainEnableField: enable
+    #以下是script表的配置
+    scriptTableName: iot_script
+    scriptApplicationNameField: application_name
+    scriptIdField: script_id
+    scriptNameField: script_name
+    scriptDataField: script_data
+    scriptTypeField: script_type
+    scriptLanguageField: script_language
+    scriptEnableField: enable
+
+
+#uniapp的个推
+uniPush:
+  enabled: false
+  appId: 12154545
+  appKey: 45454545
+  masterSecret: 4545454
+
+rc.pay:
+  order-no-prefix: P
+  refund-no-prefix: R
+  order-notify-url: http://localhost:8080/pay/notify/order/
+  refund-notify-url: http://localhost:8080/pay/notify/refund/

+ 187 - 0
yanfan-admin/src/main/resources/application-prod.yml

@@ -0,0 +1,187 @@
+# 数据源配置
+spring:
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driverClassName: com.mysql.cj.jdbc.Driver
+    druid:
+      # 主库数据源
+      master:
+        url: jdbc:mysql://mysql/yanfan?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
+        username: root
+        password: yanfan
+      # 从库数据源
+      slave:
+        enabled: false      # 从数据源开关/默认关闭
+        url:
+        username:
+        password:
+      # TDengine数据库
+      tdengine-server:
+        enabled: true       # 默认不启用TDengine,true=启用,false=不启用
+        driverClassName: com.taosdata.jdbc.TSDBDriver
+        url: jdbc:TAOS://tdengine:6030/yanfan_log?timezone=UTC-8&charset=utf-8
+        username: root
+        password: taosdata
+        dbName: yanfan_log
+        precision: ns     # 精度,ms毫秒 us微秒 ns纳秒
+        keep: 3650        # 天,数据保留 3650 天
+        duration: 1       # 天,文件切割间隔 1天
+        buffer: 256        # MB,内存池大小 32MB
+
+      initialSize: 5                        # 初始连接数
+      minIdle: 10                           # 最小连接池数量
+      maxActive: 20                         # 最大连接池数量
+      maxWait: 60000                        # 配置获取连接等待超时的时间
+      timeBetweenEvictionRunsMillis: 60000  # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
+      minEvictableIdleTimeMillis: 300000    # 配置一个连接在池中最小生存的时间,单位是毫秒
+      maxEvictableIdleTimeMillis: 900000    # 配置一个连接在池中最大生存的时间,单位是毫秒
+      validationQuery: SELECT 1 FROM DUAL   # 配置检测连接是否有效
+      testWhileIdle: true
+      testOnBorrow: false
+      testOnReturn: false
+      webStatFilter:
+        enabled: true
+      statViewServlet:
+        enabled: true
+        # 设置白名单,不填则允许所有访问
+        allow:
+        url-pattern: /druid/*
+        # 控制台管理用户名和密码
+        login-username: yanfan
+        login-password: yanfan
+      filter:
+        stat:
+          enabled: true
+          # 慢SQL记录
+          log-slow-sql: true
+          slow-sql-millis: 1000
+          merge-sql: true
+        wall:
+          config:
+            multi-statement-allow: true
+  # redis 配置
+  redis:
+    host: redis                        # 地址
+    port: 6379                              # 端口,默认为6379
+    database: 0                             # 数据库索引
+    password: yanfan                       # 密码
+    timeout: 10s                            # 连接超时时间
+    lettuce:
+      pool:
+        min-idle: 0                         # 连接池中的最小空闲连接
+        max-idle: 8                         # 连接池中的最大空闲连接
+        max-active: 8                       # 连接池的最大数据库连接数
+        max-wait: -1ms                      # 连接池最大阻塞等待时间(使用负值表示没有限制)
+  # mqtt 配置
+  mqtt:
+    username: yanfan                       # 账号(仅用于后端自认证)
+    password: yanfan                       # 密码(仅用于后端自认证)
+    #    host-url: tcp://emqx:1883         # 连接 Emqx 消息服务器地址
+    host-url: tcp://java:1883       # 内置netty mqtt broker地址
+    client-id: ${random.int}                # 客户端Id,不能相同,采用随机数 ${random.value}
+    default-topic: test                     # 默认主题
+    timeout: 30                             # 超时时间
+    keepalive: 30                           # 保持连接
+    clearSession: true                      # 清除会话(设置为false,断开连接,重连后使用原来的会话 保留订阅的主题,能接收离线期间的消息)
+    prod-def-user: yanfan                   # mqtt产品管理的默认账号
+    maxInflight: 1000                       # mqtt产品管理的默认账号
+
+# redisson 配置
+redisson:
+  # redis key前缀
+  keyPrefix:
+  # 线程池数量
+  threads: 4
+  # Netty线程池数量
+  nettyThreads: 8
+  # 单节点配置
+  singleServerConfig:
+    # 客户端名称
+    clientName: ${yanfan.name}
+    # 最小空闲连接数
+    connectionMinimumIdleSize: 8
+    # 连接池大小
+    connectionPoolSize: 32
+    # 连接空闲超时,单位:毫秒
+    idleConnectionTimeout: 10000
+    # 命令等待超时,单位:毫秒
+    timeout: 3000
+    # 发布和订阅连接池大小
+    subscriptionConnectionPoolSize: 50
+# sip 配置
+sip:
+  enabled: true                             # 是否启用视频监控SIP,true为启用
+  ## 本地调试时,绑定网卡局域网IP,设备在同一局域网,设备接入IP填写绑定IP
+  ## 部署服务端时,默认绑定容器IP,设备接入IP填写服务器公网IP
+  ip: java
+  port: 5061                                # SIP端口(保持默认)
+  domain: 3402000000                        # 由省级、市级、区级、基层编号组成
+  id: 34020000002000000001                  # 同上,另外增加编号,(可保持默认)
+  password: 12345678                        # 监控设备接入的密码
+
+# 日志配置
+logging:
+  level:
+    com.yanfan: error
+    com.yomahub: warn
+    org.dromara: warn
+    org.springframework: warn
+
+# Swagger配置
+swagger:
+  enabled: true                             # 是否开启swagger
+  pathMapping: /prod-api                    # 请求前缀
+
+jeecg :
+  jmreport:
+    #自定义项目前缀,必须与前端 process.env.VUE_APP_BASE_API 的值一致
+    customPrePath: /prod-api
+
+
+liteflow:
+  #FlowExecutor的execute2Future的线程数
+  main-executor-works: 128
+  #FlowExecutor的execute2Future的自定义线程池Builder
+  main-executor-class: com.yanfan.ruleEngine.config.MainExecutorBuilder
+  #并行节点的线程池Builder
+  thread-executor-class: com.yanfan.ruleEngine.config.WhenExecutorBuilder
+  rule-source-ext-data-map:
+    # 应用名称,规则链和脚本组件名称需要一致,不要修改
+    applicationName: yanfan
+    #是否开启SQL日志
+    sqlLogEnabled: true
+    # 规则多时,启用快速加载模式
+    fast-load: false
+    #是否开启SQL数据轮询自动刷新机制 默认不开启
+    pollingEnabled: false
+    pollingIntervalSeconds: 60
+    pollingStartSeconds: 60
+    #以下是chain表的配置
+    chainTableName: iot_scene
+    chainApplicationNameField: application_name
+    chainNameField: chain_name
+    elDataField: el_data
+    chainEnableField: enable
+    #以下是script表的配置
+    scriptTableName: iot_script
+    scriptApplicationNameField: application_name
+    scriptIdField: script_id
+    scriptNameField: script_name
+    scriptDataField: script_data
+    scriptTypeField: script_type
+    scriptLanguageField: script_language
+    scriptEnableField: enable
+
+
+#uniapp的个推
+uniPush:
+  enabled: false
+  appId: 12154545
+  appKey: 45454545
+  masterSecret: 4545454
+
+rc.pay:
+  order-no-prefix: P
+  refund-no-prefix: R
+  order-notify-url: http://localhost:8080/pay/notify/order/
+  refund-notify-url: http://localhost:8080/pay/notify/refund/

+ 165 - 0
yanfan-admin/src/main/resources/application.yml

@@ -0,0 +1,165 @@
+# 项目相关配置
+yanfan:
+  name: yanfan         # 名称
+  version: 3.8.5            # 版本
+  copyrightYear: 2023-2024       # 版权年份
+  demoEnabled: true         # 实例演示开关
+  # 文件路径,以uploadPath结尾 示例( Windows配置 D:/uploadPath,Linux配置 /uploadPath)
+  profile: /uploadPath
+  addressEnabled: true      # 获取ip地址开关
+  captchaType: math         # 验证码类型 math 数组计算 char 字符验证
+
+# 开发环境配置
+server:
+  port: 8080                # 服务器的HTTP端口,默认为8080
+  servlet:
+    context-path: /         # 应用的访问路径
+  tomcat:
+    uri-encoding: UTF-8     # tomcat的URI编码
+    accept-count: 1000      # 连接数满后的排队数,默认为100
+    threads:
+      max: 800              # tomcat最大线程数,默认为200
+      min-spare: 100        # Tomcat启动初始化的线程数,默认值10
+  # 基于netty的服务器
+  broker:
+    enabled: true           # mqttBroker类型选择, true: 基于netty的mqttBroker和webSocket  false: emq的mqttBroker
+    broker-node: node1       # 服务器集群节点
+    port: 1883
+    openws: true             # 控制webSocket是否开启
+    websocket-port: 8083
+    websocket-path: /mqtt
+    keep-alive: 70          # 默认的全部客户端心跳上传时间
+  #TCP服务端口
+  tcp:
+    enabled: true          # 控制tcp端口是否开启
+    port: 8888
+    keep-alive: 70
+    delimiter: 0x7e
+  udp:
+    enabled: false          # 控制udp端口是否开启
+    port: 8889
+    read-idle: 300          # udp保活时间 默认5分钟
+  http:
+    enabled: false
+    port: 8081
+    auth:
+      type: Basic          # 支持Basic,Digest
+      user:
+        name: yanfan
+        password: yanfan
+  coap:
+    enabled: false
+    port: 5683
+  energy:
+    enabled: true
+  zutai:
+    enabled: true
+
+
+  #平台判断离线时间 是心跳时间的2倍
+  device:
+    platform:
+      expried: 120
+
+# Spring配置
+spring:
+  # 环境配置,dev=开发环境,prod=生产环境
+  profiles:
+    active: dev               # 环境配置,dev=开发环境,local=本地-测试环境,prod=生产环境
+  # 资源信息
+  messages:
+    # 国际化资源文件路径
+    basename: i18n/messages
+  # 文件上传
+  servlet:
+    multipart:
+      max-file-size: 10MB                             # 单个文件大小
+      max-request-size: 20MB                          # 设置总上传的文件大小
+  # 服务模块
+  devtools:
+    restart:
+      enabled: true                                    # 热部署开关
+  task:
+    execution:
+      pool:
+        core-size: 20                                  # 最小连接数
+        max-size: 200                                  # 最大连接数
+        queue-capacity: 3000                           # 最大容量
+        keep-alive: 60
+  # 缓存配置
+  cache:
+    enable: false
+    type: none              # none=不使用缓存 redis=使用redis缓存
+    ttl: 60                 # 缓存过期时间(默认60秒)
+
+#集群配置
+cluster:
+  enable: true
+  type: redis
+
+
+# 用户配置
+user:
+  password:
+    maxRetryCount: 5                                    # 密码最大错误次数
+    lockTime: 10                                        # 密码锁定时间(默认10分钟)
+
+# token配置
+token:
+  header: Authorization                                 # 令牌自定义标识
+  secret: abcdefghijklyanfansmartrstuvwxyz             # 令牌密钥
+  expireTime: 1440                                      # 令牌有效期(默认30分钟)1440为一天
+
+# MyBatis配置
+#mybatis:
+#  typeAliasesPackage: com.yanfan.**.domain             # 搜索指定包别名
+#  mapperLocations: classpath*:mapper/**/*Mapper.xml     # 配置mapper的扫描,找到所有的mapper.xml映射文件
+#  configLocation: classpath:mybatis/mybatis-config.xml  # 加载全局的配置文件
+
+# mybatis-plus配置
+mybatis-plus:
+  typeAliasesPackage: com.yanfan.**.domain             # 搜索指定包别名
+  mapperLocations: classpath*:mapper/**/*Mapper.xml     # 配置mapper的扫描,找到所有的mapper.xml映射文件
+  configLocation: classpath:mybatis/mybatis-config.xml  # 加载全局的配置文件
+  global-config:
+    db-config:
+      id-type: AUTO # 自增 ID
+      logic-delete-value: 1 # 逻辑已删除值(默认为 1)
+      logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
+
+# PageHelper分页插件
+pagehelper:
+  helperDialect: mysql
+  supportMethodsArguments: true
+  params: count=countSql
+
+# 防止XSS攻击
+xss:
+  enabled: true                                         # 过滤开关
+  excludes: /system/notice                              # 排除链接(多个用逗号分隔)
+  urlPatterns: /system/*,/monitor/*,/tool/*             # 匹配链接
+
+# EMQX API配置需要在运行emqx之后去EMQX管理后台手动创建API Key和Secret,并配置到application.yml中
+emqx:
+  host: localhost                                            # EMQX服务器地址
+  port: 18083
+  ApiKey: ApiKey                                             # EMQX API Key
+  ApiSecret: ApiSecret                                       # EMQX API Secret
+
+forest: # Forest配置 版本为1.5.36
+  backend: okhttp3             # 后端HTTP框架(默认为 okhttp3)
+  max-connections: 1000        # 连接池最大连接数(默认为 500)
+  max-route-connections: 500   # 每个路由的最大连接数(默认为 500)
+  max-request-queue-size: 100  # [自v1.5.22版本起可用] 最大请求等待队列大小
+  max-async-thread-size: 300   # [自v1.5.21版本起可用] 最大异步线程数
+  max-async-queue-size: 16     # [自v1.5.22版本起可用] 最大异步线程池队列大小
+  connect-timeout: 3000        # 连接超时时间,单位为毫秒(默认为 timeout)
+  read-timeout: 3000           # 数据读取超时时间,单位为毫秒(默认为 timeout)
+  max-retry-count: 0           # 请求失败后重试次数(默认为 0 次不重试)
+  ssl-protocol: TLS            # 单向验证的HTTPS的默认TLS协议(默认为 TLS)
+  log-enabled: true            # 打开或关闭日志(默认为 true)
+  log-request: true            # 打开/关闭Forest请求日志(默认为 true)
+  log-response-status: true    # 打开/关闭Forest响应状态日志(默认为 true)
+  log-response-content: true   # 打开/关闭Forest响应内容日志(默认为 false)
+  async-mode: platform         # [自v1.5.27版本起可用] 异步模式(默认为 platform)
+

+ 2 - 0
yanfan-admin/src/main/resources/banner.txt

@@ -0,0 +1,2 @@
+Application Version: ${yanfan.version}
+Spring Boot Version: ${spring-boot.version}

+ 192 - 0
yanfan-admin/src/main/resources/i18n/messages.properties

@@ -0,0 +1,192 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.device.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+device.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+device.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+device.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+device.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+device.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D

+ 193 - 0
yanfan-admin/src/main/resources/i18n/messages_en_US.properties

@@ -0,0 +1,193 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.device.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+device.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+device.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+device.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+device.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+device.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D
+device.can.send=No permission operation at present

+ 193 - 0
yanfan-admin/src/main/resources/i18n/messages_zh_CN.properties

@@ -0,0 +1,193 @@
+#\u9519\u8BEF\u6D88\u606F
+not.null=* \u5FC5\u987B\u586B\u5199
+user.jcaptcha.error=\u9A8C\u8BC1\u7801\u9519\u8BEF
+user.jcaptcha.expire=\u9A8C\u8BC1\u7801\u5DF2\u5931\u6548
+user.not.exists=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.not.match=\u7528\u6237\u4E0D\u5B58\u5728/\u5BC6\u7801\u9519\u8BEF
+user.password.retry.limit.count=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21
+user.password.retry.limit.exceed=\u5BC6\u7801\u8F93\u5165\u9519\u8BEF{0}\u6B21\uFF0C\u5E10\u6237\u9501\u5B9A{1}\u5206\u949F
+user.password.delete=\u5BF9\u4E0D\u8D77\uFF0C\u60A8\u7684\u8D26\u53F7\u5DF2\u88AB\u5220\u9664
+user.blocked=\u7528\u6237\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+role.blocked=\u89D2\u8272\u5DF2\u5C01\u7981\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.logout.success=\u9000\u51FA\u6210\u529F
+length.not.valid=\u957F\u5EA6\u5FC5\u987B\u5728{min}\u5230{max}\u4E2A\u5B57\u7B26\u4E4B\u95F4
+user.username.not.valid=* 2\u523020\u4E2A\u6C49\u5B57\u3001\u5B57\u6BCD\u3001\u6570\u5B57\u6216\u4E0B\u5212\u7EBF\u7EC4\u6210\uFF0C\u4E14\u5FC5\u987B\u4EE5\u975E\u6570\u5B57\u5F00\u5934
+user.password.not.valid=* 5-50\u4E2A\u5B57\u7B26
+user.email.not.valid=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+user.mobile.phone.number.not.valid=\u624B\u673A\u53F7\u683C\u5F0F\u9519\u8BEF
+user.login.success=\u767B\u5F55\u6210\u529F
+user.register.success=\u6CE8\u518C\u6210\u529F
+user.notfound=\u8BF7\u91CD\u65B0\u767B\u5F55
+user.forcelogout=\u7BA1\u7406\u5458\u5F3A\u5236\u9000\u51FA\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+user.unknown.error=\u672A\u77E5\u9519\u8BEF\uFF0C\u8BF7\u91CD\u65B0\u767B\u5F55
+##\u6743\u9650
+no.permission=\u60A8\u6CA1\u6709\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.create.permission=\u60A8\u6CA1\u6709\u521B\u5EFA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.update.permission=\u60A8\u6CA1\u6709\u4FEE\u6539\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.delete.permission=\u60A8\u6CA1\u6709\u5220\u9664\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.export.permission=\u60A8\u6CA1\u6709\u5BFC\u51FA\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+no.view.permission=\u60A8\u6CA1\u6709\u67E5\u770B\u6570\u636E\u7684\u6743\u9650\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458\u6DFB\u52A0\u6743\u9650 [{0}]
+##\u6587\u4EF6\u4E0A\u4F20\u6D88\u606F
+upload.exceed.maxSize=\u4E0A\u4F20\u7684\u6587\u4EF6\u5927\u5C0F\u8D85\u51FA\u9650\u5236\u7684\u6587\u4EF6\u5927\u5C0F\uFF01<br/>\u5141\u8BB8\u7684\u6587\u4EF6\u6700\u5927\u5927\u5C0F\u662F\uFF1A{0}MB\uFF01
+upload.filename.exceed.length=\u4E0A\u4F20\u7684\u6587\u4EF6\u540D\u6700\u957F{0}\u4E2A\u5B57\u7B26
+upload.success=\u4E0A\u4F20\u6210\u529F
+##\u6587\u4EF6\u4E0B\u8F7D\u6D88\u606F
+download.filename.not.valid=\u6587\u4EF6\u540D\u79F0[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+download.file.failed=\u4E0B\u8F7D\u6587\u4EF6\u5931\u8D25
+download.resource.not.valid=\u8D44\u6E90\u6587\u4EF6[{}]\u975E\u6CD5\uFF0C\u4E0D\u5141\u8BB8\u4E0B\u8F7D
+##Dept
+dept.add.failed.name.exists=\u65B0\u589E\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.name.exists=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u673A\u6784\u540D\u79F0\u5DF2\u5B58\u5728
+dept.update.failed.parent.not.valid=\u4FEE\u6539\u673A\u6784[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u673A\u6784\u4E0D\u80FD\u662F\u81EA\u5DF1
+dept.update.failed.child.not.valid=\u8BE5\u673A\u6784\u5305\u542B\u672A\u505C\u7528\u7684\u5B50\u673A\u6784\uFF01
+dept.delete.failed.child.exists=\u5B58\u5728\u4E0B\u7EA7\u673A\u6784\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+dept.delete.failed.user.exists=\u673A\u6784\u5B58\u5728\u7528\u6237\uFF0C\u4E0D\u5141\u8BB8\u5220\u9664
+##Dict
+dict.add.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+dict.update.failed.type.exists=\u65B0\u589E\u5B57\u5178[{}]\u5931\u8D25\uFF0C\u5B57\u5178\u7C7B\u578B\u5DF2\u5B58\u5728
+##Index
+index.welcome.message=\u6B22\u8FCE\u4F7F\u7528{}\u540E\u53F0\u7BA1\u7406\u6846\u67B6\uFF0C\u5F53\u524D\u7248\u672C\uFF1Av{}\uFF0C\u8BF7\u901A\u8FC7\u524D\u7AEF\u5730\u5740\u8BBF\u95EE\u3002
+##Menu
+menu.add.failed.name.exists=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.add.failed.path.not.valid=\u65B0\u589E\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.name.exists=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u83DC\u5355\u540D\u79F0\u5DF2\u5B58\u5728
+menu.update.failed.path.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u5730\u5740\u5FC5\u987B\u4EE5http(s)://\u5F00\u5934
+menu.update.failed.parent.not.valid=\u4FEE\u6539\u83DC\u5355[{}]\u5931\u8D25\uFF0C\u4E0A\u7EA7\u83DC\u5355\u4E0D\u80FD\u9009\u62E9\u81EA\u5DF1
+menu.delete.failed.child.exists=\u5B58\u5728\u5B50\u83DC\u5355,\u4E0D\u5141\u8BB8\u5220\u9664
+menu.delete.failed.role.exists=\u83DC\u5355\u5DF2\u5206\u914D,\u4E0D\u5141\u8BB8\u5220\u9664
+##Post
+post.add.failed.name.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.add.failed.code.exists=\u65B0\u589E\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+post.update.failed.name.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u540D\u79F0\u5DF2\u5B58\u5728
+post.update.failed.code.exists=\u4FEE\u6539\u5C97\u4F4D[{}]\u5931\u8D25\uFF0C\u5C97\u4F4D\u7F16\u7801\u5DF2\u5B58\u5728
+##User
+user.username.exists=\u7CFB\u7EDF\u8D26\u53F7\u540D\u79F0\u5DF2\u5B58\u5728\uFF0C\u8BF7\u4FEE\u6539\u540E\u91CD\u8BD5
+user.password.differ=\u4E24\u6B21\u5BC6\u7801\u4E0D\u4E00\u81F4\uFF0C\u8BF7\u91CD\u65B0\u8F93\u5165
+user.add.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.add.failed.phone.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.add.failed.email.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.password.wrong=\u4FEE\u6539\u5BC6\u7801\u5931\u8D25\uFF0C\u65E7\u5BC6\u7801\u9519\u8BEF
+user.update.failed.password.repeat=\u65B0\u5BC6\u7801\u4E0D\u80FD\u4E0E\u65E7\u5BC6\u7801\u76F8\u540C
+user.update.password.failed=\u4FEE\u6539\u5BC6\u7801\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.update.failed.name.exists=\u65B0\u589E\u7528\u6237[{}]\u5931\u8D25\uFF0C\u767B\u5F55\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed.phone.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u624B\u673A\u53F7\u7801\u5DF2\u5B58\u5728
+user.update.failed.email.exists=\u4FEE\u6539\u7528\u6237[{}]\u5931\u8D25\uFF0C\u90AE\u7BB1\u8D26\u53F7\u5DF2\u5B58\u5728
+user.update.failed=\u4FEE\u6539\u4E2A\u4EBA\u4FE1\u606F\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.delete.failed=\u5F53\u524D\u7528\u6237\u4E0D\u80FD\u5220\u9664
+user.upload.avatar.failed=\u4E0A\u4F20\u56FE\u7247\u5F02\u5E38\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+user.not.login=\u8BF7\u767B\u5F55\u540E\u91CD\u8BD5
+user.access.denied=\u7528\u6237\u62D2\u7EDD\u8BBF\u95EE
+##Role
+role.add.manager.failed=\u4E0D\u5141\u8BB8\u8BBE\u7F6E\u7BA1\u7406\u5458\u89D2\u8272\u6807\u8BC6
+role.add.failed.name.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.add.failed.key.exists=\u65B0\u589E\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed.name.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u540D\u79F0\u5DF2\u5B58\u5728
+role.update.failed.key.exists=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u89D2\u8272\u6743\u9650\u5DF2\u5B58\u5728
+role.update.failed=\u4FEE\u6539\u89D2\u8272[{}]\u5931\u8D25\uFF0C\u8BF7\u8054\u7CFB\u7BA1\u7406\u5458
+##Import
+import.failed.file.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u8BF7\u5148\u4E0A\u4F20\u6587\u4EF6\uFF01
+import.failed.data.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u5BFC\u5165\u6570\u636E\u4E3A\u7A7A\uFF01
+import.failed.device.name.null=\u5BFC\u5165\u5931\u8D25\uFF0C\u6A21\u677F\u91CC\u8BBE\u5907\u540D\u79F0\u4E0D\u80FD\u4E3A\u7A7A\uFF01
+import.success=\u5BFC\u5165\u6210\u529F
+##General
+success=\u6210\u529F
+fail=\u5931\u8D25
+query.success=\u67E5\u8BE2\u6210\u529F
+operate.success=\u64CD\u4F5C\u6210\u529F
+create.success=\u521B\u5EFA\u6210\u529F
+create.failed=\u521B\u5EFA\u5931\u8D25
+save.success=\u4FDD\u5B58\u6210\u529F
+save.failed=\u4FDD\u5B58\u5931\u8D25
+authorization.success=\u6388\u6743\u6210\u529F
+##Email
+email.format.error=\u90AE\u7BB1\u683C\u5F0F\u9519\u8BEF
+email.verification.code.send=\u90AE\u7BB1\u9A8C\u8BC1\u7801\u5DF2\u53D1\u9001
+##Firmware
+firmware.task.upgrade.failed.time.not.valid=\u9884\u5B9A\u5347\u7EA7\u65F6\u95F4\u5E94\u5927\u4E8E\u5F53\u524D\u65F6\u95F4
+##Media
+media.record.query.failed=\u8FDE\u63A5\u8D85\u65F6\u6216\u53D1\u751F\u9519\u8BEF\uFF0C\u672A\u83B7\u53D6\u5230\u6570\u636E
+##Modbus
+modbus.type.null=\u7C7B\u578B\u4E3A\u7A7A
+##Netty
+netty.client.not.exists=\u5BA2\u6237\u7AEF\u4E0D\u5B58\u5728
+##Runtime
+runtime.message.id.null=\u6D88\u606Fid\u4E3A\u7A7A
+##Wechat
+wechat.verify.type.null=\u8BF7\u4F20\u5165\u9A8C\u8BC1\u65B9\u5F0F
+wechat.bind.message.id.null=\u8BF7\u4F20\u5165\u7ED1\u5B9A\u4FE1\u606FID
+##AuthResource
+auth.resource.product.query.success=\u67E5\u8BE2\u4EA7\u54C1\u5217\u8868\u6210\u529F
+##Device
+device.user.id.null=\u7528\u6237ID\u4E0D\u80FD\u4E3A\u7A7A
+device.product.id.null=\u8BBE\u5907\u7F16\u53F7\u548C\u4EA7\u54C1ID\u4E0D\u80FD\u4E3A\u7A7A
+device.dept.id.null=\u8BF7\u9009\u62E9\u5206\u914D\u673A\u6784
+device.id.null=\u8BF7\u9009\u62E9\u8BBE\u5907
+##DeviceJob
+job.add.failed.cron.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.add.failed.rmi.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.add.failed.ldap.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.add.failed.http.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.add.failed.string.error=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.add.failed.string.not.valid=\u65B0\u589E\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.update.failed.cron.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0CCron\u8868\u8FBE\u5F0F\u4E0D\u6B63\u786E
+job.update.failed.rmi.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'rmi'\u8C03\u7528
+job.update.failed.ldap.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'ldap(s)'\u8C03\u7528
+job.update.failed.http.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5141\u8BB8'http(s)'\u8C03\u7528
+job.update.failed.string.error=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u5B58\u5728\u8FDD\u89C4
+job.update.failed.string.not.valid=\u4FEE\u6539\u4EFB\u52A1[{}]\u5931\u8D25\uFF0C\u76EE\u6807\u5B57\u7B26\u4E32\u4E0D\u5728\u767D\u540D\u5355\u5185
+job.not.exists=\u4EFB\u52A1\u4E0D\u5B58\u5728\u6216\u5DF2\u8FC7\u671F
+##DeviceUser
+device.user.delete.failed.user.not.valid=\u8BBE\u5907\u6240\u6709\u8005\u4E0D\u80FD\u5220\u9664
+##GoviewProject
+goview.project.data.save.failed.id.null=\u6CA1\u6709\u8BE5\u9879\u76EEID
+goview.project.data.execute.sql.failed=\u8BF7\u7F16\u5199sql\u8BED\u53E5
+##ThingsModel
+things.model.identifier.repeat=\u4EA7\u54C1\u4E0B\u7684\u6807\u8BC6\u7B26\u4E0D\u80FD\u91CD\u590D
+things.model.import.failed.identifier.repeat=[{}]\u6761\u6570\u636E\u672A\u5BFC\u5165\uFF0C\u6807\u8BC6\u7B26\u91CD\u590D
+##MQTT
+mqtt.unauthorized=mqtt\u8D26\u53F7\u548C\u5BC6\u7801\u4E0E\u8BA4\u8BC1\u670D\u52A1\u5668\u914D\u7F6E\u4E0D\u5339\u914D
+##Oauth
+oauth.response.type.not.valid=response_type\u53C2\u6570\u503C\u53EA\u5141\u8BB8code\u548Ctoken
+oauth.grant.type.null=\u672A\u77E5\u6388\u6743\u7C7B\u578B
+oauth.grant.type.implicit.not.support=Token\u63A5\u53E3\u4E0D\u652F\u6301implicit\u6388\u6743\u6A21\u5F0F
+oauth.access.token.null=\u8BBF\u95EE\u4EE4\u724C\u4E0D\u80FD\u4E3A\u7A7A
+obtain.basic.authorization.failed=client_id\u6216client_secret\u672A\u6B63\u786E\u4F20\u9012
+##Record
+record.app.null=app\u4E0D\u80FD\u4E3A\u7A7A
+record.stream.null=stream\u4E0D\u80FD\u4E3A\u7A7A
+record.time.not.valid=\u9519\u8BEF\u7684\u5F00\u59CB\u65F6\u95F4\u6216\u7ED3\u675F\u65F6\u95F4
+record.file.null=\u672A\u627E\u5230\u89C6\u9891\u6587\u4EF6
+##ErrorCodeConstants
+app.not.found=App \u4E0D\u5B58\u5728
+app.is.disable=App \u5DF2\u7ECF\u88AB\u7981\u7528
+app.exist.order.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u652F\u4ED8\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+app.exist.refund.cant.delete=\u652F\u4ED8\u5E94\u7528\u5B58\u5728\u9000\u6B3E\u8BA2\u5355\uFF0C\u65E0\u6CD5\u5220\u9664
+channel.not.found=\u652F\u4ED8\u6E20\u9053\u7684\u914D\u7F6E\u4E0D\u5B58\u5728
+channel.is.disable=\u652F\u4ED8\u6E20\u9053\u5DF2\u7ECF\u7981\u7528
+channel.exists.same.channel.error=\u5DF2\u5B58\u5728\u76F8\u540C\u7684\u6E20\u9053
+order.not.found=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5B58\u5728
+order.status.is.not.waiting=\u652F\u4ED8\u8BA2\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.status.is.success=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u5237\u65B0\u9875\u9762
+order.is.expired=\u652F\u4ED8\u8BA2\u5355\u5DF2\u7ECF\u8FC7\u671F
+order.submit.channel.error=\u53D1\u8D77\u652F\u4ED8\u62A5\u9519\uFF0C\u9519\u8BEF\u7801\uFF1A{}\uFF0C\u9519\u8BEF\u63D0\u793A\uFF1A{}
+order.refund.fail.status.error=\u652F\u4ED8\u8BA2\u5355\u9000\u6B3E\u5931\u8D25\uFF0C\u539F\u56E0\uFF1A\u72B6\u6001\u4E0D\u662F\u5DF2\u652F\u4ED8\u6216\u5DF2\u9000\u6B3E
+order.extension.not.found=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5B58\u5728
+order.extension.status.is.not.waiting=\u652F\u4ED8\u4EA4\u6613\u62D3\u5C55\u5355\u4E0D\u5904\u4E8E\u5F85\u652F\u4ED8
+order.extension.is.paid=\u8BA2\u5355\u5DF2\u652F\u4ED8\uFF0C\u8BF7\u7B49\u5F85\u652F\u4ED8\u7ED3\u679C
+refund.price.exceed=\u9000\u6B3E\u91D1\u989D\u8D85\u8FC7\u8BA2\u5355\u53EF\u9000\u6B3E\u91D1\u989D
+refund.has.refunding=\u5DF2\u7ECF\u6709\u9000\u6B3E\u5728\u5904\u7406\u4E2D
+refund.exists=\u5DF2\u7ECF\u5B58\u5728\u9000\u6B3E\u5355
+refund.not.found=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5B58\u5728
+refund.statue.is.not.waiting=\u652F\u4ED8\u9000\u6B3E\u5355\u4E0D\u5904\u4E8E\u5F85\u9000\u6B3E
+demo.order.not.found=\u793A\u4F8B\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.update.paid.status.not.unpaid=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u8BA2\u5355\u4E0D\u662F\u3010\u672A\u652F\u4ED8\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.order.id.error=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.update.paid.fail.pay.order.status.not.success=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u72B6\u6001\u4E0D\u662F\u3010\u652F\u4ED8\u6210\u529F\u3011\u72B6\u6001
+demo.order.update.paid.fail.pay.price.not.match=\u793A\u4F8B\u8BA2\u5355\u66F4\u65B0\u652F\u4ED8\u72B6\u6001\u5931\u8D25\uFF0C\u652F\u4ED8\u5355\u91D1\u989D\u4E0D\u5339\u914D
+demo.order.refund.fail.not.paid=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u672A\u652F\u4ED8
+demo.order.refund.fail.refunded=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u793A\u4F8B\u8BA2\u5355\u5DF2\u9000\u6B3E
+demo.order.refund.fail.refund.not.found=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u4E0D\u5B58\u5728
+demo.order.refund.fail.refund.not.success=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u8BA2\u5355\u672A\u9000\u6B3E\u6210\u529F
+demo.order.refund.fail.refund.order.id.error=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u7F16\u53F7\u4E0D\u5339\u914D
+demo.order.refund.fail.refund.price.not.match=\u53D1\u8D77\u9000\u6B3E\u5931\u8D25\uFF0C\u9000\u6B3E\u5355\u91D1\u989D\u4E0D\u5339\u914D
+device.can.send=\u6682\u65E0\u6743\u9650\u64CD\u4F5C

+ 150 - 0
yanfan-admin/src/main/resources/logback.xml

@@ -0,0 +1,150 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<configuration>
+    <!-- 日志存放路径 -->
+    <property name="log.path" scope="context" value="/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_debug" class="ch.qos.logback.core.rolling.RollingFileAppender">
+        <file>${log.path}/sys-debug.log</file>
+        <!-- 循环政策:基于时间创建日志文件 -->
+        <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            <!-- 日志文件名格式 -->
+            <fileNamePattern>${log.path}/sys-debug.%d{yyyy-MM-dd}.log</fileNamePattern>
+            <!-- 日志最大的历史 10天 -->
+            <maxHistory>10</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <!-- 过滤的级别 DEBUG-->
+            <level>DEBUG</level>
+            <!-- 匹配时的操作:接收(记录) -->
+            <onMatch>ACCEPT</onMatch>
+            <!-- 不匹配时的操作:拒绝(不记录) -->
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </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>
+            <!-- 日志最大的历史 10天 -->
+            <maxHistory>10</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>
+            <!-- 日志最大的历史 10天 -->
+            <maxHistory>10</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>
+            <!-- 日志最大的历史 10天 -->
+            <maxHistory>10</maxHistory>
+        </rollingPolicy>
+        <encoder>
+            <pattern>${log.pattern}</pattern>
+        </encoder>
+    </appender>
+
+    <!-- 规则脚本日志输出  -->
+    <appender name="script" class="ch.qos.logback.classic.sift.SiftingAppender">
+        <discriminator>
+            <Key>scriptId</Key>
+            <DefaultValue>0</DefaultValue>
+        </discriminator>
+        <sift>
+            <appender name="execute-script" class="ch.qos.logback.core.rolling.RollingFileAppender">
+                <file>${log.path}/script/${scriptId}.log</file>
+                <Append>true</Append>
+                <rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">-->
+                    <!-- 按月回滚 daily -->
+                    <fileNamePattern>${log.path}/rule.%d{yyyy-MM}.log</fileNamePattern>
+                    <!-- 日志最大的历史 3个月 -->
+                    <maxHistory>3</maxHistory>
+                </rollingPolicy>
+                <encoder>
+                    <pattern>%d{HH:mm:ss.SSS} [%method,%line] - %msg%n</pattern>
+                </encoder>
+                <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+                    <level>INFO</level>
+                </filter>
+            </appender>
+        </sift>
+    </appender>
+
+    <!-- 系统模块日志级别控制  -->
+    <logger name="com.yanfan" level="debug"/>
+    <!-- Spring日志级别控制  -->
+    <logger name="org.springframework" level="warn"/>
+
+    <root level="info">
+        <appender-ref ref="console"/>
+    </root>
+
+    <!--系统操作日志-->
+    <root level="info">
+        <appender-ref ref="file_debug"/>
+        <appender-ref ref="file_info"/>
+        <appender-ref ref="file_error"/>
+    </root>
+
+    <!--系统用户操作日志-->
+    <logger name="sys-user" level="info">
+        <appender-ref ref="sys-user"/>
+    </logger>
+
+    <!--规则引擎日志-->
+    <logger name="script" level="info">
+        <appender-ref ref="script"/>
+    </logger>
+
+</configuration>

+ 20 - 0
yanfan-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>

BIN
yanfan-admin/src/main/resources/static/jmreport/desreport_/corelib/logo.png


BIN
yanfan-admin/src/main/resources/static/jmreport/desreport_/logoimage/jim_logo_20200814094127.png


+ 213 - 0
yanfan-common/pom.xml

@@ -0,0 +1,213 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xmlns="http://maven.apache.org/POM/4.0.0"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>yanfan</artifactId>
+        <groupId>com.yanfan</groupId>
+        <version>3.8.5</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>yanfan-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>
+
+        <!-- mybatis-plus -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>${mybatis-plus-generator.version}</version>
+        </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>
+
+        <!-- 动态数据源 -->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>dynamic-datasource-spring-boot-starter</artifactId>
+            <version>3.5.2</version>
+        </dependency>
+
+        <!-- 阿里JSON解析器 -->
+        <dependency>
+            <groupId>com.alibaba.fastjson2</groupId>
+            <artifactId>fastjson2</artifactId>
+        </dependency>
+
+        <!-- io常用工具类 -->
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
+
+        <!-- 文件上传工具类 -->
+        <dependency>
+            <groupId>commons-fileupload</groupId>
+            <artifactId>commons-fileupload</artifactId>
+        </dependency>
+
+        <!-- excel工具 -->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+        </dependency>
+
+        <!-- yml解析器 -->
+        <dependency>
+            <groupId>org.yaml</groupId>
+            <artifactId>snakeyaml</artifactId>
+        </dependency>
+
+        <!-- Token生成与解析-->
+        <dependency>
+            <groupId>io.jsonwebtoken</groupId>
+            <artifactId>jjwt</artifactId>
+        </dependency>
+
+        <!-- Jaxb -->
+        <dependency>
+            <groupId>javax.xml.bind</groupId>
+            <artifactId>jaxb-api</artifactId>
+        </dependency>
+
+        <!-- redis 缓存操作 -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <!-- pool 对象池 -->
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+        </dependency>
+
+        <!-- 解析客户端操作系统、浏览器等 -->
+        <dependency>
+            <groupId>eu.bitwalker</groupId>
+            <artifactId>UserAgentUtils</artifactId>
+        </dependency>
+
+        <!-- servlet包 -->
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>io.swagger</groupId>
+            <artifactId>swagger-annotations</artifactId>
+            <version>1.6.2</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.eclipse.paho</groupId>
+            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
+            <version>1.2.5</version>
+            <scope>compile</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.datatype</groupId>
+            <artifactId>jackson-datatype-jsr310</artifactId>
+        </dependency>
+
+        <!-- 工具类相关 -->
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+        </dependency>
+
+        <!--        <dependency>-->
+        <!--            <groupId>org.redisson</groupId>-->
+        <!--            <artifactId>redisson-spring-boot-starter</artifactId>-->
+        <!--        </dependency>-->
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>easyexcel-core</artifactId>
+        </dependency>
+
+        <!-- 短信快捷包 -->
+        <dependency>
+            <groupId>org.dromara.sms4j</groupId>
+            <artifactId>sms4j-spring-boot-starter</artifactId>
+            <version>3.0.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-jdk8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-processor</artifactId>
+        </dependency>
+
+    </dependencies>
+
+</project>

+ 14 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/Anonymous.java

@@ -0,0 +1,14 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 匿名访问不鉴权注解
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Anonymous {
+}

+ 16 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/CacheBatch.java

@@ -0,0 +1,16 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @description: 缓存批量清除注解
+ * @author: laizhenghua
+ * @date: 2022/5/22 22:25
+ */
+@Inherited
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface CacheBatch {
+    CacheBatchEvict[] batchEvict() default {};
+}

+ 27 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/CacheBatchEvict.java

@@ -0,0 +1,27 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * @description: 缓存批量清除注解
+ * @author: laizhenghua
+ * @date: 2022/5/22 22:25
+ */
+@Inherited
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target({ElementType.TYPE, ElementType.METHOD})
+public @interface CacheBatchEvict {
+    /**
+     * 指定缓存组件
+     */
+    String cacheNames() default "";
+    /**
+     * key需要指定一个spEL表达式,通过spEL表达式获取方法参数
+     */
+    String key() default "";
+    /**
+     * 是否清除所有
+     */
+    boolean isClearAll() default false;
+}

+ 28 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/DataScope.java

@@ -0,0 +1,28 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 数据权限过滤注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface DataScope {
+    /**
+     * 部门表的别名
+     */
+    String deptAlias() default "";
+
+    /**
+     * 用户表的别名
+     */
+    String userAlias() default "";
+
+    /**
+     * 权限字符(用于多个角色匹配符合要求的权限)默认根据权限注解@ss获取,多个权限用逗号分隔开来
+     */
+    String permission() default "";
+}

+ 23 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/DataSource.java

@@ -0,0 +1,23 @@
+package com.yanfan.common.annotation;
+
+import com.yanfan.common.enums.DataSourceType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义多数据源切换注解
+ * <p>
+ * 优先级:先方法,后类,如果方法覆盖了类上的数据源类型,以方法的为准,否则以类上的为准
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.METHOD, ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface DataSource {
+    /**
+     * 切换数据源名称
+     */
+    DataSourceType value() default DataSourceType.MASTER;
+}

+ 22 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/DictFormat.java

@@ -0,0 +1,22 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 字典格式化
+ * <p>
+ * 实现将字典数据的值,格式化成字典数据的标签
+ */
+@Target({ElementType.FIELD})
+@Retention(RetentionPolicy.RUNTIME)
+@Inherited
+public @interface DictFormat {
+
+    /**
+     * 例如说,SysDictTypeConstants、InfDictTypeConstants
+     *
+     * @return 字典类型
+     */
+    String value();
+
+}

+ 181 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/Excel.java

@@ -0,0 +1,181 @@
+package com.yanfan.common.annotation;
+
+import com.yanfan.common.utils.poi.ExcelHandlerAdapter;
+import org.apache.poi.ss.usermodel.HorizontalAlignment;
+import org.apache.poi.ss.usermodel.IndexedColors;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.math.BigDecimal;
+
+/**
+ * 自定义导出Excel数据注解
+ *
+ * @author ruoyi
+ */
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.FIELD)
+public @interface Excel {
+    /**
+     * 导出时在excel中排序
+     */
+    int sort() default Integer.MAX_VALUE;
+
+    /**
+     * 导出到Excel中的名字.
+     */
+    String name() default "";
+
+    /**
+     * 日期格式, 如: yyyy-MM-dd
+     */
+    String dateFormat() default "";
+
+    /**
+     * 如果是字典类型,请设置字典的type值 (如: sys_user_sex)
+     */
+    String dictType() default "";
+
+    /**
+     * 读取内容转表达式 (如: 0=男,1=女,2=未知)
+     */
+    String readConverterExp() default "";
+
+    /**
+     * 分隔符,读取字符串组内容
+     */
+    String separator() default ",";
+
+    /**
+     * BigDecimal 精度 默认:-1(默认不开启BigDecimal格式化)
+     */
+    int scale() default -1;
+
+    /**
+     * BigDecimal 舍入规则 默认:BigDecimal.ROUND_HALF_EVEN
+     */
+    int roundingMode() default BigDecimal.ROUND_HALF_EVEN;
+
+    /**
+     * 导出时在excel中每个列的高度 单位为字符
+     */
+    double height() default 14;
+
+    /**
+     * 导出时在excel中每个列的宽 单位为字符
+     */
+    double width() default 16;
+
+    /**
+     * 文字后缀,如% 90 变成90%
+     */
+    String suffix() default "";
+
+    /**
+     * 当值为空时,字段的默认值
+     */
+    String defaultValue() default "";
+
+    /**
+     * 提示信息
+     */
+    String prompt() default "";
+
+    /**
+     * 设置只能选择不能输入的列内容.
+     */
+    String[] combo() default {};
+
+    /**
+     * 是否需要纵向合并单元格,应对需求:含有list集合单元格)
+     */
+    boolean needMerge() default false;
+
+    /**
+     * 是否导出数据,应对需求:有时我们需要导出一份模板,这是标题需要但内容需要用户手工填写.
+     */
+    boolean isExport() default true;
+
+    /**
+     * 另一个类中的属性名称,支持多级获取,以小数点隔开
+     */
+    String targetAttr() default "";
+
+    /**
+     * 是否自动统计数据,在最后追加一行统计数据总和
+     */
+    boolean isStatistics() default false;
+
+    /**
+     * 导出类型(0数字 1字符串 2图片)
+     */
+    ColumnType cellType() default ColumnType.STRING;
+
+    /**
+     * 导出列头背景色
+     */
+    IndexedColors headerBackgroundColor() default IndexedColors.GREY_50_PERCENT;
+
+    /**
+     * 导出列头字体颜色
+     */
+    IndexedColors headerColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格背景色
+     */
+    IndexedColors backgroundColor() default IndexedColors.WHITE;
+
+    /**
+     * 导出单元格字体颜色
+     */
+    IndexedColors color() default IndexedColors.BLACK;
+
+    /**
+     * 导出字段对齐方式
+     */
+    HorizontalAlignment align() default HorizontalAlignment.CENTER;
+
+    /**
+     * 自定义数据处理器
+     */
+    Class<?> handler() default ExcelHandlerAdapter.class;
+
+    /**
+     * 自定义数据处理器参数
+     */
+    String[] args() default {};
+
+    /**
+     * 字段类型(0:导出导入;1:仅导出;2:仅导入)
+     */
+    Type type() default Type.ALL;
+
+    enum Type {
+        ALL(0), EXPORT(1), IMPORT(2);
+        private final int value;
+
+        Type(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+
+    enum ColumnType {
+        NUMERIC(0), STRING(1), IMAGE(2);
+        private final int value;
+
+        ColumnType(int value) {
+            this.value = value;
+        }
+
+        public int value() {
+            return this.value;
+        }
+    }
+}

+ 17 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/Excels.java

@@ -0,0 +1,17 @@
+package com.yanfan.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 {
+    Excel[] value();
+}

+ 41 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/Log.java

@@ -0,0 +1,41 @@
+package com.yanfan.common.annotation;
+
+import com.yanfan.common.enums.BusinessType;
+import com.yanfan.common.enums.OperatorType;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义操作日志记录注解
+ *
+ * @author ruoyi
+ */
+@Target({ElementType.PARAMETER, ElementType.METHOD})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface Log {
+    /**
+     * 模块
+     */
+    String title() default "";
+
+    /**
+     * 功能
+     */
+    BusinessType businessType() default BusinessType.OTHER;
+
+    /**
+     * 操作人类别
+     */
+    OperatorType operatorType() default OperatorType.MANAGE;
+
+    /**
+     * 是否保存请求的参数
+     */
+    boolean isSaveRequestData() default true;
+
+    /**
+     * 是否保存响应的参数
+     */
+    boolean isSaveResponseData() default true;
+}

+ 36 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/RateLimiter.java

@@ -0,0 +1,36 @@
+package com.yanfan.common.annotation;
+
+import com.yanfan.common.constant.CacheConstants;
+import com.yanfan.common.enums.LimitType;
+
+import java.lang.annotation.*;
+
+/**
+ * 限流注解
+ *
+ * @author ruoyi
+ */
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RateLimiter {
+    /**
+     * 限流key
+     */
+    String key() default CacheConstants.RATE_LIMIT_KEY;
+
+    /**
+     * 限流时间,单位秒
+     */
+    int time() default 60;
+
+    /**
+     * 限流次数
+     */
+    int count() default 100;
+
+    /**
+     * 限流类型
+     */
+    LimitType limitType() default LimitType.DEFAULT;
+}

+ 24 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/RepeatSubmit.java

@@ -0,0 +1,24 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 自定义注解防止表单重复提交
+ *
+ * @author ruoyi
+ */
+@Inherited
+@Target(ElementType.METHOD)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface RepeatSubmit {
+    /**
+     * 间隔时间(ms),小于此时间视为重复提交
+     */
+    int interval() default 5000;
+
+    /**
+     * 提示消息
+     */
+    String message() default "不允许重复提交,请稍候再试";
+}

+ 24 - 0
yanfan-common/src/main/java/com/yanfan/common/annotation/SysProtocol.java

@@ -0,0 +1,24 @@
+package com.yanfan.common.annotation;
+
+import java.lang.annotation.*;
+
+/**
+ * 表示系统内部协议解析器
+ *
+ * @author gsb
+ * @date 2022/10/24 10:33
+ */
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+public @interface SysProtocol {
+
+    /*协议名*/
+    String name() default "";
+
+    /*协议编码*/
+    String protocolCode() default "";
+
+    //协议描述
+    String description() default "";
+}

+ 114 - 0
yanfan-common/src/main/java/com/yanfan/common/config/DeviceTask.java

@@ -0,0 +1,114 @@
+package com.yanfan.common.config;
+
+import com.yanfan.common.constant.YanfanConstant;
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.EnableAsync;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+
+import java.util.concurrent.Executor;
+import java.util.concurrent.ThreadPoolExecutor;
+
+/**
+ * 设备报文处理线程池
+ *
+ * @author bill
+ */
+@Configuration
+@EnableAsync
+@ConfigurationProperties(prefix = "spring.task.execution.pool")
+@Data
+public class DeviceTask {
+
+    private int coreSize;
+
+    private int maxSize;
+
+    private int queueCapacity;
+
+    private int keepAlive;
+
+    /*设备状态池*/
+    @Bean(YanfanConstant.TASK.DEVICE_STATUS_TASK)
+    public Executor deviceStatusTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_STATUS_TASK);
+    }
+
+    /*平台自动获取线程池(例如定时获取设备信息)*/
+    @Bean(YanfanConstant.TASK.DEVICE_FETCH_PROP_TASK)
+    public Executor deviceFetchTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_FETCH_PROP_TASK);
+    }
+
+    /*设备回调信息(下发指令(服务)设备应答信息)*/
+    @Bean(YanfanConstant.TASK.DEVICE_REPLY_MESSAGE_TASK)
+    public Executor deviceReplyTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_REPLY_MESSAGE_TASK);
+    }
+
+    /*设备主动上报(设备数据有变化主动上报)*/
+    @Bean(YanfanConstant.TASK.DEVICE_UP_MESSAGE_TASK)
+    public Executor deviceUpMessageTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_UP_MESSAGE_TASK);
+    }
+
+    /*指令下发(服务下发)*/
+    @Bean(YanfanConstant.TASK.FUNCTION_INVOKE_TASK)
+    public Executor functionInvokeTaskExecutor() {
+        return builder(YanfanConstant.TASK.FUNCTION_INVOKE_TASK);
+    }
+
+    /*内部消费线程*/
+    @Bean(YanfanConstant.TASK.MESSAGE_CONSUME_TASK)
+    public Executor messageConsumeTaskExecutor() {
+        return builder(YanfanConstant.TASK.MESSAGE_CONSUME_TASK);
+    }
+
+    @Bean(YanfanConstant.TASK.MESSAGE_CONSUME_TASK_PUB)
+    public Executor messageConsumePubTaskExecutor() {
+        return builder(YanfanConstant.TASK.MESSAGE_CONSUME_TASK_PUB);
+    }
+
+    @Bean(YanfanConstant.TASK.MESSAGE_CONSUME_TASK_FETCH)
+    public Executor messageConsumeFetchTaskExecutor() {
+        return builder(YanfanConstant.TASK.MESSAGE_CONSUME_TASK_FETCH);
+    }
+
+    @Bean(YanfanConstant.TASK.DELAY_UPGRADE_TASK)
+    public Executor delayedTaskExecutor() {
+        return builder(YanfanConstant.TASK.DELAY_UPGRADE_TASK);
+    }
+
+    /*设备其他消息处理*/
+    @Bean(YanfanConstant.TASK.DEVICE_OTHER_TASK)
+    public Executor deviceOtherTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_OTHER_TASK);
+    }
+
+    @Bean(YanfanConstant.TASK.DEVICE_TEST_TASK)
+    public Executor deviceTestTaskExecutor() {
+        return builder(YanfanConstant.TASK.DEVICE_TEST_TASK);
+    }
+    @Bean(YanfanConstant.TASK.INNER_MQTT_TASK)
+    public Executor innerMqttTaskExecutor() {
+        return builder(YanfanConstant.TASK.INNER_MQTT_TASK);
+    }
+
+    /*组装线程池*/
+    private ThreadPoolTaskExecutor builder(String threadNamePrefix) {
+        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
+        executor.setCorePoolSize(coreSize);
+        executor.setMaxPoolSize(maxSize);
+        executor.setKeepAliveSeconds(keepAlive);
+        executor.setQueueCapacity(queueCapacity);
+        // 线程池对拒绝任务的处理策略
+        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.DiscardOldestPolicy());
+        //线程池名的前缀
+        executor.setThreadNamePrefix(threadNamePrefix);
+        executor.initialize();
+        return executor;
+    }
+
+}

+ 126 - 0
yanfan-common/src/main/java/com/yanfan/common/config/RuoYiConfig.java

@@ -0,0 +1,126 @@
+package com.yanfan.common.config;
+
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+/**
+ * 读取项目相关配置
+ *
+ * @author ruoyi
+ */
+@Component
+@ConfigurationProperties(prefix = "yanfan")
+public class RuoYiConfig {
+    /**
+     * 上传路径
+     */
+    private static String profile;
+    /**
+     * 获取地址开关
+     */
+    private static boolean addressEnabled;
+    /**
+     * 验证码类型
+     */
+    private static String captchaType;
+    /**
+     * 项目名称
+     */
+    private String name;
+    /**
+     * 版本
+     */
+    private String version;
+    /**
+     * 版权年份
+     */
+    private String copyrightYear;
+    /**
+     * 实例演示开关
+     */
+    private boolean demoEnabled;
+
+    public static String getProfile() {
+        return profile;
+    }
+
+    public void setProfile(String profile) {
+        RuoYiConfig.profile = profile;
+    }
+
+    public static boolean isAddressEnabled() {
+        return addressEnabled;
+    }
+
+    public void setAddressEnabled(boolean addressEnabled) {
+        RuoYiConfig.addressEnabled = addressEnabled;
+    }
+
+    public static String getCaptchaType() {
+        return captchaType;
+    }
+
+    public void setCaptchaType(String captchaType) {
+        RuoYiConfig.captchaType = captchaType;
+    }
+
+    /**
+     * 获取导入上传路径
+     */
+    public static String getImportPath() {
+        return getProfile() + "/import";
+    }
+
+    /**
+     * 获取头像上传路径
+     */
+    public static String getAvatarPath() {
+        return getProfile() + "/avatar";
+    }
+
+    /**
+     * 获取下载路径
+     */
+    public static String getDownloadPath() {
+        return getProfile() + "/download/";
+    }
+
+    /**
+     * 获取上传路径
+     */
+    public static String getUploadPath() {
+        return getProfile() + "/upload";
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getVersion() {
+        return version;
+    }
+
+    public void setVersion(String version) {
+        this.version = version;
+    }
+
+    public String getCopyrightYear() {
+        return copyrightYear;
+    }
+
+    public void setCopyrightYear(String copyrightYear) {
+        this.copyrightYear = copyrightYear;
+    }
+
+    public boolean isDemoEnabled() {
+        return demoEnabled;
+    }
+
+    public void setDemoEnabled(boolean demoEnabled) {
+        this.demoEnabled = demoEnabled;
+    }
+}

+ 63 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/CacheConstants.java

@@ -0,0 +1,63 @@
+package com.yanfan.common.constant;
+
+/**
+ * 缓存的key 常量
+ *
+ * @author ruoyi
+ */
+public class CacheConstants {
+    /**
+     * 登录用户 redis key
+     */
+    public static final String LOGIN_TOKEN_KEY = "login_tokens:";
+
+    /**
+     * 登录用户 redis key
+     */
+    public static final String LOGIN_USERID_KEY = "login_userId:";
+
+    /**
+     * 验证码 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:";
+
+    /**
+     * 短信登录验证码 redis key
+     */
+    public static final String LOGIN_SMS_CAPTCHA_PHONE = "login_sms_captcha_phone:";
+
+    /**
+     * 微信获取accessToken redis key
+     */
+    public static final String WECHAT_GET_ACCESS_TOKEN_APPID = "wechat_get_accessToken:";
+
+    /**
+     * 短信注册验证码 redis key
+     */
+    public static final String REGISTER_SMS_CAPTCHA_PHONE = "register_sms_captcha_phone:";
+}

+ 156 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/Constants.java

@@ -0,0 +1,156 @@
+package com.yanfan.common.constant;
+
+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";
+
+    /**
+     * 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 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:";
+
+    /**
+     * 定时任务白名单配置(仅允许访问的包名,如其他需要可以自行添加)
+     */
+    public static final String[] JOB_WHITELIST_STR = {"com.yanfan"};
+
+    /**
+     * 定时任务违规的字符
+     */
+    public static final String[] JOB_ERROR_STR = {"java.net.URL", "javax.naming.InitialContext", "org.yaml.snakeyaml", "org.springframework", "org.apache", "com.yanfan.common.utils.file", "com.yanfan.common.config"};
+
+    /**
+     * 语言类型
+     */
+    public static final String LANGUAGE = "language";
+    public static final String ZH_CN = "zh-CN";
+    public static final String EN_US = "en-US";
+
+    /**
+     * 翻译数据类型
+     */
+    public static final String MENU = "menu";
+    public static final String DICT_DATA = "dict_data";
+    public static final String DICT_TYPE = "dict_type";
+    public static final String THINGS_MODEL = "things_model";
+    public static final String THINGS_MODEL_TEMPLATE = "things_model_template";
+}

+ 183 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/GenConstants.java

@@ -0,0 +1,183 @@
+package com.yanfan.common.constant;
+
+/**
+ * 代码生成通用常量
+ *
+ * @author ruoyi
+ */
+public class GenConstants {
+    /**
+     * 单表(增删改查)
+     */
+    public static final String TPL_CRUD = "crud";
+
+    /**
+     * 树表(增删改查)
+     */
+    public static final String TPL_TREE = "tree";
+
+    /**
+     * 主子表(增删改查)
+     */
+    public static final String TPL_SUB = "sub";
+
+    /**
+     * 树编码字段
+     */
+    public static final String TREE_CODE = "treeCode";
+
+    /**
+     * 树父编码字段
+     */
+    public static final String TREE_PARENT_CODE = "treeParentCode";
+
+    /**
+     * 树名称字段
+     */
+    public static final String TREE_NAME = "treeName";
+
+    /**
+     * 上级菜单ID字段
+     */
+    public static final String PARENT_MENU_ID = "parentMenuId";
+
+    /**
+     * 上级菜单名称字段
+     */
+    public static final String PARENT_MENU_NAME = "parentMenuName";
+
+    /**
+     * 数据库字符串类型
+     */
+    public static final String[] COLUMNTYPE_STR = {"char", "varchar", "nvarchar", "varchar2"};
+
+    /**
+     * 数据库文本类型
+     */
+    public static final String[] COLUMNTYPE_TEXT = {"tinytext", "text", "mediumtext", "longtext"};
+
+    /**
+     * 数据库时间类型
+     */
+    public static final String[] COLUMNTYPE_TIME = {"datetime", "time", "date", "timestamp"};
+
+    /**
+     * 数据库数字类型
+     */
+    public static final String[] COLUMNTYPE_NUMBER = {"tinyint", "smallint", "mediumint", "int", "number", "integer", "bit", "bigint", "float", "double", "decimal"};
+
+    /**
+     * 页面不需要编辑字段
+     */
+    public static final String[] COLUMNNAME_NOT_EDIT = {"id", "create_by", "create_time", "del_flag"};
+
+    /**
+     * 页面不需要显示的列表字段
+     */
+    public static final String[] COLUMNNAME_NOT_LIST = {"id", "create_by", "create_time", "del_flag", "update_by", "update_time"};
+
+    /**
+     * 页面不需要查询字段
+     */
+    public static final String[] COLUMNNAME_NOT_QUERY = {"id", "create_by", "create_time", "del_flag", "update_by", "update_time", "remark"};
+
+    /**
+     * Entity基类字段
+     */
+    public static final String[] BASE_ENTITY = {"createBy", "createTime", "updateBy", "updateTime", "remark"};
+
+    /**
+     * Tree基类字段
+     */
+    public static final String[] TREE_ENTITY = {"parentName", "parentId", "orderNum", "ancestors", "children"};
+
+    /**
+     * 文本框
+     */
+    public static final String HTML_INPUT = "input";
+
+    /**
+     * 文本域
+     */
+    public static final String HTML_TEXTAREA = "textarea";
+
+    /**
+     * 下拉框
+     */
+    public static final String HTML_SELECT = "select";
+
+    /**
+     * 单选框
+     */
+    public static final String HTML_RADIO = "radio";
+
+    /**
+     * 复选框
+     */
+    public static final String HTML_CHECKBOX = "checkbox";
+
+    /**
+     * 日期控件
+     */
+    public static final String HTML_DATETIME = "datetime";
+
+    /**
+     * 图片上传控件
+     */
+    public static final String HTML_IMAGE_UPLOAD = "imageUpload";
+
+    /**
+     * 文件上传控件
+     */
+    public static final String HTML_FILE_UPLOAD = "fileUpload";
+
+    /**
+     * 富文本控件
+     */
+    public static final String HTML_EDITOR = "editor";
+
+    /**
+     * 字符串类型
+     */
+    public static final String TYPE_STRING = "String";
+
+    /**
+     * 整型
+     */
+    public static final String TYPE_INTEGER = "Integer";
+
+    /**
+     * 长整型
+     */
+    public static final String TYPE_LONG = "Long";
+
+    /**
+     * 浮点型
+     */
+    public static final String TYPE_DOUBLE = "Double";
+
+    /**
+     * 高精度计算类型
+     */
+    public static final String TYPE_BIGDECIMAL = "BigDecimal";
+
+    /**
+     * 时间类型
+     */
+    public static final String TYPE_DATE = "Date";
+
+    /**
+     * 模糊查询
+     */
+    public static final String QUERY_LIKE = "LIKE";
+
+    /**
+     * 相等查询
+     */
+    public static final String QUERY_EQ = "EQ";
+
+    /**
+     * 需要
+     */
+    public static final String REQUIRE = "1";
+}

+ 104 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/HttpStatus.java

@@ -0,0 +1,104 @@
+package com.yanfan.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 USER_NO_EXIST = 450;
+
+    /**
+     * 系统内部错误
+     */
+    public static final int ERROR = 500;
+
+    /**
+     * 接口未实现
+     */
+    public static final int NOT_IMPLEMENTED = 501;
+
+    /**
+     * 不弹窗显示
+     */
+    public static final int NO_MESSAGE_ALERT = 502;
+
+
+    /**
+     * 系统警告消息
+     */
+    public static final int WARN = 601;
+}

+ 20 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/MagicValueConstants.java

@@ -0,0 +1,20 @@
+package com.yanfan.common.constant;
+
+/**
+ * 魔法值常量
+ *
+ * @author ruoyi
+ */
+public class MagicValueConstants {
+    /**
+     * 3600
+     */
+    public static final Integer VALUE_3600 = 3600;
+
+    /**
+     * 60
+     */
+    public static final Integer VALUE_60 = 60;
+
+
+}

+ 40 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/ProductAuthConstant.java

@@ -0,0 +1,40 @@
+package com.yanfan.common.constant;
+
+/**
+ * @author fastb
+ * @date 2023-08-03 10:20
+ */
+public class ProductAuthConstant {
+
+    /**
+     * 产品设备认证方式-简单认证
+     */
+    public static final Integer AUTH_WAY_SIMPLE = 1;
+    /**
+     * 产品设备认证方式-简单认证
+     */
+    public static final Integer AUTH_WAY_ENCRYPT = 2;
+    /**
+     * 产品设备认证方式-简单认证
+     */
+    public static final Integer AUTH_WAY_SIMPLE_AND_ENCRYPT = 3;
+
+    /**
+     * 产品设备客户端ID认证类型-简单认证
+     */
+    public static final String CLIENT_ID_AUTH_TYPE_SIMPLE = "S";
+
+    /**
+     * 产品设备客户端ID认证类型-简单认证
+     */
+    public static final String CLIENT_ID_AUTH_TYPE_ENCRYPT = "E";
+    /**
+     * 设备授权
+     */
+    public static final Integer AUTHORIZE = 1;
+    /**
+     * 设备没有授权
+     */
+    public static final Integer NO_AUTHORIZE = 1;
+
+}

+ 14 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/ScadaConstant.java

@@ -0,0 +1,14 @@
+package com.yanfan.common.constant;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 组态常量类
+ * @date 2024-01-02 14:40
+ */
+public class ScadaConstant {
+
+    public static final String COMPONENT_TEMPLATE_DEFAULT = "<div id=\"app\" class=\"h2-text\">\n    <h2>自定义组件案例</h2>\n    <h4>支持element ui、样式自定义、vue的语法等</h4>\n    <el-button type=\"primary\" @click=\"handleClick\">点击按钮</el-button>\n</div>";
+    public static final String COMPONENT_SCRIPT_DEFAULT = "export default {\n    data() {\n        return {}\n    },\n    created() {\n\n    },\n    mounted(){\n\n    },\n    methods:{\n        handleClick(){\n             this.$message('这是一条消息提示');\n        }\n    }\n}";
+    public static final String COMPONENT_STYLE_DEFAULT = "h2 {\n    color:#409EFF\n}\n\nh4 {\n    color:#F56C6C\n}";
+}

+ 47 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/SceneModelConstants.java

@@ -0,0 +1,47 @@
+package com.yanfan.common.constant;
+
+/**
+ * @author fastb
+ * @version 1.0
+ * @description: 场景相关的场景
+ * @date 2024-06-04 15:26
+ */
+public class SceneModelConstants {
+
+    /**
+     * 时
+     */
+    public static final String CYCLE_HOUR = "hour";
+
+    /**
+     * 日
+     */
+    public static final String CYCLE_DAY = "day";
+
+    /**
+     * 周
+     */
+    public static final String CYCLE_WEEK = "week";
+
+    /**
+     * 月
+     */
+    public static final String CYCLE_MONTH = "month";
+
+    /**
+     * 当日
+     */
+    public static final Integer CYCLE_TO_TYPE_NOW_DAY = 1;
+    /**
+     * 次日
+     */
+    public static final Integer CYCLE_TO_TYPE_SECOND_DAY = 2;
+    /**
+     * 周
+     */
+    public static final Integer CYCLE_TO_TYPE_WEEK = 3;
+    /**
+     * 月
+     */
+    public static final Integer CYCLE_TO_TYPE_MONTH = 4;
+}

+ 56 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/ScheduleConstants.java

@@ -0,0 +1,56 @@
+package com.yanfan.common.constant;
+
+/**
+ * 任务调度通用常量
+ *
+ * @author ruoyi
+ */
+public class ScheduleConstants {
+    public static final String TASK_CLASS_NAME = "TASK_CLASS_NAME";
+
+    /**
+     * 执行目标key
+     */
+    public static final String TASK_PROPERTIES = "TASK_PROPERTIES";
+
+    /**
+     * 默认
+     */
+    public static final String MISFIRE_DEFAULT = "0";
+
+    /**
+     * 立即触发执行
+     */
+    public static final String MISFIRE_IGNORE_MISFIRES = "1";
+
+    /**
+     * 触发一次执行
+     */
+    public static final String MISFIRE_FIRE_AND_PROCEED = "2";
+
+    /**
+     * 不触发立即执行
+     */
+    public static final String MISFIRE_DO_NOTHING = "3";
+
+    public enum Status {
+        /**
+         * 正常
+         */
+        NORMAL("0"),
+        /**
+         * 暂停
+         */
+        PAUSE("1");
+
+        private final String value;
+
+        Status(String value) {
+            this.value = value;
+        }
+
+        public String getValue() {
+            return value;
+        }
+    }
+}

+ 9 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/SipConstants.java

@@ -0,0 +1,9 @@
+package com.yanfan.common.constant;
+
+public class SipConstants {
+    public static final String MESSAGE_CATALOG = "Catalog";
+    public static final String MESSAGE_KEEP_ALIVE = "Keepalive";
+    public static final String MESSAGE_DEVICE_INFO = "DeviceInfo";
+    public static final String MESSAGE_RECORD_INFO = "RecordInfo";
+    public static final String MESSAGE_MEDIA_STATUS = "MediaStatus";
+}

+ 111 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/UserConstants.java

@@ -0,0 +1,111 @@
+package com.yanfan.common.constant;
+
+/**
+ * 用户常量信息
+ *
+ * @author ruoyi
+ */
+public class UserConstants {
+    /**
+     * 平台内系统用户的唯一标志
+     */
+    public static final String SYS_USER = "SYS_USER";
+
+    /**
+     * 正常状态
+     */
+    public static final String NORMAL = "0";
+
+    /**
+     * 异常状态
+     */
+    public static final String EXCEPTION = "1";
+
+    /**
+     * 用户封禁状态
+     */
+    public static final String USER_DISABLE = "1";
+
+    /**
+     * 角色封禁状态
+     */
+    public static final String ROLE_DISABLE = "1";
+
+    /**
+     * 部门正常状态
+     */
+    public static final String DEPT_NORMAL = "0";
+
+    /**
+     * 部门停用状态
+     */
+    public static final String DEPT_DISABLE = "1";
+
+    /**
+     * 字典正常状态
+     */
+    public static final String DICT_NORMAL = "0";
+
+    /**
+     * 是否为系统默认(是)
+     */
+    public static final String YES = "Y";
+
+    /**
+     * 是否菜单外链(是)
+     */
+    public static final String YES_FRAME = "0";
+
+    /**
+     * 是否菜单外链(否)
+     */
+    public static final String NO_FRAME = "1";
+
+    /**
+     * 菜单类型(目录)
+     */
+    public static final String TYPE_DIR = "M";
+
+    /**
+     * 菜单类型(菜单)
+     */
+    public static final String TYPE_MENU = "C";
+
+    /**
+     * 菜单类型(按钮)
+     */
+    public static final String TYPE_BUTTON = "F";
+
+    /**
+     * Layout组件标识
+     */
+    public final static String LAYOUT = "Layout";
+
+    /**
+     * ParentView组件标识
+     */
+    public final static String PARENT_VIEW = "ParentView";
+
+    /**
+     * InnerLink组件标识
+     */
+    public final static String INNER_LINK = "InnerLink";
+
+    /**
+     * 校验返回结果码
+     */
+    public final static String UNIQUE = "0";
+    public final static String NOT_UNIQUE = "1";
+
+    /**
+     * 用户名长度限制
+     */
+    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;
+}

+ 356 - 0
yanfan-common/src/main/java/com/yanfan/common/constant/YanfanConstant.java

@@ -0,0 +1,356 @@
+package com.yanfan.common.constant;
+
+/**
+ * 常量
+ *
+ * @author bill
+ */
+public interface YanfanConstant {
+
+    interface SERVER {
+        String UFT8 = "UTF-8";
+        String GB2312 = "GB2312";
+
+
+        String MQTT = "mqtt";
+        String PORT = "port";
+        String ADAPTER = "adapter";
+        String FRAMEDECODER = "frameDecoder";
+        String DISPATCHER = "dispatcher";
+        String DECODER = "decoder";
+        String ENCODER = "encoder";
+        String MAXFRAMELENGTH = "maxFrameLength";
+        String SLICER = "slicer";
+        String DELIMITERS = "delimiters";
+        String IDLE = "idle";
+        String WS_PREFIX = "web-";
+        String WM_PREFIX = "server-";
+        String FAST_PHONE = "phone-";
+
+        /*MQTT平台判定离线时间 keepAlive*1.5 */ Long DEVICE_PING_EXPIRED = 90000L;
+    }
+
+    interface CLIENT {
+        //加盐
+        String TOKEN = "yanfan-smart!@#$123";
+    }
+
+    /*webSocket配置*/
+    interface WS {
+        String HEART_BEAT = "heartbeat";
+        String HTTP_SERVER_CODEC = "httpServerCodec";
+        String AGGREGATOR = "aggregator";
+        String COMPRESSOR = "compressor";
+        String PROTOCOL = "protocol";
+        String MQTT_WEBSOCKET = "mqttWebsocket";
+        String DECODER = "decoder";
+        String ENCODER = "encoder";
+        String BROKER_HANDLER = "brokerHandler";
+
+    }
+
+    interface TASK {
+        /**
+         * 设备上下线任务
+         */
+        String DEVICE_STATUS_TASK = "deviceStatusTask";
+        /**
+         * 设备主动上报任务
+         */
+        String DEVICE_UP_MESSAGE_TASK = "deviceUpMessageTask";
+        /**
+         * 设备回调任务
+         */
+        String DEVICE_REPLY_MESSAGE_TASK = "deviceReplyMessageTask";
+        /**
+         * 设备下行任务
+         */
+        String DEVICE_DOWN_MESSAGE_TASK = "deviceDownMessageTask";
+        /**
+         * 服务调用(指令下发)任务
+         */
+        String FUNCTION_INVOKE_TASK = "functionInvokeTask";
+        /**
+         * 属性读取任务,区分服务调用
+         */
+        String DEVICE_FETCH_PROP_TASK = "deviceFetchPropTask";
+        /**
+         * 设备其他消息处理
+         */
+        String DEVICE_OTHER_TASK = "deviceOtherMsgTask";
+        /**
+         * 数据调试任务
+         */
+        String DEVICE_TEST_TASK = "deviceTestMsgTask";
+        /**
+         * 消息消费线程
+         */
+        String MESSAGE_CONSUME_TASK = "messageConsumeTask";
+        /**
+         * 内部消费线程publish
+         */
+        String MESSAGE_CONSUME_TASK_PUB = "messageConsumeTaskPub";
+        /**
+         * 内部消费线程Fetch
+         */
+        String MESSAGE_CONSUME_TASK_FETCH = "messageConsumeTaskFetch";
+        /**
+         * OTA升级延迟队列
+         */
+        String DELAY_UPGRADE_TASK = "delayUpgradeTask";
+
+        /**
+         * 内部MQTT任务
+         */
+        String INNER_MQTT_TASK = "inner_mqtt_task";
+
+    }
+
+    interface MQTT {
+        //*上报平台前缀*//*
+        String UP_TOPIC_SUFFIX = "post";
+        //*下发设备前缀*//*
+        String DOWN_TOPIC_SUFFIX = "get";
+
+        /*模拟设备后缀*/ String PROPERTY_GET_SIMULATE = "simulate";
+
+        String PREDIX = "/+/+";
+
+        String DUP = "dup";
+        String QOS = "qos";
+        String RETAIN = "retain";
+        String CLEAN_SESSION = "cleanSession";
+
+        /*集群方式*/ String REDIS_CHANNEL = "redis";
+        String ROCKET_MQ = "rocketmq";
+    }
+
+    /*集群,全局发布的消息类型*/
+    interface CHANNEL {
+        /*设备状态*/ String DEVICE_STATUS = "device_status";
+        /*平台读取属性*/ String PROP_READ = "prop_read";
+        /*推送消息*/ String PUBLISH = "publish";
+        /*服务下发*/ String FUNCTION_INVOKE = "function_invoke";
+        /*事件*/ String EVENT = "event";
+        /*other*/ String OTHER = "other";
+        /*Qos1 推送应答*/ String PUBLISH_ACK = "publish_ack";
+        /*Qos2 发布消息收到*/ String PUB_REC = "pub_rec";
+        /*Qos 发布消息释放*/ String PUB_REL = "pub_rel";
+        /*Qos2 发布消息完成*/ String PUB_COMP = "pub_comp";
+
+        String UPGRADE = "upgrade";
+
+        /*-------------------------ROCKETMQ-------------------------*/ String SUFFIX = "group";
+        /*设备状态*/ String DEVICE_STATUS_GROUP = DEVICE_STATUS + SUFFIX;
+        String PROP_READ_GROUP = PROP_READ + SUFFIX;
+        /*服务下发*/ String FUNCTION_INVOKE_GROUP = FUNCTION_INVOKE + SUFFIX;
+        /*推送消息*/ String PUBLISH_GROUP = PUBLISH + SUFFIX;
+        /*Qos1 推送应答*/ String PUBLISH_ACK_GROUP = PUBLISH_ACK + SUFFIX;
+        /*Qos2 发布消息收到*/ String PUB_REC_GROUP = PUB_REC + SUFFIX;
+        /*Qos 发布消息释放*/ String PUB_REL_GROUP = PUB_REL + SUFFIX;
+        /*Qos2 发布消息完成*/ String PUB_COMP_GROUP = PUB_COMP + SUFFIX;
+        /*OTA升级*/ String UPGRADE_GROUP = UPGRADE + SUFFIX;
+    }
+
+
+    /**
+     * redisKey 定义
+     */
+    interface REDIS {
+        /*redis全局前缀*/ String GLOBAL_PREFIX_KEY = "yanfan:";
+        /*设备在线状态*/ String DEVICE_STATUS_KEY = "device:status";
+        /*在线设备列表*/ String DEVICE_ONLINE_LIST = "device:online:list";
+        /*设备实时状态key*/ String DEVICE_RUNTIME_DATA = "device:runtime:";
+        /*通讯协议参数*/ String DEVICE_PROTOCOL_PARAM = "device:param:";
+        /**
+         * 设备消息id缓存key
+         */
+        String DEVICE_MESSAGE_ID = "device:messageId:";
+        /**
+         * 设备消息id缓存key
+         */
+        String DEVICE_MESSAGE_USER_ID = "device:messageuserid";
+        /**
+         * 固件版本key
+         */
+        String FIRMWARE_VERSION = "device:firmware:";
+        /**
+         * 设备信息
+         */
+        String DEVICE_MSG = "device:msg:";
+
+        /**
+         * 采集点变更记录缓存key
+         */
+        String COLLECT_POINT_CHANGE = "collect:point:change:";
+        /**
+         * 属性下发回调
+         */
+        String PROP_READ_STORE = "prop:read:store:";
+        /**
+         * sip
+         */
+        String RECORDINFO_KEY = "sip:recordinfo:";
+        String DEVICEID_KEY = "sip:deviceid:";
+        String STREAM_KEY = "sip:stream:";
+        String INVITE_KEY = "sip:invite:";
+        String SIP_CSEQ_PREFIX = "sip:CSEQ:";
+        String DEFAULT_SIP_CONFIG = "sip:config";
+        String DEFAULT_MEDIA_CONFIG = "sip:mediaconfig";
+
+        /**
+         * rule
+         */
+        String RULE_SILENT_TIME = "rule:SilentTime";
+
+
+        /**
+         * 当前连接数
+         */
+        String MESSAGE_CONNECT_COUNT = "messages:connect:count";
+        /**
+         * 总保留消息
+         */
+        String MESSAGE_RETAIN_TOTAL = "message:retain:total";
+
+        /**
+         * 主题数
+         */
+        String MESSAGE_TOPIC_TOTAL = "message:topic:total";
+        /*发送消息数*/ String MESSAGE_SEND_TOTAL = "message:send:total";
+        /*接收消息数*/ String MESSAGE_RECEIVE_TOTAL = "message:receive:total";
+        /*连接次数*/ String MESSAGE_CONNECT_TOTAL = "message:connect:total";
+        /**
+         * 认证次数
+         */
+        String MESSAGE_AUTH_TOTAL = "message:auth:total";
+        /**
+         * 订阅次数
+         */
+        String MESSAGE_SUBSCRIBE_TOTAL = "message:subscribe:total";
+
+        /**
+         * 今日接收消息
+         */
+        String MESSAGE_RECEIVE_TODAY = "message:receive:today";
+        /**
+         * 今日发送消息
+         */
+        String MESSAGE_SEND_TODAY = "message:send:today";
+
+
+        // 物模型值命名空间:Key:TSLV:{productId}_{deviceNumber}   HKey:{identity#V/identity#S/identity#M/identity#N}
+        /**
+         * v-值
+         * s-影子值
+         * m-是否为检测值
+         * n-名称
+         */
+        String DEVICE_PRE_KEY = "TSLV:";
+
+        // 物模型命名空间:Key:TSL:{productId}
+        String TSL_PRE_KEY = "TSL:";
+
+        String MODBUS_PRE_KEY = "MODBUS:";
+
+        /**
+         * modbus缓存指令
+         */
+        String POLL_MODBUS_KEY = "MODBUS:POLL:";
+        /**
+         * modbus运行时数据
+         */
+        String MODBUS_RUNTIME = "MODBUS:RUNTIME:";
+
+        String MODBUS_LOCK = "MODBUS:LOCK:";
+
+        /**
+         * 通知企业微信应用消息accessToken缓存key
+         */
+        String NOTIFY_WECOM_APPLY_ACCESSTOKEN = "notify:wecom:apply:";
+
+        // 场景变量命名空间:Key:SMTV:{sceneModelTagId}
+        String SCENE_MODEL_TAG_ID = "SMTV:";
+
+
+    }
+
+    interface TOPIC {
+        /*属性上报*/ String PROP = "properties";
+        //事件
+        String EVENT = "events";
+        //功能
+        String FUNCTION = "functions";
+        /*非OTA消息回复*/ String MSG_REPLY = "message/reply";
+        /*OTA升级回复*/ String UPGRADE_REPLY = "upgrade/reply";
+        /*网关子设备结尾*/ String SUB = "/sub";
+    }
+
+    interface PROTOCOL {
+        String HJ212 = "HJ-212";
+        String DLT698_45 = "DLT698-45";
+        String ModbusTcp = "MODBUS-TCP";
+        String ModbusRtu = "MODBUS-RTU";
+        String YinErDa = "YinErDa";
+        String JsonObject = "JSONOBJECT";
+        String JsonArray = "JSON";
+        String ModbusRtuPak = "MODBUS-RTU-PAK";
+        String FlowMeter = "FlowMeter";
+        String RJ45 = "RJ45";
+        String ModbusToJson = "MODBUS-JSON";
+        String ModbusToJsonHP = "MODBUS-JSON-HP";
+        String ModbusToJsonZQWL = "MODBUS-JSON-ZQWL";
+        String JsonObject_ChenYi = "JSONOBJECT-CHENYI";
+        String GEC6100D = "MODBUS-JSON-GEC6100D";
+        String SGZ = "SGZ";
+        String CH = "CH";
+        String SZY206 = "SZY206";
+        String JT808 = "JT808";
+
+
+    }
+
+    interface URL {
+        /**
+         * 微信小程序订阅消息推送url前缀
+         */
+        String WX_MINI_PROGRAM_PUSH_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/message/subscribe/send";
+        /**
+         * 微信网站、移动应用登录获取用户access_token
+         */
+        String WX_GET_ACCESS_TOKEN_URL_PREFIX = "https://api.weixin.qq.com/sns/oauth2/access_token";
+        /**
+         * 微信小程序登录获取用户会话参数
+         */
+        String WX_MINI_PROGRAM_GET_USER_SESSION_URL_PREFIX = "https://api.weixin.qq.com/sns/jscode2session";
+        /**
+         * 微信小程序、公众号获取access_token
+         */
+        String WX_MINI_PROGRAM_GET_ACCESS_TOKEN_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential";
+        /**
+         * 微信获取用户信息
+         */
+        String WX_GET_USER_INFO_URL_PREFIX = "https://api.weixin.qq.com/sns/userinfo";
+        /**
+         * 获取用户手机号信息
+         */
+        String WX_GET_USER_PHONE_URL_PREFIX = "https://api.weixin.qq.com/wxa/business/getuserphonenumber?access_token=";
+        /**
+         * 企业微信获取accessToken
+         */
+        String WECOM_GET_ACCESSTOKEN = "https://qyapi.weixin.qq.com/cgi-bin/gettoken";
+        /**
+         * 企业微信发送应用消息
+         */
+        String WECOM_APPLY_SEND = "https://qyapi.weixin.qq.com/cgi-bin/message/send?access_token=";
+        /**
+         * 微信公众号获取用户信息
+         */
+        String WX_PUBLIC_ACCOUNT_GET_USER_INFO_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/user/info";
+        /**
+         * 微信公众号发送模版消息
+         */
+        String WX_PUBLIC_ACCOUNT_TEMPLATE_SEND_URL_PREFIX = "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=";
+    }
+
+}

+ 195 - 0
yanfan-common/src/main/java/com/yanfan/common/core/controller/BaseController.java

@@ -0,0 +1,195 @@
+package com.yanfan.common.core.controller;
+
+import com.yanfan.common.constant.CacheConstants;
+import com.yanfan.common.constant.HttpStatus;
+import com.yanfan.common.core.domain.AjaxResult;
+import com.yanfan.common.core.domain.model.LoginUser;
+import com.yanfan.common.core.page.PageDomain;
+import com.yanfan.common.core.page.TableDataInfo;
+import com.yanfan.common.core.page.TableSupport;
+import com.yanfan.common.core.redis.RedisCache;
+import com.yanfan.common.utils.*;
+import com.yanfan.common.utils.sql.SqlUtil;
+import com.github.pagehelper.PageHelper;
+import com.github.pagehelper.PageInfo;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.web.bind.WebDataBinder;
+import org.springframework.web.bind.annotation.InitBinder;
+
+import javax.annotation.Resource;
+import java.beans.PropertyEditorSupport;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * web层通用数据处理
+ *
+ * @author ruoyi
+ */
+public class BaseController {
+    protected final Logger logger = LoggerFactory.getLogger(this.getClass());
+
+    @Resource
+    private RedisCache redisCache;
+
+    /**
+     * 将前台传递过来的日期格式的字符串,自动转化为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(MessageUtils.message("query.success"));
+        rspData.setRows(list);
+        rspData.setTotal(new PageInfo(list).getTotal());
+        return rspData;
+    }
+
+    /**
+     * 返回成功
+     */
+    public AjaxResult success() {
+        return AjaxResult.success();
+    }
+
+    /**
+     * 返回失败消息
+     */
+    public AjaxResult error() {
+        return AjaxResult.error();
+    }
+
+    /**
+     * 返回成功消息
+     */
+    public AjaxResult success(String message) {
+        return AjaxResult.success(message);
+    }
+
+    /**
+     * 返回成功消息
+     */
+    public AjaxResult success(Object data) {
+        return AjaxResult.success(data);
+    }
+
+    /**
+     * 返回失败消息
+     */
+    public AjaxResult error(String message) {
+        return AjaxResult.error(message);
+    }
+
+    /**
+     * 返回警告消息
+     */
+    public AjaxResult warn(String message) {
+        return AjaxResult.warn(message);
+    }
+
+    /**
+     * 响应返回结果
+     *
+     * @param rows 影响行数
+     * @return 操作结果
+     */
+    protected AjaxResult toAjax(int rows) {
+        return rows > 0 ? AjaxResult.success() : AjaxResult.error();
+    }
+
+    /**
+     * 响应返回结果
+     *
+     * @param result 结果
+     * @return 操作结果
+     */
+    protected AjaxResult toAjax(boolean result) {
+        return result ? success() : error();
+    }
+
+    protected AjaxResult toAjax(Object result) {
+        return result != null ? success(result) : error();
+    }
+
+    /**
+     * 页面跳转
+     */
+    public String redirect(String url) {
+        return StringUtils.format("redirect:{}", url);
+    }
+
+    /**
+     * 获取用户缓存信息
+     * 由于不同端不能获取最新用户信息,所以优先以用户id缓存key获取用户信息
+     */
+    public LoginUser getLoginUser() {
+        LoginUser loginUser = SecurityUtils.getLoginUser();
+        Long userId = loginUser.getUserId();
+        if (userId != null) {
+            String userKey = CacheConstants.LOGIN_USERID_KEY + userId;
+            return redisCache.getCacheObject(userKey);
+        }
+        return loginUser;
+    }
+
+    /**
+     * 获取登录用户id
+     */
+    public Long getUserId() {
+        return getLoginUser().getUserId();
+    }
+
+    /**
+     * 获取登录部门id
+     */
+    public Long getDeptId() {
+        return getLoginUser().getDeptId();
+    }
+
+    /**
+     * 获取登录用户名
+     */
+    public String getUsername() {
+        return getLoginUser().getUsername();
+    }
+}

+ 66 - 0
yanfan-common/src/main/java/com/yanfan/common/core/device/DeviceAndProtocol.java

@@ -0,0 +1,66 @@
+package com.yanfan.common.core.device;
+
+import lombok.Data;
+
+/**
+ * @author gsb
+ * @date 2024/6/14 9:25
+ */
+@Data
+public class DeviceAndProtocol {
+
+    /**
+     * 子设备编号
+     */
+    private Long deviceId;
+    /**
+     * 设备编号
+     */
+    private String serialNumber;
+    /**
+     * 协议编号
+     */
+    private String protocolCode;
+    /**
+     * 产品id
+     */
+    private Long productId;
+
+    private String transport;
+
+    /**
+     * 设备类型
+     */
+    private Integer deviceType;
+    /**
+     * 子设备地址
+     */
+    private Integer slaveId;
+    /**
+     * 网关绑定的子设备地址
+     */
+    private Integer proSlaveId;
+    /**
+     * 网关设备id
+     */
+    private Long gwDeviceId;
+    /**
+     * 网关设备产品id
+     */
+    private Long gwProductId;
+    /**
+     * 网关设备编号
+     */
+    private String gwSerialNumber;
+    /**
+     * 网关设备名
+     */
+    private String gwDeviceName;
+    /**
+     * 网关产品名
+     */
+    private String gwProductName;
+
+    private Long tenantId;
+
+}

+ 199 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/AjaxResult.java

@@ -0,0 +1,199 @@
+package com.yanfan.common.core.domain;
+
+import com.yanfan.common.constant.HttpStatus;
+import com.yanfan.common.utils.StringUtils;
+
+import java.util.HashMap;
+
+/**
+ * 操作消息提醒
+ *
+ * @author ruoyi
+ */
+public class AjaxResult extends HashMap<String, Object> {
+    /**
+     * 状态码
+     */
+    public static final String CODE_TAG = "code";
+    /**
+     * 返回内容
+     */
+    public static final String MSG_TAG = "msg";
+    /**
+     * 数据对象
+     */
+    public static final String DATA_TAG = "data";
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 初始化一个新创建的 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);
+        }
+    }
+
+
+    /**
+     * 初始化一个新创建的 AjaxResult 对象
+     *
+     * @param code 状态码
+     * @param msg  返回内容
+     * @param data 数据对象
+     */
+    public AjaxResult(int code, String msg, Object data, int total) {
+        super.put(CODE_TAG, code);
+        super.put(MSG_TAG, msg);
+        if (StringUtils.isNotNull(data)) {
+            super.put(DATA_TAG, data);
+        }
+        super.put("total", total);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @return 成功消息
+     */
+    public static AjaxResult success() {
+        return AjaxResult.success("操作成功");
+    }
+
+    /**
+     * 返回成功数据
+     *
+     * @return 成功消息
+     */
+    public static AjaxResult success(Object data) {
+        return AjaxResult.success("操作成功", data);
+    }
+
+    /**
+     * 返回成功数据
+     *
+     * @return 成功消息
+     */
+    public static AjaxResult success(Object data, int total) {
+        return new AjaxResult(HttpStatus.SUCCESS, "操作成功", data, total);
+    }
+
+    /**
+     * 返回成功消息
+     *
+     * @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);
+    }
+
+    /**
+     * 方便链式调用
+     *
+     * @param key   键
+     * @param value 值
+     * @return 数据对象
+     */
+    @Override
+    public AjaxResult put(String key, Object value) {
+        super.put(key, value);
+        return this;
+    }
+}

+ 54 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/BaseDO.java

@@ -0,0 +1,54 @@
+package com.yanfan.common.core.domain;
+
+import com.baomidou.mybatisplus.annotation.TableLogic;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+/**
+ * 基类,时间类型改为LocalDateTime
+ *
+ * @author fastb
+ * @date 2023-08-22 9:11
+ */
+@Data
+public class BaseDO implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 创建者
+     */
+    @ApiModelProperty("创建者")
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新者
+     */
+    @ApiModelProperty("更新者")
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+
+    /**
+     * 逻辑删除
+     */
+    @ApiModelProperty("逻辑删除")
+    @TableLogic
+    private Boolean delFlag;
+
+}

+ 127 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/BaseEntity.java

@@ -0,0 +1,127 @@
+package com.yanfan.common.core.domain;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonInclude;
+import io.swagger.annotations.ApiModelProperty;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Entity基类
+ *
+ * @author ruoyi
+ */
+public class BaseEntity implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 搜索值
+     */
+    @ApiModelProperty("搜索值")
+    @JsonIgnore
+    private String searchValue;
+
+    /**
+     * 创建者
+     */
+    @ApiModelProperty("创建者")
+    private String createBy;
+
+    /**
+     * 创建时间
+     */
+    @ApiModelProperty("创建时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date createTime;
+
+    /**
+     * 更新者
+     */
+    @ApiModelProperty("更新者")
+    private String updateBy;
+
+    /**
+     * 更新时间
+     */
+    @ApiModelProperty("更新时间")
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private Date updateTime;
+
+    /**
+     * 备注
+     */
+    @ApiModelProperty("备注")
+    private String remark;
+
+    /**
+     * 请求参数
+     */
+    @TableField(exist = false)
+    @ApiModelProperty("请求参数")
+    @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;
+    }
+}

+ 112 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/CommonResult.java

@@ -0,0 +1,112 @@
+package com.yanfan.common.core.domain;
+
+import com.yanfan.common.enums.GlobalErrorCodeConstants;
+import com.yanfan.common.exception.ErrorCode;
+import com.yanfan.common.exception.ServiceException;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+import org.springframework.util.Assert;
+
+import java.io.Serializable;
+import java.util.Objects;
+
+/**
+ * 通用返回
+ *
+ * @param <T> 数据泛型
+ */
+@Data
+public class CommonResult<T> implements Serializable {
+
+    /**
+     * 错误码
+     *
+     * @see ErrorCode#getCode()
+     */
+    private Integer code;
+    /**
+     * 返回数据
+     */
+    private T data;
+    /**
+     * 错误提示,用户可阅读
+     *
+     * @see ErrorCode#getMsg() ()
+     */
+    private String msg;
+
+    /**
+     * 将传入的 result 对象,转换成另外一个泛型结果的对象
+     * <p>
+     * 因为 A 方法返回的 CommonResult 对象,不满足调用其的 B 方法的返回,所以需要进行转换。
+     *
+     * @param result 传入的 result 对象
+     * @param <T>    返回的泛型
+     * @return 新的 CommonResult 对象
+     */
+    public static <T> CommonResult<T> error(CommonResult<?> result) {
+        return error(result.getCode(), result.getMsg());
+    }
+
+    public static <T> CommonResult<T> error(Integer code, String message) {
+        Assert.isTrue(!GlobalErrorCodeConstants.SUCCESS.getCode().equals(code), "code 必须是错误的!");
+        CommonResult<T> result = new CommonResult<>();
+        result.code = code;
+        result.msg = message;
+        return result;
+    }
+
+    public static <T> CommonResult<T> error(ErrorCode errorCode) {
+        return error(errorCode.getCode(), errorCode.getMsg());
+    }
+
+    public static <T> CommonResult<T> success(T data) {
+        CommonResult<T> result = new CommonResult<>();
+        result.code = GlobalErrorCodeConstants.SUCCESS.getCode();
+        result.data = data;
+        result.msg = "";
+        return result;
+    }
+
+    public static boolean isSuccess(Integer code) {
+        return Objects.equals(code, GlobalErrorCodeConstants.SUCCESS.getCode());
+    }
+
+    public static <T> CommonResult<T> error(ServiceException serviceException) {
+        return error(serviceException.getCode(), serviceException.getMessage());
+    }
+
+    @JsonIgnore // 避免 jackson 序列化
+    public boolean isSuccess() {
+        return isSuccess(code);
+    }
+
+    // ========= 和 Exception 异常体系集成 =========
+
+    @JsonIgnore // 避免 jackson 序列化
+    public boolean isError() {
+        return !isSuccess();
+    }
+
+    /**
+     * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
+     */
+    public void checkError() throws ServiceException {
+        if (isSuccess()) {
+            return;
+        }
+        // 业务异常
+        throw new ServiceException(code, msg);
+    }
+
+    /**
+     * 判断是否有异常。如果有,则抛出 {@link ServiceException} 异常
+     * 如果没有,则返回 {@link #data} 数据
+     */
+    @JsonIgnore // 避免 jackson 序列化
+    public T getCheckedData() {
+        checkError();
+        return data;
+    }
+
+}

+ 36 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/ImportExcelVO.java

@@ -0,0 +1,36 @@
+package com.yanfan.common.core.domain;
+
+import com.yanfan.common.annotation.Excel;
+import lombok.Data;
+
+/**
+ * @author admin
+ * @version 1.0
+ * @description: TODO
+ * @date 2024-07-12 16:20
+ */
+@Data
+public class ImportExcelVO {
+
+    @Excel(name = "ID")
+    private Long id;
+
+    @Excel(name = "城市ID")
+    private String code;
+
+    @Excel(name = "行政归属")
+    private String city;
+
+    @Excel(name = "城市简称")
+    private String simCity;
+
+    @Excel(name = "拼音")
+    private String cn;
+
+    @Excel(name = "lat")
+    private String lat;
+
+    @Excel(name = "lon")
+    private String lon;
+
+}

+ 25 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/OutputExcelVO.java

@@ -0,0 +1,25 @@
+package com.yanfan.common.core.domain;
+
+import lombok.Data;
+
+import java.util.List;
+
+/**
+ * @author admin
+ * @version 1.0
+ * @description: TODO
+ * @date 2024-07-12 16:25
+ */
+@Data
+public class OutputExcelVO {
+
+    private String code;
+
+    private String name;
+
+    private String lat;
+
+    private String lon;
+
+    private List<OutputExcelVO> children;
+}

+ 25 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/PageParam.java

@@ -0,0 +1,25 @@
+package com.yanfan.common.core.domain;
+
+import lombok.Data;
+
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class PageParam implements Serializable {
+
+    private static final Integer PAGE_NO = 1;
+    private static final Integer PAGE_SIZE = 10;
+
+    @NotNull(message = "页码不能为空")
+    @Min(value = 1, message = "页码最小值为 1")
+    private Integer pageNo = PAGE_NO;
+
+    @NotNull(message = "每页条数不能为空")
+    @Min(value = 1, message = "每页条数最小值为 1")
+    @Max(value = 100, message = "每页条数最大值为 100")
+    private Integer pageSize = PAGE_SIZE;
+
+}

+ 42 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/PageResult.java

@@ -0,0 +1,42 @@
+package com.yanfan.common.core.domain;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+@Api(tags = "分页结果")
+@Data
+public final class PageResult<T> implements Serializable {
+
+    @ApiModelProperty(value = "数据", required = true)
+    private List<T> list;
+
+    @ApiModelProperty(value = "总量", required = true)
+    private Long total;
+
+    public PageResult() {
+    }
+
+    public PageResult(List<T> list, Long total) {
+        this.list = list;
+        this.total = total;
+    }
+
+    public PageResult(Long total) {
+        this.list = new ArrayList<>();
+        this.total = total;
+    }
+
+    public static <T> PageResult<T> empty() {
+        return new PageResult<>(0L);
+    }
+
+    public static <T> PageResult<T> empty(Long total) {
+        return new PageResult<>(total);
+    }
+
+}

+ 99 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/R.java

@@ -0,0 +1,99 @@
+package com.yanfan.common.core.domain;
+
+import com.yanfan.common.constant.HttpStatus;
+
+import java.io.Serializable;
+
+/**
+ * 响应信息主体
+ *
+ * @author ruoyi
+ */
+public class R<T> implements Serializable {
+    /**
+     * 成功
+     */
+    public static final int SUCCESS = HttpStatus.SUCCESS;
+    /**
+     * 失败
+     */
+    public static final int FAIL = HttpStatus.ERROR;
+    private static final long serialVersionUID = 1L;
+    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 static <T> Boolean isError(R<T> ret) {
+        return !isSuccess(ret);
+    }
+
+    public static <T> Boolean isSuccess(R<T> ret) {
+        return R.SUCCESS == ret.getCode();
+    }
+
+    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;
+    }
+}

+ 56 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/SortingField.java

@@ -0,0 +1,56 @@
+package com.yanfan.common.core.domain;
+
+import java.io.Serializable;
+
+/**
+ * 排序字段 DTO
+ * <p>
+ * 类名加了 ing 的原因是,避免和 ES SortField 重名。
+ */
+public class SortingField implements Serializable {
+
+    /**
+     * 顺序 - 升序
+     */
+    public static final String ORDER_ASC = "asc";
+    /**
+     * 顺序 - 降序
+     */
+    public static final String ORDER_DESC = "desc";
+
+    /**
+     * 字段
+     */
+    private String field;
+    /**
+     * 顺序
+     */
+    private String order;
+
+    // 空构造方法,解决反序列化
+    public SortingField() {
+    }
+
+    public SortingField(String field, String order) {
+        this.field = field;
+        this.order = order;
+    }
+
+    public String getField() {
+        return field;
+    }
+
+    public SortingField setField(String field) {
+        this.field = field;
+        return this;
+    }
+
+    public String getOrder() {
+        return order;
+    }
+
+    public SortingField setOrder(String order) {
+        this.order = order;
+        return this;
+    }
+}

+ 20 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/TenantBaseDO.java

@@ -0,0 +1,20 @@
+package com.yanfan.common.core.domain;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 拓展多租户的 BaseDO 基类
+ *
+ * @author yanfan
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public abstract class TenantBaseDO extends BaseDO {
+
+    /**
+     * 多租户编号
+     */
+    private Long tenantId;
+
+}

+ 78 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/TreeEntity.java

@@ -0,0 +1,78 @@
+package com.yanfan.common.core.domain;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Tree基类
+ *
+ * @author ruoyi
+ */
+public class TreeEntity extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 父菜单名称
+     */
+    private String parentName;
+
+    /**
+     * 父菜单ID
+     */
+    private Long parentId;
+
+    /**
+     * 显示顺序
+     */
+    private Integer orderNum;
+
+    /**
+     * 祖级列表
+     */
+    private String ancestors;
+
+    /**
+     * 子部门
+     */
+    private List<?> children = new ArrayList<>();
+
+    public String getParentName() {
+        return parentName;
+    }
+
+    public void setParentName(String parentName) {
+        this.parentName = parentName;
+    }
+
+    public Long getParentId() {
+        return parentId;
+    }
+
+    public void setParentId(Long parentId) {
+        this.parentId = parentId;
+    }
+
+    public Integer getOrderNum() {
+        return orderNum;
+    }
+
+    public void setOrderNum(Integer orderNum) {
+        this.orderNum = orderNum;
+    }
+
+    public String getAncestors() {
+        return ancestors;
+    }
+
+    public void setAncestors(String ancestors) {
+        this.ancestors = ancestors;
+    }
+
+    public List<?> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<?> children) {
+        this.children = children;
+    }
+}

+ 74 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/TreeSelect.java

@@ -0,0 +1,74 @@
+package com.yanfan.common.core.domain;
+
+import com.yanfan.common.core.domain.entity.SysDept;
+import com.yanfan.common.core.domain.entity.SysMenu;
+import com.fasterxml.jackson.annotation.JsonInclude;
+
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * Treeselect树结构实体类
+ *
+ * @author ruoyi
+ */
+public class TreeSelect implements Serializable {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 节点ID
+     */
+    private Long id;
+
+    /**
+     * 节点名称
+     */
+    private String label;
+
+    /**
+     * 子节点
+     */
+    @JsonInclude(JsonInclude.Include.NON_EMPTY)
+    private List<TreeSelect> children;
+
+    public TreeSelect() {
+
+    }
+
+    public TreeSelect(SysDept dept) {
+        this.id = dept.getDeptId();
+        this.label = dept.getDeptName();
+        this.children = dept.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public TreeSelect(SysMenu menu) {
+        this.id = menu.getMenuId();
+        this.label = menu.getMenuName();
+        this.children = menu.getChildren().stream().map(TreeSelect::new).collect(Collectors.toList());
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public void setLabel(String label) {
+        this.label = label;
+    }
+
+    public List<TreeSelect> getChildren() {
+        return children;
+    }
+
+    public void setChildren(List<TreeSelect> children) {
+        this.children = children;
+    }
+}

+ 334 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDept.java

@@ -0,0 +1,334 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 部门表 sys_dept
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysDept", description = "部门表 sys_dept")
+public class SysDept extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 部门ID
+     */
+    @ApiModelProperty("部门ID")
+    private Long deptId;
+
+    /**
+     * 机构系统账号ID
+     */
+    private Long deptUserId;
+
+    /**
+     * 父部门ID
+     */
+    @ApiModelProperty("父部门ID")
+    private Long parentId;
+
+    /**
+     * 祖级列表
+     */
+    @ApiModelProperty("祖级列表")
+    private String ancestors;
+
+    /**
+     * 部门名称
+     */
+    @ApiModelProperty("部门名称")
+    private String deptName;
+
+    /**
+     * 显示顺序
+     */
+    @ApiModelProperty("显示顺序")
+    private Integer orderNum;
+
+    /**
+     * 负责人
+     */
+    @ApiModelProperty("负责人")
+    private String leader;
+
+    /**
+     * 联系电话
+     */
+    @ApiModelProperty("联系电话")
+    private String phone;
+
+    /**
+     * 邮箱
+     */
+    @ApiModelProperty("邮箱")
+    private String email;
+
+    /**
+     * 部门状态:0正常,1停用
+     */
+    @ApiModelProperty("部门状态:0正常,1停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @ApiModelProperty("删除标志(0代表存在 2代表删除)")
+    private String delFlag;
+
+    /**
+     * 父部门名称
+     */
+    @ApiModelProperty("父部门名称")
+    private String parentName;
+
+    /**
+     * 子部门
+     */
+    @ApiModelProperty("子部门")
+    private List<SysDept> children = new ArrayList<SysDept>();
+
+    /**
+     * 系统账号名称
+     */
+    private String userName;
+
+    /**
+     * 系统账号密码
+     */
+    private String password;
+
+    /**
+     * 确认密码
+     */
+    private String confirmPassword;
+
+    /**
+     * 机构类型
+     */
+    private Integer deptType;
+    /**
+     * 是否显示自己
+     */
+    private Boolean showOwner;
+    /**
+     * 管理员姓名
+     */
+    private String deptUserName;
+    /**
+     * 部门ID
+     */
+    @ApiModelProperty("部门ID")
+    private Long menuId;
+
+    /**
+     * 设备新增限制次数
+     * @return
+     */
+    @ApiModelProperty("部门ID")
+    private Integer devmun;
+
+    public Boolean getShowOwner() {
+        return showOwner;
+    }
+
+    public void setShowOwner(Boolean showOwner) {
+        this.showOwner = showOwner;
+    }
+
+    public String getDeptUserName() {
+        return deptUserName;
+    }
+
+    public void setDeptUserName(String deptUserName) {
+        this.deptUserName = deptUserName;
+    }
+
+    public Integer getDeptType() {
+        return deptType;
+    }
+
+    public void setDeptType(Integer deptType) {
+        this.deptType = deptType;
+    }
+
+    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 getConfirmPassword() {
+        return confirmPassword;
+    }
+
+    public void setConfirmPassword(String confirmPassword) {
+        this.confirmPassword = confirmPassword;
+    }
+
+    public Long getDeptUserId() {
+        return deptUserId;
+    }
+
+    public void setDeptUserId(Long deptUserId) {
+        this.deptUserId = deptUserId;
+    }
+
+    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;
+    }
+
+    public Long getmenuId() {
+        return menuId;
+    }
+
+    public void setMenuId(Long menuId) {
+        this.menuId = menuId;
+    }
+
+    public Integer getDevmun() {return devmun;}
+
+    public void setDevmun(Integer devmun) {this.devmun = devmun;}
+
+    @Override
+    public String toString() {
+        return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
+                .append("deptId", getDeptId())
+                .append("deptUserId", getDeptUserId())
+                .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())
+                .append("menuId", getmenuId())
+                .append("devmun", getDevmun())
+                .toString();
+    }
+}

+ 212 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDictData.java

@@ -0,0 +1,212 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.annotation.Excel;
+import com.yanfan.common.annotation.Excel.ColumnType;
+import com.yanfan.common.constant.UserConstants;
+import com.yanfan.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典数据表 sys_dict_data
+ *
+ * @author ruoyi
+ */
+@Data
+@ApiModel(value = "SysDictData", description = "字典数据表 sys_dict_data")
+public class SysDictData extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典编码
+     */
+    @ApiModelProperty("字典编码")
+    @Excel(name = "字典编码", cellType = ColumnType.NUMERIC)
+    private Long dictCode;
+
+    /**
+     * 字典排序
+     */
+    @ApiModelProperty("字典排序")
+    @Excel(name = "字典排序", cellType = ColumnType.NUMERIC)
+    private Long dictSort;
+
+    /**
+     * 字典标签
+     */
+    @ApiModelProperty("字典标签")
+    @Excel(name = "字典标签")
+    private String dictLabel;
+
+    /**
+     * 字典标签
+     */
+    @ApiModelProperty("中文字典标签")
+    private String dictLabel_zh_CN;
+
+    /**
+     * 字典标签
+     */
+    @ApiModelProperty("英文字典标签")
+    private String dictLabel_en_US;
+
+    /**
+     * 字典键值
+     */
+    @ApiModelProperty("字典键值")
+    @Excel(name = "字典键值")
+    private String dictValue;
+
+    /**
+     * 字典类型
+     */
+    @ApiModelProperty("字典类型")
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 样式属性(其他样式扩展)
+     */
+    @ApiModelProperty("样式属性(其他样式扩展)")
+    private String cssClass;
+
+    /**
+     * 表格字典样式
+     */
+    @ApiModelProperty("表格字典样式")
+    private String listClass;
+
+    /**
+     * 是否默认(Y是 N否)
+     */
+    @ApiModelProperty("是否默认(Y是 N否)")
+    @Excel(name = "是否默认", readConverterExp = "Y=是,N=否")
+    private String isDefault;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ApiModelProperty("状态(0正常 1停用)")
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    @Deprecated
+    private String language;
+
+    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;
+    }
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    @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();
+    }
+}

+ 117 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysDictType.java

@@ -0,0 +1,117 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.annotation.Excel;
+import com.yanfan.common.annotation.Excel.ColumnType;
+import com.yanfan.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * 字典类型表 sys_dict_type
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysDictType", description = "字典类型表 sys_dict_type")
+public class SysDictType extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 字典主键
+     */
+    @ApiModelProperty("字典主键")
+    @Excel(name = "字典主键", cellType = ColumnType.NUMERIC)
+    private Long dictId;
+
+    /**
+     * 字典名称
+     */
+    @ApiModelProperty("字典名称")
+    @Excel(name = "字典名称")
+    private String dictName;
+
+    /**
+     * 字典类型
+     */
+    @ApiModelProperty("字典类型")
+    @Excel(name = "字典类型")
+    private String dictType;
+
+    /**
+     * 状态(0正常 1停用)
+     */
+    @ApiModelProperty("状态(0正常 1停用)")
+    @Excel(name = "状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    @Deprecated
+    private String language;
+
+
+    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;
+    }
+
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+
+    @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();
+    }
+}

+ 305 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysMenu.java

@@ -0,0 +1,305 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 菜单权限表 sys_menu
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysMenu", description = "菜单权限表 sys_menu")
+public class SysMenu extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 菜单ID
+     */
+    @ApiModelProperty("菜单ID")
+    private Long menuId;
+
+    /**
+     * 菜单名称
+     */
+    @ApiModelProperty("菜单名称")
+    private String menuName;
+
+    /**
+     * 父菜单名称
+     */
+    @ApiModelProperty("父菜单名称")
+    private String parentName;
+
+    /**
+     * 父菜单ID
+     */
+    @ApiModelProperty("父菜单ID")
+    private Long parentId;
+
+    /**
+     * 显示顺序
+     */
+    @ApiModelProperty("显示顺序")
+    private Integer orderNum;
+
+    /**
+     * 路由地址
+     */
+    @ApiModelProperty("路由地址")
+    private String path;
+
+    /**
+     * 组件路径
+     */
+    @ApiModelProperty("组件路径")
+    private String component;
+
+    /**
+     * 路由参数
+     */
+    @ApiModelProperty("路由参数")
+    private String query;
+
+    /**
+     * 是否为外链(0是 1否)
+     */
+    @ApiModelProperty("是否为外链(0是 1否)")
+    private String isFrame;
+
+    /**
+     * 是否缓存(0缓存 1不缓存)
+     */
+    @ApiModelProperty("是否缓存(0缓存 1不缓存)")
+    private String isCache;
+
+    /**
+     * 类型(M目录 C菜单 F按钮)
+     */
+    @ApiModelProperty("类型(M目录 C菜单 F按钮)")
+    private String menuType;
+
+    /**
+     * 显示状态(0显示 1隐藏)
+     */
+    @ApiModelProperty("显示状态(0显示 1隐藏)")
+    private String visible;
+
+    /**
+     * 菜单状态(0正常 1停用)
+     */
+    @ApiModelProperty("菜单状态(0正常 1停用)")
+    private String status;
+
+    /**
+     * 权限字符串
+     */
+    @ApiModelProperty("权限字符串")
+    private String perms;
+
+    /**
+     * 菜单图标
+     */
+    @ApiModelProperty("菜单图标")
+    private String icon;
+
+    /**
+     * 子菜单
+     */
+    @ApiModelProperty("子菜单")
+    private List<SysMenu> children = new ArrayList<SysMenu>();
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 菜单语言
+     */
+    @Deprecated
+    private String language;
+
+    public String getLanguage() {
+        return language;
+    }
+
+    public void setLanguage(String language) {
+        this.language = language;
+    }
+
+    public Long getDeptId() {
+        return deptId;
+    }
+
+    public void setDeptId(Long deptId) {
+        this.deptId = deptId;
+    }
+
+    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 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("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();
+    }
+}

+ 317 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysRole.java

@@ -0,0 +1,317 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.annotation.Excel;
+import com.yanfan.common.annotation.Excel.ColumnType;
+import com.yanfan.common.core.domain.BaseEntity;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import java.util.Set;
+
+/**
+ * 角色表 sys_role
+ *
+ * @author ruoyi
+ */
+@ApiModel(value = "SysRole", description = "角色表 sys_role")
+public class SysRole extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 角色ID
+     */
+    @ApiModelProperty("角色ID")
+    @Excel(name = "角色序号", cellType = ColumnType.NUMERIC)
+    private Long roleId;
+
+    /**
+     * 角色名称
+     */
+    @ApiModelProperty("角色名称")
+    @Excel(name = "角色名称")
+    private String roleName;
+
+    /**
+     * 角色权限
+     */
+    @ApiModelProperty("角色权限")
+    @Excel(name = "角色权限")
+    private String roleKey;
+
+    /**
+     * 角色排序
+     */
+    @ApiModelProperty("角色排序")
+    @Excel(name = "角色排序")
+    private Integer roleSort;
+
+    /**
+     * 数据范围(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)
+     */
+    @ApiModelProperty(value = "数据范围", notes = "(1:所有数据权限;2:自定义数据权限;3:本部门数据权限;4:本部门及以下数据权限;5:仅本人数据权限)")
+    @Excel(name = "数据范围", readConverterExp = "1=所有数据权限,2=自定义数据权限,3=本部门数据权限,4=本部门及以下数据权限,5=仅本人数据权限")
+    private String dataScope;
+
+    /**
+     * 菜单树选择项是否关联显示( 0:父子不互相关联显示 1:父子互相关联显示)
+     */
+    @ApiModelProperty(value = "菜单树选择项是否关联显示", notes = "( 0:父子不互相关联显示 1:父子互相关联显示)")
+    private boolean menuCheckStrictly;
+
+    /**
+     * 部门树选择项是否关联显示(0:父子不互相关联显示 1:父子互相关联显示 )
+     */
+    @ApiModelProperty(value = "部门树选择项是否关联显示", notes = "(0:父子不互相关联显示 1:父子互相关联显示 )")
+    private boolean deptCheckStrictly;
+
+    /**
+     * 角色状态(0正常 1停用)
+     */
+    @ApiModelProperty("角色状态(0正常 1停用)")
+    @Excel(name = "角色状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @ApiModelProperty("删除标志")
+    private String delFlag;
+
+    /**
+     * 用户是否存在此角色标识 默认不存在
+     */
+    private boolean flag = false;
+
+    /**
+     * 菜单组
+     */
+    @ApiModelProperty("菜单组")
+    private Long[] menuIds;
+
+    /**
+     * 部门组(数据权限)
+     */
+    @ApiModelProperty("部门组")
+    private Long[] deptIds;
+
+    /**
+     * 角色菜单权限
+     */
+    @ApiModelProperty("角色菜单权限")
+    private Set<String> permissions;
+
+    /**
+     * 部门id
+     */
+    private Long deptId;
+
+    /**
+     * 部门名称
+     */
+    private String deptName;
+
+    /**
+     * 是否显示下级机构数据
+     */
+    private Boolean showChild;
+
+    /**
+     * 是否可以修改用户角色
+     */
+    private Boolean canEditRole;
+
+    /**
+     * 是否是机构管理员角色
+     */
+    private Boolean manager;
+
+    public SysRole() {
+
+    }
+
+    public SysRole(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public static boolean isAdmin(Long roleId) {
+        return roleId != null && 1L == roleId;
+    }
+
+    public Boolean getManager() {
+        return manager;
+    }
+
+    public void setManager(Boolean manager) {
+        this.manager = manager;
+    }
+
+    public Boolean getCanEditRole() {
+        return canEditRole;
+    }
+
+    public void setCanEditRole(Boolean canEditRole) {
+        this.canEditRole = canEditRole;
+    }
+
+    public Boolean getShowChild() {
+        return showChild;
+    }
+
+    public void setShowChild(Boolean showChild) {
+        this.showChild = showChild;
+    }
+
+    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 getRoleId() {
+        return roleId;
+    }
+
+    public void setRoleId(Long roleId) {
+        this.roleId = roleId;
+    }
+
+    public boolean isAdmin() {
+        return isAdmin(this.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();
+    }
+}

+ 41 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysTranslate.java

@@ -0,0 +1,41 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.annotation.Excel;
+import com.yanfan.common.core.domain.BaseEntity;
+import lombok.Data;
+
+/**
+ * 翻译对象 sys_translate
+ *
+ * @author ruoyi
+ */
+@Data
+public class SysTranslate extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * ID
+     */
+    @Excel(name = "ID")
+    private Long id;
+
+    /**
+     * zh_CN
+     */
+    @Excel(name = "zh-CN")
+    private String zh_CN;
+
+    /**
+     * en_US
+     */
+    @Excel(name = "en-US")
+    private String en_US;
+
+    /**
+     * 物模型翻译表使用
+     */
+    private Long productId;
+
+    private String tableName;
+
+}

+ 251 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/SysUser.java

@@ -0,0 +1,251 @@
+package com.yanfan.common.core.domain.entity;
+
+import com.yanfan.common.annotation.Excel;
+import com.yanfan.common.annotation.Excel.ColumnType;
+import com.yanfan.common.annotation.Excel.Type;
+import com.yanfan.common.annotation.Excels;
+import com.yanfan.common.core.domain.BaseEntity;
+import com.yanfan.common.xss.Xss;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Getter;
+import lombok.Setter;
+import org.apache.commons.lang3.builder.ToStringBuilder;
+import org.apache.commons.lang3.builder.ToStringStyle;
+
+import javax.validation.constraints.Email;
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Size;
+import java.util.Date;
+import java.util.List;
+
+/**
+ * 用户对象 sys_user
+ *
+ * @author ruoyi
+ */
+@Getter
+@Setter
+@ApiModel(value = "SysUser", description = "用户对象 sys_user")
+public class SysUser extends BaseEntity {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 用户ID
+     */
+    @ApiModelProperty("用户ID")
+    @Excel(name = "用户序号", cellType = ColumnType.NUMERIC, prompt = "用户编号")
+    private Long userId;
+
+    /**
+     * 部门ID
+     */
+    @ApiModelProperty("部门ID")
+    @Excel(name = "部门编号", type = Type.IMPORT)
+    private Long deptId;
+
+    /**
+     * 用户账号
+     */
+    @ApiModelProperty("用户账号")
+    @Excel(name = "登录名称")
+    private String userName;
+
+    /**
+     * 用户昵称
+     */
+    @ApiModelProperty("用户昵称")
+    @Excel(name = "用户名称")
+    private String nickName;
+
+    /**
+     * 用户邮箱
+     */
+    @ApiModelProperty("用户邮箱")
+    @Excel(name = "用户邮箱")
+    private String email;
+
+    /**
+     * 手机号码
+     */
+    @ApiModelProperty("手机号码")
+    @Excel(name = "手机号码")
+    private String phonenumber;
+
+    /**
+     * 用户性别
+     */
+    @ApiModelProperty("用户性别")
+    @Excel(name = "用户性别", readConverterExp = "0=男,1=女,2=未知")
+    private String sex;
+
+    /**
+     * 用户头像
+     */
+    @ApiModelProperty("用户头像")
+    private String avatar;
+
+    /**
+     * 密码
+     */
+    @ApiModelProperty("密码")
+    private String password;
+
+    /**
+     * 帐号状态(0正常 1停用)
+     */
+    @ApiModelProperty("帐号状态(0正常 1停用)")
+    @Excel(name = "帐号状态", readConverterExp = "0=正常,1=停用")
+    private String status;
+
+    /**
+     * 删除标志(0代表存在 2代表删除)
+     */
+    @ApiModelProperty("删除标志")
+    private String delFlag;
+
+    /**
+     * 最后登录IP
+     */
+    @ApiModelProperty("最后登录IP")
+    @Excel(name = "最后登录IP", type = Type.EXPORT)
+    private String loginIp;
+
+    /**
+     * 最后登录时间
+     */
+    @ApiModelProperty("最后登录时间")
+    @Excel(name = "最后登录时间", width = 30, dateFormat = "yyyy-MM-dd HH:mm:ss", type = Type.EXPORT)
+    private Date loginDate;
+
+    /**
+     * 部门对象
+     */
+    @ApiModelProperty("部门对象")
+    @Excels({@Excel(name = "部门名称", targetAttr = "deptName", type = Type.EXPORT), @Excel(name = "部门负责人", targetAttr = "leader", type = Type.EXPORT)})
+    private SysDept dept;
+
+    /**
+     * 角色对象
+     */
+    @ApiModelProperty("角色对象")
+    private List<SysRole> roles;
+
+    /**
+     * 角色组
+     */
+    @ApiModelProperty("角色组")
+    private Long[] roleIds;
+
+    /**
+     * 岗位组
+     */
+    @ApiModelProperty("岗位组")
+    private Long[] postIds;
+
+    /**
+     * 角色ID
+     */
+    @ApiModelProperty("角色ID")
+    private Long roleId;
+
+    /**
+     * 是否显示下级机构数据
+     */
+    private Boolean showChild;
+
+    /**
+     * 是否是机构管理员
+     */
+    private Boolean manager;
+    /**
+     * 语言
+     */
+    private String language;
+    /**
+     * 时区
+     */
+    private String timeZone;
+    /**
+     * 是否可以修改用户角色
+     */
+    private Boolean canEditRole;
+
+    public SysUser() {
+
+    }
+
+    public SysUser(Long userId) {
+        this.userId = userId;
+    }
+
+    public static boolean isAdmin(Long userId) {
+        return userId != null && 1L == userId;
+    }
+
+
+    public boolean isAdmin() {
+        return isAdmin(this.userId);
+    }
+
+    @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;
+    }
+
+    @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();
+    }
+}

+ 10 - 0
yanfan-common/src/main/java/com/yanfan/common/core/domain/entity/vo/SysMenuVo.java

@@ -0,0 +1,10 @@
+package com.yanfan.common.core.domain.entity.vo;
+
+import com.yanfan.common.core.domain.entity.SysMenu;
+import lombok.Data;
+
+@Data
+public class SysMenuVo extends SysMenu {
+    public String label;
+    public Long value;
+}

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov