diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml new file mode 100644 index 00000000..a8276a4c --- /dev/null +++ b/ruoyi-admin/pom.xml @@ -0,0 +1,125 @@ + + + + ruoyi-ai + org.ruoyi + ${revision} + ../pom.xml + + 4.0.0 + jar + ruoyi-admin + + + web服务入口 + + + + + + + com.mysql + mysql-connector-j + + + + + com.oracle.database.jdbc + ojdbc8 + + + + + org.postgresql + postgresql + + + + + com.microsoft.sqlserver + mssql-jdbc + + + + org.ruoyi + ruoyi-common-doc + + + + org.ruoyi + ruoyi-system + + + + org.ruoyi + ruoyi-fusion + + + + org.ruoyi + ruoyi-knowledge + + + + + + org.ruoyi + ruoyi-demo + + + + org.springframework.boot + spring-boot-starter-test + test + + + + + net.coobird + thumbnailator + 0.4.11 + + + io.github.ollama4j + ollama4j + 1.0.79 + compile + + + + + + ${project.artifactId} + + + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.version} + + + + repackage + + + + + + org.apache.maven.plugins + maven-jar-plugin + ${maven-jar-plugin.version} + + + org.apache.maven.plugins + maven-war-plugin + ${maven-war-plugin.version} + + false + ${project.artifactId} + + + + + + diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIApplication.java b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java similarity index 96% rename from ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIApplication.java rename to ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java index 68748bc1..2d0693c3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIApplication.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIApplication.java @@ -1,4 +1,4 @@ -package org.ruoyi.system; +package org.ruoyi; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIServletInitializer.java b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIServletInitializer.java similarity index 94% rename from ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIServletInitializer.java rename to ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIServletInitializer.java index 16d037c5..626d7a31 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/RuoYiAIServletInitializer.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/RuoYiAIServletInitializer.java @@ -1,4 +1,4 @@ -package org.ruoyi.system; +package org.ruoyi; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/AuthController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java similarity index 89% rename from ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/AuthController.java rename to ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java index 360abeb7..e78d09c0 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/AuthController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/AuthController.java @@ -1,12 +1,14 @@ -package org.ruoyi.system.controller.system; +package org.ruoyi.controller; import cn.dev33.satoken.annotation.SaIgnore; import cn.hutool.core.collection.CollUtil; -import jakarta.servlet.http.HttpServletRequest; -import lombok.RequiredArgsConstructor; import org.ruoyi.common.core.constant.Constants; import org.ruoyi.common.core.domain.R; -import org.ruoyi.common.core.domain.model.*; +import org.ruoyi.common.core.domain.model.EmailLoginBody; +import org.ruoyi.common.core.domain.model.LoginBody; +import org.ruoyi.common.core.domain.model.RegisterBody; +import org.ruoyi.common.core.domain.model.SmsLoginBody; +import org.ruoyi.common.core.domain.model.VisitorLoginBody; import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.StreamUtils; import org.ruoyi.common.core.utils.StringUtils; @@ -14,12 +16,16 @@ import org.ruoyi.common.satoken.utils.LoginHelper; import org.ruoyi.common.tenant.helper.TenantHelper; import org.ruoyi.system.domain.bo.SysTenantBo; import org.ruoyi.system.domain.vo.LoginTenantVo; -import org.ruoyi.system.domain.vo.LoginVo; import org.ruoyi.system.domain.vo.SysTenantVo; import org.ruoyi.system.domain.vo.TenantListVo; import org.ruoyi.system.service.ISysTenantService; + import org.ruoyi.system.service.SysLoginService; import org.ruoyi.system.service.SysRegisterService; +import org.ruoyi.system.domain.vo.LoginVo; + +import jakarta.servlet.http.HttpServletRequest; +import lombok.RequiredArgsConstructor; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.*; @@ -42,15 +48,6 @@ public class AuthController { private final SysRegisterService registerService; private final ISysTenantService tenantService; - -// @PostMapping("/xcxLogin") -// public R login(@Validated @RequestBody String xcxCode) throws WxErrorException { -// -// String openidFromCode = loginService.getOpenidFromCode((String) JSONUtil.parseObj(xcxCode).get("xcxCode")); -// LoginVo loginVo = loginService.mpLogin(openidFromCode); -// return R.ok(loginVo); -// } - /** * 登录方法 * @@ -67,7 +64,6 @@ public class AuthController { body.getUsername(), body.getPassword(), body.getCode(), body.getUuid()); loginVo.setToken(token); - loginVo.setAccess_token(token); loginVo.setUserInfo(LoginHelper.getLoginUser()); return R.ok(loginVo); } @@ -89,7 +85,6 @@ public class AuthController { /** * 访客登录 - * * @param loginBody 登录信息 * @return token信息 */ @@ -128,7 +123,7 @@ public class AuthController { */ @PostMapping("/register") public R register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) { - String domainName = request.getServerName(); + String domainName = request.getServerName(); user.setDomainName(domainName); registerService.register(user); return R.ok(); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/CaptchaController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/CaptchaController.java similarity index 97% rename from ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/CaptchaController.java rename to ruoyi-admin/src/main/java/org/ruoyi/controller/CaptchaController.java index 8ebe2236..89cf2437 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/CaptchaController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/CaptchaController.java @@ -1,14 +1,10 @@ -package org.ruoyi.system.controller.system; +package org.ruoyi.controller; import cn.dev33.satoken.annotation.SaIgnore; import cn.hutool.captcha.AbstractCaptcha; import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.RandomUtil; -import jakarta.validation.Valid; -import jakarta.validation.constraints.NotBlank; -import lombok.RequiredArgsConstructor; -import lombok.extern.slf4j.Slf4j; import org.ruoyi.common.core.constant.Constants; import org.ruoyi.common.core.constant.GlobalConstants; import org.ruoyi.common.core.domain.R; @@ -26,6 +22,10 @@ import org.ruoyi.common.web.config.properties.CaptchaProperties; import org.ruoyi.common.web.enums.CaptchaType; import org.ruoyi.system.domain.request.EmailRequest; import org.ruoyi.system.domain.vo.CaptchaVo; +import jakarta.validation.Valid; +import jakarta.validation.constraints.NotBlank; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; import org.springframework.expression.Expression; import org.springframework.expression.ExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser; @@ -36,8 +36,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import java.time.Duration; -import java.util.HashMap; -import java.util.Map; +import java.util.*; /** * 验证码操作处理 @@ -95,6 +94,7 @@ public class CaptchaController { String suffix = configService.getConfigValue("mail", "suffix"); String prompt = configService.getConfigValue("mail", "prompt"); if(StringUtils.isNotEmpty(suffix)){ + // 动态的域名列表 String[] invalidDomains = suffix.split(","); for (String domain : invalidDomains) { if (emailRequest.getUsername().endsWith(domain)) { @@ -107,7 +107,7 @@ public class CaptchaController { String mailTitle = configService.getConfigValue("mail", "mailTitle"); String replacedModel = model.replace("{code}", code); try { - MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel); + MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel); } catch (Exception e) { log.error("邮箱验证码发送异常 => {}", e.getMessage()); return R.fail(e.getMessage()); diff --git a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/IndexController.java b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java similarity index 53% rename from ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/IndexController.java rename to ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java index 72b6828d..4da12bc8 100644 --- a/ruoyi-modules/ruoyi-system/src/main/java/org/ruoyi/system/controller/system/IndexController.java +++ b/ruoyi-admin/src/main/java/org/ruoyi/controller/IndexController.java @@ -1,9 +1,9 @@ -package org.ruoyi.system.controller.system; +package org.ruoyi.controller; import cn.dev33.satoken.annotation.SaIgnore; import lombok.RequiredArgsConstructor; +import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; /** * 首页 @@ -12,7 +12,7 @@ import org.springframework.web.bind.annotation.RestController; */ @SaIgnore @RequiredArgsConstructor -@RestController +@Controller public class IndexController { /** @@ -20,7 +20,17 @@ public class IndexController { */ @GetMapping("/") public String index() { - return "RuoYi-AI 启动成功"; + return "index.html"; + } + + @GetMapping("/success") + public String success(){ + return "paySuccess.html"; + } + + @GetMapping("/cancel") + public String cancel(){ + return "cancel"; } } diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/application-dev.yml b/ruoyi-admin/src/main/resources/application-dev.yml similarity index 79% rename from ruoyi-modules/ruoyi-system/src/main/resources/application-dev.yml rename to ruoyi-admin/src/main/resources/application-dev.yml index 44530d49..09c609c3 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/application-dev.yml +++ b/ruoyi-admin/src/main/resources/application-dev.yml @@ -25,10 +25,9 @@ spring: master: type: ${spring.datasource.type} driverClassName: com.mysql.cj.jdbc.Driver - url: jdbc:mysql://43.139.70.230:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true - username: ruoyi-ai - password: ruoyi-ai - + url: jdbc:mysql://43.139.70.230:3306/ry-vue?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true + username: ry-vue + password: xx hikari: # 最大连接池数量 @@ -97,3 +96,23 @@ sms: signName: 测试 # 腾讯专用 sdkAppId: + +spring: + ai: + openai: + api-key: sk-xX + base-url: https://api.pandarobot.chat + ollama: + base-url: http://localhost:11434 + init: + pull-model-strategy: always + timeout: 60s + max-retries: 1 + mcp: + client: + enabled: true + name: call-mcp-server + sse: + connections: + server1: + url: http://127.0.0.1:8080 diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/application-prod.yml b/ruoyi-admin/src/main/resources/application-prod.yml similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/application-prod.yml rename to ruoyi-admin/src/main/resources/application-prod.yml diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml similarity index 95% rename from ruoyi-modules/ruoyi-system/src/main/resources/application.yml rename to ruoyi-admin/src/main/resources/application.yml index a414d371..26173564 100644 --- a/ruoyi-modules/ruoyi-system/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -318,22 +318,5 @@ wechat: token: '' aesKey: '' - # spring ai配置 -spring: - ai: - openai: - api-key: sk-xx - base-url: https://api.pandarobot.chat/ - mcp: - client: - enabled: true - name: call-mcp-server - sse: - connections: - server1: - url: http://127.0.0.1:8080 - ollama: - init: - pull-model-strategy: always - timeout: 60s - max-retries: 1 + + diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/banner.txt b/ruoyi-admin/src/main/resources/banner.txt similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/banner.txt rename to ruoyi-admin/src/main/resources/banner.txt diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages.properties b/ruoyi-admin/src/main/resources/i18n/messages.properties similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages.properties rename to ruoyi-admin/src/main/resources/i18n/messages.properties diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages_en_US.properties b/ruoyi-admin/src/main/resources/i18n/messages_en_US.properties similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages_en_US.properties rename to ruoyi-admin/src/main/resources/i18n/messages_en_US.properties diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages_zh_CN.properties b/ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/i18n/messages_zh_CN.properties rename to ruoyi-admin/src/main/resources/i18n/messages_zh_CN.properties diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/ip2region.xdb b/ruoyi-admin/src/main/resources/ip2region.xdb similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/ip2region.xdb rename to ruoyi-admin/src/main/resources/ip2region.xdb diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml b/ruoyi-admin/src/main/resources/logback-plus.xml similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/logback-plus.xml rename to ruoyi-admin/src/main/resources/logback-plus.xml diff --git a/ruoyi-modules/ruoyi-system/src/main/resources/spy.properties b/ruoyi-admin/src/main/resources/spy.properties similarity index 100% rename from ruoyi-modules/ruoyi-system/src/main/resources/spy.properties rename to ruoyi-admin/src/main/resources/spy.properties diff --git a/ruoyi-admin/src/main/resources/static/.gitignore b/ruoyi-admin/src/main/resources/static/.gitignore new file mode 100644 index 00000000..9e339689 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/.gitignore @@ -0,0 +1,46 @@ +###################################################################### +# 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 + +### JRebel ### +rebel.xml + +### NetBeans ### +nbproject/private/ +build/* +nbbuild/ +nbdist/ +.nb-gradle/ + +###################################################################### +# Others +*.log +*.xml.versionsBackup +*.swp + +!*/build/*.java +!*/build/*.html +!*/build/*.xml diff --git a/ruoyi-admin/src/main/resources/static/.nojekyll b/ruoyi-admin/src/main/resources/static/.nojekyll new file mode 100644 index 00000000..e69de29b diff --git a/ruoyi-admin/src/main/resources/static/CNAME b/ruoyi-admin/src/main/resources/static/CNAME new file mode 100644 index 00000000..3a194c70 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/CNAME @@ -0,0 +1 @@ +plus-doc.dromara.org \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/README.md b/ruoyi-admin/src/main/resources/static/README.md new file mode 100644 index 00000000..b50e2523 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/README.md @@ -0,0 +1,74 @@ +# 框架介绍 +- - - +- `RuoYi-Vue-Plus` 分布式集群框架 [文档跳转](/ruoyi-vue-plus/home.md) +- `RuoYi-Cloud-Plus` 微服务框架 [文档跳转](/ruoyi-cloud-plus/home.md) +- `plus-ui` 统一 Vue3 前端项目 [文档跳转](/plus-ui/home.md) +- `plus-doc` 统一文档项目 + +## 特别赞助 + + + +
+ + +
+ + +[如何成为赞助商 加群联系作者详谈](/common/add_group.md) + +## 代码地址 + +| 介绍 | 项目名 | 项目地址 | 注意事项 | +|------------|:-----------------|------------------------------------------------------------------------------------------------------------------------|----------------------------| +| 🔥 分布式集群框架 | RuoYi-Vue-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus)
- [GitHub](https://github.com/dromara/RuoYi-Vue-Plus) | 重写RuoYi-Vue全方位升级(不兼容原框架) | +| 🔥 微服务框架 | RuoYi-Cloud-Plus | - [Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus)
- [GitHub](https://github.com/dromara/RuoYi-Cloud-Plus) | 重写RuoYi-Cloud全方位升级(不兼容原框架) | +| 🔥 统一前端项目 | plus-ui | - [Gitee](https://gitee.com/JavaLionLi/plus-ui)
- [GitHub](https://github.com/JavaLionLi/plus-ui) | Vue与Cloud项目通用前端 | +| 🔥 统一文档项目 | plus-doc | - [Gitee](https://gitee.com/dromara/plus-doc)
- [GitHub](https://github.com/dromara/plus-doc) | 通用文档 | + + +## 业务功能 + +| 功能 | 介绍 | +|-------|---------------------------------------| +| 租户管理 | 配置系统租户,支持 SaaS 场景下的多租户功能。 | +| 用户管理 | 用户是系统操作者,该功能主要完成系统用户配置。 | +| 部门管理 | 配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 | +| 岗位管理 | 配置系统用户所属担任职务。 | +| 菜单管理 | 配置系统菜单,操作权限,按钮权限标识等。 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分。 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护。 | +| 参数管理 | 对系统动态配置常用参数。 | +| 通知公告 | 系统通知公告信息发布维护。 | +| 操作日志 | 系统正常操作日志记录和查询;系统异常信息日志记录和查询。 | +| 登录日志 | 系统登录日志记录查询包含登录异常。 | +| 文件管理 | 系统文件上传、下载等管理。 | +| 定时任务 | 在线(添加、修改、删除)任务调度包含执行结果日志。 | +| 代码生成 | 前后端代码的生成(java、html、xml、sql)支持CRUD下载 。 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档。 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等。 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | +| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | +| 使用案例 | 系统的一些功能案例 | + +## 关注作者 + +作者博客: [https://lionli.blog.csdn.net/?type=blog](https://lionli.blog.csdn.net/?type=blog) + +公众号: **<狮子领域 程序圈>** +
+![输入图片说明](https://foruda.gitee.com/images/1678975769377570440/507062df_1766278.png "屏幕截图") + +## 捐献作者 + +**作者为兼职做开源,平时还需要工作,如果帮到了您可以请作者吃个盒饭** +
+ + +## Dromara 全家福 + +社区仓库地址: [dromara开源社区](https://gitee.com/organizations/dromara/projects) + +![输入图片说明](https://foruda.gitee.com/images/1706071866226295002/68cffcf6_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/_coverpage.md b/ruoyi-admin/src/main/resources/static/_coverpage.md new file mode 100644 index 00000000..d84bf0dc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/_coverpage.md @@ -0,0 +1,32 @@ + + + +
+
+
百搭AI
+ + +[![码云Gitee](https://gitee.com/ageerle/ruoyi-ai/badge/star.svg?theme=blue)](https://gitee.com/ageerle/ruoyi-ai) +[![GitHub](https://img.shields.io/github/stars/ageerle/ruoyi-ai.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/ageerle/ruoyi-ai/blob/master/LICENSE) +
+[![ruoyi-ai](https://img.shields.io/badge/ruoyi-ai-5.2.2-success.svg)](https://gitee.com/ageerle/ruoyi-ai) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]() + +
+
+ +
+ +
+ + +> 百搭AI是一个整合了多种大语言模型API的开源平台,实现了AI对话、绘图、声音克隆和私有知识库等功能。 +> +> 平台配备管理后台,支持微信支付、微信公众号、微信多开、Stripe国际支付和百度文本审核等运营功能。 +> +> 项目采用Java+Vue+Vben5技术栈构建,遵循MIT License,允许二次开发并用于商业销售。 + +Copyright © 2023-2024 版权所有:ageerle@163.com 备案号:鄂ICP备2023007672号 + +[开始使用 Let's Go](/README.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/_footer.md b/ruoyi-admin/src/main/resources/static/_footer.md new file mode 100644 index 00000000..7f5f9a3f --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/_footer.md @@ -0,0 +1,2 @@ + +对文档有疑问?欢迎您帮助我们 [完善此文档](https://gitee.com/JavaLionLi/plus-doc) ! \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/_navbar.md b/ruoyi-admin/src/main/resources/static/_navbar.md new file mode 100644 index 00000000..e893825f --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/_navbar.md @@ -0,0 +1,9 @@ + + +* [文档导航](/README.md) +* [Vue版本](/ruoyi-vue-plus/home.md) +* [Cloud版本](/ruoyi-cloud-plus/home.md) +* [前端文档](/plus-ui/home.md) +* [常见问题](/questions/lombok.md) +* [视频教程](/common/video.md) +* [演示系统](/common/demo_system.md) diff --git a/ruoyi-admin/src/main/resources/static/_sidebar.md b/ruoyi-admin/src/main/resources/static/_sidebar.md new file mode 100644 index 00000000..0446edc6 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/_sidebar.md @@ -0,0 +1,16 @@ + +- **特别赞助** +- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) +- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) +- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) + +- **开始** + - [框架介绍](/README.md) + - [演示系统](/common/demo_system.md) + - [官方视频教程](/common/video.md) + - [粉丝专栏](/common/column.md) + - [参与贡献项目](/common/contribution.md) + - [如何提交PR](/common/pr.md) + - [如何加群](/common/add_group.md) + - [使用者登记](/common/user_register.md) + - [黑名单](/common/blacklist.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/common/add_group.md b/ruoyi-admin/src/main/resources/static/common/add_group.md new file mode 100644 index 00000000..f6957bc4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/add_group.md @@ -0,0 +1,27 @@ +# 加群方式 +- - - +### 交流群(不提供任何问题解答 纯交流) + +**加 <小助手> 微信备注 <加群>**
+**视频课程咨询或其他问题咨询请查看下方信息(小助手是机器人)** + + + +### VIP群(付费加群 提供问题解答、技术支持、技术分享) + +首先感谢 `RuoYi` 提供分享开源 框架基于 `RuoYi` 重写大部分功能实现
+项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
+VIP群是作者提供的私人服务 不代表着项目收费 + +> 问问题等于做习题 听作者解答问题等于习题讲解
+> 一个人接触的问题有限 一群人接触的问题无限 早进群早接触更多的问题(每天99+)
+> 承诺: 看见必回复 让你感受作者有多话痨
+ +两种途径: +1. 购买官方视频进群 [官方视频](/common/video.md) +2. 扫描下方二维码付款进群(无视频) + +支付后申请加群即可 QQ群号 : **<637757165>**
+ +**加群扫码**
+ diff --git a/ruoyi-admin/src/main/resources/static/common/blacklist.md b/ruoyi-admin/src/main/resources/static/common/blacklist.md new file mode 100644 index 00000000..67594bd3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/blacklist.md @@ -0,0 +1,7 @@ +# 黑名单 +- - - + +地址: https://github.com/QNAV/RuoYi-X-Plus +
+上榜缘由 使用本框架二次开源并未有任何声明与标注 将所有代码的作者名全都改成了自己 剽窃本框架代码 + diff --git a/ruoyi-admin/src/main/resources/static/common/column.md b/ruoyi-admin/src/main/resources/static/common/column.md new file mode 100644 index 00000000..b2155a3c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/column.md @@ -0,0 +1,18 @@ +# 粉丝专栏 +- - - +**由上到下 从易到难** + +> 粉丝整理 欢迎投稿 + +| 作者 | 文档地址 | 说明 | +|---------------|---------------------------------------------------------------|--------------------| +| 抓蛙师 | https://www.bilibili.com/video/BV1TG41157Ef/ | 学会问问题(小白必看) | +| 抓蛙师 | https://www.bilibili.com/video/BV1mr4y1j75M | Vue框架基础视频专栏(新人必看) | +| 抓蛙师 | https://www.bilibili.com/video/BV1Na411u7eC | Vue框架改造视频专栏(新人必看) | +| 抓蛙师 | https://www.bilibili.com/video/BV1te4y1D7hi | 小程序鉴权与uniapp联动 | +| 抓蛙师 | https://www.bilibili.com/video/BV1zt4y137UP | 公众号集成 | +| mayuanfei | https://note.youdao.com/s/XpvKnxAb | 入门专栏(新人必看) | +| 程序猿一枚_ | https://blog.csdn.net/zhaozhiqiang1981/category_12221291.html | 玩转RuoYi-Cloud-Plus | +| 程序猿一枚_ | https://www.bilibili.com/video/BV1yA411r7ji/ | Cloud环境搭建以及进阶开发 | +| MichelleChung | https://blog.csdn.net/michelle_zhong/category_11109741.html | 源码解析专栏(进阶必看) | +| MichelleChung | https://blog.csdn.net/michelle_zhong/category_12058476.html | Cloud源码解析专栏 | diff --git a/ruoyi-admin/src/main/resources/static/common/contribution.md b/ruoyi-admin/src/main/resources/static/common/contribution.md new file mode 100644 index 00000000..6b5909e6 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/contribution.md @@ -0,0 +1,69 @@ +# 参与贡献的方式 +- - - +参与贡献开源的方式有很多种 听作者来介绍 + +## 为开源项目点一个Star + +> Star的多少关系到项目能否被更多人看到 +
+同时Star也是作者前进的动力(作者每天都在盯着Star 涨了会开心 跌了会失落) +
+
+> 大家在寻找开源项目的时候, 大多数情况也是会先看Star比较多的项目 +
+所以请给您觉得好的开源项目点一个小小的Star, 让好的项目能够被更多人看到 +
+ +![输入图片说明](https://foruda.gitee.com/images/1678934493115487351/0c45121e_1766278.png "屏幕截图") +
+Vue版本: [Gitee我要点Star](https://gitee.com/dromara/RuoYi-Vue-Plus/stargazers) [Github我要点Star](https://github.com/dromara/RuoYi-Vue-Plus) +
+Cloud版本: [Gitee我要点Star](https://gitee.com/dromara/RuoYi-Cloud-Plus/stargazers) [Github我要点Star](https://github.com/dromara/RuoYi-Cloud-Plus) + +## 为社区处理问题 + +> Issue是社区的交流地 大家会在这里提出自己的问题 或者是项目的功能异常 + +> 提问的规范在Issue的模板里已经写好了 按照模板填写有助于作者或者其他社区人员快速有效的回答问题 +![输入图片说明](https://foruda.gitee.com/images/1678935068341532603/4b9d7af9_1766278.png "屏幕截图") + +> 为提出问题的小伙伴答疑 可以有效降的帮助别人
+> 而且可以降低社区人员的精力分散 使精力全部投入到项目设计研发中 +![输入图片说明](https://foruda.gitee.com/images/1678935380481365514/dddc9ce9_1766278.png "屏幕截图") + +## 改进社区文档 + +> 大家都知道 我们程序员都不擅长写作
+> 有时候作者把文档写完了也不知道用户是什么感觉 是否能看懂
+ +> 所以参与社区文档建设绝对是一件意义重大的事情
+> 大家可以在Issue提出观后感 觉得哪看不懂 觉得哪应该详细说明
+> 当然了 大家也可以对文档进行改进后提交PR修改申请 + +文档仓库: [plus-doc](https://gitee.com/JavaLionLi/plus-doc) 👈点他点他 +![输入图片说明](https://foruda.gitee.com/images/1678935992827063291/d7c4dc5b_1766278.png "屏幕截图") + +## 贡献代码 + +> 想参与贡献代码的小伙伴 重点来了: 作者会经常在Issue里发布需求认领
+> 觉得自己能做的可以在Issue里跟作者讨论 如需求还不够清晰 或者做的过程中遇到了什么问题 + + + +> 需求确定了以后就可以开始专注的写代码了
+> 但在开始写代码之前 一定要先看一下如何正确的提交PR + +一点要仔细看: [如何提交PR](/common/pr.md) 👈点他点他 + +## 如何成为项目成员 + +> 1.对框架有重大贡献者(由作者与团队成员判定)
+> 2.完成社区发布的两项复杂任务
+> 3.持续完成社区发布的简单任务若干(作者会关注到)
+> 4.持续为社区优化文档或处理issue若干(作者会关注到)
+ +## 项目成员待遇 + +> 1.可免费进入vip收费群
+> 2.每年还会发放IDEA正版授权
+ diff --git a/ruoyi-admin/src/main/resources/static/common/demo_system.md b/ruoyi-admin/src/main/resources/static/common/demo_system.md new file mode 100644 index 00000000..18424e90 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/demo_system.md @@ -0,0 +1,13 @@ +# 系统演示(请大家不要乱改数据 影响他人体验 谢谢配合) +- - - +**感谢 `孤舟烟雨` 贡献的演示服务器** + +**1核2G 小服务器 经不起压测 请理性操作 违者直接封IP** + +> 访问地址: [http://43.138.9.96/](http://43.138.9.96/) + +> 登录账户 admin/admin123 + +> Admin监控中心 ruoyi/123456 + +> 任务调度中心 admin/123456 diff --git a/ruoyi-admin/src/main/resources/static/common/pr.md b/ruoyi-admin/src/main/resources/static/common/pr.md new file mode 100644 index 00000000..e9684dd4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/pr.md @@ -0,0 +1,37 @@ +# 如何提交PR贡献代码 +- - - +### 步骤一 Fork项目到自己仓库 + +![输入图片说明](https://foruda.gitee.com/images/1673427084798343408/142a55d0_1766278.png "屏幕截图") + +### 步骤二 基于dev分支 新建一个此PR功能点的专属分支 + +![输入图片说明](https://foruda.gitee.com/images/1673427220695789412/14c4f4ff_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1673427193964585607/16ea99d9_1766278.png "屏幕截图") + +### 步骤三 使用Git工具 将自己仓库的项目拉去到本地做代码编写 + +![输入图片说明](https://foruda.gitee.com/images/1673427313201488937/f2df59bf_1766278.png "屏幕截图") + +### 步骤四 使用Idea打开项目 切换到新建的功能分支 + +![输入图片说明](https://foruda.gitee.com/images/1673427394686229310/c479a5a5_1766278.png "屏幕截图") + +### 步骤五 将编写好的代码 提交到自己的远程仓库 + +![输入图片说明](https://foruda.gitee.com/images/1673427519150795591/d88c2bc9_1766278.png "屏幕截图") + +### 步骤六 创建PR申请(此操作在自己仓库或者要PR的仓库都可以) + +![输入图片说明](https://foruda.gitee.com/images/1673427616155043776/fe2ce097_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1673427865031025513/0f58a137_1766278.png "屏幕截图") + +### 步骤七 等待作者评审 按要求更改 直到没有问题后被作者合并 + +![输入图片说明](https://foruda.gitee.com/images/1673428029932524584/93234628_1766278.png "屏幕截图") + +### 评审期间 如需对PR内容做更改 直接在新功能分支提交代码即可 +### 无需重复提交PR申请 这边会自动比对两个分支的差异 + +![输入图片说明](https://foruda.gitee.com/images/1673428054139366497/4ecb6e98_1766278.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/common/user_register.md b/ruoyi-admin/src/main/resources/static/common/user_register.md new file mode 100644 index 00000000..9c221cd1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/user_register.md @@ -0,0 +1,80 @@ +# 使用者登记 +- - - +**使用此开源项目的公司或者组织** +> Vue版本登记地址: https://gitee.com/dromara/RuoYi-Vue-Plus/issues/I4QP39 + +> Cloud版本登记地址: https://gitee.com/dromara/RuoYi-Cloud-Plus/issues/I4VJ7G + +| 公司名 | 官网 | LOGO | +|-------------------|:-------------------------------|----------------------------------------------------------------------------------------------------------------| +| 中国联通(长春分公司) | http://www.10010.com | | +| 中国电信(湖南分公司) | http://www.189.cn/hn/ | | +| 南京感知信息技术有限公司 | https://njgzxx.cn/ | | +| 陕西骏景索道运营管理有限公司 | https://www.junjingsuodao.com/ | | +| 悠码科技有限公司 | https://orise.trytowish.cn/ | | +| 苏州龙的信息系统股份有限公司 | http://www.longdayinfo.com/ | | +| 北京数通智达科技有限公司 | http://www.bzdtech.com/ | | +| 广州六六七七科技有限公司 | https://artiversehub.ai/ | | +| 宁波三品软件科技有限公司 | http://nbsanpin.com/ | | +| 北京御一科技信息技术有限公司 | https://www.yudoctor.com | | +| 成都卡恩特医疗科技有限公司 | http://www.scknot.com | | +| 无锡科艾思科技有限公司 | https://www.kyoeis.com | | +| 深圳市海联天下科技有限公司 | www.sealinkin.com | | +| 上海非定义旅游服务有限公司 | http://www.anonymity.love/ | | +| 重庆威爱云科技有限公司 | https://www.51vive.com | | +| 中城智联(成都)创新科技有限公司 | http://www.zc-zl.com/ | | +| 浙江海亮股份有限公司 | https://www.hailiangstock.com | | +| 河北雄安山禾咨询工程有限公司 | https://shanheqei.club/ | | +| 数舵(河北雄安)信息科技有限公司 | http://www.shuduokeji.com | | +| 南昌鼎欣科技股份有限公司 | https://www.openzt.com | | +| 东莞市码载网络科技有限公司 | https://www.codeload.top | | +| 北京农信通科技有限责任公司 | http://www.nxt.com.cn | | +| 中康腾华网络科技(重庆)有限公司 | https://www.zkthwlkj.com/ | | +| 杭州码恒信息科技有限公司 | http://www.mh-barcode.com/ | | +| 南京晶益科技有限公司 | https://www.nanjingjingyi.com/ | | +| 合肥智享亿云科技有限公司 | http://www.izxyy.com | | +| 锡简科技 | https://www.xj-fast.com | | +| 福建亘前科技有限公司 | https://genqian.top | | +| 北京联宇信通科技有限公司 | http://www.lyxtkj.com/ | | +| 厦门市熵时光科技有限公司 | https://www.xetsoft.com | | +| 广州润沁教育科技有限公司 | https://www.ca163.net | | +| 广东乐善智能装备股份有限公司 | https://www.china-leshan.com/ | | +| 数字江西科技有限公司 | https://www.digitaljx.com/ | | +| 上海极锐星瀚传感技术有限公司 | http://www.jrsensing.com/ | | +| 北京数影互联科技有限公司 | http://www.dataflying.top/ | | +| 广州创服信息科技有限公司 | https://www.cfkjcloud.com | | +| 茂名云智科技有限公司 | http://www.winzkj.com | | +| 成都时光旅迹科技有限公司 | https://www.ttmup.com/ | | +| 成都炫影全息科技有限公司 | http://xyqxgs.com | | +| 中山厚德快速模具有限公司 | http://hordrt.com | | +| 深圳市深南夙星科技有限公司 | http://www.szsnsx.com/ | | +| 陕西华恒军创信息科技有限公司 | http://hhjc.cc | | +| 河南小牛信息科技有限公司 | http://www.hnxn888.com/ | | +| 武汉华智讯网络信息技术有限公司 | http://www.xun188.com | | +| 易税信息技术有限公司 | https://www.etax.top | | +| 广西华景城建筑设计有限公司 | http://www.hjcadc.com | | +| 铭创科技有限公司 | https://www.mcck.cn/ | | +| 西安鼎慧网络科技有限公司 | | | +| 营口鼎瑞网络科技有限公司 | | | +| 南昌漫库书店有限公司 | | | +| 广西文韬智能科技有限公司 | | | +| 贵州亿瑞祺科技有限公司 | | +| 贵州新绿视界环保科技有限公司 | | +| 湖南智才伯乐数据科技有限公司 | | +| 德州商储超市有限公司 | | +| 曲沃亿分科技中心 | | +| 南京杰度信息技术有限公司 | | +| 武汉忆秋科技有限公司 | | +| 济南千惠网络科技有限公司 | | +| 江苏泛联科技有限公司 | | +| 沈阳市果冻网络信息科技有限责任公司 | | +| 灵劲科技有限公司 | | +| 亿世达餐饮管理(北京)有限公司 | | +| 深圳市凯帝电子商务有限公司 | | +| 成都数智源蓉卡科技有限公司 | | +| 上海振福信息科技有限公司 | | +| 重庆六客会科技有限公司 | | +| 无限创优(西安)科技有限公司 | | +| 惠族网络科技发展有限公司 | | +| 纳森科技有限公司 | | + diff --git a/ruoyi-admin/src/main/resources/static/common/video.md b/ruoyi-admin/src/main/resources/static/common/video.md new file mode 100644 index 00000000..14fc2752 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/common/video.md @@ -0,0 +1,85 @@ +# 视频教程(联合出品) + +### 主讲与后期剪辑: `抓蛙师` + +抓蛙师简介: B站知名UP主 B站首页: https://space.bilibili.com/520725002 + +### 知识点统筹与内容审核: `疯狂的狮子Li` + +疯狂的狮子Li简介: RuoYi-Vue-Plus 与 RuoYi-Cloud-Plus 作者 + +## 已完结🎉🎉🎉 优惠价: 598(仅限前500名) ~~原价: 698~~ + +**注意: 视频采用 RuoYi-Vue-Plus 版本 4.X 分支讲解!!! (内容为通用技术与版本关联性不大)**
+**内容为框架内所用到的技术与设计原理(打破不知道、不会用、不知应用场景等问题)** + +课程简介: https://www.bilibili.com/video/BV16j411D7BX/ +
+试看课程: https://www.bilibili.com/video/BV1uS411P7JD/ +
+试看课程: https://www.bilibili.com/video/BV1vLbNeuESn/ +
+试看课程: https://www.bilibili.com/video/BV1xV4y127KM/ +
+试看课程: https://www.bilibili.com/video/BV1W5v8eBEgs/ +
+课程总结: https://www.bilibili.com/video/BV1734y1g7fk/ +
+ +## 购买方式 + +**小本生意 用心录制 拒绝砍价 已更新到 236 集 课程完结**
+> 课程咨询或购买请联系 价格598
+> QQ: 906670865 (疯狂的狮子Li)
+> QQ: 770492966 (抓蛙师) + +## 购买前常见问题答疑 +> 问题1: 购买后是否有群可以解答问题
+> 答: 购买后有专属课程付费群(千人大群)讲师在线答疑 +> +> 问题2: 是否持续更新 如新版本功能
+> 答: 课程目录即为全部课程内容 以课程目录为准 明年大概会出二期来讲新版本内容
+> 因为持续更新会导致前面的技术老旧 新购买的人无法及时学习新技术
+> 故而采用分期出课程制度 已经购买过的老客户 再次购买下一次会给力度非常大的折扣 +> +> 问题3: 目前视频未全部录制完成 后续更新是否二次收费
+> 答: 视频目录即为全部视频内容 一次收费后续更新仍然可看直到视频全部更新完成(明年出二期课程不算在内) +> +> 问题4: 视频如何下载如何观看
+> 答: 视频文件已加密 采用专门的播放器(播放器只限制截图录屏等不限制其他软件使用) 由管理员发放授权码观看
+> 支持通过 百度云 或者 阿里云 网盘下载视频资源 +> +> 问题5: 视频平均时长和总时长大概多久
+> 答: 视频每集短的大概10分钟以上 长的大概40个分钟左右 平均时长20多分钟每集
+> 目前已经录制了236集总时长为80多个小时 +> +> 问题6: 是否有讲解 Cloud 版本相关内容
+> 答: 视频主要讲解内容为框架内所用到的技术与设计原理 无论什么版本 功能和设计都是一样的
+> Cloud 版本只是多了 alibaba 的几个组件完全可以B站自学 + +## 课程目录 + +![输入图片说明](https://foruda.gitee.com/images/1695105467795304336/58fcd6db_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105494170842444/10f98fed_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105523526589287/f131c614_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105547992880680/9f4137f3_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105560849590514/d19fad6a_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105586641712428/349a971b_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105595501187093/fb819d35_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105609163585390/833dd89c_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105630469565265/8dbba1d2_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695105659037093525/09a4f6e1_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1695714493079698007/311980ee_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1697446957351573520/cab3617d_1766278.png "屏幕截图") + +## 学员观后感 + +| | | +|---------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------| +| ![输入图片说明](https://foruda.gitee.com/images/1691386100129796781/44b69dae_1766278.jpeg "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1691386076834242484/a6073f7d_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1691386089186649583/98ac8b7c_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1691386108722171132/b937b23a_1766278.jpeg "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1695714607596127461/513b6893_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1692804549604261480/09ef12f6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1692804541482477905/578e5448_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1695714614517941469/cac681fb_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1698225407961714462/4d271901_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698225416488201339/30572e7f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1698807198508085566/16c37a1b_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698807208125772586/ceed632e_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1698807214013013096/ad3bc016_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1698807221010472627/72b10901_1766278.png "屏幕截图") | diff --git a/ruoyi-admin/src/main/resources/static/index.html b/ruoyi-admin/src/main/resources/static/index.html new file mode 100644 index 00000000..76e44328 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/index.html @@ -0,0 +1,74 @@ + + + + + plus-doc + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md b/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md new file mode 100644 index 00000000..00197250 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/_sidebar.md @@ -0,0 +1,22 @@ + +- **特别赞助** +- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) +- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) +- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) + + +* **简介** + * [项目简介](/plus-ui/home.md) +* **开发文档** + * [通用方法](/plus-ui/devdoc/common_func.md) + * [开发规范](/plus-ui/devdoc/dev_norm.md) + * [请求流程](/plus-ui/devdoc/request_process.md) + * [路由使用](/plus-ui/devdoc/router_use.md) + * [组件使用](/plus-ui/devdoc/component_use.md) + * [权限使用](/plus-ui/devdoc/permissions_use.md) + * [页签缓存](/plus-ui/devdoc/page_cache.md) + * [使用图标](/plus-ui/devdoc/icon_use.md) + * [使用字典](/plus-ui/devdoc/dict_use.md) + * [使用参数](/plus-ui/devdoc/param_use.md) + * [异常处理](/plus-ui/devdoc/exception_handling.md) + * [内容复制](/plus-ui/devdoc/content_copy.md) diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md new file mode 100644 index 00000000..e359c03c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/common_func.md @@ -0,0 +1,234 @@ +# 通用方法 +- - - + +### $tab对象 +> `$tab`对象用于做页签操作、刷新页签、关闭页签、打开页签、修改页签等,它定义在`plugins/tab.ts`文件中,它有如下方法 +* 打开页签 + +```typescript +// 打开页签 +proxy?.$tab.openPage('/system/user'); +// 打开页签并指定页签标题 +proxy?.$tab.openPage('/system/user', '用户管理'); +proxy?.$tab.openPage('/system/user', '用户管理').then(() => { + // 执行结束的逻辑 +}) +``` + +* 修改页签 + +```typescript +// 修改当前页签 +const obj = Object.assign({}, route, { title: '自定义标题' }); +proxy?.$tab.updatePage(obj); +``` +* 关闭页签 + +```typescript +// 关闭当前 +proxy?.$tab.closePage(); +// 关闭指定页签 +const obj = { path: "/system/user", name: "User" }; +proxy?.$tab.closePage(obj); + +proxy?.$tab.closePage(obj).then(() => { + // 执行结束的逻辑 +}) +``` + +* 刷新页签 + +```typescript +// 刷新当前页签 +proxy?.$tab.refreshPage(); + +// 刷新指定页签 +const obj = { path: "/system/user", name: "User" }; +proxy?.$tab.refreshPage(obj); + +proxy?.$tab.refreshPage(obj).then(() => { + // 执行结束的逻辑 +}) +``` + +* 关闭所有页签 + +```typescript +proxy?.$tab.closeAllPage(); + +proxy?.$tab.closeAllPage().then(() => { + // 执行结束的逻辑 +}) +``` + +* 关闭左侧页签 + +```typescript +// 关闭当前页签的左侧页签 +proxy?.$tab.closeLeftPage(); + +// 关闭指定页签的左侧页签 +const obj = { path: "/system/user", name: "User" }; +proxy?.$tab.closeLeftPage(obj); + +proxy?.$tab.closeLeftPage(obj).then(() => { + // 执行结束的逻辑 +}) +``` + +* 关闭右侧页签 + +```typescript +// 关闭当前页签的右侧页签 +proxy?.$tab.closeRightPage(); + +// 关闭指定页签的右侧页签 +const obj = { path: "/system/user", name: "User" }; +proxy?.$tab.closeRightPage(obj); + +proxy?.$tab.closeRightPage(obj).then(() => { + // 执行结束的逻辑 +}) +``` + +* 关闭其他页签 + +```typescript +proxy?.$tab.closeOtherPage(); + +const obj = { path: "/system/user", name: "User" }; +proxy?.$tab.closeOtherPage(obj); + +proxy?.$tab.closeOtherPage(obj).then(() => { + // 执行结束的逻辑 +}) +``` + +### $modal对象 +> `$modal`对象用于做消息提示、通知提示、对话框提醒、二次确认、遮罩等,它定义在`plugins/modal.ts`文件中,它有如下方法 + +* 提供成功、警告和错误等反馈信息 + +```typescript +proxy?.$modal.msg("默认反馈"); +proxy?.$modal.msgError("错误反馈"); +proxy?.$modal.msgSuccess("成功反馈"); +proxy?.$modal.msgWarning("警告反馈"); +``` + +* 提供成功、警告和错误等提示信息 + +```typescript +proxy?.$modal.alert("默认提示"); +proxy?.$modal.alertError("错误提示"); +proxy?.$modal.alertSuccess("成功提示"); +proxy?.$modal.alertWarning("警告提示"); +``` + +* 提供成功、警告和错误等通知信息 + +```typescript +proxy?.$modal.notify("默认通知"); +proxy?.$modal.notifyError("错误通知"); +proxy?.$modal.notifySuccess("成功通知"); +proxy?.$modal.notifyWarning("警告通知"); +``` + +* 提供确认窗体信息 + +```typescript +proxy?.$modal.confirm('确认信息').then(function() { + ... +}).then(() => { + ... +}).catch(() => {}); +``` + +* 提供遮罩层信息 + +```typescript +// 打开遮罩层 +proxy?.$modal.loading("正在导出数据,请稍后..."); + +// 关闭遮罩层 +proxy?.$modal.closeLoading(); +``` + +### $auth对象 +> `$auth`对象用于验证用户是否拥有某(些)权限或角色,它定义在`plugins/auth.ts`文件中,它有如下方法 + +* 验证用户权限 + +```typescript +// 验证用户是否具备某权限 +proxy?.$auth.hasPermi("system:user:add"); +// 验证用户是否含有指定权限,只需包含其中一个 +proxy?.$auth.hasPermiOr(["system:user:add", "system:user:update"]); +// 验证用户是否含有指定权限,必须全部拥有 +proxy?.$auth.hasPermiAnd(["system:user:add", "system:user:update"]); +``` + +* 验证用户角色 + +```typescript +// 验证用户是否具备某角色 +proxy?.$auth.hasRole("admin"); +// 验证用户是否含有指定角色,只需包含其中一个 +proxy?.$auth.hasRoleOr(["admin", "common"]); +// 验证用户是否含有指定角色,必须全部拥有 +proxy?.$auth.hasRoleAnd(["admin", "common"]); +``` + +### $cache对象 +> `$cache`对象用于处理缓存。我们并不建议您直接使用`sessionStorage`或`localStorage`(vue3版本推荐使用useStorage),因为项目的缓存策略可能发生变化,通过`$cache`对象做一层调用代理则是一个不错的选择。`$cache`提供`session`和`local`两种级别的缓存,如下: + +| 对象名称 | 缓存类型 | +| -------- | ---------------------------------- | +| session | 会话级缓存,通过sessionStorage实现 | +| local | 本地级缓存,通过localStorage实现 | + + +**示例** + +```typescript +// local 普通值 +proxy?.$cache.local.set('key', 'local value') +console.log(proxy?.$cache.local.get('key')) // 输出'local value' + +// session 普通值 +proxy?.$cache.session.set('key', 'session value') +console.log(proxy?.$cache.session.get('key')) // 输出'session value' + +// local JSON值 +proxy?.$cache.local.setJSON('jsonKey', { localProp: 1 }) +console.log(proxy?.$cache.local.getJSON('jsonKey')) // 输出'{localProp: 1}' + +// session JSON值 +proxy?.$cache.session.setJSON('jsonKey', { sessionProp: 1 }) +console.log(proxy?.$cache.session.getJSON('jsonKey')) // 输出'{sessionProp: 1}' + +// 删除值 +proxy?.$cache.local.remove('key') +proxy?.$cache.session.remove('key') +``` + +### $download对象 + +> `$download`对象用于文件下载,它定义在`plugins/download.ts`文件中,它有如下方法 + +* 通过ossId从存储中下载文件 + +``` typescript +// 默认下载方法 +proxy?.$download.oss(ossId); +``` + +* 根据请求地址下载zip包 + +```typescript +const url = '/tool/gen/batchGenCode?tables=' + tableNames; +const name = 'ruoyi'; + +// 默认方法 +proxy?.$download.zip(url, name); +``` diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md new file mode 100644 index 00000000..18886db5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/component_use.md @@ -0,0 +1,55 @@ +# 组件使用 +- - - + +vue 注册组件的两种方式 +在 `@/components` 下创建的.vue文件自动为全局组件,可直接在任意位置使用。 + +### 局部注册 +在对应页使用`components`注册组件。 +```typescript + + + +``` + +### 全局注册 +我们可以使用[ Vue 应用实例](https://cn.vuejs.org/guide/essentials/application.html)的 `.component()` 方法,让组件在当前 Vue 应用中全局可用。 +```typescript +import { createApp } from 'vue' + +const app = createApp({}) + +app.component( + // 注册的名字 + 'MyComponent', + // 组件的实现 + { + /* ... */ + } +) +``` +如果使用单文件组件,你可以注册被导入的 `.vue` 文件: +```typescript +import MyComponent from './App.vue' + +app.component('MyComponent', MyComponent) +``` +`.component()` 方法可以被链式调用: +```typescript +app + .component('ComponentA', ComponentA) + .component('ComponentB', ComponentB) + .component('ComponentC', ComponentC) +``` +全局注册的组件可以在此应用的任意组件的模板中使用: +```Typescript +// 这在当前应用的任意组件中都可用 + + + +``` +所有的子组件也可以使用全局注册的组件,这意味着这三个组件也都可以在彼此内部使用。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md new file mode 100644 index 00000000..a4150d72 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/content_copy.md @@ -0,0 +1,4 @@ +# 内容复制 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md new file mode 100644 index 00000000..de714a13 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dev_norm.md @@ -0,0 +1,16 @@ +# 开发规范 +- - - + +### 新增view +> 在`@/views`文件下创建对应的文件夹,一般性一个路由对应一个文件, 该模块下的功能就建议在本文件夹下创建一个新文件夹,各个功能模块维护自己的`utils`或`components`组件。 + +### 新增api +> 在`@/api`文件夹下创建本模块对应的api服务。 +> 在api服务同级创建`types.ts`类型声明文件。 + +### 新增组件 +> 在全局的`@/components`写一些全局的组件,如富文本,各种搜索组件,封装的分页组件等等能被公用的组件。 每个页面或者模块特定的业务组件则会写在当前`@/views`下面。 +如:`@/views/system/user/components/xxx.vue`。这样拆分大大减轻了维护成本。 + +### 新增样式 +> 页面的样式和组件是一个道理,全局的`@/style`放置一下全局公用的样式,每一个页面的样式就写在当前 views下面,请记住加上scoped 就只会作用在当前组件内了,避免造成全局的样式污染。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md new file mode 100644 index 00000000..7c6f9ba5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/dict_use.md @@ -0,0 +1,4 @@ +# 使用字典 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md new file mode 100644 index 00000000..8de87fa2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/exception_handling.md @@ -0,0 +1,4 @@ +# 异常处理 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md new file mode 100644 index 00000000..923e66ae --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/icon_use.md @@ -0,0 +1,4 @@ +# 使用图标 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md new file mode 100644 index 00000000..0531b465 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/page_cache.md @@ -0,0 +1,4 @@ +# 页签缓存 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md new file mode 100644 index 00000000..0cd93759 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/param_use.md @@ -0,0 +1,4 @@ +# 使用参数 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md new file mode 100644 index 00000000..e18642f4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/permissions_use.md @@ -0,0 +1,4 @@ +# 权限使用 +- - - + +文档建设中 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md new file mode 100644 index 00000000..146f7a8c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/request_process.md @@ -0,0 +1,65 @@ +# 请求流程 +- - - + +### 交互流程 +一个完整的前端UI交互到服务器端处理流程是这样的: + +1. UI 组件交互操作; +2. 调用统一管理的 api service 请求函数; +3. 使用封装的 request.js 发送请求; +4. 获取服务端返回; +5. 更新 data; + +为了方便管理维护,统一的请求处理都放在`@/src/api`文件夹中,并且一般按照`model`维度进行拆分文件,如: +``` +api/ + system/ + user/ + index.ts + types.ts + role/ + index.ts + types.ts + monitor/ + operlog/ + index.ts + types.ts + logininfor/ + index.ts + types.ts + ... +``` +> **提示** +> 其中`@/src/utils/request.ts`是基于 axios 的封装,便于统一处理 POST,GET 等请求参数,请求头,以及错误提示信息等。 它封装了全局request拦截器、response拦截器、统一的错误处理、统一做了超时处理、baseURL设置等。 + +### 请求示例 +```typescript +// @/api/system/user/index.ts +import request from '@/utils/request'; +import { AxiosPromise } from 'axios'; +import { UserQuery, UserVO } from './types'; + +export const listUser = (query: UserQuery): AxiosPromise => { + return request({ + url: '/system/user/list', + method: 'get', + params: query + }); +}; + +// @/views/system/user/index.vue +import api from '@/api/system/user'; +const res = await api.listUser(proxy?.addDateRange(queryParams.value, dateRange.value)); +``` +> **提示** +> 如果有不同的`baseURL`,直接通过覆盖的方式,让它具有不同的`baseURL`。 +> ```typescript +> export const listUser = (query: UserQuery): AxiosPromise => { +> return request({ +> url: '/system/user/list', +> method: 'get', +> params: query, +> baseURL: process.env.BASE_API +> }); +> }; +> ``` diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md new file mode 100644 index 00000000..b13812bc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/devdoc/router_use.md @@ -0,0 +1,82 @@ +# 路由使用 +- - - + +框架的核心是通过路由自动生成对应导航,所以除了路由的基本配置,还需要了解框架提供了哪些配置项。 +### 路由配置 +```typescript +// 当设置 true 的时候该路由不会在侧边栏出现 如401,login等页面,或者如一些编辑页面/edit/1 +hidden: true // (默认 false) + +//当设置 noRedirect 的时候该路由在面包屑导航中不可被点击 +redirect: 'noRedirect' + +// 当你一个路由下面的 children 声明的路由大于1个时,自动会变成嵌套的模式--如组件页面 +// 只有一个时,会将那个子路由当做根路由显示在侧边栏--如引导页面 +// 若你想不管路由下面的 children 声明的个数都显示你的根路由 +// 你可以设置 alwaysShow: true,这样它就会忽略之前定义的规则,一直显示根路由 +alwaysShow: true + +name: 'router-name' // 设定路由的名字,一定要填写不然使用时会出现各种问题 +query: '{"id": 1, "name": "ry"}' // 访问路由的默认传递参数 +roles: ['admin', 'common'] // 访问路由的角色权限 +permissions: ['a:a:a', 'b:b:b'] // 访问路由的菜单权限 + +meta: { + title: 'title' // 设置该路由在侧边栏和面包屑中展示的名字 + icon: 'svg-name' // 设置该路由的图标,支持 svg-class,也支持 el-icon-x element-ui 的 icon + noCache: true // 如果设置为true,则不会被 缓存(默认 false) + breadcrumb: false // 如果设置为false,则不会在breadcrumb面包屑中显示(默认 true) + affix: true // 如果设置为true,它则会固定在tags-view中(默认 false) + + // 当路由设置了该属性,则会高亮相对应的侧边栏。 + // 这在某些场景非常有用,比如:一个文章的列表页路由为:/article/list + // 点击文章进入文章详情页,这时候路由为/article/1,但你想在侧边栏高亮文章列表的路由,就可以进行如下设置 + activeMenu: '/article/list' +} +``` +**普通示例** +```json +{ + path: '/system/test', + component: Layout, + redirect: 'noRedirect', + hidden: false, + alwaysShow: true, + meta: { title: '系统管理', icon : "system" }, + children: [{ + path: 'index', + component: (resolve) => require(['@/views/index'], resolve), + name: 'Test', + meta: { + title: '测试管理', + icon: 'user' + } + }] +} +``` +**外链示例** +```json +{ + path: 'http://ruoyi.vip', + meta: { title: '若依官网', icon : "guide" } +} +``` +### 静态路由 +代表那些不需要动态判断权限的路由,如登录页、404、等通用页面,在`@/router/index.ts`配置对应的公共路由。 +### 动态路由 +代表那些需要根据用户动态判断权限并通过addRoutes动态添加的页面,在`@/store/modules/permission.ts`加载后端接口路由配置。 +> **提示** +> * 动态路由可以在系统管理-菜单管理进行新增和修改操作,前端加载会自动请求接口获取菜单信息并转换成前端对应的路由。 +> * 动态路由在生产环境下会默认使用路由懒加载,实现方式参考loadView方法的判断。 +### 常用方法 +想要跳转到不同的页面,使用`router.push`方法 +```Typescript +const router = useRouter(); +router.push({ path: "/system/user" }); +``` +跳转页面并设置请求参数,使用`query`属性 +```Typescript +const router = useRouter(); +router.push({ path: "/system/user", query: {id: "1", name: "若依"} }); +``` +更多使用可以参考[vue-router](https://router.vuejs.org/zh/)官方文档。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/plus-ui/home.md b/ruoyi-admin/src/main/resources/static/plus-ui/home.md new file mode 100644 index 00000000..b389b5ca --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/plus-ui/home.md @@ -0,0 +1,53 @@ +# 项目简介 + +--- + +## 平台简介 + +- 本仓库为前端技术栈 [Vue3](https://v3.cn.vuejs.org) + [Element Plus](https://element-plus.org/zh-CN) + [Vite](https://cn.vitejs.dev) 版本。 +- 配套后端代码仓库地址 +- [RuoYi-Vue-Plus 5.X(注意版本号)](https://gitee.com/dromara/RuoYi-Vue-Plus) +- [RuoYi-Cloud-Plus 2.X(注意版本号)](https://gitee.com/dromara/RuoYi-Cloud-Plus) + +## 前端运行 + +```bash +# 克隆项目 +git clone https://gitee.com/JavaLionLi/plus-ui.git + +# 安装依赖 +npm install --registry=https://registry.npmmirror.com + +# 启动服务 +npm run dev + +# 推荐使用yarn或pnpm包管理工具 +# 构建测试环境 yarn build:stage +# 构建生产环境 yarn build:prod +# 前端访问地址 http://localhost:80 +``` + +## 后端改造 + +参考后端代码内 `ruoyi-gen/resources/vm/vue/v3/readme.txt` 说明 + +## 内置功能 + +1. 租户管理:配置系统租户,支持 SaaS 场景下的多租户功能。 +2. 用户管理:用户是系统操作者,该功能主要完成系统用户配置。 +3. 部门管理:配置系统组织机构(公司、部门、小组),树结构展现支持数据权限。 +4. 岗位管理:配置系统用户所属担任职务。 +5. 菜单管理:配置系统菜单,操作权限,按钮权限标识等。 +6. 角色管理:角色菜单权限分配、设置角色按机构进行数据范围权限划分。 +7. 字典管理:对系统中经常使用的一些较为固定的数据进行维护。 +8. 参数管理:对系统动态配置常用参数。 +9. 通知公告:系统通知公告信息发布维护。 +10. 操作日志:系统正常操作日志记录和查询;系统异常信息日志记录和查询。 +11. 登录日志:系统登录日志记录查询包含登录异常。 +12. 在线用户:当前系统中活跃用户状态监控。 +13. 定时任务:在线(添加、修改、删除)任务调度包含执行结果日志。 +14. 代码生成:前后端代码的生成(java、html、xml、sql)支持 CRUD 下载 。 +15. 系统接口:根据业务代码自动生成相关的 api 接口文档。 +16. 服务监控:监视当前系统 CPU、内存、磁盘、堆栈等相关信息。 +17. 缓存监控:对系统的缓存信息查询,命令统计等。 +18. 在线构建器:拖动表单元素生成相应的 HTML 代码。(TS 版本正在开发中。) diff --git a/ruoyi-admin/src/main/resources/static/questions/_sidebar.md b/ruoyi-admin/src/main/resources/static/questions/_sidebar.md new file mode 100644 index 00000000..2d74fb20 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/_sidebar.md @@ -0,0 +1,34 @@ + +- **特别赞助** +- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) +- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) +- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) + + + +* **常见问题** + * [Lombok注解爆红](/questions/lombok.md) + * [如何使用Tomcat](/questions/use_tomcat.md) + * [如何使用druid连接池](/questions/use_druid.md) + * [vue与boot整合部署](/questions/deploy_vue.md) + * [导入excel实体类为空](/questions/import_excel.md) + * [如何同步项目更新](/questions/synchronous_update.md) + * [ParseException SQL解析异常](/questions/parse_exception.md) + * [swagger相关问题](/questions/swagger.md) + * [实体bean为空问题](/questions/bean_null.md) + * [Redis 报错 Permission denied](/questions/permission_denied.md) + * [关于HTTPS配置](/questions/https_config.md) + * [放行接口提示认证失败](/questions/identify_fail.md) + * [打包jar运行报错](/questions/jar_run_fail.md) + * [如何指定dubbo注册ip](/questions/dubbo_ip.md) + * [Sentinel页面404问题](/questions/sentinel_404.md) + * [无法读取nacos配置](/questions/nacos_read_fail.md) + * [接口文档对接knife4j](/questions/kinfe4j.md) + * [不支持ST请求](/questions/st_not_support.md) + * [Only one connection receive subscriber allowed](/questions/only_one_subscriber.md) + * [nacos 报错 The Raft Group [naming_instance_metadata]](/questions/nacos_naming_instance_metadata.md) + * [unable to read meta-data for class xxx](/questions/read_metadata.md) + * [JCE cannot authenticate the provider BC](/questions/jce_cannot.md) + * [关于请求响应参数解密](/questions/api_encrypt.md) + * [关于登录调试步骤](/questions/login_step.md) + * [如何对接国产数据库](/questions/domestic_databases.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md b/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md new file mode 100644 index 00000000..95b516d4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/api_encrypt.md @@ -0,0 +1,148 @@ +# 关于请求响应参数解密 +--- +## 1:前端加密请求 + +![输入图片说明](https://foruda.gitee.com/images/1717033672316716771/8e30a2f1_4959041.png "屏幕截图") + +通过控制台获取加密结果: + +![输入图片说明](https://foruda.gitee.com/images/1717033792384655437/900a0e0d_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1717033896868612970/55581f0a_4959041.png "屏幕截图") + + +加密密钥: + +``` +PAg/fZzpV/cz0T1fMUJMJo/LEZvwVLb4bZgtCHkbB6FQAJWlLm/RLKtQ5fOo1blMjAkY+9ryWhsAfCqoMPTU4w== +``` + +请求参数加密结果: + +``` +F+Qxq6PzShcudDsUZHhp50lA67eBeTe63x5uGbdm/HJGgcDmjKncUk5VQm0evD8pz1sbmCbmmSl3X1D07K/qgHvP1YhjYSRBJf/M0GTfMkfOZqIkOtvfE5Z6fSFd8RYf6ji/qYxAmCiRmP/uADyJUAoBY1gMi5+zuvyHH3In/FyoFeD0rmJWvO4o4fn3n5GElHMWbP0O/HWPfgHFfg1F7bZQPuf4zAuDKQIqUG3jJTem3O97kAbTWw6lSSuYi1/8tV4cE9rq8SMSjx36/ZLSog== +``` + +### 解密步骤 + +1. 使用配置文件私钥对加密密钥解密 + +```java +// 参数说明: +// requestKey:即请求标头加密密钥 +// privateKey:application.yml 配置文件私钥 +String decryptByRsa = EncryptUtils.decryptByRsa(requestKey, privateKey); +``` + +2. 对步骤一结果进行 Base64 解密,得到 AES 加密密钥 + +```java +String aesPassword = EncryptUtils.decryptByBase64(decryptByRsa); +``` + +3. 使用步骤二得到的密钥,对请求参数进行解密 + +```java +String decryptBody = EncryptUtils.decryptByAes(requestBody, aesPassword); +``` + +得到解密请求参数(已格式化): + +```json +{ + "tenantId": "000000", + "username": "admin", + "password": "admin123", + "rememberMe": false, + "uuid": "a39962b22c874f60872ef5db1cd811f5", + "code": "5", + "clientId": "e5cd7e4891bf95d1d19206ce24a7b32e", + "grantType": "password" +} +``` + +|参数名|说明| +|---|---| +|tenantId| 租户id | +|username| 用户名 | +|password| 密码 | +|rememberMe| 记住密码 | +|uuid| - | +|code| 验证码结果 | +|clientId| 客户端id(表 sys_client) | +|grantType| 授权类型(表 sys_client) | + +## 2:后端加密响应 + +对请求使用了注解 `@ApiEncrypt(response = true)` + +![输入图片说明](https://foruda.gitee.com/images/1717035066844744866/2286b394_4959041.png "屏幕截图") + +通过控制台获取加密结果: + +![输入图片说明](https://foruda.gitee.com/images/1717035156784270596/156f2aa7_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1717035193189175688/214631e5_4959041.png "屏幕截图") + +加密密钥: + +``` +MXnKYnXcXeFYWKZg8utuhDtbz54cPDcov11E1KT5l19/vMt37d4NhzzwBWnqug72SOgOK5URGaWPJSs9VdaP0Q== +``` + +响应参数加密结果: + +``` +70 O63EMmwvbAyWPqDDmVOGTy+BOQnIVgKInMFNRtp8Zwzs8DEL20VgL2IslYrL8bc1u7lPhYNU/6 Q3iTYebm4EokwiG+styaT+LO3M9bUimggoAGpBTW8gCRF/34 kJaOITSRqYqYcXIJKn73+Gqn7jevyKUHyRXog/3 q/PlBdmUjNiB4gtxlOO/Vm+4 o+0 W4jcEe0xwwzV91+Ze3S6Eu/1 XN21g0iOsYT34emv/vhd9Hy3p5LfJlAHvn96x/c3MQBQUU32uM3Vkk3o6IpVHjJljE64gnGximSwB9vrmMA21xX+fq9HYioumknmDDbaY/JAKh32CDgn5M5hdaIklf08sU38r1IyvipySzrHX+ci9GmOZhP2ttCtoZ7SGvFFbNEuyojssxwxXEmJHAsG/OhIAeRXMUr3+dzDJ++XvvMuMgNJR0BMldNydFAjNOQEszgcVM1QEGwxfW5rElW8VxQaaqPyDATX+y2JrK1vdKxxdI/hF5dGpQMdU4FAEhHIftoIbD/FH4XcWJamZjJpbVtZvTkFYpbhiU7sz9MICSuKwaoSFJ8JGANc0bDdVoWpA8sXi7a27IM0pDzk9gD/FADcFGHXxPYUhENkXiUcnmg5LSdigiY4J6HrqEJdH6zNSwoGubcsXhiPdlB3V0DqcLAHFt+GYj5lcxZeqUAmixGVGCV7gSBWNiyo9/NnXcynA/EIlV3OZIvgzjWxiKzcVJ1HOKoXGEcg3Q54QNh5pCqEa7AtqVkKO7/Ffgg8nSEeCdJPzTV7zmr3n94Hn671OL8A== +``` + +### 解密步骤 + +1. 使用前端配置文件私钥对加密密钥解密 + +```java +// 参数说明: +// responseKey:即响应标头加密密钥 +// privateKey:前端 .env.development | .env.production 配置文件私钥,注意和后端私钥区分 +String decryptByRsa = EncryptUtils.decryptByRsa(responseKey, privateKey); +``` + +2. 对步骤一结果进行 Base64 解密,得到 AES 加密密钥 + +```java +String aesPassword = EncryptUtils.decryptByBase64(decryptByRsa); +``` + +3. 使用步骤二得到的密钥,对响应参数进行解密 + +```java +String decryptBody = EncryptUtils.decryptByAes(responseBody, aesPassword); +``` + +得到解密请求参数(已格式化): + +```json +{ + "code": 200, + "msg": "操作成功", + "data": { + "scope": null, + "openid": null, + "access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJsb2dpblR5cGUiOiJsb2dpbiIsImxvZ2luSWQiOiJzeXNfdXNlcjoxIiwicm5TdHIiOiJjOVNWU1hRRVY4QVhFRkt4b2FrbndSSWxPczd4ajdRZCIsImNsaWVudGlkIjoiZTVjZDdlNDg5MWJmOTVkMWQxOTIwNmNlMjRhN2IzMmUiLCJ0ZW5hbnRJZCI6IjAwMDAwMCIsInVzZXJJZCI6MSwidXNlck5hbWUiOiJhZG1pbiIsImRlcHRJZCI6MTAzLCJkZXB0TmFtZSI6IueglOWPkemDqOmXqCJ9.YuaXPu6eTzJVkLyQC3ekzmPS_jXp50ykaIB2nWy11qM", + "refresh_token": null, + "expire_in": 604799, + "refresh_expire_in": null, + "client_id": "e5cd7e4891bf95d1d19206ce24a7b32e" + } +} +``` + +|参数名|说明| +|---|---| +|scope| 令牌权限 | +|openid| 用户 openid | +|access_token| 授权令牌 | +|refresh_token| 刷新令牌 | +|expire_in| 授权令牌 access_token 的有效期 | +|refresh_expire_in| 刷新令牌 refresh_token 的有效期 | +|clientId| 客户端id(表 sys_client) | \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/bean_null.md b/ruoyi-admin/src/main/resources/static/questions/bean_null.md new file mode 100644 index 00000000..bf04048c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/bean_null.md @@ -0,0 +1,10 @@ +# 实体bean为空问题 +- - - +### 问题排查 + +检查是否存在 `链式调用` 注解 `@Accessors(chain = true)` 删除即可 + +### 原因 +java 规范 set 返回值为 `void` 链式调用 set 返回值为 `this`
+故多数框架底层使用 jdk 工具导致找不到 set 方法
+例如: `easyexcel` `cglib` `mybatis` 等 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md b/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md new file mode 100644 index 00000000..348a1680 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/deploy_vue.md @@ -0,0 +1,13 @@ +# 关于vue与boot整合部署 +- - - +* [前端静态资源如何整合到后端访问](https://doc.ruoyi.vip/ruoyi-vue/other/faq.html#前端静态资源如何整合到后端访问) + +3.X 需在 `pom.xml` 增加资源过滤排除 + +```xml + + src/main/resources/页面目录 + + false + +``` diff --git a/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md b/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md new file mode 100644 index 00000000..e79762ba --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/domestic_databases.md @@ -0,0 +1,41 @@ +# 如何对接国产数据库 + +> 1. 框架采用 mybatis-plus 几乎支持大部分市面上的数据库且框架内几乎没有sql语句存在 +
+所以不用担心兼容性问题(顶多就是有一些关键字什么的 对接很简单) +
+> 2. 国产数据库大多都兼容主流三大数据库 mysql oracle postgresql +
+例如 达梦兼容oracle 人大金仓兼容mysql oceanbase兼容mysql 等等 + +# 对接方式 + +### 这里用 `达梦` 数据库为例 + +1.首先增加 jdbc依赖包 `vue版本在ruoyi-admin模块下` `cloud版本在ruoyi-common-mybatis模块下` + +![输入图片说明](https://foruda.gitee.com/images/1723288594335994875/216ae8e7_1766278.png "屏幕截图") + +2.在配置文件yml内配置数据库连接 + +![输入图片说明](https://foruda.gitee.com/images/1723288760519808620/3db91ba5_1766278.png "屏幕截图") + +3.sql脚本使用框架内自带的sql文件根据兼容的数据库模式 例如 达梦用oracle的sql脚本 + +![输入图片说明](https://foruda.gitee.com/images/1723289018873298537/4d95c892_1766278.png "屏幕截图") + +4.在代码生成器内 增加对应的数据库生成器依赖 代码生成器使用 anyline 支持几百种数据库只需要增加对应的依赖即可 + +![输入图片说明](https://foruda.gitee.com/images/1723288974693848785/3e8fc61f_1766278.png "屏幕截图") + +这样基本就完成了所有需要做的事可以尝试启动项目了 + +5.如果项目启或者运行动过程中有sql报错 不要慌基本上都是一些关键字引起的 +
+例如 达梦内的`domain`就是关键字 在我们的`SysOssConfig`表内使用`domain`进行自定义的域名存储 +
+我们只需要在`SysOssConfig`实体类的`domain`属性增加一个注解即可解决此问题 +
+**注意: 各种数据库处理关键字的标识符不一样注意替换** + +![输入图片说明](https://foruda.gitee.com/images/1723289232470339283/480d5172_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md b/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md new file mode 100644 index 00000000..43cb2346 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/dubbo_ip.md @@ -0,0 +1,18 @@ +# 如何指定dubbo注册ip +- - - +## 重点说明 +以下方法指定IP必须是本地有网卡的自己可以访问的IP 不可以随意乱写
+(云服务器公网IP是没有网卡的) + +## 在`nacos`指定协议IP地址(全局生效) +```yml +dubbo: + protocol: + # 指定dubbo协议注册ip + host: 192.168.0.100 +``` + +## docker指定dubbo环境变量(单服务生效) + +![输入图片说明](https://foruda.gitee.com/images/1678981332028792584/7eeef9c5_1766278.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/questions/https_config.md b/ruoyi-admin/src/main/resources/static/questions/https_config.md new file mode 100644 index 00000000..e590729e --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/https_config.md @@ -0,0 +1,27 @@ +# 关于HTTPS配置 +- - - +### 后端 HTTPS 改造 + +将申请的 `https` 证书放置到 `nginx` 对应目录内
+根据框架 `nginx https` 示例 更改后端代理为 `https`
+ +![输入图片说明](https://foruda.gitee.com/images/1678981283573122208/87cf19ad_1766278.png "屏幕截图") + +### 监控中心 与 任务调度中心 改造 + +`监控中心` 与 `任务调度中心` 属于系统管控服务
+应在内网使用 不应该暴漏到外网 也无需配置 `https` + +更改 `系统 -> 菜单管理 -> 监控中心 与 任务调度中心` 菜单配置
+将其改为 `外链访问` 访问路径为 **注意: 如果是外网使用 url需配置为 http://外网ip:端口** + +![输入图片说明](https://foruda.gitee.com/images/1678981287686638349/3734f085_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678981292545287978/f2471f97_1766278.png "屏幕截图") + +`nginx` 配置 `独立的端口` 进行反向代理即可访问(代理编写方式参考后端反向代理) + +### Minio https 改造 + +下方链接包含 minio+nginx 与 minio本身配置https 两种方案
+[终极版minio配置https教程](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/identify_fail.md b/ruoyi-admin/src/main/resources/static/questions/identify_fail.md new file mode 100644 index 00000000..4e258067 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/identify_fail.md @@ -0,0 +1,10 @@ +# 放行接口提示认证失败 +- - - +## 可能的原因 +接口放行后不需要token即可访问
+但是没有token也就无法获取用户信息与鉴权 + +## 解决方案 +删除接口上的鉴权注解
+删除接口内获取用户信息功能
+删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/import_excel.md b/ruoyi-admin/src/main/resources/static/questions/import_excel.md new file mode 100644 index 00000000..431863e8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/import_excel.md @@ -0,0 +1,4 @@ +# 关于导入excel实体类为空 +- - - +* 禁止在导入实体使用 `lombok` 链式调用注解 `@Accessors(chain = true)` +* 会导致找不到 `set` 方法无法注入内容 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md b/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md new file mode 100644 index 00000000..cef9bcd2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/jar_run_fail.md @@ -0,0 +1,12 @@ +# 打包jar运行报错问题 +- - - + +**常见于 windows 平台以命令方式启动** + +windows 平台默认编码为 GBK 所以读取到所有的配置都是乱码 + +## 解决方案 + +需要在命令增加 `-Dfile.encoding=utf-8` 指定文件编码 + +例如: `java -Dfile.encoding=utf-8 -jar ruoyi-xxx.jar` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md b/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md new file mode 100644 index 00000000..a1baf9dd --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/jce_cannot.md @@ -0,0 +1,3 @@ +# 问题说明 由于 OracleJDK 强校验加密证书导致 + +解决方案 禁止使用 oraclejdk 更换为其他例如 openjdk \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md b/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md new file mode 100644 index 00000000..5051a782 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/kinfe4j.md @@ -0,0 +1,66 @@ +# 对接前声明 + +经常有小伙伴希望可以对接 knife4j + +那么这里将介绍如何使用 框架生成的 openapi 对接 knife4j + +# 如何对接 + +**重点声明: 本框架生成标准openapi结构 如对接后遇到不好用等问题 皆与本框架无关** + +knife4j 本身提供了独立的文档中间件 可以零成本的介入 openapi + +文档地址: https://doc.xiaominfo.com/docs/middleware-sources + +**注意: 此组件应单独搞一个boot项目 不要往框架里做任何代码上的更改** + +使用文档提供的 Cloud 模式 对接咱们框架的 openapi 地址即可完成对接 + +![输入图片说明](https://foruda.gitee.com/images/1685953873117929554/22dce56e_1766278.png "屏幕截图") + +vue版本对接配置如下: + +```yml +knife4j: + enable-aggregation: true + cloud: + enable: true + routes: + - name: 演示模块 + uri: localhost:8080 + location: /v3/api-docs/1.演示模块 + - name: 系统模块 + uri: localhost:8080 + location: /v3/api-docs/2.系统模块 + - name: 代码生成模块 + uri: localhost:8080 + location: /v3/api-docs/3.代码生成模块 +``` + +cloud版本对接配置如下: + +```yml +knife4j: + enable-aggregation: true + cloud: + enable: true + routes: + - name: 演示模块 + uri: localhost:8080 + location: /demo/v3/api-docs + - name: 认证服务 + uri: localhost:8080 + location: /auth/v3/api-docs + - name: 资源服务 + uri: localhost:8080 + location: /resource/v3/api-docs + - name: 系统服务 + uri: localhost:8080 + location: /system/v3/api-docs + - name: 监控服务 + uri: localhost:8080 + location: /monitor/v3/api-docs + - name: 代码生成服务 + uri: localhost:8080 + location: /gen/v3/api-docs +``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/login_step.md b/ruoyi-admin/src/main/resources/static/questions/login_step.md new file mode 100644 index 00000000..c1d4fcc9 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/login_step.md @@ -0,0 +1,69 @@ +# 关于登录调试步骤 + +## 1:关闭 api 接口加密 + +1. 修改后端配置文件 `application.yml` + +![输入图片说明](https://foruda.gitee.com/images/1717037518256330645/c5a9f0fc_4959041.png "屏幕截图") + +2. 修改前端配置文件 `.env.development` | `.env.production` + +![输入图片说明](https://foruda.gitee.com/images/1717037555118359683/0e73a369_4959041.png "屏幕截图") + +## 2:登录参数 + +![输入图片说明](https://foruda.gitee.com/images/1717038201634120005/e02882d3_4959041.png "屏幕截图") + +|参数名|说明| +|---|---| +|tenantId| 租户id | +|username| 用户名 | +|password| 密码 | +|rememberMe| 记住密码 | +|uuid| - | +|code| 验证码结果 | +|clientId| 客户端id(表 sys_client) | +|grantType| 授权类型(表 sys_client) | + +## 3:使用接口文档调试 + +### 3.1:使用接口文档请求 + +1. 配置接口文档([参考文档](/ruoyi-vue-plus/framework/association/doc)) +2. 请求接口 `http://localhost:8080/auth/login` + +![输入图片说明](https://foruda.gitee.com/images/1717039200581756307/97efbc9c_4959041.png "屏幕截图") + +### 3.2:使用 idea 请求 + +![输入图片说明](https://foruda.gitee.com/images/1717039459944753490/040d2b9d_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1717039534863944601/df91df67_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1717039598067298052/cc9fe61b_4959041.png "屏幕截图") + +### 3.3:获取验证码以及 uuid + +!> 验证码以及 uuid 获取方式: Redis | 控制台 + +方式一、Redis: + +![输入图片说明](https://foruda.gitee.com/images/1717040260329977942/42f7ed62_4959041.png "屏幕截图") + +> **如果没有验证码相关 key,说明已经过期被清理了,去前端页面刷新一下即可。** + +方式二、控制台: + +![输入图片说明](https://foruda.gitee.com/images/1717040428227070908/1ef7562a_4959041.png "屏幕截图") + +### 3.4:关闭验证码 + +如果嫌验证码太麻烦,可以关闭,修改后端配置文件 `application.yml` + +![输入图片说明](https://foruda.gitee.com/images/1717040533266608114/054fd984_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1717040745251872562/374267e8_4959041.png "屏幕截图") + +请求参数: + +![输入图片说明](https://foruda.gitee.com/images/1717040762860943102/81c9b44a_4959041.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/lombok.md b/ruoyi-admin/src/main/resources/static/questions/lombok.md new file mode 100644 index 00000000..47125153 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/lombok.md @@ -0,0 +1,4 @@ +# 关于lombok注解爆红 +- - - +* 已知 lombok 插件与 idea中文插件 存在兼容性问题 +* 移除中文插件或手动关闭idea检查 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md b/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md new file mode 100644 index 00000000..ae35d937 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/nacos_naming_instance_metadata.md @@ -0,0 +1,35 @@ +# nacos 报错 The Raft Group [naming_instance_metadata] +- - - +## Nacos 服务下线报错问题 + +问题描述: + +Nacos 服务管理 > 服务列表 > 详情 > 下线 报错 + + + +报错详情: + +``` +caused: errCode: 500, errMsg: do metadata operation failed ;caused: com.alibaba.nacos.consistency.exception.ConsistencyException: The Raft Group [naming_instance_metadata] did not find the Leader node;caused: The Raft Group [naming_instance_metadata] did not find the Leader node; +``` + + + +解决方案: + +**删除 Nacos 根目录下 data 文件夹下的 protocol 文件夹** + +(推荐使用全局搜索软件查询,windows 环境根目录一般在 C:\Users\用户名\nacos) + + + +问题原因: + +> Nacos 采用 raft 算法来计算 Leader,并且会记录上次启动的集群地址,所以当我们自己的服务器 IP 改变时(网络环境不稳定,如WIFI, IP 地址也经常变化),导致 raft 记录的集群地址失效,导致选 Leader 出现问题。 + + + +参考目录: + +[解决疑难问题之服务下线报:The Raft Group naming_instance_metadata\] did not find the Leader node; - 嘉美祥瑞 - 博客园 (cnblogs.com)](https://www.cnblogs.com/whl-jx911/p/16736625.html) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md b/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md new file mode 100644 index 00000000..f6cc36d9 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/nacos_read_fail.md @@ -0,0 +1,15 @@ +# 无法读取nacos配置 +- - - +### 检查 `group` 与 `namespace` 是否一致 + +如果未使用框架自带 `ry-config.sql` 文件进行配置 会导致 `namespace` 不一致 无法查询配置 + +### 检查 `8848` `9848` `9849` 端口是否开启可用 + +### 检查配置文件名是否一致 例如: "xxx" 与 "xxx.yml" 的区别 + +### 检查是否手动改过 `nacos` 数据库数据 + +`nacos` 数据表层层关联 不要自作聪明手动改数据库 + +已经改过的 需要重新导入 `ry-config.sql` 之后在页面进行改数据操作 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md b/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md new file mode 100644 index 00000000..f8d690e1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/only_one_subscriber.md @@ -0,0 +1,11 @@ +# Only one connection receive subscriber allowed +- - - +## 问题原因 +**经多人反馈 共同点为全都是做`小程序开发`使用的`uniapp`发送的网络请求而出现这种问题** + +`uniapp` 错误设置 `Content-Type` 将所有请求类型全都设置成了 `json` 导致不该读body的请求也读取了body 最终导致报错 + +## 解决方案 + +方案1: 升级 1.4.0 已经对这种不合规发的请求做了兼容处理(被迫)
+方案2: `uniapp` 内的请求设置正确的 `Content-Type` diff --git a/ruoyi-admin/src/main/resources/static/questions/parse_exception.md b/ruoyi-admin/src/main/resources/static/questions/parse_exception.md new file mode 100644 index 00000000..67a7a114 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/parse_exception.md @@ -0,0 +1,40 @@ +# ParseException SQL解析异常 +- - - +## 异常内容 + +`net.sf.jsqlparser.parser.ParseException: Encountered unexpected token:` + +![输入图片说明](https://foruda.gitee.com/images/1678981169309778625/a17ff852_1766278.png "屏幕截图") + +此异常为 SQL 解析异常, 应检查 SQL 语句内是否包含 SQL 关键字 + +异常通常都会提供坐标 + +![输入图片说明](https://foruda.gitee.com/images/1678981173813116217/a6f9ee32_1766278.png "屏幕截图") + +检查报错 SQL 相关坐标位置 + +![输入图片说明](https://foruda.gitee.com/images/1678981179153564043/bf4912b4_1766278.png "屏幕截图") + +## 异常由来 +由 Mybatis-Plus 拦截器进行 SQL 解析导致
+常见拦截器导致问题 `TenantLineInnerInterceptor` `DataPermissionInterceptor` + +## 解决方案 + +> 将关键字增加标识符区别开 + +1.实体类字段处理(以下仅限于mysql 其他数据库方法各不相同) + +![输入图片说明](https://foruda.gitee.com/images/1678981183515542682/fccd85ad_1766278.png "屏幕截图") + +2.自定义 SQL 或 XML 处理 + +![输入图片说明](https://foruda.gitee.com/images/1678981187926917963/38437edb_1766278.png "屏幕截图") + +3.Mapper排除 +> 查看具体使用了哪些拦截器导致问题 使用忽略注解依次进行排除即可 + +![输入图片说明](https://foruda.gitee.com/images/1678981192902044584/fb1c41eb_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/questions/permission_denied.md b/ruoyi-admin/src/main/resources/static/questions/permission_denied.md new file mode 100644 index 00000000..76d955db --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/permission_denied.md @@ -0,0 +1,15 @@ +# Redis 报错 Permission denied +- - - +### 此报错为无权限 + +需确保 redis 数据存储文件夹具有写权限 + +```shell +chmod 777 /docker/redis/data +``` + +没有写权限无法对数据进行存储 + +### 关于RDB报错 `/etc` 无权限问题 + +增加redis密码校验 无密码导致配置不安全 diff --git a/ruoyi-admin/src/main/resources/static/questions/read_metadata.md b/ruoyi-admin/src/main/resources/static/questions/read_metadata.md new file mode 100644 index 00000000..b91165fd --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/read_metadata.md @@ -0,0 +1,11 @@ +# unable to read meta-data for class xxx +- - - +## 问题原因 + +此问题由改包名导致框架内组件 spring 的 spi 配置文件包名被改乱套 + +## 解决方案 + +更正组件包下的 spring spi 配置文件内的类包名 + +![输入图片说明](https://foruda.gitee.com/images/1668608724503582409/50a77b4b_1766278.jpeg "test.jpg") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md b/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md new file mode 100644 index 00000000..7e51fb58 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/sentinel_404.md @@ -0,0 +1,8 @@ +# Sentinel页面404问题 +- - - +## 原因 +检查 `webapp` 目录是否为资源目录 低版本 `idea` 不会自动解析 +## 解决方案 +手动设置 `webapp` 为资源目录即可
+ +![输入图片说明](https://foruda.gitee.com/images/1678981354612151228/52f2a886_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/questions/st_not_support.md b/ruoyi-admin/src/main/resources/static/questions/st_not_support.md new file mode 100644 index 00000000..a3012805 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/st_not_support.md @@ -0,0 +1,11 @@ +# 不支持ST请求 +- - - +## 问题原因 +**经多人反馈 共同点为全都是做`小程序开发`使用的`uniapp`发送的网络请求而出现这种问题** + +`uniapp` 错误设置 `Content-Type` 将所有请求类型全都设置成了 `json` 导致不该读body的请求也读取了body 最终导致报错 + +## 解决方案 + +方案1: 升级 1.4.0 已经对这种不合规发的请求做了兼容处理(被迫)
+方案2: `uniapp` 内的请求设置正确的 `Content-Type` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/swagger.md b/ruoyi-admin/src/main/resources/static/questions/swagger.md new file mode 100644 index 00000000..8b0a6e01 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/swagger.md @@ -0,0 +1,3 @@ +# 框架内没有任何swagger + +想使用接口文档功能 请查看框架接口文档说明 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md b/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md new file mode 100644 index 00000000..70803f58 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/synchronous_update.md @@ -0,0 +1,3 @@ +# 如何同步项目更新 +- - - +参考文章: [关于如何同步更新开源项目](https://blog.csdn.net/qq_31360283/article/details/118345795) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/use_druid.md b/ruoyi-admin/src/main/resources/static/questions/use_druid.md new file mode 100644 index 00000000..77f3f605 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/use_druid.md @@ -0,0 +1,20 @@ +# 如何使用druid连接池 +- - - +## 为何移除druid + +性能低下 bug频发 内含fastjson问题众多 监控不支持集群(鸡肋) 不支持一些高版本数据库 社区活跃度冰点 + +### 性能对比图 +![输入图片说明](https://foruda.gitee.com/images/1667888745256002635/1bbd3481_1766278.png "屏幕截图") +### 包大小对比图 +![输入图片说明](https://foruda.gitee.com/images/1667888760611300040/87af8d82_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1667888766932068690/7b379298_1766278.png "屏幕截图") + +## 为何使用hikari(中文: 光) + +spring默认自带 代码量少结构简单 稳定可靠 性能突出(自行百度一堆测评) + +## 参考提交记录反向操作即可 + +https://gitee.com/dromara/RuoYi-Vue-Plus/commit/1f42bd3d22c104aaa2d780c20a555b5e467858bf
+https://gitee.com/dromara/RuoYi-Vue-Plus/commit/a63abbf268e4c0a60344f63b5cba828a1347e178 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md b/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md new file mode 100644 index 00000000..113d239f --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/questions/use_tomcat.md @@ -0,0 +1,9 @@ +# 关于如何使用Tomcat +- - - +### 查看ruoyi-framework模块的pom.xml文件,根据注释更改依赖 + +![输入图片说明](https://foruda.gitee.com/images/1678981109106652929/0803004d_1766278.png "屏幕截图") + +### 查看ruoyi-admin模块中的application.yml文件,根据注释更改配置 + +![输入图片说明](https://foruda.gitee.com/images/1678981112652965294/dda8df86_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md new file mode 100644 index 00000000..4580b86c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/_sidebar.md @@ -0,0 +1,70 @@ + +- **特别赞助** +- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) +- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) +- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) + + +* **简介** + * [项目简介](/ruoyi-cloud-plus/home.md) + * [更新日志](/ruoyi-cloud-plus/changlog.md) +* **快速开始** + * [项目初始化](/ruoyi-cloud-plus/quickstart/init.md) + * [1.X项目初始化](/ruoyi-cloud-plus/quickstart/1.Xinit.md) + * [工作流初始化](/ruoyi-cloud-plus/quickstart/worker_init.md) + * [idea环境配置](/ruoyi-cloud-plus/quickstart/idea_environment.md) + * [应用部署](/ruoyi-cloud-plus/quickstart/deploy.md) + * [扩展项目](/ruoyi-cloud-plus/quickstart/extend_project.md) + * [搭建SnailJob调度中心](/ruoyi-cloud-plus/quickstart/snail_job_init.md) + * [(废弃)搭建PowerJob调度中心](/ruoyi-cloud-plus/quickstart/power_job_init.md) +* **框架功能** + * [项目结构](/ruoyi-cloud-plus/framework/tree.md) + * [软件架构图](/ruoyi-cloud-plus/framework/architecture_diagram.md) + * 框架相关 + * [创建新服务](/ruoyi-cloud-plus/framework/association/new_module.md) + * [修改包名](/ruoyi-cloud-plus/framework/association/update_package_name.md) + * [接口文档](/ruoyi-cloud-plus/framework/association/doc.md) + * [修改应用路径](/ruoyi-cloud-plus/framework/association/update_url.md) + * [国际化](/ruoyi-cloud-plus/framework/association/i18n.md) + * [多团队开发](/ruoyi-cloud-plus/framework/association/collaboration.md) + * [内网鉴权](/ruoyi-cloud-plus/framework/association/inner_authentication.md) + * 基础功能 + * [系统用户相关](/ruoyi-cloud-plus/framework/basic/user.md) + * [权限控制](/ruoyi-cloud-plus/framework/basic/permissions_control.md) + * [导出功能](/ruoyi-cloud-plus/framework/basic/export.md) + * [导入功能](/ruoyi-cloud-plus/framework/basic/import.md) + * [参数校验](/ruoyi-cloud-plus/framework/basic/param_check.md) + * [代码生成](/ruoyi-cloud-plus/framework/basic/code_generate.md) + * [分页功能](/ruoyi-cloud-plus/framework/basic/page.md) + * [OSS功能](/ruoyi-cloud-plus/framework/basic/oss.md) + * [数据权限](/ruoyi-cloud-plus/framework/basic/permissions.md) + * [网关路由与放行](/ruoyi-cloud-plus/framework/basic/router_release.md) + * [多租户功能](/ruoyi-cloud-plus/framework/basic/tenant.md) + * [第三方授权功能](/ruoyi-cloud-plus/framework/basic/social.md) + * [客户端管理功能](/ruoyi-cloud-plus/framework/basic/client.md) + * 扩展功能 + * [多数据源](/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md) + * [短信模块](/ruoyi-cloud-plus/framework/extend/sms.md) + * [邮件功能](/ruoyi-cloud-plus/framework/extend/mail.md) + * [防重幂等](/ruoyi-cloud-plus/framework/extend/idempotent.md) + * [数据脱敏](/ruoyi-cloud-plus/framework/extend/sensitive.md) + * [API加解密](/ruoyi-cloud-plus/framework/extend/api_encrypt.md) + * [数据加解密](/ruoyi-cloud-plus/framework/extend/encrypt.md) + * [翻译功能](/ruoyi-cloud-plus/framework/extend/translation.md) + * [WebSocket功能](/ruoyi-cloud-plus/framework/extend/websocket.md) + * 功能说明 + * [事务相关](/ruoyi-cloud-plus/framework/explain/transaction.md) + * [单元测试](/ruoyi-cloud-plus/framework/explain/test.md) + * [主键使用说明](/ruoyi-cloud-plus/framework/explain/key.md) + * [关于多表查询](/ruoyi-cloud-plus/framework/explain/about_join.md) +* **扩展功能** + * [ELK搭建](/ruoyi-cloud-plus/extend-function/elk.md) + * [ES搜索引擎](/ruoyi-cloud-plus/extend-function/es.md) + * [RabbitMQ搭建](/ruoyi-cloud-plus/extend-function/rabbitmq.md) + * [RocketMQ搭建](/ruoyi-cloud-plus/extend-function/rocketmq.md) + * [Kafka搭建](/ruoyi-cloud-plus/extend-function/kafka.md) + * [Nacos集群搭建](/ruoyi-cloud-plus/extend-function/nacos.md) + * [SkyWalking搭建与集成](/ruoyi-cloud-plus/extend-function/skywalking.md) + * [Prometheus+Grafana搭建](/ruoyi-cloud-plus/extend-function/prometheus_grafana.md) + * [Sharding-Proxy搭建分库分表](/ruoyi-cloud-plus/extend-function/shardingproxy.md) + * [对接MaxKey单点登录](/ruoyi-cloud-plus/extend-function/maxkey.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md new file mode 100644 index 00000000..368844cb --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/changlog.md @@ -0,0 +1,1385 @@ +# 更新日志 +- - - + +## v2.2.1 - 2024-08-26 + +### 重大改动 + +* 增加 ruoyi-common-sse 模块 支持SSE推送 比ws更轻量更稳定的推送 +* 增加 springboot snailjob 等 actuator 账号密码认证 杜绝内外网信息泄漏问题 +* 增加 重构代码生成器 集成anyline开源框架 支持400+种数据库适配 + +### 依赖升级 + +* update springboot 3.2.6 => 3.2.9 +* update snailjob 1.0.1 => 1.1.2 +* update mapstruct-plus 1.4.3 => 1.4.4 +* update hutool 5.8.27 => 5.8.31 解决hutool不兼容jakarta问题 +* update anyline 8.7.2-20240808 +* update sms4j 3.2.1 => 3.3.2 +* update redisson 3.31.0 => 3.34.1 +* update mapstruct-plus 1.3.6 => 1.4.3 +* update lombok 1.18.32 => 1.18.34 +* update easyexcel 3.3.4 => 4.0.2 +* update springdoc 2.5.0 => 2.6.0 +* update flowable 7.0.0 => 7.0.1 + +### cloud内容更新 + +* update springcloud 2023.0.2 => 2023.0.3 +* update springcloud-alibaba 2023.0.1.0 => 2023.0.1.2 +* update redis 6.2.7 => 6.2.12 解决订阅key报错问题 +* update 优化 seata dockerfile 增加环境变量 +* update 优化 增加日志处理器顺序说明 +* update 优化 使用 seata-server 官方依赖简化seata集成方式 +* update 优化 屏蔽 sentinel 心跳日志 +* update 优化 dubbo元数据注册redis支持timeout(注意时间必须使用数字) +* update 优化 调整sentinel日志级别 屏蔽心跳日志 +* update 优化 sky-agent 默认开启即使连不上服务端也跟踪配置 (有些人就爱这么用) +* update 优化 kafka 自动创建 topic 部分人副本数不够报错问题 +* add 增加 nacos sentinel snailjob 健康检查 actuator 账号密码认证 +* fix 修复 dubbo redis元数据中心 获取监听器null问题 +* fix 修复 nacos sentinel seata 不适配新版undertow问题 先换回tomcat +* fix 修复 依赖漏洞 限制部分依赖版本 +* fix 修复 由于alibaba sentinel 初始化机制变更导致的无法连接问题 +* fix 修复 dubbo 日志输出异常判断错误 +* remove 删除 kafka-streams 所有人都不会用也不学怎么用 删除了事 + +### 功能更新 + +* update 优化 去除日志部署环境判断 通过日志级别控制 +* update 优化 忽略租户与忽略数据权限支持嵌套使用(感谢 amadeus5201) +* update 优化 租户相关controller 增加租户开关配置控制是否注册 +* update 优化 移除 alibaba ttl 与线程池搭配有问题(可传递但无法清除与更新) +* update 优化 个人中心编辑 忽略数据权限 +* update 优化 兼容部分用户不想给用户分配角色与部门的场景 +* update 优化 租户套餐重名校验 +* update 优化 部门下存在岗位不允许删除 +* update 优化 角色编辑状态未校验问题 +* update 优化 用户脱敏增加编辑权限标识符 +* update 优化 代码生成器 自动适配oss翻译 +* update 优化 临时升级 undertow 版本 解决虚拟线程溢出问题 +* update 优化 支持通过配置文件关闭工作流 +* update 优化 增加mybatis-plus填充器兜底策略 +* update 优化 TenantSpringCacheManager 处理逻辑 +* update 优化 角色权限判断 +* update 优化 增加删除标志位常量优化查询代码 +* update 优化 监控使用独立web依赖 +* update 优化 更多脱敏策略(感谢 hemengji) +* update 优化 设置nginx sse相关代理参数 +* update 优化 调整默认推送使用SSE +* update 优化 Monitor监控服务通知分类打印(感谢 AprilWind) +* update 优化 限流注解 又写key又不是表达式的情况 +* update 优化 WorkflowUtils查询用户信息发送消息未查询邮件和手机号(感谢 yanzy) +* update 优化 注释掉其他数据库 jdbc 依赖 由用户手动添加 +* update 优化 oracle snailjob 兼容低版本oracle索引名称长度限制 +* update 优化 数据权限支持通过菜单标识符获取数据所有权 +* update 优化 数据权限支持自定义连接符 +* update 优化 TestDemo 删除前校验数据权限 +* update 优化 更换docker镜像底层系统 避免无字体情况 + +### 问题修复 + +* fix 修复 三方登录构建去除无用代码 +* fix 修复 多线程对同一个session发送ws消息报错问题 +* fix 修复 依赖漏洞 限制部分依赖版本 +* fix 修复 excel 基于其他字段 合并错误问题 +* fix 修复 一级缓存key未区分租户问题 +* fix 修复 id字符串格式转换错误问题 +* fix 修复 登出无法正确删除对应的租户数据问题 +* fix 修复 登录错误锁定不区分租户问题 +* fix 修复 转换模型缺少分类字段 +* fix 修复 权限标识符处理未设置成功状态问题 +* fix 修复 无法导入 bpmn 类型文件问题 + +### 前端改动 + +* update element-plus 2.7.5 => 2.7.8 +* update vue 3.4.25 => 3.4.34 +* update vite 5.2.10 => 5.2.12 +* add 增加 使用 vueuse 编写 sse 推送功能 +* update 优化 使用匹配模式简化预编译配置 +* update 优化 时间搜索组件统一 +* update 优化 oss 配置按钮 使用ossConfig权限标识符与oss权限分离 +* update 优化 类型报错问题 +* update 优化 切换租户后刷新首页 +* update 优化 实现表格行选中切换 +* update 优化 使用 vueuse 重构 websocket 实现 +* update 优化 代码生成器编辑页禁用缓存 防止同步后页面不更新问题 +* update 优化 调整默认推送使用SSE +* fix 修复 租户套餐导出路径错误问题 +* fix 修复 登出后重新登录 sse推送报错问题 + + +## v2.2.0 - 2024-07-09 + +### 重大更新 + +* [重大更新] 使用 caffeine 重构 PlusSaTokenDao 层实现 减少将近90%的redis查询提高性能 +* [重大更新] 新增 PlusCacheWrapper 装饰器 为 SpringCache 增加本地缓存减少redis查询提高性能 +* [重大更新] 升级 awsS3 到2.X版本 支持异步与自动分片上传下载(感谢 AprilWind) +* [重大更新] 新增 flowable 工作流功能(感谢 May) +* [重大更新] 新增 snailjob 调度中心 移除 powerjob (投诉的人太多) (感谢 dhb52) +* [重大更新] 重构 将spring-cloud-stream改为普通的mq依赖用法(感谢 Xbhog) +* [重大更新] 新增 ruoyi-common-bus 消息总线组件 基于MQ跨服务投递事件消息 + +### 依赖升级 + +* update springboot 3.1.7 => 3.2.6 支持虚拟线程 +* update springboot-admin 3.1.8 => 3.2.3 +* update springdoc 2.2.0 => 2.5.0 +* update redisson 3.24.3 => 3.29.0 支持虚拟线程 +* update hutool 5.8.22 => 5.8.26 +* update dynamic-ds 4.2.0 => 4.3.0 +* update mybatis-plus 3.5.4 => 3.5.7 修复与boot代码冲突问题 +* update lock4j 2.2.5 => 2.2.7 消除启动警告 +* update sms4j 2.2.0 => 3.2.1 支持自定义配置key 可用于多厂商多租户等 +* update mapstruct-plus 1.3.5 => 1.3.6 +* update easyexcel 3.3.3 => 3.3.4 +* update lombok 1.18.30 => 1.18.32 +* update satoken 1.37.0 -> 1.38.0 +* update aws-oss 1.12.600 => 2.25.15 + +### 功能更新 + +* update 优化 StreamUtils 抽取 findFirst findAny 方法 +* update 优化 更新使用 Spring 官方推荐 JDK +* update 优化 webscoket 配置与异常拦截 +* update 优化 isTenantAdmin 空校验 +* update 优化 修改路由name命名规则(感谢 玲娜贝er) +* update 优化 大数据量下join卡顿问题 使用子查询提高性能 +* update 优化 用户ID查询角色列表(感谢 AprilWind) +* update 优化 获取用户账户(感谢 AprilWind) +* update 优化 租户列表接口 避免登录之后列表被域名过滤 +* update 优化 三方登录不同域名获取不到租户id问题 +* update 优化 获取aop代理的方式 减少与其他使用aop的功能冲突的概率 +* update 优化 临时解决 spring 启动报 warn 问题 +* update 优化 移除表单构建菜单(没有可用组件 用处不大以后再考虑) +* update 优化 修改用户信息接口(感谢 AprilWind) +* update 优化 切换动态租户 默认线程内切换(如需全局 手动传参) +* update 优化 适配最新前端代码生成模板 +* update 优化 代码生成 el-radio 标签过期属性 +* update 优化 文件下载(使用对流传递 降低内存使用量)(感谢 秋辞未寒) +* update 优化 去除gc日志参数(有需要自己加) +* update 优化 拆分异常处理器 +* update 优化 常规web异常状态码 +* update 优化 设置静态资源路径防止所有请求都可以访问静态资源 +* update 优化 代码生成表导入 排除工作流相关表 +* update 优化 redis 对Long值的存储类型不同问题 +* update 优化 去除加密请求类型限制 +* update 优化 mp多租户插件注入逻辑 +* update 优化 移除删表语句 用户自行处理 +* update 优化 RedisUtils 支持忽略租户 +* update 更新 ip地址 xdb文件 +* update 优化 新增修改菜单权限字符校验 +* update 优化 验证码背景色改为浅灰色 +* update 优化 更新 mybatis 多包扫描配置 +* update 优化 RateLimiter 注解使用体验(感谢 ly-chn) +* update 优化 GET 方法响应体支持加密 +* update 优化 excel 单元格合并可以基于注解选择需要依赖哪些字段(感谢 司猫子) +* update 优化 OssFactory 获取实例锁性能(感谢 fanc) +* update 优化 登录消息 支持集群发送 +* update 优化 数据权限 使用预扫描mapper注解提升代码性能 +* update 优化 数据加密 使用预扫描实体类提升代码性能(感谢 老马) +* update 优化 Async 针对虚拟线程配置 与其他注意事项注释 +* update 优化 框架整体sql提高查询性能 +* update 优化 将p6spy配置文件统一放置到 common-mybatis 插件包内 +* update 优化 使用翻译注解简化用户查询 调整用户查询逻辑 + + +### 新增功能 + +* add 新增 SMS异常处理器(感谢 AprilWind) +* add 新增 在线设备管理(个人中心)(感谢 AprilWind) +* add 新增 岗位编码与部门编码 并将岗位放到部门下(感谢 秋辞未寒) +* add 新增 分布式锁Lock4j异常拦截(感谢 AprilWind) +* add 新增 BaseMapperPlus提供一组可选是否抛出异常的selectVoOne方法(感谢 秋辞未寒) +* add 新增 用户、部门、角色、岗位 下拉选接口与代码实现优化 +* add 新增 JustAuth 整合 TopIam 单点登录(感谢 马铃薯头) +* add 新增 StringUtils.isVirtual 方法 +* add 新增 正则工具类 字符串提取 字符串校验 + +### 问题修复 + +* fix 修复 isLogin 方法抛异常无法正常返回值问题 +* fix 修复 spring路径规则 导致 actuator 被特殊方式访问问题 +* fix 修复token无效时关闭ws(感谢 AprilWind) +* fix 修复 oss未使用租户 拼接租户id null问题 +* fix 修复 用户昵称修改后未清除对应缓存问题 +* fix 修复 文件上传图片预览问题 +* fix 修复 三方账号可以被同一个用户多次绑定问题 +* fix 修复 兼容redis5.0出现的问题 +* fix 修复 字典键值可重复配置问题 +* fix 修复 部分浏览器无法获取加密响应头问题 +* fix 修复 用户未设置部门 登录报错问题 +* fix 修复 全局异常处理器 空指针null问题 +* fix 修复 excel 表达式字典 下拉框导出格式错误 +* fix 修复 InjectionMetaObjectHandler 已存在数据依旧会获取用户信息报异常问题 +* fix 修复 关闭租户功能 三方登录报错问题 +* fix 修复 部门树排序问题 +* fix 修复 CryptoFilter 代码逻辑问题 + +### 前端改动 + +* update 升级 element vite 版本 最低nodejs版本提升到18.18.0 +* update 优化 更改客户端状态接口 使用clientId传参 +* update 优化 ws开关改为常开(vite5修复了崩溃bug) +* update 优化 移除cjs +* update 优化 对Volar支持 +* update 优化 富文本组件,修复两个组件上传图片位置错乱问题 +* update 优化 request请求类判断请求头方式 +* update 优化 密码校验策略增加非法字符限制 +* update 优化 支持全局开启或关闭接口加密功能 +* update 优化 暗黑模式,增加vxe的暗黑模式 +* update 优化 首页打开topNav不展开菜单问题 +* update 优化 el-select 与 el-input 全局样式 +* update 优化 跟密码相关的默认前端关闭防重功能 +* add 新增 社交登录整合 TopIam +* add 新增 图片上传组件增加压缩功能支持,可自行开关 +* add 新增 vxe-table依赖支持 +* add 新增 全局用户选择组件 +* add 新增 工作流相关页面与组件 +* add 新增 使用bpmnjs流程预览 +* add 新增 在线登录设备管理(感谢 AprilWind) +* add 新增 用户选择角色时 可搜索功能(感谢 追梦稻草人Li) +* fix 修复 登录失效,重新登录丢失参数问题(感谢 爱宇阳) +* fix 修复 websocket 非index页面刷新无法重连问题 +* fix 修复 全局属性找不到的问题(感谢 ahaos) +* fix 修复 vue 类型识别问题 +* fix 修复 富文本编辑器 单页面多实例图片混乱问题 +* fix 修复 i18n无感刷新问题 +* fix 修复 文件预览大写后缀不展示的问题(感谢 北桥) +* fix 修复 面板因为min width原因收缩不全 +* fix 修复 移动端下 无法展开菜单问题 +* fix 修复 菜单搜索下方出现白色区域 +* fix 修复 el-tag标签类型不一致问题 +* fix 修复 角色必填*号 + +### 微服务修改 + +* update springcloud 2022.0.4 => 2023.0.2 +* update springcloud-alibaba 2022.0.0.0 => 2023.0.1.0 +* update dubbo 3.2.7 => 3.2.14 +* update easy-es 2.0.0-beta4 => 2.0.0 正式版 +* update nacos 2.2.1 => 2.3.2 默认开启nacos服务端授权认证 (感谢 OldDriver9527) +* update rocketmq 4.9.4 => 5.2.0 docker镜像升级 +* update kafka 3.2.0 => 3.6.2 docker镜像升级 +* update rabbitmq 3.10.6 => 3.13.3 docker镜像升级 +* update sentinel 1.8.6 => 1.8.8 +* update skywalking 9.3.0 => 9.7.0 +* update skywalking-agent 8.16.0 => 9.2.0 +* update 优化 dubbo 使用 redis 作为元数据中心管理 支持过期时间 避免过期数据堆积 解放nacos存储空间 +* update 优化 调整配置文件语法 +* update 优化 使用spring工具自定义dubbo ip获取方法(针对多网卡ip获取不正确问题) +* update 优化 common-dubbo 删除无用依赖 +* update 优化 去除重复的扫描器 @EnableDubbo 会自行扫描包 +* update 优化 加密组件 mp依赖改为可选 +* update 优化 mybatis依赖设置为可选依赖 避免出现不应该注入的情况 +* fix 修复 sentinel-dashboard的pom引入logaback冲突问题 +* fix 修复 nacos 不兼容 logback 1.4 新版本问题 +* fix 修复 开启数据库加密 auth服务报错问题 +* fix 修复 gateway sentinel 限流报错问题(临时方案) https://github.com/alibaba/Sentinel/issues/3298 + + +## v2.1.2 - 2023-12-22 + +### 依赖升级 + +* update springboot 3.1.5 => 3.1.7 +* update springboot 2.7.17 => 2.7.18(扩展服务升级到boot2最终版本) +* update mybatis-boot 3.0.2 => 3.0.3 优化依赖传递 +* update powerjob 4.3.3 => 4.3.6 +* update easyexcel 3.3.2 => 3.3.3 +* update transmittable-thread-local 2.14.2 => 2.14.4 +* update justauth 1.16.5 => 1.16.6 +* update redisson 3.24.1 => 3.24.3 修复订阅重启连接超时问题 +* update easy-es 1.1.1 => 2.0.0-beta4 + +### 功能更新 + +* update 优化 oss 远程调用 支持降级处理 +* update 优化 丰富RedisUtils对List Set类型的操作 +* update 优化 为 admin 模块 单独增加ratelimiter模块 +* update 优化 验证码接口 增加限流配置 +* update 优化 excel合并注解会根据第一合并列的结果来决定后续的列合并 (感谢 Simple) +* update 优化 SocialUtils 代码 +* update 优化 删除无用异常类 +* update 优化 补全三方登录校验国际化 +* update 优化 sms组件 预留自动配置类 +* update 更新 关于数据库的说明 +* update 优化 sms组件 预留自动配置类 +* update 优化 将 OSS配置 改为全局模式 降低使用难度 保留sql便于用户自行扩展(常规项目用不上配置分多租户) +* update 优化 细化oss配置管理权限控制 +* update 优化 开启 redisson 脚本缓存 减少网络传输 +* update 优化 删除 hikaricp 官方不推荐使用的配置 jdbc4 协议自带校验方法 +* update 优化 减少 PlusSaTokenDao 不必要的查询优化性能 +* update 优化 更新用户异常提示 使用登录账号 +* update 优化 使用登录用户判断是否登录 提高效率 +* update 优化 重构 LoginHelper 将本地存储代码操作封装 +* update 优化 getTenantId 判断是否开启多租户 +* update 优化 Dockerfile 使用shell模式 支持环境变量传入jvm参数 +* update 优化 WebSocketUtils 连接关闭改为警告 +* update 优化 excel多sheet页导出 (感谢 May) +* update 优化 删除无用接口实现 +* update 优化 jvm参数调整 全面启用zgc +* update 优化 使用动态租户重构业务对租户的逻辑 +* update 优化 TenantHelper 动态租户支持函数式方法 +* update 优化 支持多租户绑定相同的三方登录 +* update 优化 更新用户登录信息方法忽略数据权限 +* update 优化 补全三方绑定时间字段 删除无用excel注解 +* update 优化 将登录记录抽取到监听器统一处理 +* update 优化 登录消息推送异常拦截(未启动resource也不耽误用) +* update 优化 租户插件 ignoreTable 方法支持动态租户 + +### 新增功能 + +* add 新增 RedisUtils.setObjectIfExists 如果存在则设置方法 +* add 新增 丰富RedisUtils对List Set类型的操作 +* add 新增 翻译组件 用户昵称翻译实现 +* add 新增 响应加密功能 支持注解强制加密接口数据 (感谢 MichelleChung) +* add 新增 common-ratelimiter 限流模块 用于自定义业务限流 与 sentinel不冲突 + +### 问题修复 + +* fix 修复 stream-mq 测试服务未导入租户模块 导致鉴权不一致问题 +* fix 修复 使用zgc导致seata报错(未知原因 将alibaba组件全还原) +* fix 修复 sentinel 镜像添加了多余接口参数 +* fix 修复 注册接口获取开关未在租户范围内问题 +* fix 修复 seata-server logback版本冲突问题 +* fix 修复 selectDictTypeByType 查询方法错误问题 +* fix 修复 一些不正常类无法加载报错问题 +* fix 修复 powerjob sql脚本针对其他数据库转义符问题 (感谢 branches) +* fix 修复 MybatisSystemException 空指针问题 +* fix 修复 excel合并注解会根据第一合并列的结果来决定后续的列合并 +* fix 修复 session 多账号共用覆盖问题 改为 tokenSession 独立存储 +* fix 修复 token 失效后 登录获取用户null问题 +* fix 修复 powerjob部署方案 高版本nginx不生效问题 +* fix 修复 OssFactory 并发多创建实例问题 +* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 + +### 前端改动 + +* update 优化 用户头像 img 变量无确定类型问题 +* update 优化 细化oss配置管理权限控制 +* update 优化 明确打包命令 +* update 优化 代码中存在的警告 +* update 优化 前端白名单页面放行逻辑 +* update 优化 页面关于权限标识符说明 +* fix 修复 append-to-body 编写错误 (感谢 Ai3_刘小龙) +* fix 关闭动态路由tab页签时不清理组件缓存 (感谢 NickLuo) +* fix 删除重复环境变量ElUploadInstance (感谢 棉花) +* fix 修复 在线用户 强推按钮点击取消控制台警告问题 +* fix 修复 字典使用 default 样式报警告问题 + +## v1.8.2 - 2023-11-27 + +### 依赖升级 + +* update springboot 2.7.16 => 2.7.18 升级到2.X最终版本(官方停更) +* update mybatis-plus 3.5.3.2 => 3.5.4 +* update satoken 1.36.0 => 1.37.0 +* update hutool 5.8.20 => 5.8.22 +* update aws-java-sdk-s3 1.12.400 => 1.12.540 +* update vue-quill 1.1.0 => 1.2.0 + +### 功能更新 + +* update 优化 页面关于权限标识符说明 +* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 +* update 优化 部门数据权限使用默认兜底方案 +* update 优化 补全代码生成 columnList 接口参数注解缺失 +* update 优化 AddressUtils 兼容linux系统本地ip +* update 优化 操作日志 部门信息完善 +* update 优化 数据权限 减少二次校验查询 +* update 修改 获取用户token和后端不一致的问题 (感谢 bestrevens) +* update 优化 vue3 版本用户初始密码从字典查询 +* update 优化 富文本Editor组件检验图片格式 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 全局数据存储用户编号 +* update 优化 菜单管理类型为按钮状态可选 + +### 问题修复 + +* fix 修复 OssFactory 并发多创建实例问题 +* fix 修复 demo页面字段编写错误 +* fix 修复 数据权限优化后 update delete 报null问题 +* fix 修复 五级路由缓存无效问题 +* fix 修复 oss服务无法连接 +* fix 修复 内链iframe没有传递参数问题 +* fix 修复 外链带端口出现的异常 +* fix 修复 普通角色编辑使用内置管理员code越权问题 +* fix 修复 seata XA模式缺失druid工具问题 +* fix 修复 代码生成 是否必填与数据库不匹配问题 +* fix 修复 富文本上传接口地址错误 +* fix 修复 HeaderSearch组件跳转query参数丢失问题 +* fix 修复树结构代码生成新增方法赋值错误 + +## v2.1.1 - 2023-11-14 + +### 依赖升级 + +* update springboot 3.1.3 => 3.1.5 +* update springboot 2.7.14 => 2.7.17(扩展服务) +* update springboot-admin 3.1.5 => 3.1.7 +* update satoken 1.35.0.RC => 1.37.0 +* update mybatis-plus 3.5.3.2 => 3.5.4 适配mp新版本改动 +* update dynamic-ds 4.1.3 => 4.2.0 +* update bouncycastle 1.72 => 1.76 +* update poi 5.2.3 => 5.2.4 +* update redisson 3.23.2 => 3.24.1 +* update hutool 5.8.20 => 5.8.22 +* update lombok 1.18.26 => 1.18.30(适配支持jdk21) +* update vue-quill 1.1.0 => 1.2.0 +* update seata 1.7.0 => 1.7.1 +* update dubbo 3.2.5 => 3.2.7 + +### 功能更新 + +* update 优化 移除不合理的方法 携带附件的邮件建议直接集成插件发送 +* update 优化 携带 clientid 跨域问题 +* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 +* update 优化 适配 maxkey 新版本 +* update 优化 @Sensitive脱敏增加角色和权限校验 (感谢 盘古给你一斧) +* update 优化 部门数据权限使用默认兜底方案 +* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) +* update 优化 登录策略代码优化(感谢 David Wei) +* update 优化 补全代码生成 columnList 接口参数注解缺失 +* update 优化 nginx 配置支持 websocket +* update 优化 notice 新增通知公告发送ws推送 +* update 优化 websocket 模块减少日志输出 增加登录推送 +* update 优化 重构登录策略增加扩展性降低复杂度 +* update 优化 addressUtils 兼容linux系统本地ip +* update 优化 补全操作日志部门数据 +* update 优化 支持数据库操作在非web环境下切换租户 +* update 优化 排除powerjob无用的依赖 减少打包30M体积 +* update 优化 删除 satoken yml 时间配置 此功能已迁移至客户端管理 +* update 优化 redis 集群模式注释说明 +* update 优化 客户端禁用限制 +* update 优化 登录日志, 在线用户展示信息(增加 客户端, 设备类型)(感谢 MichelleChung) +* update 优化 限制框架中的fastjson版本 +* update 优化 数据权限 减少二次校验查询 +* update 优化 将部门id存入token避免过度查询redis +* update 优化 增加租户ID为Null错误日志 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) +* update 优化 为 sys_grant_type 字典增加样式 +* update 优化 代码生成 页面输入框样式 +* update 优化 全业务分页查询增加排序规则避免因where条件导致乱序问题 +* update 优化 登录接口租户id被强制校验问题 +* update 优化 加密模块 支持父类统一使用加密注解(感谢 Tyler Ge) +* update 优化 将graalvm镜像更新为openjdk镜像 需要的人自行切换即可 +* update 优化 部分使用者乱设权限导致无法获取用户信息 增加权限提示 +* update 优化 表格列的显示与隐藏小组件(感谢 bestrevens) +* update 优化 增加表单构建不能使用说明 +* update 优化 富文本Editor组件检验图片格式 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 菜单管理类型为按钮状态可选 +* update 优化 用户初始密码从参数配置查询 +* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) +* update 优化 字典标签支持数组和多标签(感谢 抓蛙师) + +### 新增功能 + +* add 新增 websocket 群发功能 +* add 新增 前端接入websocket接收消息(感谢 三个三) +* add 增加 rpc消息推送接口与实现 +* add 新增 CacheController Redis 缓存监控接口(感谢 Michelle.Chung) + +### 问题修复 + +* fix 修复 因扩展服务不支持boot3导致无法引入common-web包 日志写出不生效问题 +* fix 修复 seata XA模式缺失druid工具问题 +* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 +* fix 修复 租户id为null 无法匹配字符串导致的嵌套key问题 +* fix 修复 部门管理orderNum排序失效问题 +* fix 修复 外链带端口出现的异常 +* fix 修复 普通角色编辑使用内置管理员code越权问题 +* fix 修复 代码生成 是否必填与数据库不匹配问题 +* fix 修复 用户注册接口校验用户名不区分租户问题 +* fix 修复 错误增加组导致的校验不生效问题 +* fix 修复 新增校验主键id问题 +* fix 修复 powerjob 使用 nginx 部署无法访问的问题 +* fix 修复 SysUserMapper 内标签使用错误(不影响使用) +* fix 修复 新增或编辑 SysOssConfig 数据后 推送到 redis 数据不完整 +* fix 修复 树表生成查询变量使用错误 +* fix 修复 个人信息修改密码接口隐藏新旧密码参数明文(感谢 bleachtred) +* fix 修复 删除字段后 * update sql 未更新问题 +* fix 修复 三方登录支付宝source与实际支付宝业务code不匹配问题 +* fix 修复 五级路由缓存无效问题 +* fix 修复 内链iframe没有传递参数问题 +* fix 修复 绑定第三方帐号参数“wechar”更正为“wechat” (感谢 scmiot) +* fix 修复 用户注册缺失 clientid 问题 +* fix 修复 HeaderSearch组件跳转query参数丢失问题 +* fix 修复 自定义字典样式不生效的问题 +* fix 修复 login 页面 loading 未关闭问题 + +## v1.8.1 - 2023-09-26 + +### 依赖升级 + +* update springboot 2.7.14 => 2.7.16 +* update springboot-admin 2.7.10 => 2.7.11 +* update satoken 1.35.0.RC => 1.36.0 +* update lombok 1.18.26 =. 1.18.30 +* update springboot 2.7.13 => 2.7.14 +* update mybatis-plus 3.5.3.1 => 3.5.3.2 +* update easyexcel 3.3.1 => 3.3.2 +* update hutool 5.8.18 => 5.8.20 +* update dubbo 3.1.8 => 3.1.11 + +### 功能更新 + +* update 优化 代码生成 vo实体类序列化 +* update 优化 excel 导出不必要的请求头 +* update 优化 字典标签支持传分隔符分隔的字符串和数组 +* update 优化 控制台debuger位置错误问题 +* update 优化 TopNav 菜单样式 +* update 优化 注册用户异常报错不正确问题 +* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 +* update 优化 用户管理 只查询未禁用的部门角色岗位数据 +* update 优化 岗位如果绑定了用户则不允许禁用 +* update 优化 部门与角色如果绑定了用户则不允许禁用 +* update 优化 加密实现 使用 EncryptUtils 统一处理 +* update 优化 适配 mysql 8.0.34 升级连接机制 +* update 优化 excel导出字典转下拉框 无需标记index自动处理 +* update 优化 excel 导出字典默认转为下拉框 +* update 删除一些跟swagger有关的字眼 避免误解 +* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 +* update 优化 xxljob 端口随着主应用端口飘逸 避免集群冲突 + +### 问题修复 + +* fix 修复 自定义字典样式不生效的问题 +* fix 修复 新建用户可能会存在的越权行为 +* fix 修复 字典缓存删除方法参数错误问题 +* fix 修复 修复树模板父级编码变量错误 +* fix 修复 demo 模块缺少 security 依赖问题 +* fix 修复 升级 mp 版本导致的问题 +* fix 修复 加密模块数据转换异常问题 +* fix 修复 动态设置 token 有效期不生效问题 +* fix 修复 token 过期登出无法清理在线用户问题 + + +## v2.1.0 - 2023-09-06 + +# 开发历程 + +* 2023年5月 开始 2.1.0 计划 历经1个月的设计与讨论 +* 2023年6月 开始着手开发 历经2个多月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 +* 2023年8月 开始公测 历经将近1个月的公测与修复工作(期间成功支持多位使用者生产使用) +* 2023年9月初 正式发布(经过多个小伙伴的生产实践 已基本可尝试生产使用) +> 关于1.X的说明 由于SpringBoot2.X与vue2.X均在11月底停止维护
+> 故而咱们vue版本1.X也无法再继续更新
+> 介于1.X的用户量特别庞大 功能也非常的稳定
+> 计划于11月底同Boot2.X一同停止更新但还会持续维护修复bug(修复的形式为直接提交到1.X分支停止发版)
+ +# 视频介绍 + +为了更好的让大家了解 2.1.0 作者录制了相关的视频 供大家快速了解上手 + +* 2.1.0 新功能与变更介绍: https://www.bilibili.com/video/BV1fj411y71X/ + +# 更新日志 + +### 重大更新 + +* [重大更新] 优化 相关代码 完成代码生成多数据源统一存储(感谢 WangBQ) +* [不兼容更新] 移除 原短信功能 集成更强大的 sms4j 短信工具包(感谢 友杰) +* [不兼容更新] 对接 powerjob 实现分布式任务调度 删除原有 xxljob 原因为社区不更新功能太少只支持mysql(感谢 yhan219) +* [重大更新] 新增 三方授权绑定登录功能 基于 justauth 支持市面上大部分三方登录(感谢 三个三) +* [不兼容更新] 新增 客户端授权功能 不需要更改任何代码即可完成多端动态对接(感谢 Michelle.Chung) +* [重大更新] 新增 前后端接口请求加密传输 基于AES+RSA动态高强度加密(感谢 wdhcr) +* [重大更新] 新增 三方授权登录 对接 maxkey 单点登录 +* [不兼容更新] 优化 redis序列化配置 更改为通用格式(升级需清除redis所有数据) +* [重大更新] 新增 通过 sharding-proxy 实现分库分表(感谢 rice666 !pr94) + +### 依赖升级 + +* update springboot 3.0.7 => 3.1.3 +* update springboot-admin 3.1.3 => 3.1.5 +* update springcloud 2022.0.2 => 2022.0.4 +* update springcloud-alibaba 2022.0.0.0-RC2 => 2022.0.0.0 +* update springdoc 2.1.0 => 2.2.0 +* update spring-mybatis 3.0.1 => 3.0.2 +* update mybatis-plus 3.5.3.1 => 3.5.3.2 +* update easyexcel 3.2.1 => 3.3.2 +* update mapstruct-plus 1.2.3 => 1.3.5 解决修改实体类 idea不编译问题 +* update satoken 1.34.0 => 1.35.0.RC 优化过期配置 支持多端token自定义有效期 +* update dynamic-ds 3.6.1 => 4.1.3 支持 SpringBoot3 +* update sms4j 2.2.0 +* update hutool 5.8.18 => 5.8.20 +* update redisson 3.20.1 => 3.23.4 +* update lock4j 2.2.4 => 2.2.5 +* update aws-java-sdk-s3 1.12.400 => 1.12.540 +* update maven-surefire-plugin 3.0.0 => 3.1.2 +* update seata 1.6.1 => 1.7.0 +* update sharding-proxy 5.4.0 +* update dubbo 3.2.2 => 3.2.5 +* update skywalking-toolkit 8.14.0 => 8.16.0 +* update logstash 7.2 => 7.4 + +### 功能更新 + +* update 优化 与 vue 版本同步代码结构 +* update 优化 放行springboot默认error接口 +* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 +* update 调整 gateway 访问日志输出等级 +* update 优化 修改角色如果未绑定用户则无需清理 +* update 优化 用户昵称非空校验 +* update 优化 在全局异常拦截器中增加两类异常处理 +* update 优化 StreamUtils 方法过滤null值 +* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 +* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 +* update 修改代码生成模版,日期范围统一采用addDateRange方法 +* update 优化 树表生成前端缺少 children 字段 +* update 优化 ruoyi-resource 服务添加 websocket 模块 +* update 优化 放行验证码接口、第三方登录请求与回调 +* update 更新 GlobalLogFilter#filter 根据请求头判断加密参数(感谢 Michelle.Chung !pr100) +* update 优化 SaReactorFilter 过滤器判断 token 客户端 id 是否有效(感谢 Michelle.Chung !pr101) +* update 删除一些跟swagger有关的字眼 避免误解 +* update 优化 兼容 clientid 通过 param 传输 +* update 优化 excel导出字典转下拉框 无需标记index自动处理(感谢 一夏coco) +* update 优化 增加线程池销毁配置 +* update 优化 屏蔽 powerjob 无用的心跳日志 +* update 优化 适配 mysql 8.0.34 升级连接机制 +* update 优化 加密实现 使用 EncryptUtils 统一处理 +* update 优化 删除字典无用状态字段(基本用不上 禁用后还会导致回显问题) +* update 优化 部门与角色如果绑定了用户则不允许禁用 +* update 优化 岗位如果绑定了用户则不允许禁用 +* update 优化 用户管理 只查询未禁用的部门角色岗位数据 +* update 优化 登录用户增加昵称返回 +* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 +* update 优化 将部门管理 负责人选项改为下拉框选择 +* update 优化 登录用户缓存 去除冗余统一存储 +* update 优化 注册用户异常报错不正确问题 +* update 优化 放宽菜单权限 角色关联菜单无需管理员 + +### 新增功能 + +* add 增加 RedisUtils 批量删除 hash key 方法 +* add 新增 Oss 上传 File 文件方法(感谢 jenn) +* add 增加 excel 导出下拉框功能 +* add 新增 RedisUtils.setObjectIfAbsent 如果不存在则设置方法 + +### 修复问题 + +* fix 修复 用户重名登录报错问题 +* fix 修复 服务未添加 common-security 模块导致异常拦截器不生效问题 +* fix 修复 用户篡改管理员角色标识符越权问题 +* fix 修复 文件管理 创建人未翻译问题 +* fix 修复 monitor 监控无法展示数据问题 +* fix 修复 更换 satoken dubbo 插件导致包名不一致问题 +* fix 修复 字典缓存注解使用错误问题 +* fix 修复 接口文档未拼接服务路径问题 +* fix 修复 excel 枚举反向解析失败问题 +* fix 修复 查询部门下拉树未过滤数据权限问题 +* fix 修复 CacheName 缓存key存储错误问题 +* fix 修复 oss 列表 用户名回显错误 +* fix 修复 不同vo相同字段mybatis会自动赋值问题 +* fix 修复 删除 skywalking dubbo 2.X 插件避免与 3.X 出现兼容性问题 +* fix 修复 新增角色使用内置管理员标识符问题 +* fix 修复 token 过期登出无法清理在线用户问题 +* fix 修复 动态设置 token 有效期不生效问题 +* fix 修复 加密模块数据转换异常问题 +* fix 修复 dubbo 更改内部序列化方式 导致异常类无法反序列化问题 +* fix 修复 客户端编辑时授权类型变更未保存的问题 +* fix 修正 缺失 SysClientVoConvert 导致转换异常(感谢 Michelle.Chung) +* fix 修正 auth 模块缺失引用导致解密异常(感谢 Michelle.Chung) +* fix 修复 demo 与 stream-mq 模块缺少 security 依赖问题 +* fix 修复 导入用户数据 变量使用错误问题 +* fix 修复 验证码开关未动态刷新问题 +* fix 修复 自动填充数据 loginUser 为 null(感谢 charles !pr108) +* fix 修复 修复树模板父级编码变量错误 +* fix 修复 部署部分系统出现乱码问题 +* fix 修复 一级菜单无法显示问题 +* fix 修复 新建用户可能会存在的越权行为 +* fix 修复 代码生成页面参数缺少逗号问题 + +### 移除功能 + +* remove 移除原有短信功能(建议使用sms4j) +* remove 移除xxljob功能(建议使用powerjob) + + +## v1.8.0 - 2023-07-11 + +### 重大更新 + +* [重大更新] 新增 sms4j 短信融合框架整合(支持数十种短信厂商接入、发送限制、负载均衡等功能) +* [不兼容更新] 移除 原短信功能(建议使用新 sms4j 功能) +* [重要迁移] 迁移 vue3 前端到主仓库统一维护 + +### 依赖升级 + +* update springboot 2.7.11 => 2.7.13 +* update spring-cloud 2021.0.7 => 2021.0.8 +* update satoken 1.34.0 => 1.35.0.RC +* update easyexcel 3.2.1 => 3.3.1 +* update sms4j 2.2.0 +* update element 2.15.12 => 2.15.13 + +### 功能更新 + +* update 优化 StreamUtils 方法过滤null值 +* update 优化 页签在Firefox浏览器被遮挡 +* update 优化 在全局异常拦截器中增加两类异常处理 +* update 优化 下载zip方法增加遮罩层(感谢@梁剑锋) +* update 优化 用户昵称非空校验 +* update 优化 修改角色如果未绑定用户则无需清理 +* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 +* update 优化 satoken 过期配置 支持多端token自定义有效期 +* update 优化 加密注解注释错误 +* update 优化 切换 maven 仓库到华为云(aliyun 不可用) +* update 优化 excel 导出存在合并项时在初始化类时进行数据的处理避免多次调用(感谢@yueye) +* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 +* update 补全 SysLogininforMapper.xml 缺失字段 +* update 优化 demo 模块 路径适配统一前端 +* update 调整 gateway 访问日志输出等级 + +### 新增功能 + +* add 新增 RedisUtils.setObjectIfAbsent 不存在则设置方法 +* add 新增 Excel 导出附带有下拉框(字典自动导出为下拉框) 可自定义多级下拉框(感谢@Emil.Zhang) +* add 新增 OssClient File 文件上传方法 +* add 增加 RedisUtils 批量删除 hash key 方法 + +### 问题修复 + +* fix 修复 sa-token.check-same-token 开关对网关鉴权无效问题 +* fix 修复 服务未添加 common-security 模块导致异常拦截器不生效问题 +* fix 修复 删除 skywalking dubbo 2.X 插件避免与 3.X 出现兼容性问题 +* fix 修复 excel 枚举反向解析失败问题 +* fix 修复 字典缓存注解使用错误问题 +* fix 修复 新增角色使用内置管理员标识符问题 +* fix 修复 缓存监控图表 支持跟随屏幕大小自适应调整(感谢@抓蛙师) +* fix 修复 防重组件 错删注解问题 +* fix 修复 CacheName 缓存key存储错误问题 +* fix 修复 字典缓存注解使用错误问题 +* fix 修复 用户篡改管理员角色标识符越权问题 +* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 +* fix 修复 OssClient 切换服务 实例不正确问题 +* fix 修复 element ui 因版本而未被工具识别问题(感谢@梁剑锋) +* fix 修复 admin监控 切换tab页需要重复登录问题 +* fix 修复 个人中心tab栏关闭页面内容压缩问题 + +## v2.0.0 - 2023-06-15 + +**重点说明: 由于 SpringCloudAlibaba 一直未发布正式版 导致系统底层组件可能存在些许问题 故而不建议生产使用 框架也将直接开启后续 2.1.0 的开发工作** + +### 重大更新 + +* [不兼容升级] java 版本从 jdk 8 升级到 jdk 17 且需要使用 graalvm 运行(暂时未解决原生jdk存在的问题) +* [不兼容升级] springboot 升级 3.0 版本 +* [不兼容升级] 重构 项目模块结构 采用插件化结构 易扩展易解耦 +* [不兼容升级] com.sun.mail 更改为 jakarta.mail 修改最新写法 +* [不兼容升级] javax.servlet 替换为 jakarta.servlet 更新所有代码 +* [简化性升级] 默认开启复杂结构 resultMap 自动映射 简化xml编码(多结构实体需带上主键id) +* [数据库改动] 更新 create_by update_by 字段类型 (保存用户id) +* [数据库改动] 新增 create_dept 字段 (保存创建部门id) +* [不兼容更新] system 模块 所有实体类均使用 bo|vo 规范化 +* [重大更新] 新增 多租户功能设计 整体框架代码结构与数据库更改 +* [重大更新] 新增 mapstruct-plus 替换 BeanUtil 与 BeanCopyUtils 工具 +* [不兼容更新] 重构 登录注解接口与cloud版本统一接口路径 +* [不兼容更新] 重构 BaseMapperPlus接口 去除 `@param Mapper` 泛型 +* [不兼容更新] 移除 vue2 前端工程 全面启用 vue3 +* [重大更新] 新增 vue3 + TS 版本前端(独立仓库后续与Cloud版本共用) +* [重大更新] 增加 websocket 模块 支持token鉴权 支持分布式集群消息同步 +* [重大更新] 框架文档全面翻新 https://plus-doc.dromara.org +* [不兼容更新] 代码生成 支持代码生成多数据源统一存储(主库存储子库的表 无需子库加gen表了) +* [不兼容更新] 重构 将系统内置配置放置到common包内独立加载 不允许用户随意修改 + +### 依赖升级 + +* update java 1.8 => 17 +* update springboot 2.7.7 => 3.0.7 +* update springcloud 2021.0.6 => 2022.0.2 +* update springcloud-alibaba 2022.0.0.0-RC2 +* update springboot-admin 2.7.10 => 3.0.4 +* update springdoc 1.6.14 => 2.1.0 +* udpate dubbo 3.1.8 => 3.2.2 +* update lock4j 2.2.3 => 2.2.4 +* update dynamic-ds 3.5.2 => 3.6.1 +* update easyexcel 3.1.5 => 3.2.1 +* update hutool 5.8.11 => 5.8.18 +* update redisson 3.19.2 => 3.20.1 +* update lombok 1.18.24 => 1.18.26 +* update spring-boot.mybatis 2.2.2 => 3.0.1 +* update mapstruct-plus 1.2.3 +* update maven-compiler-plugin 3.10.1 => 3.11.0 +* update maven-surefire-plugin 3.0.0-M7 => 3.0.0 +* update docker mysql 8.0.31 => 8.0.33 +* update docker nginx 1.22.1 => 1.32.4 +* update docker redis 6.2.7 => 6.2.12 +* update docker minio RELEASE.2023-04-13T03-08-07Z + +### 功能更新 + +* update 适配 AsyncConfig 替换过期继承类改为实现 AsyncConfigurer 接口 +* update 适配 redis 新版本配置文件写法 +* update 适配 获取redis 监控参数接口 替换过期语法 +* update 适配 sa-token 替换新依赖 sa-token-spring-boot3-starter +* update 适配 springboot-admin 改为最新 spring-security 写法 +* update 适配 springdoc 新版本配置方式 +* update 适配 ServletUtils 更换继承 JakartaServletUtil +* update 适配 新序列化注解 +* update 优化 利用 resultMap 自动映射配置 简化 xml (非嵌套) +* update 优化 调整 system entity 实体与 controller 包结构 +* update 优化 实体类中校验注解的提示信息 +* update 优化 使用 jdk17 语法优化代码 +* update 优化 所有 properties 文件改为注解启用 +* update 更新 docker 基础镜像 graalvm java17 +* update 优化 用户头像 改为存储 ossId 使用转换模块转为 url 展示 +* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 +* update 优化 登录流程代码注释 +* update 优化 将框架内的swagger命名更改为springdoc命名避免误解 + +### 新增功能 + +* add 新增 flatten-maven-plugin 插件统一版本号管理 +* add 新增 ip2region 实现离线IP地址定位库 + +### 移除功能 + +* remove 移除 BeanCopyUtils 工具类 与 JDK17 不兼容 +* remove 移除 devtools 依赖 并不好用(建议直接用idea自带的热更) +* remove 移除 vue2 前端工程 统一使用 vue3 工程 + +### 修复功能 + +* fix 修复 根据 seata 官方提交记录 临时修复 seata 关于jdk17代理的bug +* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 +* fix 修复 common-core 包使用aop注解 但未添加aop实现类导致单独使用报错问题 + +## v1.7.0 - 2023-05-10 + +### 依赖升级 + +* update springboot 2.7.9 => 2.7.11 修复 DoS 漏洞 修复CVE漏洞 +* update springcloud 2021.0.6 => 2021.0.7 +* update springcloud-alibaba 2021.0.4.0 => 2021.0.5.0 +* update dubbo 3.1.7 => 3.1.10 +* update nacos 2.2.0 => 2.2.1 +* update xxljob 2.3.1 => 2.4.0 +* update minio 升级至最新版 避免低版本信息泄漏问题 +* update hutool 5.8.15 => 5.8.18 +* update redisson 3.20.0 => 3.20.1 +* update lombok 1.18.24 => 1.18.26 + +### 功能更新 + +* update 优化 更改 sys_oss_config 表注释 避免误解 +* update 优化 sys_logininfor 丰富多种信息 +* update 项目正式入驻 dromara 开源社区 更改项目地址 +* update 全新 logo 全新背景图(设计师打造) +* update 优化 代码生成模块的数据同步功能 +* update 修改多团队开发插件,支持多网卡 +* update 修改controller中校验直接返回R.fail +* update 优化 角色sort值一样的排序问题 +* update 更换默认用户头像 +* update 优化 WebFluxUtils.getOriginalRequestUrl 方法获取空路径报错问题 +* update 去除same-token有限期配置,使用默认配置(一天) +* update 优化固定头部页签滚动条被隐藏的问题 +* update delete vue-multiselect style +* update 按代码规范补全重写注解 +* update 优化 极端情况获取LoginUser可能为null问题 +* update 优化 更改系统所有服务日志配置文件命名为 logback-plus.xml 避免与其他框架默认配置冲突 +* update 优化 skywalking-agent 探针日志等级调整为 WARN 减少无用日志输出 +* update 优化 加解密模块 将null判断下推防止任何可能的null出现 +* update 优化 在线用户token获取方式 +* update 优化 用户更改角色 踢掉角色相关所有在线用户 + +### 新功能 + +* add 集成 ip2region 实现离线IP地址定位库 +* add 增加 邮箱验证码发送接口 +* add 增加 邮箱登陆接口 +* add 增加 EncryptUtils 加解密安全工具类 可以处理base64,aes,sm4,sm2,rsa,md5,sha256加解密 +* add 增加 EncryptUtils 类中增加国密sm3的不可逆加密算法 +* add 新增 忽略数据权限写法 防止异常不执行关闭问题 + +### 问题修复 + +* fix 修复 MybatisExceptionHandler 未自动装载问题 +* fix 修复 代码生成 点选按钮不生效问题 +* fix 修复 Nacos 服务 SpringBoot-admin 客户端功能失效问题 +* fix 修复 findInSet 在mysql下方法搜索非数字字段时 无引号报错问题 +* fix 修复 ruoyi-demo postgres 数据库用户名密码变量错误 +* fix 修复 oracle postgres 数据库日志表索引创建错误 +* fix 修复 无法注入 mailProperties 导致 resource 模块无法启动问题 +* fix 修复tab栏”关闭其他“异常的问题 +* fix 修复 加解密拦截器 对象属性为null问题 +* fix 修复 取消oss预览状态修改 图标变化不正常问题 +* fix 修复 nacos 新版本升级后 与 docker 基础镜像系统存在兼容性问题 + + +## v1.6.0 - 2023-03-14 + +### 重大更新 + +[重大更新] add 新增 通用翻译模块 `ruoyi-common-translation` 实现(部门名、字典、oss、用户名) +[重大更新] add 新增 数据加解密模块 `ruoyi-common-encrypt` + + +### 依赖升级 + +* update springboot 2.7.7 => 2.7.9 +* update springcloud 2021.0.5 => 2021.0.6 +* update easyexcel 3.1.5 => 3.2.1 +* update redisson 3.19.1 => 3.20.0 +* update springdoc 1.6.14 => 1.6.15 +* update hutool 5.8.12 => 5.8.15 (13与14有问题勿使用) +* update logstash-sdk 7.1.1 => 7.2 +* update aws-java-sdk-s3 1.12.373 => 1.12.400 +* update tencent-sms 3.1.660 => 3.1.687 +* update skywalking 8.9.1 => 9.3.0 +* update skywalking-agent 8.13.0 => 8.14.0 +* update dubbo 3.1.4 => 3.1.7 解决dubbo报一些无用警告问题 +* update element-ui 2.15.10 => 2.15.12 + +### 功能更新 + +* update 优化 修改 oss 配置页面开关说明 避免造成误解 +* update 优化 `gateway` 对接 `sentinel` 使用网关特定模式 +* update 优化 转移 `logback-common` 配置到 `common-web` 模块 `gateway` 单独处理 +* update 优化 调整连接池默认参数 +* update 优化 `zookeeper` 自带控制台占用 `8080` 端口 +* update 优化 `DictDataMapper` 注解标注过期 推荐使用 `@Translation` 注解 +* update 优化 获取菜单数据权限接口 删除无用角色属性与逻辑 +* update 优化 调整连接池最长生命周期 防止出现警告 +* update 优化 连接池增加 `keepaliveTime` 探活参数 +* update 优化 `DataPermissionHelper` 增加 `开启/关闭` 忽略数据权限功能 +* update 重构 `OssFactory` 加载方式 改为每次比对配置做实例更新 +* update 优化 更新角色后踢掉所有相关的登录用户 用户量过大会导致redis阻塞卡顿(应粉丝要求) +* update 优化 翻译组件 支持返回值泛型 支持多种类型数据翻译(例如: 根据主键翻译成对象) +* update 优化 `tagsView` 右选框,首页不应该存在关闭左侧选项 +* update 优化 `copyright 2023` +* update 优化 日志注解支持排除指定的请求参数 +* update 优化 业务校验优化代码 +* update 优化 日志管理使用索引提升查询性能 +* update 优化 框架时间检索使用时间默认值 `00:00:00 - 23:59:59` +* update 优化 oss 预览使用 `ImagePreview` 组件 +* update 优化 统一登录接口令牌key + + +### 新功能 + +* add 新增 数据加解密模块 测试案例 +* add 新增 `StringUtils` `splitTo` 与 `splitList` 方法 优化业务代码 + +### 问题修复 + +* fix 修复 vue3模板 删除功能书写错误 +* fix 修复 部分服务未开启日志存储 +* fix 修复 接口问题开关不生效问题 +* fix 修复 优化文件下载出现的异常 +* fix 修复 修改密码日志存储明文问题 +* fix 修复 代码生成 `postgreSQL` 查出多余的已删除字段 + +## v1.5.0 - 2023-01-13 + +### 重大更新 + +* [重大更新] 框架主体业务与代码生成器 完成 oracle postgres 多数据库类型支持(中间件不支持) +* [重大更新] 使用 spring 事件发布机制 重构登录日志与操作日志 支持多事件监听无入侵扩展 +* 例如: 可以增加一个监听者将日志上传至ES等存储 对原有逻辑无影响 + +### 依赖升级 + +* update springboot 2.7.6 => 2.7.7 +* update springboot-admin 2.7.7 => 2.7.10 +* update dubbo 3.1.3 => 3.1.4 +* update seata 1.5.2 => 1.6.1 适配升级 +* update nacos 2.1.2 => 2.2.0 适配升级 +* update mybatis-plus 3.5.2 => 3.5.3.1 +* update sa-token 1.33.0 => 1.34.0 +* update springdoc 1.6.13 => 1.6.14 +* update snakeyaml 1.32 => 1.33 +* update easyexcel 3.1.3 => 3.1.5 +* update redisson 3.18.0 => 3.19.1 +* update easy-es 1.1.0 => 1.1.1 +* update hutool 5.8.10 => 5.8.11 +* update aws-s3 1.12.349 => 1.12.373 +* update aliyun-sms 2.0.22 => 2.0.23 +* update tencent-sms 3.1.635 => 3.1.660 +* update echarts 4.9.0 => 5.4.0 + +### 功能更新 + +* update 优化 BaseMapperPlus 使用 MP V3.5.3 新工具类 Db 简化批处理操作实现 +* update 优化 demo服务 过滤健康检查 sql 打印 +* update 优化 代码生成与框架主体使用相同的主键生成器 全局统一避免问题 +* update 优化 系统登录 使用单表查询校验用户 避免多次join查询 +* update 优化 适配框架多数据库支持 完成 oracle postgres 数据库适配(放弃 sqlserver 适配 原因: 基础中间件均不支持) +* update 优化 删除主 sql 内无用数据 +* update 优化 删除 vue3 模板无用参数 +* update 优化 重构 ExcelUtil 全导出方法支持 OutputStream 流导出 不局限于 response +* update 优化 maven 地址切换回 aliyun 仓库 +* update 优化 springdoc 配置鉴权头写死问题 增加持久化鉴权头配置 +* update 优化 actuator 依赖整合到 common-web 模块 +* update 优化 验证码结果使用 spel 引擎自动计算 +* update 优化 数据权限处理器 变量命名错误 +* update 优化 去除 RedisUtils 无用继承 +* update 优化 弹窗内容过多展示不全问题 +* update 优化 删除 fuse 无效选项 maxPatternLength +* update 优化 minio 安装警告 使用新版本参数 +* update 优化 使用 spring 事件发布机制 重构登录日志与操作日志 +* update 优化 使用 spring 事件机制 重构 OssConfig 缓存更新 +* update 优化 单元格合并判断cellValue是否相等方法 +* update 优化 调整 gateway 拦截器执行顺序 优先处理 xss 过滤 然后进行缓存处理 + +### 新功能 + +* add 增加 GET 请求提交日期参数 默认格式化配置 +* add 增加 RedisUtils 检查缓存对象是否存在方法 +* add 增加 oracle postgres docker编排 +* add 新增 代码生成器适配 多数据库可切换生成代码 +* add 新增 oracle postgres 数据库框架sql脚本 +* add 增加 DataBaseHelper 数据库助手 用于适配多类型数据库 +* add 新增 BeanCopyUtils#mapToMap 方法 + +### 问题修复 + +* fix 修复 注册页面 验证码开关不生效问题 +* fix 修复 新版本 dubbo-filter-seata 插件内核与seata不一致问题(临时) +* fix 修复 根据 key 更新参数配置报 null 问题 +* fix 修复 用户注册 用户类型字段书写错误 +* fix 修复 代码生成图片/文件/单选时选择必填无法校验问题 +* fix 修复 修改参数键名时 未移除过期缓存配置 +* fix 修复 内网鉴权 Filter 优先级问题 导致 websocket 连接失败 +* fix 修复 gateway 流控规则生效但不显示问题 +* fix 修复 新版本 Redisson 存在与 boot 2.X 的兼容性问题 + +## v1.4.0 - 2022-12-01 + +### 重大更新 +* [重大更新] 新增 对接 skywalking 全功能(详细看下方新功能列表) +* [重大更新] 重构 ruoyi-nacos 使用官方依赖整合 解决一些问题 并升级 2.1.2 版本 +* [重大更新] 新增 oss 私有库功能(数据库结构改动 需执行升级sql) +* [重大更新] 优化 数据源连接池从 druid 切换到 hikari(原因看文档) +* [重大更新] 新增 对接 prometheus + grafana 全功能(详细看下方新功能列表) + +### 依赖升级 +* update springcloud 2021.0.4 => 2021.0.5 +* update springboot 2.7.4 => 2.7.6 +* update springboot-admin 2.7.5 => 2.7.7 +* update springdoc 1.6.11 => 1.6.13 +* update poi 5.2.2 => 5.2.3 +* update hutool 5.8.6 => 5.8.10 +* update aliyun-sms 2.0.18 => 2.0.22 +* update tencent-sms 3.1.591 => 3.1.611 +* update sa-token 1.30.0 => 1.33.0 +* update redisson 3.17.6 => 3.18.0 +* update easy-es 1.0.2 => 1.1.0 +* update easyexcel 3.1.1 => 3.1.3 +* update lock4j 2.2.2 => 2.2.3 +* update s3-adk 1.12.300 => 1.12.349 +* update sentinel 1.8.5 => 1.8.6 +* update nacos 2.1.1 => 2.1.2 +* update ELK 7.17.2 => 7.17.6 升级镜像版本 +* update nginx 1.21.6 => 1.22.1 修复漏洞 +* update mysql-docker 8.0.29 => 8.0.31 + +### 功能更新 +* update 优化 分页对象 PageQuery 支持多排序 适配 文件管理 页面支持多排序 +* update 优化 获取用户信息getInfo接口 使用缓存数据获取 +* update 优化 rpc文件上传 增加 ossId 数据返回 +* update 优化 nacos 集群模式搭建 关于 nacos.home 注释说明 +* update 优化 修改头像在小屏幕上页面布局错位的问题 +* update 优化 oss 云厂商增加 华为obs关键字 +* update 优化 重置时取消部门选中 +* update 优化 新增返回警告消息提示 +* update 优化 抽取 logback 通用配置 logback-common.xml 简化其他服务日志文件书写 +* update 更改 nacos 配置文件目录 从dev文件夹迁移到nacos文件夹与其他配置区分 +* update 优化 gateway 只缓存body +* update 优化 Dockerfile 创建目录命令简化操作 +* update 优化 gateway filter顺序 与 代码工具封装 +* update 优化 将空 catch 块形参重命名为 ignored +* update 优化 satoken 依赖传递 +* update 优化 重写字典查询 使用本地缓存优化网络开销 提升到上级实现减少rpc调用频率 使用流处理减少字符串操作 +* update 优化 减小腾讯短信引入jar包的体积 +* update 优化 简化一些方法的写法 +* update 优化 消除Vue3控制台出现的警告信息 +* update 优化 忽略不必要的属性数据返回 +* update 优化 重构 mysql-jdbc 依赖到 mybatis 包内 替换为最新坐标 + +### 新功能 +* add 新增 所有服务 docker 部署对接 skywalking +* add 新增 三大 mq 整合 skywalking +* add 新增 seata 整合 skywalking 手动编译 seata 插件包 +* add 新增 ruoyi-common-skylog 整合 skywalking 日志推送 +* add 增加 skywalking docker编排 +* add 增加 ruoyi-seata-server redis模式配置 +* add 新增 ruoyi-common-prometheus 模块 用于对接 prometheus 监控 +* add 新增 docker prometheus + grafana 容器编排 +* add 新增 ruoyi-monitor 监控服务 提供 prometheus http_sd 服务发现功能 +* add 新增 所有服务整合 ruoyi-common-prometheus 模块 +* add 新增 grafana 监控大屏配置文件(框架定制) +* add 新增 使用 mica-metrics 为 undertow 提供健康检查 +* add 新增 字典数据映射翻译注解 +* add 增加 RedisUtils 获取缓存Map的key列表 + +### 问题修复 +* fix 修复 开启账号同端互斥登录 被顶掉后登出报null异常问题 +* fix 修复 设置NameMapper导致队列功能异常问题 +* fix 修复 EnvironmentPostProcessor 不生效问题 +* fix 修复 文件上传组件格式验证问题 +* fix 修复 ruoyi-xxl-job-admin 服务健康检查配置缺失问题 +* fix 修复 Excel导出字典值转换方法由于内部调用缓存不生效bug +* fix 修复 SysOss 方法内部调用导致缓存不生效 bug +* fix 修复 主题颜色在Drawer组件不会加载问题 +* fix 修复 修改用户信息 校验用户名未排除当前用户问题 +* fix 修复 升级 nginx 修复漏洞 https://www.oschina.net/news/214309 +* fix 修复 用户编辑时角色和部门存在无法修改情况 +* fix 修复 RemoteDictServiceImpl 代理对象获取异常bug +* fix 修复 菜单激活无法填充颜色 去除某些svg图标的fill属性 +* fix 修复 使用透明底png图片时, 自动填充黑色背景 +* fix 修复 table中更多按钮切换主题色未生效修复问题 +* fix 修复 dubbo 使用 tri 协议 header 请求头变为小写导致无法获取参数问题 +* fix 修复 DubboRequestFilter 优先级过高导致的 skywalking tid 取不到问题 +* fix 修复 前端脚本乱码问题 +* fix 修复 WebFluxUtils 读取空 body 报 null 问题 +* fix 修复 Log注解GET请求记录不到参数问题 +* fix 修复 某些特性的环境生成代码变乱码TXT文件问题 +* fix 修复 开启TopNav没有子菜单隐藏侧边栏 +* fix 修复 回显数据字典数组异常问题 +* fix 修复 升级 satoken 导致白名单热更不生效问题 +* fix 修复 swagger 版本与 springdoc 版本不一致导致找不到class问题 +* fix 修复 grafana 监控模板绑定数据源ID 导致无法正常读取数据问题 + +## v1.3.0 - 2022-09-29 + +### 重大更新 + +* [重大更新] 新增 ruoyi-nacos 源码集成 nacos 服务端控制台 支持单机/集群模式 +* [重大更新] 重写 spring-cache 实现 更人性化的操作 支持注解指定ttl等一些参数 +* [重大更新] 新增 RuoYi-Cloud-Plus-UI 项目 Vue3 前端分支 +* [重大更新] 移除maven docker插件 过于老旧功能缺陷大 使用idea自带的docker插件替代 +* [重大更新] 优化 ruoyi-common-job 支持通过调度中心服务名注册 xxl-job-admin +* [重大更新] 新增 ruoyi-common-sentinel 模块 支持使用服务名注册 sentinel 控制台 + +### 依赖升级 + +* update spring-cloud 2021.0.3 => 2021.0.4 +* update springboot 2.7.2 => 2.7.4 +* update springboot-admin 2.7.3 => 2.7.5 +* update sentinel 1.8.4 => 1.8.5 集成新 dubbo3 插件 +* update springdoc 1.6.9 => 1.6.11 +* update easy-es 0.9.80 => 1.0.2 +* update dubbo 3.0.10 => 3.1.1 +* update redisson 3.17.5 => 3.17.6 +* update druid 1.2.11 => 1.2.12 +* update hutool 5.8.5 => 5.8.6 +* update dynamic-ds 3.5.1 => 3.5.2 +* update aws-java-sdk-s3 1.12.264 => 1.12.300 +* update aliyun-sms 2.0.16 => 2.0.18 +* update tencent-sms 3.1.555 => 3.1.591 +* update snakeyaml 1.30 => 1.32 + +### 功能更新 + +* update 优化 getLoginId 增加必要参数空校验 +* update 优化 将 elasticsearch 解压后放入 避免造成用户误解 +* update 优化 修改资料头像与部门被覆盖的问题 +* update 优化 字典管理操作类型新增其他 +* update 优化 使用 spring-cache 注解优化缓存 +* update 优化 easy-es.enable=false 关闭 actuator 健康检查 +* update 优化 优化多角色数据权限匹配规则 +* update dubbo 升级 3.1.0 删除自行处理的源码修复 采用官方修复后的代码 +* update 优化 页面内嵌iframe切换tab不刷新数据 +* update 优化 调整 oss表key 与 ossconfig的service 字段长度不匹配 +* update 优化 操作日志密码脱敏 +* update 优化 补全缺失的接口 更改更新日志链接 +* update 优化 插入 SysOperLog 时, 限制 operUrl 属性的长度 +* update 优化 satoken 鉴权拦截器 优化多次校验 + +### 新功能 + +* add 增加 项目中使用到的请求头放行跨域 +* add 新增 获取oss对象元数据方法 +* add 新增 字典管理操作类型 其他 + +### 问题修复 + +* fix 修复 个人中心卡死或鼠标点击和键盘输入无效 +* fix 修复 BaseMapperPlus 方法命令不一致问题 +* fix 修复 图片预览组件src属性为null值控制台报错问 +* fix 修复 短信功能是否启用判断不生效 +* fix 修复 web模块 不引入nacos依赖报错问题 +* fix 修复 sentinel 构建无法读取webapp目录问题 +* fix 修复 菜单管理遗漏的prop属性 +* fix 修复 minio配置https遇到的问题 +* fix 修复 点击删除后点击取消控制台报错问题 +* fix 修复 文件/图片上传组件 第一次上传报错导致后续上传无限loading问题 +* fix 修复 ruoyi-auth 服务与 elasticsearch 端口号冲突问题 +* fix 修复 ruoyi-resource 服务与 elasticsearch 端口号冲突问题 +* fix 修复 角色部门状态字典错误 与 菜单注释错误 +* fix 修复 hutool 存在多版本问题 +* fix 修复 openapi结构体 因springdoc缓存导致多次拼接接口路径问题 +* fix 修复 oss配置删除内部数据id匹配类型问题 +* fix 修复 没有权限的用户编辑部门缺少数据 +* fix 修复 用户导入存在则更新不生效 +* fix 修复 日志转换非json数据导致报错 +* fix 修复 p6spy输出sql语句时间格式化不正确问题 +* fix 修复 不同网段因reset请求头导致下载导出跨域问题 +* fix 修复 在线用户设置永不过期 超时时间-1推送redis无效问题 +* fix 修复 snakeyaml 1.31 依旧存在漏洞 升级 1.32 + +## v1.2.0 - 2022-08-09 + +### 重大更新 + +* [重大更新] 新增 ruoyi-common-elasticsearch 模块 集成 easy-es 傻瓜式操作搜索引擎 +* [重大更新] 新增 ruoyi-common-doc 整合 springdoc 基于 javadoc 实现无注解零入侵生成接口文档 +* [不兼容更新] 移除 swagger 所属 ruoyi-doc ruoyi-common-swagger 两个模块 建议使用 ruoyi-common-doc 模块 + +### 依赖升级 + +* update springboot 2.6.9 => 2.7.2 重构使用最新自动配置方式 +* update springboot-admin 2.6.7 => 2.7.3 +* update dubbo 3.0.9 => 3.0.10 +* update redisson 3.17.4 => 3.17.5 +* update hutool 5.8.3 => 5.8.5 +* update okhttp 4.9.1 => 4.10.0 +* update aws-java-sdk-s3 1.12.248 => 1.12.264 修复依赖安全漏洞 +* update aliyun.sms 2.0.9 => 2.0.16 +* update tencent.sms 3.1.537 => 3.1.555 +* update guava 30.0-jre => 31.1-jre + +### 功能更新 + +* update 修改 资源服务 不提供默认短信 sdk 依赖 +* update 优化表格上右侧工具条(搜索按钮显隐&右侧样式凸出) +* update 优化 前后端多环境部署保持一致 删除无用环境文件 +* update 优化 错误登录锁定与新增解锁功能 +* update 优化字典数据使用store存取 +* update 优化布局设置使用el-drawer抽屉显示 +* update 更新框架文档 专栏与视频 链接地址 +* update 优化 对象上传 主动设置文件公共读 解决天翼云OSS文件私有问题 +* update 优化 网关验证码过滤器 路径匹配改为严格匹配 +* update 优化 数据导致权限生成 SQL 重复问题 + +### 新功能 + +* add 增加 全局跨域过滤器 处理跨域请求 适配移动端访问 +* add 增加 搜索引擎 crud 演示案例 + +### 问题修复 + +* fix 防止date-picker组件报错,降级element-ui版本 +* fix 修复 RedisUtils 并发 set ttl 错误问题 +* fix 防止vue3主键字段名与row或ids一致导致报错的问题 +* fix 修复 幂等组件 逻辑问题导致线程变量未清除 +* fix 修复 图片回显查询 路径错误问题 +* fix 修复 脱敏没有实现类导致返回数据异常问题 +* fix 修复 xxljob 错误导入配置文件引发的问题 +* fix 修复 gateway模块 dockerfile 端口编写错误 +* fix 修复用户导出字典使用错误 +* fix 修复 demo 模块 远程调用失败问题 +* fix 修复 sentinel 控制台未适配 springboot 2.6 新路由策略导致无法登录问题 + +## v1.1.0 - 2022-07-18 + +### 重大更新 + +* [重大更新] 新增 ELK 分布式日志中心整合 +* [重大更新] 新增 ruoyi-stream-mq 演示模块 完成 RabbitMQ RocketMQ Kafka 整合 +* [重大更新] 优化 docker 部署方式 使用 host 模式简化部署流程 降低使用成本 +* [重大更新] 调整 dubbo 服务注册命名空间与 cloud 服务保持一致 通过注册组区分访问服务 +* [安全性] 优化 nginx 限制外网访问内网 actuator 相关路径 建议升级 + +### 依赖升级 + +* update springboot 2.6.8 => 2.6.9 +* update easyexcel 3.1.0 => 3.1.1 +* update hutool 5.8.2 => 5.8.3 +* update redisson 3.17.2 => 3.17.4 +* update aws-java-sdk-s3 1.12.215 => 1.12.248 +* update tencentcloud-sdk-java 3.1.500 => 3.1.537 +* update dubbo 3.0.8 => 3.0.9 +* update seata 1.5.1 => 1.5.2 + +### 功能更新 + +* update 增加 redisson key 前缀配置 +* update 优化 DateColumn 支持单模板多key场景 +* update 优化部署脚本 增加 elk kafka rabbitmq rocketmq 等配置 +* update 修改 oss 客户端自定义域名 统一使用https开关控制协议头 +* update 优化 使用 StreamUtils 简化业务流操纵 +* update 优化 ruoyi-demo 模块 去除用不上的 seata 依赖 +* update 优化 接口文档 接口地址与服务地址不匹配问题 +* update 优化字典数据回显样式下拉框显示值 +* update 默认不启用压缩文件缓存防止node_modules过大 +* update 优化登出方法 + +### 新功能 + +* add 增加 rocketmq docker编排 +* add 新增 rabbitmq docker编排 包含延迟插件 +* add 新增 kafka docker编排 +* add 增加 es ik 分词器插件集成 +* add 增加 StreamUtils 流工具 简化 stream 流操纵 + +### 问题修复 + +* fix 修复 获取 SensitiveService 空问题 增加空兼容 +* fix 修复 演示页面导出路径错误 +* fix 修复 minio 上传自定义域名回显路径错误问题 +* fix 修复 hutool 工具返回不可操纵类型 导致报错问题 +* fix 修复 远程调用短信功能返回实体 SysSms 序列化报错问题 +* fix 修复 复制过程错误 导致演示excel文件损坏问题 +* fix 修复 dubbo 注册组不生效问题 通过覆盖源码方式 +* fix 修复代码生成首字母大写问题 + + +## v1.0.0 - 2022-06-20 + +### 新增/优化 工程模块 + +* add 新增 ruoyi-common-alibaba-bom 工程管理 alibaba 相关依赖 +* add 新增 ruoyi-common-bom 工程管理 ruoyi-common 相关依赖 +* add 新增 ruoyi-api-bom 工程管理 ruoyi-api 依赖项 +* add 新增 ruoyi-api-resource 模块 规范用法 移除 ruoyi-file 模块 +* add 新增 ruoyi-common-web 模块 使用 undertow 替换 tomcat +* add 新增 ruoyi-common-dubbo 整合 dubbo 3.X 实现高性能 rpc 远程调用 替换 feign +* add 新增 ruoyi-common-dict 实现字典多服务调用 +* add 新增 ruoyi-common-loadbalancer 自定义负载均衡模块 用于多团队开发 +* add 新增 ruoyi-common-excel 模块 集成 Alibaba EasyExcel 替换 自带excel实现 +* add 新增 ruoyi-common-oss 模块 支持 AWS S3 协议 分布式文件存储 +* add 新增 ruoyi-common-mail 邮件模块 +* add 新增 ruoyi-common-sms 短信模块 整合 阿里云、腾讯云 短信功能 +* add 新增 ruoyi-common-idempotent 分布式幂等模块 +* add 新增 ruoyi-common-satoken 整合 sa-token 重写所有权限 +* add 新增 ruoyi-xxl-job-admin 整合 xxljob 替换 quartz 支持分布式任务调度 +* add 新增 ruoyi-job 模块 统一远程处理任务 规范用法 +* add 新增 ruoyi-doc 模块 集成 Knife4j 替换 swagger +* add 新增 ruoyi-seata-server 源码集成 Seata 1.5.X 服务端 +* add 新增 ruoyi-sentinel-dashboard 模块 源码集成 sentinel 控制台 +* update 抽取所有公用配置到 maven profile 管理 + +### 代码依赖改动 + +* update SpringCloud 2021.0.3 +* update 适配 SpringCloudAlibaba 2021.0.1.0 全新配置方式 +* update poi 4.1.2 => 5.2.2 性能大幅提升 +* update 重构 整合 jackson 替换 fastjson +* update 重构 整合 redisson 客户端 +* update 重构 整合 mybatis-plus +* update 重写 数据权限实现 基于 mybatis-plus +* add 增加 lombok 优化原生代码 +* add 整合 hutool 优化相关代码 +* add 新增 国际化 功能 +* add 新增 lock4j 分布式锁 +* add 增加监控中心 在线日志监控 优化日志文件格式 +* add 适配 docker 部署方式 + +### 后续/进行中计划 + +* 增加 Vue3 前端工程 +* 应用模块 适配 Oracle、PostgreSQL、SQLServer +* 增加 SpringCloud Stream 支持 +* 适配 Apache Kafka、Apache RocketMQ、RabbitMQ +* 适配 ElasticSearch 分布式搜索引擎 +* 适配 Alibaba Canal 分布式数据同步中心 +* 适配 Apache SkyWalking 分布式链路追踪监控中心 +* 适配 ELK 分布式日志中心 +* 适配 Prometheus、Grafana 分布式全方位数据大屏监控 diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md new file mode 100644 index 00000000..58c2eda8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/elk.md @@ -0,0 +1,37 @@ +# ELK搭建 +- - - +# 环境搭建 + +项目内置 `ELK` 的 `docker-compose` 编排 可查看 `/docker/docker-compose.yml` 文件下方扩展编排 + +**注意: `/docker/elk/elasticsearch/` 目录下所有文件夹 均需要写权限** + +`chmod 777 /docker/elk/elasticsearch/data`
+`chmod 777 /docker/elk/elasticsearch/logs`
+`chmod 777 /docker/elk/elasticsearch/plugins`
+**注意: es插件需要解压后放入 `plugins` 目录** + +# 运行命令 + +```shell +docker-compose up -d elasticsearch kibana logstash +``` + +# 参考文章 +[docker-compose 搭建 ELK 7.X 并整合 SpringBoot](https://lionli.blog.csdn.net/article/details/125743132) + +# 项目内配置 + +服务引入依赖项 + +```xml + + + com.ruoyi + ruoyi-common-logstash + +``` + +更改主 `pom` 文件 `logstash.address` 地址
+ +![输入图片说明](https://foruda.gitee.com/images/1678981534923588112/ba6cb5b7_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md new file mode 100644 index 00000000..65d9c4d4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/es.md @@ -0,0 +1,26 @@ +# ES搜索引擎 +- - - +## 环境搭建(如果已经搭建了ELK则跳过) + +项目内置 `ELK` 的 `docker-compose` 编排 可查看 `/docker/docker-compose.yml` 文件下方扩展编排 + +**注意: `/docker/elk/elasticsearch/` 目录下所有文件夹 均需要写权限** + +`chmod 777 /docker/elk/elasticsearch/data`
+`chmod 777 /docker/elk/elasticsearch/logs`
+`chmod 777 /docker/elk/elasticsearch/plugins`
+**注意: es插件需要解压后放入 `plugins` 目录** + +## 运行命令 + +```shell +docker-compose up -d elasticsearch +``` + +## Easy-ES 文档 +[Easy-ES 文档](https://www.easy-es.cn/) + +## 用法 + +基本配置和用法可参考 `ruoyi-demo` 模块 更多高级用法请参考 Easy-ES 文档
+![输入图片说明](https://foruda.gitee.com/images/1660030085169129908/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md new file mode 100644 index 00000000..78521431 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/kafka.md @@ -0,0 +1,9 @@ +# Kafka搭建 +- - - +## 环境搭建 +参考文章: [docker-compose 安装 Kafka 3.X 附带可视化界面](https://lionli.blog.csdn.net/article/details/125855550) + +## 用法参考 +参考 `ruoyi-stream-mq` 模块内的测试案例 + +![输入图片说明](https://foruda.gitee.com/images/1660031528265343174/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md new file mode 100644 index 00000000..4b4b4305 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/maxkey.md @@ -0,0 +1,20 @@ +# 对接 MaxKey 单点登录 +- - - + +# 安装 MaxKey 应用服务 + +参考 MaxKey 官方文档安装 [MaxKey安装部署](http://www.maxkey.top/doc/docs/intro/) + +# 配置应用 OAuth2.0 认证注册 + +![输入图片说明](https://foruda.gitee.com/images/1693377802128677240/0927270a_1766278.png "屏幕截图") + +# 配置后端服务 + +找到 `Nacos` 内的 `ruoyi-auth.yml` 配置文件 + +修改 `maxkey` 对应的 `client-id` 与 `client-secret` + +![输入图片说明](https://foruda.gitee.com/images/1693378118762354596/2f02c8a3_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1693378168538263792/24476d2a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md new file mode 100644 index 00000000..18e6aefb --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/nacos.md @@ -0,0 +1,13 @@ +# Nacos集群搭建 +- - - +## 集群搭建两种方式 +### 文件寻址集群 +[【RuoYi-Cloud-Plus】学习笔记 02 - Nacos(二)寻址机制之文件寻址分析](https://blog.csdn.net/Michelle_Zhong/article/details/127423521) + +### 地址服务器寻址集群(推荐) +[【RuoYi-Cloud-Plus】学习笔记 03 - Nacos(三)使用 Nginx 实现地址服务器寻址及其原理分析](https://blog.csdn.net/Michelle_Zhong/article/details/127474238) + +## 集群路由代理设置 +[【RuoYi-Cloud-Plus】学习笔记 04 - Nacos(四)使用 Nginx 简单实现 Nacos 集群负载均衡](https://blog.csdn.net/Michelle_Zhong/article/details/127486350) + +设置好代理之后 跟单机用法一致 后端nacos地址写代理 `ip:端口` 即可 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md new file mode 100644 index 00000000..2df4870b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/prometheus_grafana.md @@ -0,0 +1,45 @@ +# Prometheus+Grafana搭建 +- - - +## 基础搭建 + +参考文章: https://lionli.blog.csdn.net/article/details/127959009 + +## 框架内扩展 + +框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 + +```shell +docker-compose up -d prometheus grafana +``` + +## 应用配置 + +各个服务引入 `ruoyi-common-prometheus` 模块 + +![输入图片说明](https://foruda.gitee.com/images/1668998415863943539/413dc560_1766278.png "屏幕截图") + +修改 `prometheus.yml` 配置采集数据源 + +![输入图片说明](https://foruda.gitee.com/images/1668998433756761442/bf31c212_1766278.png "屏幕截图") + +修改 `Nacos` 地址 与 `SpringBoot-Admin` 监控地址 用于数据采集
+如都为本地应用则无需更改 + +![输入图片说明](https://foruda.gitee.com/images/1668998317973042740/2d3590ec_1766278.png "屏幕截图") + +## 导入框架特制模板 +**注意: 此处数据源名称必须与图片保持一致 不然会和模板对应不上导致无法读取数据**
+![输入图片说明](https://foruda.gitee.com/images/1669866309495145064/1de987ce_1766278.png "屏幕截图") + +> 找到框架内的特制模板json文件 在grafana点击上传json文件 导入模板
+ +![输入图片说明](https://foruda.gitee.com/images/1668998149634542527/f0881c8e_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1668998179391197847/b1d3a630_1766278.png "屏幕截图") + +## 选择查看监控 + +点击右侧菜单浏览 选择想要查看的监控即可 + +![输入图片说明](https://foruda.gitee.com/images/1668998515814170229/817ac8b0_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1668998567335384306/acdf2833_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1668998616894681785/ac27538b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md new file mode 100644 index 00000000..75e0187c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rabbitmq.md @@ -0,0 +1,10 @@ +# RabbitMQ搭建 +- - - +## 环境搭建 + +参考文章: [docker-compose 安装 RabbitMQ 3.X 附带延迟队列插件](https://lionli.blog.csdn.net/article/details/125855177) + +## 用法参考 +参考 `ruoyi-stream-mq` 模块内的测试案例 + +![输入图片说明](https://foruda.gitee.com/images/1660031371503504748/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md new file mode 100644 index 00000000..98d50bb7 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/rocketmq.md @@ -0,0 +1,9 @@ +# RocketMQ搭建 +- - - +## 环境搭建 +参考文章: [docker-compose 安装 RocketMQ 4.9.X (apache官方镜像) namesrv broker 与可视化控制台 console](https://lionli.blog.csdn.net/article/details/125798865) + +## 用法参考 +参考 `ruoyi-stream-mq` 模块内的测试案例 + +![输入图片说明](https://foruda.gitee.com/images/1660031496623275622/屏幕截图.png "屏幕截图.png") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md new file mode 100644 index 00000000..ebe461bc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/shardingproxy.md @@ -0,0 +1,75 @@ +# Sharding-Proxy搭建分库分表 +- - - + +# 如何使用 + +查看 `ruoyi-demo` 服务 `TestShardingController` + +![输入图片说明](https://foruda.gitee.com/images/1688014028842337522/cd26026a_1766278.png "屏幕截图") + +## 首先在 MySQL 创建两个库 + +创建两个库 `data-center_0` `data-center_1` 分别执行如下SQL + +```sql +CREATE TABLE `t_order_0` ( + `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', + `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', + `total_money` int(10) UNSIGNED NOT NULL COMMENT '订单总金额', + PRIMARY KEY (`order_id`), + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单总表'; + +CREATE TABLE `t_order_1` ( + `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', + `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', + `total_money` int(10) UNSIGNED NOT NULL COMMENT '订单总金额', + PRIMARY KEY (`order_id`), + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单总表'; + +CREATE TABLE `t_order_item_0` ( + `order_item_id` bigint(20) UNSIGNED NOT NULL COMMENT '子订单ID', + `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', + `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', + `money` int(10) UNSIGNED NOT NULL COMMENT '子订单金额', + PRIMARY KEY (`order_item_id`), + KEY `idx_order_id` (`order_id`) USING BTREE, + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单子表'; + +CREATE TABLE `t_order_item_1` ( + `order_item_id` bigint(20) UNSIGNED NOT NULL COMMENT '子订单ID', + `order_id` bigint(20) UNSIGNED NOT NULL COMMENT '主键ID', + `user_id` bigint(20) UNSIGNED NOT NULL COMMENT '用户ID', + `money` int(10) UNSIGNED NOT NULL COMMENT '子订单金额', + PRIMARY KEY (`order_item_id`), + KEY `idx_order_id` (`order_id`) USING BTREE, + KEY `idx_user_id` (`user_id`) USING BTREE +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='订单子表'; + +``` + +## 然后更改配置文件 + +更改 `config-sharding.yaml` 配置文件内的数据库连接地址与用户名密码 + +## 服务搭建 + +参考部署文档上传 docker 文件夹 内部包含 `shardingproxy` 配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1688013921062151295/89652dda_1766278.png "屏幕截图") + +框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 + +```shell +docker-compose up -d shardingproxy +``` + +## 最后运行 demo + +运行 demo 提供的 controller 代码查看数据库内数据即可 + +## 用法参考视频(略有不同 理性观看) + +用法参考视频: https://www.bilibili.com/video/BV1XN411A7Tv/ diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md new file mode 100644 index 00000000..6ad0aecc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/extend-function/skywalking.md @@ -0,0 +1,41 @@ +# SkyWalking搭建与集成 +- - - +## 服务搭建 +参考文章: [SpringBoot 整合 SkyWalking 8.X (包含 Logback 日志采集)](https://lionli.blog.csdn.net/article/details/127656534) + +框架已经包含了 docker-compose 编排 执行如下命令启动容器即可 + +```shell +docker-compose up -d elasticsearch sky-oap sky-ui +``` + +### 本地开发使用 +参考上方文章 + +### docker部署使用 +上传探针到服务器 `/docker/skywalking/agent` 目录
+**不要使用网上下载的 请使用框架自带的 内含一些官网没有的插件**
+![输入图片说明](https://foruda.gitee.com/images/1667453098143152651/f1b4f492_1766278.png "屏幕截图") + +在对应服务的`dockerfile`内 打开 `skywalking` 相关参数注释
+![输入图片说明](https://foruda.gitee.com/images/1667452514896786032/f4322fb9_1766278.png "屏幕截图") + +服务编排增加探针路径映射
+![输入图片说明](https://foruda.gitee.com/images/1667453276389844864/7e139aa9_1766278.png "屏幕截图") + + +### 对接日志推送(不推荐 建议使用ELK收集日志) + +框架已经封装好了对应的依赖和配置 在服务内添加如下依赖 + +```xml + + + com.ruoyi + ruoyi-common-skylog + +``` + +在 `logback.xml` 日志配置文件内引入 `skylog` 配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1667452697748002725/a18212cd_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md new file mode 100644 index 00000000..05db07a3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/architecture_diagram.md @@ -0,0 +1,3 @@ +# 软件架构图 +- - - +![输入图片说明](https://foruda.gitee.com/images/1722569321458793955/8672b1fc_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md new file mode 100644 index 00000000..569aed75 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/collaboration.md @@ -0,0 +1,27 @@ +# 多团队开发 +- - - +## 功能介绍 + +> 多人员/团队开发往往会出现 调试程序 被负载均衡到别人那里 自己抓不到请求等问题
+> 正确团队开发模式 `测试机一台` 公共服务都放到测试机上
+> 本地开发人员 需启动 `ruoyi-gateway` 与 其他 调试的业务模块
+> 将所有服务都统一指向同一个 Nacos 服务
+> 前端连接本机 `ruoyi-gateway` 网关调试程序
+ +框架提供了 `ruoyi-common-loadbalancer` 多团队 负载均衡模块 可以将网关的请求锁定到与网关相同的IP服务 + +需要在 `ruoyi-gateway` `ruoyi-auth` `ruoyi-modules` 引入 `ruoyi-common-loadbalancer` 模块 + +![输入图片说明](https://foruda.gitee.com/images/1678980590168990366/afa2fdf6_1766278.png "屏幕截图") + +启动前端访问本机 `ruoyi-gateway` 网关在请求转发 和 `dubbo` 进行 RPC 调用时
+会获取与本机IP地址相同的服务优先调用(如未找到 会随机返回) + +# 重点说明 + +请检查本机是否有虚机网卡IP 如有多网卡获取IP地址会不准确 + +可使用如下代码检查本机IP是否正常 +```java +InetAddress.getLocalHost().getHostAddress() +``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md new file mode 100644 index 00000000..422aeb9e --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/doc.md @@ -0,0 +1,88 @@ +# 接口文档 +- - - +## 版本 >= `1.2.0` +## 说明 +由于 `springfox` 与 `knife4j` 均停止维护 bug众多
+故从 `1.2.0` 开始 迁移到 `springdoc` 框架
+基于 `javadoc` 无注解零入侵生成规范的 `openapi` 结构体
+由于框架自带文档UI功能单一扩展性差 故移除自带UI 建议使用外置文档工具 + +## 文档工具使用 +由于框架采用 `openapi` 行业规范 故市面上大部分的框架均支持 可自行选择
+例如: `apifox` `apipost` `postman` `torna` `knife4j` 等 根据对应工具的文档接入即可 + +## Swagger升级SpringDoc指南 + +常见功能如下 其他功能自行挖掘
+**注意: `javadoc` 只能替换基础功能 特殊功能还需要使用注解实现** + +| swagger | springdoc | javadoc | +|----------------------------------|---------------------------------|--------------------| +| @Api(name = "xxx") | @Tag(name = "xxx") | java类注释第一行 | +| @Api(description= "xxx") | @Tag(description= "xxx") | java类注释 | +| @ApiOperation | @Operation | java方法注释 | +| @ApiIgnore | @Hidden | 无 | +| @ApiParam | @Parameter | java方法@param参数注释 | +| @ApiImplicitParam | @Parameter | java方法@param参数注释 | +| @ApiImplicitParams | @Parameters | 多个@param参数注释 | +| @ApiModel | @Schema | java实体类注释 | +| @ApiModelProperty | @Schema | java属性注释 | +| @ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 无 | +| @ApiResponse | @ApiResponse | java方法@return返回值注释 | + +# 建议使用 `Apifox`(常见问题有其他对接方式) + +官网连接: [https://www.apifox.cn/](https://www.apifox.cn/)
+视频教程: [springdoc与apifox配合使用](https://www.bilibili.com/video/BV1mr4y1j75M?p=8&vd_source=8f52c77be3233dbdd1c5e332d4d45bfb) + +![输入图片说明](https://foruda.gitee.com/images/1678976476639902970/f1617b40_1766278.png "屏幕截图") + +支持 文档编写 接口调试 Mock 接口压测 自动化测试 等一系列功能 + +### 接入框架 + +> 1.下载或使用web在线版 创建一个自己的项目
+ +![输入图片说明](https://foruda.gitee.com/images/1678976502850663851/7bbd8728_1766278.png "屏幕截图") + +> 2.进入项目 选择项目设置 找到自动同步
+ +![输入图片说明](https://foruda.gitee.com/images/1678976508918240326/6a4a61a8_1766278.png "屏幕截图") + +> 3.根据项目内所有文档组完成所有数据源创建(拉取后端`openapi`结构体)
+数据源URL格式 `http://网关ip:端口/服务路径/v3/api-docs`
+项目内所需:
+`http://localhost:8080/demo/v3/api-docs` 演示服务
+`http://localhost:8080/auth/v3/api-docs` 认证服务
+`http://localhost:8080/resource/v3/api-docs` 资源服务
+`http://localhost:8080/system/v3/api-docs` 系统服务
+`http://localhost:8080/code/v3/api-docs` 代码生成服务
+ +![输入图片说明](https://foruda.gitee.com/images/1678980352012289965/24e0e4da_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678980368645148754/62308680_1766278.png "屏幕截图") + +> 4.选择 接口管理 项目概览 点击立即导入 并等待导入完成
+后续会根据策略每3个小时自动导入一次
+每次重新进入apifox也会自动同步一次
+后端有改动也可以手动点击导入
+ +![输入图片说明](https://foruda.gitee.com/images/1678980393851604773/a0c657d3_1766278.png "屏幕截图") + +> 5.(注意版本号)设置鉴权 选择接口管理 项目概览 找到Auth 按照如下配置
+ +**版本号: >= 2.X** + +![输入图片说明](https://foruda.gitee.com/images/1690966897370710566/6a688aea_1766278.png "屏幕截图") + +**版本号: 1.X** + +![输入图片说明](https://foruda.gitee.com/images/1678980398409729963/db4502a0_1766278.png "屏幕截图") + +> key对应项目配置 默认为 `Authorization`
+ +![输入图片说明](https://foruda.gitee.com/images/1678976544342001474/c2ff85d3_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678976549237304743/bcdfadda_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md new file mode 100644 index 00000000..304d3e04 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/i18n.md @@ -0,0 +1,31 @@ +# 国际化方案 +- - - +* 前端国际化参考 [ruoyi前端国际化文档](http://doc.ruoyi.vip/ruoyi-vue/document/htsc.html#前端国际化流程)
+* 参考 `demo` 模块 `TestI18nController` 国际化演示案例 + 在 `Header` 请求头 增加上下文语言参数 `content-language` 参数需与国际化配置文件后缀对应 + 如 `zh_CN` `en_US` 等
+ +![输入图片说明](https://foruda.gitee.com/images/1678976722892396585/60917594_1766278.png "屏幕截图") + +## 获取 `code` 对应国际化内容 + +![输入图片说明](https://foruda.gitee.com/images/1678976728533100954/0ab8e36a_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976733019209506/a16574d6_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976738409745057/a073b425_1766278.png "屏幕截图") + +## 使用 `Validator` 框架校验 `controller` 参数返回国际化 + +`controller` 校验接口参数 需要在类增加 `@Validated` 注解
+![输入图片说明](https://foruda.gitee.com/images/1678976741834729507/6c19b9cc_1766278.png "屏幕截图")
+参数对应校验注解 使用 `{code}` 形式标注使用国际化处理
+![输入图片说明](https://foruda.gitee.com/images/1678976746093285542/ad0989db_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976750822808564/56bd60d7_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976754755107198/b89bf173_1766278.png "屏幕截图") + +## 使用 `Validator` 框架校验 `Bean` 返回国际化 + +`Bean` 校验需要在接口校验 `Bean` 参数使用 `@Validated` 注解
+![输入图片说明](https://foruda.gitee.com/images/1678976761015767874/729da3bc_1766278.png "屏幕截图")
+`Bean` 内属性校验注解 使用 `{code}` 形式标注使用国际化处理
+![输入图片说明](https://foruda.gitee.com/images/1678976765122587920/0b1027af_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976769965314387/0c416ede_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md new file mode 100644 index 00000000..c90d2c61 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/inner_authentication.md @@ -0,0 +1,19 @@ +# 内网鉴权 +- - - +## 功能介绍 + +此功能用于防止外部请求访问内部服务应用
+在请求经过 `gateway网关` 会生成一个 `id-token` 携带到后续服务进行校验
+若未经过 `gateway网关` 调用内网服务 会出现 `id-token无效` 异常
+有效防止非法请求直接访问内网服务
+ +## 开启/关闭内网鉴权 + +更改 `application-common.yml` 配置文件的 `sa-token.check-id-token` 配置即可 + +![输入图片说明](https://foruda.gitee.com/images/1678980608778275681/9a2c1054_1766278.png "屏幕截图") + +## 放行内网鉴权 +进入 `ruoyi-common-security` 模块找到 `SecurityConfiguration` 类 增加排除路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1678980612657326393/cea32a8c_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md new file mode 100644 index 00000000..0d75525b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/new_module.md @@ -0,0 +1,39 @@ +# 创建新服务 +- - - +### 最简单的方式 +> 找个配置好的 例如 `ruoyi-system` 直接copy一份 + +> 将 `pom` 名称改掉
+ +![输入图片说明](https://foruda.gitee.com/images/1678980168782983123/c717e9ba_1766278.png "屏幕截图") + +> 服务启动类 名称改掉
+ +![输入图片说明](https://foruda.gitee.com/images/1678980179829877203/f89d5c18_1766278.png "屏幕截图") + +> `application.yml` 配置服务应用名 改掉
+ +![输入图片说明](https://foruda.gitee.com/images/1678980184047648028/e4c6c6cc_1766278.png "屏幕截图") + +> `nacos` 新建一份新的 对应新模块名称的 配置文件
+![输入图片说明](https://foruda.gitee.com/images/1678980188806372269/cfd9731a_1766278.png "屏幕截图") + +更改 `nacos` 上的 `ruoyi-gateway.yml` 增加新服务路由
+新服务访问路径 `网关ip:端口/服务路径/controller路径/接口路径`
+例子: `http://localhost:8080/system/user/list`
+ +![输入图片说明](https://foruda.gitee.com/images/1666861595048863422/9e9755b3_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1666861629037264535/bdfd5484_1766278.png "屏幕截图") + +### 注意事项 +如果是两个不同包名的模块 需要修改如下配置 + +![输入图片说明](https://foruda.gitee.com/images/1719813861680271619/82435586_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1692006501957936219/059f8526_1766278.png "屏幕截图") + +如果新服务需要使用 `seata` 分布式事务
+需要在 `nacos` 上的 `seata-server.properties` 文件内增加服务组 + +![输入图片说明](https://foruda.gitee.com/images/1692006825427360840/5b9e410c_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md new file mode 100644 index 00000000..2dcab848 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_package_name.md @@ -0,0 +1,33 @@ +# 关于修改包名 +- - - + +**注意: 老包名为 com.ruoyi** + +## 1.随便找个地方新建 org.dromara 包 +![输入图片说明](https://foruda.gitee.com/images/1708491220807198688/b95c0c34_1766278.png "屏幕截图") + +## 2.在包上右键选择 refactor -> rename 选择 All Directories +![输入图片说明](https://foruda.gitee.com/images/1683276891079076405/79808b22_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1708491697128844860/1e87ad39_1766278.png "屏幕截图") + +**因为dromara组织下有很多依赖导致idea无法识别完整包名** +
+![输入图片说明](https://foruda.gitee.com/images/1708490576909691001/692e5b37_1766278.png "屏幕截图") + +**需要先将dromara修改为 例如: ruoyi 然后重复上述步骤 这样就可以整包修改了** +
+![输入图片说明](https://foruda.gitee.com/images/1708490906933084793/ff104cd7_1766278.png "屏幕截图") + +## 3.使用IDEA全局替换 org.dromara 替换为 com.xxx + +![输入图片说明](https://foruda.gitee.com/images/1708491055347995519/dedda0d1_1766278.png "屏幕截图") + +**注意: 由于dromara组织下项目很多 非本框架的依赖模块 请勿修改 例如上图中的 org.dromara.sms4j** + +## 4.如有需要 将所有模块名逐一修改即可 + +## 5.修改完成后需查看所有common包下模块spi文件是否修改正确 + +**老版本idea或者未按照教程修改包名可能导致文件丢包问题** + +![输入图片说明](https://foruda.gitee.com/images/1708491365841192006/8bc337c2_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md new file mode 100644 index 00000000..d36012f5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/association/update_url.md @@ -0,0 +1,25 @@ +# 修改应用路径 +- - - +# 修改访问后端接口路径 + +更改 前端环境配置文件 `VITE_APP_BASE_API` 代理路径 + +![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图")
+ +![输入图片说明](https://foruda.gitee.com/images/1724317552931269967/f7515655_1766278.png "屏幕截图") + +`prod` 生产环境需修改 `nginx.conf` 后端代理路径(上述配置文件也要改) + +![输入图片说明](https://foruda.gitee.com/images/1678980501204821424/d3340308_1766278.png "屏幕截图") + +# 修改前端页面访问路径 +修改对应环境的 `.env.环境` 文件内的 `VITE_APP_CONTEXT_PATH` 应用访问路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1724317049535973756/0a2cc43b_1766278.png "屏幕截图") + +生产环境 `nginx.conf` 与之对应修改即可
+**注意: 文件真实目录为 `/usr/share/nginx/html/admin/index.html` 此功能一般为多项目部署需要 故会增加一层目录 如不需要可以自行修改**
+ +![输入图片说明](https://foruda.gitee.com/images/1678976662194341301/2720b7e9_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md new file mode 100644 index 00000000..66ae32a9 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/client.md @@ -0,0 +1,85 @@ +# 客户端管理功能 +- - - +## 版本 >= 2.X + +## 客户端管理页面 + +![输入图片说明](https://foruda.gitee.com/images/1690961819029076660/c44374ac_4959041.png "屏幕截图") + +### 客户端管理字段说明 +| 字段名称 | 取值说明 | 注意事项 | +|----------------|----------------------------|--------------------------------| +| 客户端id | 由后端生成,用于前端登录校验以及接口数据加密 | 无法修改,不要删除默认数据,否则会报错 | +| 客户端key | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | +| 客户端秘钥 | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | +| 授权类型 | 密码认证、短信认证、邮件认证、小程序认证、第三方认证 | 根据授权类型判断当前客户端是否支持该登录方式 | +| 设备类型 | PC端、APP端 | | +| Token活跃超时时间 | 自定义 | 指定时间无操作则过期(单位:秒),默认30分钟(1800秒) | +| Token固定超时时间 | 自定义 | 指定时间必定过期(单位:秒),默认七天(604800秒) | + +### 前后端使用新的客户端id + +步骤如下: +1. 前端管理页面生成新的客户端id。 +2. 将新的客户端id复制到前端配置文件。 + +![输入图片说明](https://foruda.gitee.com/images/1690962894318847386/133d2f90_4959041.png "屏幕截图") + +## 新增自定义客户端 + +### 步骤一:新增客户端数据(例如增加小程序端) + +![输入图片说明](https://foruda.gitee.com/images/1690965463070099188/baeb4441_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1690965508836621042/df06248f_4959041.png "屏幕截图") + +### 步骤二:配置前端请求头信息 + +需要在全局请求头 header 中增加 cientid
+确保客户端所有请求都携带此id 可参考项目 `request.ts` + +![输入图片说明](https://foruda.gitee.com/images/1690965768235114596/980b88d2_4959041.png "屏幕截图") + +`VITE_APP_CLIENT_ID` 即配置文件中的客户端id。 + +**重点:不同客户端登录获取到的token不同与其他端不互通(例如: app登录获取到的token无法用于pc端接口查询)** + +## 新增自定义登录方式授权类型 + +**重点说明: 不要单独增加登录接口 系统全局统一只有一个登录接口 只需增加不同的鉴权方式即可** + +如何调试使用登录看这里 -> [关于登录调试步骤](/questions/login_step.md) + +### 步骤一:新增字典数据 + +![输入图片说明](https://foruda.gitee.com/images/1690968849418013624/3b28417e_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1690968865819397010/64529fad_4959041.png "屏幕截图") + +### 步骤二:新增/修改客户端数据 + +### 步骤三:后端新增认证策略 + +新增策略实现类实现 `IAuthStrategy` 接口。
+ +![输入图片说明](https://foruda.gitee.com/images/1690972828588111954/7614a4c5_4959041.png "屏幕截图") + +参照已有策略实现类实现自定义参数校验登录方法逻辑。
+ +![输入图片说明](https://foruda.gitee.com/images/1718951146945578143/789c80e4_1766278.png "屏幕截图") + +**注意修改 `@Service` 名称保证规范性** + +![输入图片说明](https://foruda.gitee.com/images/1718951179571300385/8db730b9_1766278.png "屏幕截图") + +`LoginBody` 校验参数(可自定义)
+ +![输入图片说明](https://foruda.gitee.com/images/1718951237123374392/f7840db2_1766278.png "屏幕截图") + +例如 扩展小程序登录参数 只需要继承 `LoginBody
+ +![输入图片说明](https://foruda.gitee.com/images/1718951283931895761/e6348be5_1766278.png "屏幕截图")` + +校验分组(可自定义)
+ +![输入图片说明](https://foruda.gitee.com/images/1718951343601334215/8ef404b4_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md new file mode 100644 index 00000000..742ef939 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/code_generate.md @@ -0,0 +1,86 @@ +# 代码生成 +- - - +## 功能介绍 + +### 数据源配置 + +![输入图片说明](https://foruda.gitee.com/images/1678976867341325193/a2be0608_1766278.png "屏幕截图") + +**项目适配多种类型数据库 可以在代码生成页面切换**
+ +> 填写对应的数据源名称 点击搜索按钮 即可切换到对应的数据源
+ +![输入图片说明](https://foruda.gitee.com/images/1678976876081856486/4ef4841c_1766278.png "屏幕截图") + +**>= 2.2.1版本 项目支持100+种数据库适配 在代码生成模块增加对应的数据库依赖即可**
+ +![输入图片说明](https://foruda.gitee.com/images/1722396530340741054/3914eb72_1766278.png "屏幕截图") + + +### 导入数据表 + +> 点击导入按钮 会加载系统数据库所有的表
+ +![输入图片说明](https://foruda.gitee.com/images/1678976880393939803/3ecf1dcc_1766278.png "屏幕截图") + +> 选择需要的表 点击确定即可
+ +![输入图片说明](https://foruda.gitee.com/images/1678976885370716109/4834faa5_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976891856866728/853420d9_1766278.png "屏幕截图") + +### 编辑表生成结构 + +> 点击表对应的编辑按钮
+ +![输入图片说明](https://foruda.gitee.com/images/1678976899111822310/aeaa33f9_1766278.png "屏幕截图") + +> 更改要生成表的数据
+ +![输入图片说明](https://foruda.gitee.com/images/1678976903345795925/4326f6ee_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976908897387614/4cdf939b_1766278.png "屏幕截图") + +### 生成条件影响 + +![输入图片说明](https://foruda.gitee.com/images/1678976913809284051/24da09b0_1766278.png "屏幕截图") + + +* `插入` `编辑` 影响生成 BO 类 与 前端添加编辑页面 是否有该字段 +* `列表` 影响生成 VO 类 与 前端列表页面展示 是否有该字段 +* `查询` 影响 前端页面是否有该字段的搜索框 与 后端代码是否生成对应的查询条件 +* `查询方式` 影响生成查询条件的类型 +* `必填` 影响 BO 类 与 页面是否强制校验 +* `显示类型` 影响生成页面使用何种展示组件 +* `字典类型` 影响页面是否生成与字典的关联 + +### 树表配置 + +> 编辑表生成信息 生成模板为 `树表` 填写对应数据即可
+ +![输入图片说明](https://foruda.gitee.com/images/1678976917918548901/f5886c5c_1766278.png "屏幕截图") + +### 主子表说明 + +框架不支持也不推荐使用主子表
+原因一般业务场景 基本都是一对N表 多表关联场景
+还有一些 主 => 子 <= 主 场景 需求很复杂 很少有单纯主子表场景出现
+另外主子表关联 很容易出现 笛卡尔积 或者数据错乱等问题 需要自行sql调优场景
+所以建议大家都按照 单表生成 自行编写业务逻辑 + +### 预览功能 + +> 配置好生成信息后 可以点击预览按钮
+ +![输入图片说明](https://foruda.gitee.com/images/1678976924411765532/2e9747df_1766278.png "屏幕截图") + +> 系统会根据已经配置好的数据 生成对应的代码预览
+> 可以再此处观察代码的生成结构和数据是否正确等
+ +![输入图片说明](https://foruda.gitee.com/images/1678976945982406065/ca7383bb_1766278.png "屏幕截图") + + +### 代码结构同步 + +> 实际开发中 难免会有表结构更改的需求
+> 这时可以使用 同步功能 点击同步按钮 即可与实时数据库表进行字段同步
+ +![输入图片说明](https://foruda.gitee.com/images/1678976952919156537/3c47c078_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md new file mode 100644 index 00000000..fa901792 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/export.md @@ -0,0 +1,250 @@ +# 导出功能 + +- - - + +在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导出操作(即写 Excel)。 + +[EasyExcel 文档地址](https://easyexcel.opensource.alibaba.com/) + +## 导出功能使用流程说明 + +### 步骤一:定义导出实体对象 + +以框架中 `SysUserExportVo` 为例: + +```Java + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + // ....................... + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; +``` + +> 说明:
+> 1. 使用 `@ExcelProperty` 注解标注需要导出的属性。 +> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 +> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 + +### 步骤二:使用导出方法 + +以框架中 `SysUserController#export` 方法为例: + +```Java + /** + * 导出用户列表 + */ + @PostMapping("/export") + public void export(SysUserBo user, HttpServletResponse response) { + // 根据参数查询导出的用户列表数据 + List list = userService.selectUserList(user); + // 将列表转换为导出对象列表 + List listVo = MapstructUtils.convert(list, SysUserExportVo.class); + // 导出方法 + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); + } +``` + +> 说明:
+> 使用 `ExcelUtil.exportExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导出对象集合,Excel sheet 表名称,导出对象类型,response。 + +## 框架工具使用说明 + +### 1:字典转换器 + +字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 + +使用方式一: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; +``` + +使用方式二: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") + private String sex; +``` + +`@ExcelDictFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|------------------|--------|-----|-----------------------------------| +| dictType | String | "" | 字典的type值 (如: sys_user_sex) | +| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | +| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | + +### 2:枚举转换器 + +字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 + +使用方式: + +```Java + /** + * 用户类型 + *

+ * 使用ExcelEnumFormat注解需要进行下拉选的部分 + */ + @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) + @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") + private String userStatus; +``` + +`@ExcelEnumFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|-----------|------------|------|------------------------------| +| enumClass | Enum Class | - | 字典枚举类型 | +| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | +| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | + +### 3:合并单元格 + +`@CellMerge` 注解用于合并相同的列数据,需要结合 `CellMergeStrategy` 策略使用,标注在需要转换的属性上。 + +使用方式: + +步骤一:在属性标注 `@CellMerge` 注解: +```Java + /** + * 部门id + */ + @CellMerge + @ExcelProperty(value = "部门id") + private Long deptId; +``` + +`@CellMerge` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|---------|----------|-----|------------------------------| +| index | int | -1 | 合并列的下标,建议使用默认值 | +| mergeBy | String[] | {} | 合并需要依赖的其他字段名称(基于这个字段内容做合并条件) | + + +步骤二:导出方法开启合并: +```Java + /** + * 导出测试单表列表 + */ + @PostMapping("/export") + public void export(@Validated TestDemoBo bo, HttpServletResponse response) { + List list = testDemoService.queryList(bo); + // 参数 true 表示开启合并单元格策略 + ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, true, response); + } +``` +![输入图片说明](https://foruda.gitee.com/images/1700128921644543994/e8d4704f_1766278.png "屏幕截图") + +### 4:复杂 Excel 导出示例 +`TestExcelController` 提供了几种导出示例,如果需要可以参照相应方法进行导出。 + +#### 4.1:单列表多数据导出(模板导出) + +模板内容: + +![输入图片说明](https://foruda.gitee.com/images/1700124852002972562/d9f57a8c_4959041.png "屏幕截图") + +模板位置:`ruoyi-example/ruoyi-demo/src/main/resources/excel/` + +导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700124885532359879/0d011d05_4959041.png "屏幕截图") + +#### 4.2:多列表多数据导出(模板导出) + +模板内容: + +![输入图片说明](https://foruda.gitee.com/images/1700125025931981176/105dbaaa_4959041.png "屏幕截图") + +模板位置:`ruoyi-example/ruoyi-demo/src/main/resources/excel/` + +导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700125054011300002/71869c1d_4959041.png "屏幕截图") + +#### 4.3:导出下拉框 + +`ExcelDictFormat` 注解指定的字典项默认都会转换成下拉框 + +自定义导出省市区下拉框示例代码:参考 demo 模块 `TestExcelController` + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700125265411678973/7f767719_4959041.png "屏幕截图") + +## Easy Excel 常用注解 + +`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解,自定义注解会结合转换器一起进行说明。 + +| 类型 | 注解名称 | 使用举例 | 说明 | +|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| +| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | +| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | +| 样式注解 | @ColumnWidth | @ColumnWidth(value=值) | 设置列宽 | +| 样式注解 | @ContentFontStyle | @ContentFontStyle(color=颜色) | 可以设置字体类型,颜色,粗细,是否斜体,下划线等,具体可查看注解 `@ContentFontStyle` | +| 样式注解 | @ContentLoopMerge | @ContentLoopMerge(eachRow=行值, columnExtend=列值) | 设置循环合并的区域 | +| 样式注解 | @ContentRowHeight | @ContentRowHeight(value=值) | 设置内容行高 | +| 样式注解 | @ContentStyle | - | 设置单元格样式,具体可查看注解 `@ContentStyle` | +| 样式注解 | @HeadFontStyle | @HeadFontStyle(color=颜色) | 设置表头字体格式,类似 `@ContentFontStyle`,具体可查看注解 `@HeadFontStyle` | +| 样式注解 | @HeadRowHeight | @HeadRowHeight(value=值) | 设置表头行高 | +| 样式注解 | @HeadStyle | - | 设置表头样式,具体可查看注解 `@HeadStyle` | +| 样式注解 | @OnceAbsoluteMerge | @OnceAbsoluteMerge(firstRowIndex=开始行下标, lastRowIndex=结束行下标, firstColumnIndex=开始列下标, lastColumnIndex=结束列下标) | 根据设置值合并单元格 | +| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | +| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | +| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | + +## 扩展说明 + +### 自定义转换器实现 + +由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 +以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 + +字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 + +_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ + +#### 实现方式 + +自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") + +转换方法 `ExcelDictConvert#convertToExcelData` : + +![输入图片说明](https://foruda.gitee.com/images/1700104426131801297/72931ef0_4959041.png "屏幕截图") + +## 更多功能 + +更多导出功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/api/write)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md new file mode 100644 index 00000000..f1bbca7d --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/import.md @@ -0,0 +1,202 @@ +# 导入功能 +- - - + +在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导入操作(即读 Excel)。 + +## 导入功能使用流程说明 + +### 步骤一:定义导入实体对象 + +以框架中 `SysUserImportVo` 为例: + +```java + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + // ....................... + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; +``` + +> 说明:
+> 1. 使用 `@ExcelProperty` 注解标注需要导入的属性。 +> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 +> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 +> 4. 对象禁止使用链式注解 `@Accessors(chain = true)`,会找不到set方法。 + +### 步骤二:使用导入方法 + +以框架中 `SysUserController#importData` 方法为例: + +```Java + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + // 导入方法 + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); + return R.ok(result.getAnalysis()); + } +``` +> 说明:
+> 使用 `ExcelUtil.importExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导入文件流,导入对象类型,导入监听器 `SysUserImportListener`。 + +## 框架工具使用说明 + +### 1:字典转换器 + +字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 + +使用方式一: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; +``` + +使用方式二: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") + private String sex; +``` + +`@ExcelDictFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|------------------|--------|-----|-----------------------------------| +| dictType | String | "" | 字典的type值 (如: sys_user_sex) | +| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | +| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | + +### 2:枚举转换器 + +字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 + +使用方式: + +```Java + /** + * 用户类型 + *

+ * 使用ExcelEnumFormat注解需要进行下拉选的部分 + */ + @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) + @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") + private String userStatus; +``` + +`@ExcelEnumFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|-----------|------------|------|------------------------------| +| enumClass | Enum Class | - | 字典枚举类型 | +| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | +| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | + + +### 3:导入监听器 + +#### 3.1:ExcelListener 监听器接口 + +`ExcelListener` 扩展了 `ReadListener` 接口,增加了获取结果方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700181723794469524/99bf83c9_4959041.png "屏幕截图") + +#### 3.2:DefaultExcelListener 默认监听器 + +`DefaultExcelListener` 默认监听器在读 Excel 时调用,主要对数据进行校验、解析、异常处理、返回结果等。导入操作时如果没有特别指定则使用该监听器。 + +#### 3.3:SysUserImportListener 用户导入监听器 + +`SysUserImportListener` 用户导入监听器是在用户导入时调用的监听器。 + +该监听器重写了 `invoke` 反射接口,对导入的用户数据进行了校验;重写了 `getExcelResult` 获取结果接口,返回结果数据。 + +#### 3.4:ExportDemoListener 带下拉框的导入监听器 + +`ExportDemoListener` 是对带有下拉框的 Excel 进行处理的导入监听器。 + +## Easy Excel 常用注解 + +`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解。 + +| 类型 | 注解名称 | 使用举例 | 说明 | +|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| +| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | +| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | +| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | +| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | +| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | + +## 扩展使用 + +### 扩展一:自定义转换器实现 + +由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 +以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 + +字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 + +_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ + +#### 实现方式 + +自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") + +转换方法 `ExcelDictConvert#convertToJavaData` : + +![输入图片说明](https://foruda.gitee.com/images/1700182975516396213/d3c020f9_4959041.png "屏幕截图") + +### 扩展二:自定义监听器实现 + +自定义监听器主要用于在读取解析 Excel 数据时进行自定义操作。 +以下以框架中的用户导入监听器 `SysUserImportListener` 为例进行说明。 + +#### 实现方式 +1. 继承分析事件监听器 `AnalysisEventListener` 以及实现 Excel 监听器 `ExcelListener`。 + +![输入图片说明](https://foruda.gitee.com/images/1700184652693497753/09333dac_4959041.png "屏幕截图") + +2. 显示使用构造函数,否则将导致空指针。 + +![输入图片说明](https://foruda.gitee.com/images/1700184759075616584/cf05b0ed_4959041.png "屏幕截图") + +3. 实现 `invoke` 方法,对数据进行解析操作,可以在此方法对数据进行合法性判断。 + +4. 实现 `getExcelResult` 方法,对结果进行操作,例如返回成功、失败的统计数据。 + +## 更多功能 + +更多导入功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md new file mode 100644 index 00000000..4cb42769 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/oss.md @@ -0,0 +1,124 @@ +# 关于OSS模块使用 +- - - +## 重点注意事项 + +`桶/存储区域` 系统会根据配置自行创建分配权限
+~~如手动配置需要设置 `公有读` 权限 否则文件无法访问~~(`aliyun` 还需开通跨域配置)
+1.4.0 版本支持配置`公有/私有`权限(`aliyun` 还需开通跨域配置)
+访问站点 后严禁携带其他 `url` 例如: `/`, `/ruoyi` 等
+**阿里云与腾讯云SDK访问站点中不能包含桶名 系统会自动处理**
+**minio 站点不允许使用 localhost 请使用 127.0.0.1**
+**访问站点与自定义域名 都不要包含 `http` `https` 前缀 设置`https`请使用选项处理** + +## 代码使用 + +> 参考 `SysOssService.upload` 用法
+> 使用 `OssFactory.instance()` 获取当前启用的 `OssClient` 实例
+> 进行功能调用 获取返回值后 存储到对应的业务表 + +![输入图片说明](https://foruda.gitee.com/images/1678978345529639839/d350ec0b_1766278.png "屏幕截图") + + +## 功能配置 + +### 配置OSS + +> 进入 `系统管理 -> 文件管理 -> 配置管理` 填写对应的OSS服务相关配置
+ +![输入图片说明](https://foruda.gitee.com/images/1678978349820700551/1f91a237_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978354387669856/3a91a3a9_1766278.png "屏幕截图")
**重点说明** + +> 云厂商只需修改 `访问站点`对应的域 切勿乱改(云厂商强烈建议绑定自定义域名使用 七牛云必须绑定[官方规定])
+ +![输入图片说明](https://foruda.gitee.com/images/1678978362358100362/5c2c4d20_1766278.png "屏幕截图") + +> 七牛云 访问站点
+ + +![输入图片说明](https://foruda.gitee.com/images/1678978366254745764/e93a65ff_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978369853348732/79e8950e_1766278.png "屏幕截图") + +> 阿里云 访问站点 + +![输入图片说明](https://foruda.gitee.com/images/1678978373981462025/56a70398_1766278.png "屏幕截图") + +> 腾讯云 访问站点 + +![输入图片说明](https://foruda.gitee.com/images/1678978378697093134/785517f3_1766278.png "屏幕截图") + +### MinIO 使用 https访问站点 + +**注意:S3 API 签名计算算法不支持托管 MinIO Server API 的代理方案** + +[ minio https 配置方式](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) + +### 切换OSS + +> 再配置列表点击 `状态` 按钮开启即可(注意: 只能开启一个OSS默认配置)
+> 手动使用 `OssFactory.instance("configKey")`
+ +![输入图片说明](https://foruda.gitee.com/images/1678978383700118702/7f3fa0c5_1766278.png "屏幕截图") + +### 扩展分类 + +> 如有文件分类 建议创建多个 oss配置 进行切换存储
+ +例如: 创建一个 图片存储的 oss配置
+指定唯一的 `configKey` 与 `前缀目录` 或 直接使用独立的`桶`
+独立桶的特点 可以自定义访问权限
+例如: 创建一个私有文件存储桶 不对外开放
+ +![输入图片说明](https://foruda.gitee.com/images/1678978389139754119/140be1df_1766278.png "屏幕截图") + +> 指定需要使用的配置
+> 使用 `OssFactory.instance("image")` 获取的 `OssClient` 会加载上图的配置 从而达到上传不同的目录或桶 + + +![输入图片说明](https://foruda.gitee.com/images/1678978397550123641/1b536881_1766278.png "屏幕截图") + + +### 上传图片或文件 + +> 进入 `系统管理 -> 文件管理` 点击 `上传文件` 或 `上传图片` 根据选项选择即可 会对应上传到配置开启的OSS内
+ +![输入图片说明](https://foruda.gitee.com/images/1678978401028132972/445d058e_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978404388284503/5459da29_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978408761764835/c81651fc_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978412748494539/7bae621f_1766278.png "屏幕截图") + +### 列表展示 + +> 默认展示图片(可预览) 文件会展示路径
+ +![输入图片说明](https://foruda.gitee.com/images/1678978416327601385/af1ecb3b_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978422249633007/19d68eaa_1766278.png "屏幕截图") + +> 可以点击 `预览禁用启用` 按钮对是否展示进行更改 + +![输入图片说明](https://foruda.gitee.com/images/1678978426017014926/4f7fa3f3_1766278.png "屏幕截图") + +> 点击禁用后 图片会变成路径展示 + +![输入图片说明](https://foruda.gitee.com/images/1678978429692592556/0231d778_1766278.png "屏幕截图") + +> 也可再 `参数设置` 更改预览状态 将 `OSS预览列表资源` 改为 `false` 即可关闭预览 + +![输入图片说明](https://foruda.gitee.com/images/1678978433769403801/7d480e76_1766278.png "屏幕截图") + +### 删除功能 + +> 点击列表上方或后方 `删除` 按钮 会根据OSS服务商类型 调用对应的删除(注意: 需确保对应的服务商配置正确)
+> 可勾选多服务商类型的文件进行删除 系统会自动判断 + +![输入图片说明](https://foruda.gitee.com/images/1678978438265941745/f32edc72_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678978441938542080/43ed7c3d_1766278.png "屏幕截图") + +### 下载功能 + +> 点击列表后方对应资源的 `下载` 按钮 根据需求填写文件名 点击确认即可完成下载 + +![输入图片说明](https://foruda.gitee.com/images/1678978448927336261/409af888_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678978452761792483/ed0a4a72_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md new file mode 100644 index 00000000..2aafe47b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/page.md @@ -0,0 +1,29 @@ +# 分页功能 +- - - + +## 重点说明 + +> 项目使用 `mybatis-plus` 分页插件 实现分页功能 大致用法与 MP 一致 [MP分页文档](https://baomidou.com/pages/97710a/)
+> 项目已配置分页合理化 页数溢出 例如: 一共5页 查了第6页 默认返回第一页
+ +![输入图片说明](https://foruda.gitee.com/images/1678977804058241635/b5cb362d_1766278.png "屏幕截图") + +## 代码用法 + +> `Controller` 使用 `PageQuery` 接收分页参数 具体参数参考 `PageQuery` + +![输入图片说明](https://foruda.gitee.com/images/1678977844048821356/1f994221_1766278.png "屏幕截图") + +> 构建 `Mybatis-Plus` 分页对象
+> 使用 `PageQuery#build()` 方法 可快速(基于当前对象数据)构建 `MP` 分页对象 + +![输入图片说明](https://foruda.gitee.com/images/1678977862816976499/b82c1638_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678977876194578744/eaa7b854_1766278.png "屏幕截图")
+ +具体用法与 `MP` 一致 + +> 自定义 `SQL` 方法分页
+> 只需在 `Mapper` 方法第一个参数和返回值 重点: 第一个参数 标注分页对象 + +![输入图片说明](https://foruda.gitee.com/images/1678977898181729571/6e102731_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678977906788451483/70979292_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md new file mode 100644 index 00000000..95ee19d8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/param_check.md @@ -0,0 +1,158 @@ +# 参数校验 +- - - + +参数校验在日常开发中十分常见,在本框架中引入了 `spring-boot-starter-validation` 依赖,底层基于 `hibernate-validator`,可以对参数进行校验。 + +## 参数校验使用 + +### 方法一:使用 `@Validated` 注解 + +#### 步骤一:标注 `@Validated` + +`@Validated` 可以标注在类上,或者是参数前。 + +```Java +/** 标注在类上 **/ +@Validated +@RestController +@RequestMapping("/auth") +public class AuthController { + + @PostMapping("/login") + public R login(@RequestBody LoginBody body) { + // ... + } + +} +``` + +```Java +/** 标注在参数前 **/ +@PostMapping +public R add(@Validated @RequestBody SysUserBo user) { + // ... +} +``` + +#### 步骤二:标注校验注解 + +在参数中加入校验注解。 + +```Java +public class SysUserBo { + + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + +} +``` + +常见校验注解见文末附表。 + +_注:message 支持 EL 表达式,{max} 直接读取前面的参数值。_ + +### 方法二:使用校验工具类 `ValidatorUtils` + +`org.dromara.common.core.utils.ValidatorUtils` + +![输入图片说明](https://foruda.gitee.com/images/1700050047426137432/206bd032_4959041.png "屏幕截图") + +使用方式 1:校验所有带有校验注解的属性 + +```Java +// 校验所有带有校验注解的属性 +ValidatorUtils.validate(object); +``` + +使用方式 2:按照分组校验属性(可以传多个分组) + +```Java +// 按照分组校验属性(可以传多个分组) +ValidatorUtils.validate(object, group); +``` + +## 扩展使用 + +### 扩展一:自定义校验注解 + +除了已有的校验注解以外,可以结合业务进行自定义。 + +以框架中的 `@Xss` 注解为例进行说明。 + +```Java +@Xss(message = "用户账号不能包含脚本字符") +@NotBlank(message = "用户账号不能为空") +@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") +private String userName; +``` + +#### 1:新增 `@Xss` 注解 + +`org.dromara.common.core.xss.Xss` + +![输入图片说明](https://foruda.gitee.com/images/1700048074014527096/b4e230c2_4959041.png "屏幕截图") + +#### 2:自定义校验器 + +自定义校验器实现 `jakarta.validation.ConstraintValidator` 接口。 + +`org.dromara.common.core.xss.XssValidator` + +![输入图片说明](https://foruda.gitee.com/images/1700048474563719650/f9172bdc_4959041.png "屏幕截图") + +### 扩展二:自定义分组校验 + +同一个对象在不同的请求中需要校验的参数不同,则可以使用分组校验。 + +#### 1:自定义分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049439236073123/9e0d2e16_4959041.png "屏幕截图") + +#### 2:`@Validated` 注解指定分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049302803077030/c2a985aa_4959041.png "屏幕截图") + +#### 3:校验注解中指定分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049205699437759/96babbd6_4959041.png "屏幕截图") + +## 附录:常用校验注解 + +| 注解 | 使用(只列举特殊参数值) | 参数类型 | 说明 | +|------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------| +| @AssertFalse | @AssertFalse | boolean / Boolean | 元素值必须为 false | +| @AssertTrue | @AssertTrue | boolean / Boolean | 元素值必须为 true | +| @DecimalMax | @DecimalMax(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | +| @DecimalMin | @DecimalMin(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | +| @Digits | @Digits(integer=整数位值, fraction=小数位值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须符合整数位以及小数位范围值 | +| @Email | @Email(regexp=正则表达式, flags=标志) | CharSequence | 元素是否符合正则表达式(正则表达式非必传) | +| @Future | @Future | - java.util.Date
- java.util.Calendar
- java.time.Instant
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.time.MonthDay
- java.time.OffsetDateTime
- java.time.OffsetTime
- java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate | 元素必须是未来的时刻、日期或时间 | +| @FutureOrPresent | @FutureOrPresent | 同 @Future | 元素必须是当前或未来的时刻、日期或时间 | +| @Length | @Length(min=最小值, max=最大值) | - CharSequence | 验证字符串是否在包含的 min 和 max 之间 | +| @Max | @Max(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | +| @Min | @Min(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | +| @Negative | @Negative | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的负数(即 0 被视为无效值) | +| @NegativeOrZero | @NegativeOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为负数或 0 | +| @NotBlank | @NotBlank | CharSequence | 元素不能为 null,并且必须至少包含一个非空白字符 | +| @NotEmpty | @NotEmpty | - CharSequence
- Collection
- Map
- Array | 元素不能为 null 或空集合 | +| @NotNull | @NotNull | 不限类型 | 元素不能为 null | +| @Null | @Null | 不限类型 | 元素必须为 null | +| @Past | @Past | 同 @Future | 元素必须是过去的瞬间、日期或时间 | +| @PastOrPresent | @PastOrPresent | 同 @Future | 元素必须是过去或现在的瞬间、日期或时间 | +| @Pattern | @Pattern(regexp=正则表达式, flags=标志) | CharSequence | 元素必须与指定的正则表达式匹配(正则表达式遵循 Java 正则表达式约定) | +| @Positive | @Positive | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的正数(即 0 被视为无效值) | +| @PositiveOrZero | @PositiveOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为正数或 0 | +| @Range | @Range(min=最小值, max=最大值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 验证元素是否在包含的 min 和 max 之间 | +| @Size | @Size(min=最小值, max=最大值) | - CharSequence
- Collection
- Map
- Array | 验证元素是否在包含的 min 和 max 之间 | +| @Valid | @Valid | 对象 | 级联验证 | + +更多注解可参考包: `org.hibernate.validator` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md new file mode 100644 index 00000000..62ce2946 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions.md @@ -0,0 +1,144 @@ +# 关于数据权限 +- - - +* 参考 demo 模块用法(需导入 test.sql 文件) + +### 新版数据权限功能: +1.支持自动注入 sql 数据过滤
+2.查询、更新、删除 限制
+3.支持自定义数据字段过滤
+4.模板支持 spel 语法实现动态 Bean 处理
+5.支持与菜单权限标识符联合使用(2.2.X新功能) + +### 数据权限相关代码 + +| 类 | 说明 | 功能 | +|-------------------------------|-----------------|----------------------------------------| +| DataScopeType | 数据权限模板定义 | 用于定义数据权限模板 | +| DataPermission | 数据权限组注解 | 用于标注开启数据权限 (默认过滤部门权限) | +| DataColumn | 具体的数据权限字段标注 | 用于替换数据权限模板内的 key 变量 | +| PlusDataPermissionInterceptor | 数据权限 sql 拦截器 | 用于拦截所有 sql 检查是否标注了 `DataPermission` 注解 | +| PlusDataPermissionHandler | 数据权限处理器 | 用于处理被拦截到的 sql 为其添加数据权限过滤条件 | +| DataPermissionHelper | 数据权限助手 | 操作数据权限上下文变量 | +| SysDataScopeService | 自定义 Bean 处理数据权限 | 用于自定义扩展 | + +## 忽略数据权限 + +1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: +``` +@InterceptorIgnore(dataPermission = "true") +``` + +2.如果需要在业务层忽略数据权限,可调用以下方法: +``` +# 无返回值 +DataPermissionHelper.ignore(() -> { 业务代码 }); +# 有返回值 +Class result = DataPermissionHelper.ignore(() -> { return 业务代码 }); +``` + +### 使用方式 `参考demo模块` +数据权限体系 `用户 -> 多角色 => 角色 -> 单数据权限` +> 例子: 用户A 拥有两个角色
+> 角色A 部门经理 可查看 本部门及以下部门的数据
+> 角色B 兼职开发 可查看 仅自己的数据 + +> 创建角色 test1 为 本部门及以下 + +![输入图片说明](https://foruda.gitee.com/images/1678978669666831574/b51ed0a3_1766278.png "屏幕截图") + +> 创建角色 test2 为 仅本人 + +![输入图片说明](https://foruda.gitee.com/images/1678978674159035056/69cf32ad_1766278.png "屏幕截图") + +> 将其分配给用户 test + +![输入图片说明](https://foruda.gitee.com/images/1678978680492570269/a47b6afc_1766278.png "屏幕截图") + +### 编写列表查询(注意: 数据权限注解只能在 Mapper 层使用) + +> 标注数据权限注解 `dept_id` 为过滤部门字段 `user_id` 为过滤创建用户 + +![输入图片说明](https://foruda.gitee.com/images/1678978687179608427/d6b83c30_1766278.png "屏幕截图") + +### 重点注意: 如下情况不生效 + +> 有自定义实现方法 最终执行的mapper不是这个方法 所以无法生效 +> +> 解决方案: 一直往下点 找到最终的执行mapper重写即可 + +![输入图片说明](https://foruda.gitee.com/images/1678978692558777291/78b0a3dd_1766278.png "屏幕截图") + +### 编写数据权限模板 + +![输入图片说明](https://foruda.gitee.com/images/1678978697141183499/cfc1cb6a_1766278.png "屏幕截图") + +1.`code` 为关联角色的数据权限 `code`
+2.`sqlTemplate` 为 sql 模板
+`#{#deptName}` 为模板变量 对应权限注解的 `key`
+`#{@sdss}` 为模板 Bean 调用 调用其 Bean 的处理方法
+3.`elseSql` 为兜底 sql 处理当前角色与标注的注解 无对应的情况
+例如 数据权限为仅本人 且 方法并未标注具体过滤注解 则 填充 `1 = 0` 使条件不满足 不允许查看
+更详细用法可以参考 `DataScopeType` 注释 + +### 测试代码 + +> 使用 `管理员` 用户优先测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978703250082481/e93a68a5_1766278.png "屏幕截图") + +> 使用 `test` 用户测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978710644676604/d7f80487_1766278.png "屏幕截图") + +> 使用 `test` 删除一条不属于自己的数据 +> sql执行为不满足条件 不允许删除 + +![输入图片说明](https://foruda.gitee.com/images/1678978715711122947/441d61f7_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678978720298532619/a35b1147_1766278.png "屏幕截图") + + +> 使用 `test` 修改与删除同理
+> 具体实现为 更新和删除方法 标注数据权限注解 + +![输入图片说明](https://foruda.gitee.com/images/1678978725329242504/a70491a1_1766278.png "屏幕截图") + +### 自定义SQL模板 + +> 1.首先在角色管理 数据权限下拉框 添加自定义模板
+> 为什么不放置到系统字典问题: 因数据权限与模板绑定 不应随意改动 最好事先定义好 + +![输入图片说明](https://foruda.gitee.com/images/1678978730563169865/3459ee17_1766278.png "屏幕截图") + +> 2.代码 `DataScopeType` 自定义一个SQL模板 + +![输入图片说明](https://foruda.gitee.com/images/1678978735588305505/3f030c67_1766278.png "屏幕截图") + +> 3.标注权限注解 + +![输入图片说明](https://foruda.gitee.com/images/1678978742259837391/eabe5caa_1766278.png "屏幕截图") + +> 4.设置数据权限变量 + +![输入图片说明](https://foruda.gitee.com/images/1678978746778429543/e211201f_1766278.png "屏幕截图") + +> 5.测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978751875467640/7d210cf4_1766278.png "屏幕截图") + +### mybatis-plus 原生方法 增加数据权限过滤 + +> 首先查看需要重写的方法源码 重点`方法源码` `方法源码` `方法源码`
+> 例如重写 `selectPage` 方法
+ +![输入图片说明](https://foruda.gitee.com/images/1678978757955000897/8315695c_1766278.png "屏幕截图") + +> 复制源码到自己的 `Mapper` 并增加数据权限注解 注意左边出现重写图标 即为重写成功
+ +![输入图片说明](https://foruda.gitee.com/images/1678978763224011694/bbea25a1_1766278.png "屏幕截图") + +### 支持类标注 + +> 获取规则 `方法 > 类` 注意: 类标注后 所有方法(包括父类方法) 都会进行数据权限过滤 + +![输入图片说明](https://foruda.gitee.com/images/1678978767336534896/fb13ee99_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md new file mode 100644 index 00000000..6931ca7a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/permissions_control.md @@ -0,0 +1,178 @@ +# 权限控制 +- - - + +本文采用 `Sa-Token` 框架实现权限控制。[官方文档传送门](https://sa-token.cc/doc.html#/) + +## 权限校验 +权限校验指的是校验用户是否拥有访问某个 API 的能力。 + +通常情况下,一个 API 对应一个权限码,如果用户具备当前 API 的权限码,即代表有能力访问该 API。 + +### 1:权限标识 +在本系统中,每一个菜单功能都有对应的权限标识,可以在菜单管理中进行设置。 + +> 注: +> 1. 前后端的权限标识要保持一致。 +> 2. 权限标识可以使用通配符`*`。 + +![输入图片说明](https://foruda.gitee.com/images/1701086497939145368/133fb327_4959041.png "屏幕截图") + + +### 2:校验方法 +#### 2.1:使用 `@SaCheckPermission` 注解进行校验 +`@SaCheckPermission` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 + +- 单个权限校验: + +```Java +@SaCheckPermission("system:user:list") +``` + +- 多个权限校验(或模式,满足任意一个权限即可): + +```Java +@SaCheckPermission( + value = { + "system:user:list", + "system:user:query" + }, + mode = SaMode.OR +) +``` + +- 多个权限校验(与模式,必须满足所有权限): + +```Java +@SaCheckPermission( + value = { + "system:user:list", + "system:user:query" + }, + mode = SaMode.AND +) +``` + +#### 2.2:使用 `StpUtil` 工具类校验 +`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 + +- 判断当前用户是否拥有某个权限(返回 `boolean`): + +```Java +StpUtil.hasPermission("system:user:list"); +``` + +- 单个权限校验: + +```Java +StpUtil.checkPermission("system:user:list"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +- 多个权限校验(或模式,满足任意一个权限即可): + +```Java +StpUtil.checkPermissionOr("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +- 多个权限校验(与模式,必须满足所有权限): + +```Java +StpUtil.checkPermissionAnd("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +## 角色校验 +角色校验指的是校验用户是否拥有某个指定角色。 + +### 1:权限标识 +在本系统中,每个角色都拥有唯一的权限字符。 + +除了超级管理员角色外,其他角色的权限字符可以通过角色管理进行设置。 + +![输入图片说明](https://foruda.gitee.com/images/1701085080527279823/3255961d_4959041.png "屏幕截图") + +### 2:校验方法 +#### 2.1:使用 `@SaCheckRole` 注解校验 +`@SaCheckRole` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 + +- 单个角色校验 + +```Java +@SaCheckRole("superadmin") +``` + +- 多个角色校验(或模式,满足任意一个角色即可): + +```Java +@SaCheckRole( + value = { + "superadmin", + "admin" + }, + mode = SaMode.OR +) +``` + +- 多个角色校验(与模式,必须满足所有角色): + +```Java +@SaCheckRole( + value = { + "superadmin", + "admin" + }, + mode = SaMode.AND +) +``` + +#### 2.2:使用 `StpUtil` 工具类校验 +`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 + +- 判断当前用户是否拥有某个角色(返回 `boolean`): + +```Java +StpUtil.hasRole("superadmin") +``` + +- 单个权限校验: + +```Java +StpUtil.checkRole("system:user:list"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +- 多个权限校验(或模式,满足任意一个角色即可): + +```Java +StpUtil.checkRoleOr("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +- 多个权限校验(与模式,必须满足所有角色): + +```Java +StpUtil.checkRoleAnd("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +## 角色权限双重 `OR` 校验 +除了分开校验以外,权限和角色也可以进行组合,表示备选校验。 + +简单举个例子: + +假设某个 API 的权限码为 `system:user:list`,角色 `admin` 可以调用,则可以这样写: + +```Java +@SaCheckPermission(value = "system:user:list", orRole = "admin") +``` + +以上权限只需要满足任意一项即可。更多写法可以参考 `Sa-Token` [官方文档](https://sa-token.cc/doc.html#/use/at-check?id=_4%e3%80%81%e8%a7%92%e8%89%b2%e6%9d%83%e9%99%90%e5%8f%8c%e9%87%8d-or%e6%a0%a1%e9%aa%8c)。 + +## 当前用户的所有权限 +本系统中实现了 `StpInterface` 接口,可以对用户的权限以及角色进行管理,并且可以根据不同的用户类型进行设置。 + +具体参考类:`org.dromara.common.satoken.core.service.SaPermissionImpl` + +## 忽略权限校验 +请参考文档:[网关路由与放行](/ruoyi-cloud-plus/framework/basic/router_release?id=网关路由与放行) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md new file mode 100644 index 00000000..9b08f069 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/router_release.md @@ -0,0 +1,26 @@ +# 网关路由与放行 +- - - + +## 新增路由 +`ruoyi-gateway.yml` 配置文件 增加 `routers` 配置
+**注意: 路径格式为 `/服务路径/controller路径/接口方法路径` `*代表任意一级 **代表任意所有级`**
+下图代表 `resource/**` 将所有 `resource开头的路径` 都路由到 `ruoyi-resource` 服务
+例如: `/resource/sms/code` `resource路由到ruoyi-resource服务` `sms路由到对应的contrller` `code 路由到对应的接口`
+![输入图片说明](https://foruda.gitee.com/images/1669623462957266512/c282932b_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1669623527799049459/201a52db_1766278.png "屏幕截图") + +## 放行使用方式 +nacos 中 `ruoyi-gateway.yml` 白名单放行
+**注意: 放行路径格式为 `/服务路径/controller路径/接口方法路径` `*代表任意一级 **代表任意所有级`**
+示例: `/resource/sms/code` 代表 `ruoyi-resource服务 sms的controller code接口`
+![输入图片说明](https://foruda.gitee.com/images/1660622672461635175/屏幕截图.png "屏幕截图.png") + +## 注意事项 + +接口放行后不需要token即可访问
+但是没有token也就无法获取用户信息与鉴权 + +### 解决方案 +删除接口上的鉴权注解
+删除接口内获取用户信息功能
+删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md new file mode 100644 index 00000000..2e3cd739 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/social.md @@ -0,0 +1,68 @@ +# 第三方授权功能 +- - - +## 版本 >= 2.X + +## 前置说明 +1. 该功能基于 `JustAuth` 实现,支持多家平台实现第三方授权登录。 +2. 以 `Gitee` 授权登录为例进行本功能的使用说明。 +3. 其他第三方授权配置信息获取方式可参考 `JustAuth` [官方文档](https://www.justauth.cn/guide/)。
+ + ![输入图片说明](https://foruda.gitee.com/images/1690937097426867003/91d80587_4959041.png "屏幕截图") + +## 第三方授权配置 + +### 申请三方应用(以gitee为例) + +![输入图片说明](https://foruda.gitee.com/images/1700641775779304627/1cf1b56f_1766278.png "屏幕截图") + +### 更改后端配置 `application-dev.yml` + +![输入图片说明](https://foruda.gitee.com/images/1690936741844431943/580f8998_4959041.png "屏幕截图") + +**注:内网地址无法回调,请使用外网可以访问的地址。** + +![输入图片说明](https://foruda.gitee.com/images/1690940457570856867/ce22df18_4959041.png "屏幕截图") + +### 更改前端配置 `login.vue` + +![输入图片说明](https://foruda.gitee.com/images/1690937306197173754/5c1ece29_4959041.png "屏幕截图") + +## 授权登录(未绑定第三方平台) + +### 步骤一:个人中心授权第三方应用 + +![输入图片说明](https://foruda.gitee.com/images/1690938449386201097/ea375106_4959041.png "屏幕截图") + +### 步骤二:同意授权 + +![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") + +顶部出现授权成功,并跳转到系统首页。
+ +![输入图片说明](https://foruda.gitee.com/images/1690938559178527841/563168e4_4959041.png "屏幕截图")
+ +![输入图片说明](https://foruda.gitee.com/images/1690938636375977741/8ceb77cf_4959041.png "屏幕截图") + +查看第三方应用可看到授权成功的个人信息。
+ +![输入图片说明](https://foruda.gitee.com/images/1690938725512311321/5532a2a9_4959041.png "屏幕截图") + +## 授权登录(已绑定第三方平台) + +### 步骤一:点击登录页面图标 + +![输入图片说明](https://foruda.gitee.com/images/1690938908352243992/fd044381_4959041.png "屏幕截图") + +### 步骤二:同意授权 + +![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") + +## 解除授权绑定 + +### 步骤一:个人中心点击解绑第三方应用 + +![输入图片说明](https://foruda.gitee.com/images/1690939087877969002/4ef324e7_4959041.png "屏幕截图") + +### 步骤二:点击确定完成解绑 + +![输入图片说明](https://foruda.gitee.com/images/1690939108017661775/7236088d_4959041.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md new file mode 100644 index 00000000..b57c3f63 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/tenant.md @@ -0,0 +1,121 @@ +# 多租户功能 +- - - +## 版本 >= 2.X + +## 前置说明(重要) +1. 本框架多租户功能的实现是基于 [MyBatis-Plus 多租户插件](https://baomidou.com/pages/aef2f2/#tenantlineinnerinterceptor) 的,只支持最简单的隔离。 +2. 本系统默认开启多租户功能。 +3. 多租户业务表建表需要加上租户id `tenant_id`,可参考其他系统表。 +4. 非多租户表可在配置文件进行配置排除。 +5. 只有超级管理员支持切换租户。 + +## 多租户使用流程(先说结论再展开!) +0. 开启多租户配置(系统默认已经开启) +1. 登录界面(可以选择不同租户) +> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 +2. 设置多租户套餐 +3. 新增/修改租户(需要选择套餐) +4. 切换租户(仅超级管理员可操作) + +## 多租户配置 +`application-common.yml`
+ +> 开关 `enable` 节点不用废话。
+> 如果不需要过滤租户的表可在 `excludes` 节点下添加。 + +**注意: 如果已经基于租户模式启动了程序 关闭租户必须删除mysql与redis内的相关数据重新导入sql** + +![输入图片说明](https://foruda.gitee.com/images/1680168468127690787/2cd3279e_4959041.png "屏幕截图") + +## 忽略租户 + +1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: +``` +@InterceptorIgnore(tenantLine = "true", dataPermission = "false") +``` +**此处注意事项 使用此注解如果需要开启数据权限 dataPermission = "false" 必须添加 mp的注解默认是忽略数据权限的 会导致数据权限失效** + +2.如果需要在业务层忽略多租户,可调用以下方法(推荐使用): +``` +# 无返回值 +TenantHelper.ignore(() -> { 业务代码 }); +# 有返回值 +Class result = TenantHelper.ignore(() -> { return 业务代码 }); +``` + +## 动态切换租户 + +**仅适用于特殊需求业务(例如: 创建租户时, 对该租户操作一些数据, 或者需要去其他租户查一些数据等) 禁止乱用后果自负** + +``` +# 无返回值 +TenantHelper.dynamic(租户id, () -> { 业务代码 }); +# 有返回值 +Class result = TenantHelper.dynamic(租户id, () -> { return 业务代码 }); +``` + +## 登录界面 + +![输入图片说明](https://foruda.gitee.com/images/1680173982933030545/bca146d7_4959041.png "屏幕截图") + +> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 + +## 租户套餐管理 +### 租户套餐新增 +![输入图片说明](https://foruda.gitee.com/images/1680174317475230288/352957a1_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680174602877523112/fc194f17_4959041.png "屏幕截图") + +> 注: +> 1、先新增套餐再新增租户,因为租户新增之后无法修改所选套餐。 +> 2、租户所关联的套餐如果后续有修改可以进行同步。 + + +## 租户管理 +### 默认租户 +> 注:默认租户无法修改 + +![输入图片说明](https://foruda.gitee.com/images/1680174738913576400/b6aca11a_4959041.png "屏幕截图") + +### 新增租户 +#### 填写表单 +![输入图片说明](https://foruda.gitee.com/images/1680174945220618443/f7181b51_4959041.png "屏幕截图") + +#### 选择新增的租户套餐 +![输入图片说明](https://foruda.gitee.com/images/1680174991869792688/0dbaadd6_4959041.png "屏幕截图") + +#### 新增完成 +![输入图片说明](https://foruda.gitee.com/images/1680175033853525725/42e64b4d_4959041.png "屏幕截图") + +#### 登录租户 +![输入图片说明](https://foruda.gitee.com/images/1680176145378931134/e05f347e_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176208161104366/44a935f1_4959041.png "屏幕截图") + +### 修改租户 +#### 配置域名 +![输入图片说明](https://foruda.gitee.com/images/1680175251192690133/141fa6a6_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680175431036971650/db522d39_4959041.png "屏幕截图") + +#### 没有配置域名 +![输入图片说明](https://foruda.gitee.com/images/1680175541165540240/95e211f7_4959041.png "屏幕截图") + +#### 强调一下:这不是bug! +> 注:域名的配置就是为了绑定特定租户! + +### 同步套餐 +应用场景:租户套餐进行了修改,配置的菜单需要同步到特定租户。 +(不是所有租户都有更新套餐的权利, 这是跟钱挂钩的) + +> 点一下按钮的事,图略。 + +## 切换租户(仅超级管理员) +> 注:管理员切换租户不是切换用户,切换的只是数据,管理员拥有所有权限。 + +![输入图片说明](https://foruda.gitee.com/images/1680176324802967804/5c5d6fc3_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176431031189788/0c3f924c_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176496555243569/624ec677_4959041.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md new file mode 100644 index 00000000..99050fa7 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/basic/user.md @@ -0,0 +1,85 @@ +# 系统用户相关 +- - - + +> 框架采用sa-token控制权限 并对sa-token的api做了一定的业务封装
+ +## 用户登录 + +> 参考自带多种登录实现 不限制用户数据来源 只需要构建 LoginUser 即可完成登录
+> 例如: `同表不同类型` `不同表` `同表+扩展表`
+ +![输入图片说明](https://foruda.gitee.com/images/1699590555824776931/63d493fc_1766278.png "屏幕截图") + +## 获取用户信息 + +> 完成登录后会生成登录token返回给前端 前端需要再请求头携带token 后端方可获取到对应的用户信息 + +请求头传递格式: `Authorization: Bearer token` + +后端获取用户信息: +```java +LoginUser user = LoginHelper.getLoginUser(); +``` + +## 获取用户信息(基于token) +```java +LoginUser user = LoginHelper.getLoginUser(token); +``` + +## 获取登录用户id +```java +Long userId = LoginHelper.getUserId(); +``` + +## 获取登录用户账户名 +```java +String username = LoginHelper.getUsername(); +``` + +## 获取登录用户所属租户id +```java +String tenantId = LoginHelper.getTenantId(); +``` + +## 获取登录用户所属部门id +```java +Long deptId = LoginHelper.getDeptId(); +``` + +## 获取登录用户类型 +```java +UserType userType = LoginHelper.getUserType(); +``` + +## 获取登录用户其他扩展属性 +```java +Object obj = LoginHelper.getExtra(key); +``` + +## 设置登录用户其他扩展属性 + +参考登录设置 `clientId` 属性 + +![输入图片说明](https://foruda.gitee.com/images/1699591164562734430/42730add_1766278.png "屏幕截图") + +## 判断用户是否为超级管理员 + +```java +// 判断当前登录用户 +boolean b = LoginHelper.isSuperAdmin(); +// 判断用户基于id +boolean b = LoginHelper.isSuperAdmin(userId); +``` + +## 判断用户是否为租户管理员 + +```java +// 判断当前登录用户 +boolean b = LoginHelper.isTenantAdmin(); +// 判断用户基于角色组 +boolean b = LoginHelper.isSuperAdmin(rolePermission); +``` + +## 其他更多操作 +[Sa-Token 官方文档 - 登录认证](https://sa-token.cc/doc.html#/use/login-auth) + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md new file mode 100644 index 00000000..77cde6ef --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/about_join.md @@ -0,0 +1,12 @@ +# 关于多表查询 +- - - +## 建议单表查询 + +文章连接: [大连接查询分解好处](https://java.isture.com/db/mysql/mysql-x-optimize-decompose-connection.html) + +![输入图片说明](https://foruda.gitee.com/images/1678979482724037085/1e74f3e1_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1666336728402711844/52788205_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1666336945935088277/f60e3288_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1666336954686520161/c6c83adc_1766278.png "屏幕截图")
+**(上图出自 <高性能MySql>)** \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md new file mode 100644 index 00000000..c960140d --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/key.md @@ -0,0 +1,19 @@ +# 主键使用说明 +- - - +## 关于如何使用分布式id或雪花id + +参考 `MybatisPlusConfig` 如需自定义 修改 `Bean` 实现即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979401707903546/e25f6c06_1766278.png "屏幕截图") + +框架默认集成 雪花ID 只需全局更改 主键类型即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979411517764918/1470df04_1766278.png "屏幕截图") + +如单表使用 可单独配置注解 + +![输入图片说明](https://foruda.gitee.com/images/1678979416033986923/2a4c3736_1766278.png "屏幕截图") + +### 重点说明 +* 由于雪花id位数过长 `Long` 类型在前端会失真 +* 框架已配置序列化方案 超越 `JS` 最大值自动转字符串 参考 `BigNumberSerializer` 类 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md new file mode 100644 index 00000000..4c521ad1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/test.md @@ -0,0 +1,6 @@ +# 单元测试 +- - - +## 参考文章 +[SpringBoot 2.X 整合 JUnit5 及全方位使用手册](https://lionli.blog.csdn.net/article/details/127576604) +## 参考代码(1.4.0新增) +![输入图片说明](https://foruda.gitee.com/images/1666973151030696086/6d44f4c2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md new file mode 100644 index 00000000..2b4966dc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/explain/transaction.md @@ -0,0 +1,45 @@ +# 事务相关 +- - - +若依文档对事务注解的描述 [关于事务](https://doc.ruoyi.vip/ruoyi/document/htsc.html#%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86) 以下对多数据源事务做补充: + + +## 多服务多数据源事务(框架已默认对接 直接使用seata注解即可) + +框架支持对接 `seata` 保证分布式多数据源事务
+详情参考多数据源框架文档连接: https://www.kancloud.cn/tracy5546/dynamic-datasource/2268607 + +## 本地多数据源事务 +请使用 `@DSTransactional` 注解 会代理 `@DS` 注解切换后的数据源事务做回滚处理
+只要 `@DSTransactional` 注解下任一环节发生异常,则全局多数据源事务回滚。
+如果BC上也有 `@DSTransactional` 会有影响吗?答:没有影响的。 + +```java +//如AService调用BService和CService的方法,A,B,C分别对应不同数据源。 + +public class AService { + + @DS("a")//如果a是默认数据源则不需要DS注解。 + @DSTransactional + public void dosomething(){ + BService.dosomething(); + CService.dosomething(); + } +} + +public class BService { + + @DS("b") + public void dosomething(){ + //dosomething + } +} + +public class CService { + + @DS("c") + public void dosomething(){ + //dosomething + } +} +``` + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md new file mode 100644 index 00000000..be4ce445 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/api_encrypt.md @@ -0,0 +1,39 @@ +# 数据加解密 +- - - + +## 1:API 加密注解 `@ApiEncrypt` +1. 对于标注了 `@ApiEncrypt` 注解的接口,请求参数都必须进行加密。 +2. 注解的参数 `response` 为响应加密标识,默认 `false` 不加密,为 `true` 表示响应加密。 +3. 加密解密逻辑由过滤器实现,详情可参考 `org.dromara.common.encrypt.filter.CryptoFilter`。 + +## 2:API 加密配置 +`application-common.yml` + +![输入图片说明](https://foruda.gitee.com/images/1701133628809355269/8979704a_4959041.png "屏幕截图") + +`.env.development` / `.env.production` + +![输入图片说明](https://foruda.gitee.com/images/1709533252413969800/1d0dff25_1766278.png "屏幕截图") + +> 注: +> 1. 注意修改 Nacos 配置。 +> 2. 公私钥与前端配置文件互为配对,如果需要更换请一同更换。 +> 3. 后端公钥对应前端私钥;后端私钥对应前端公钥。 + +## 3:前端开启加密 +如果需要开启 API 加密,则需要修改 `request` 的 `headers` 内容: +```Javascript +headers: { + isEncrypt: true +} +``` + +![输入图片说明](https://foruda.gitee.com/images/1701137141916998346/5e839bbe_4959041.png "屏幕截图") + +## 4.关于请求响应参数加解密说明 + +如何加解密请求响应参数看这里 -> [关于请求响应参数解密](/questions/api_encrypt.md) + +## 密钥生成说明 + +![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md new file mode 100644 index 00000000..21114cd4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/dynamic_datasource.md @@ -0,0 +1,45 @@ +# 多数据源 +- - - + +### 框架默认 mysql 其他数据库使用说明 + +找到 `ruoyi-common-mybatis` 模块在 pom 文件内增加对应的jdbc依赖 + +![输入图片说明](https://foruda.gitee.com/images/1721098535176969987/d42870ca_1766278.png "屏幕截图") + + +### 关于多数据源事务 具体参考 `事务相关` 文档说明 + +### 多数据源框架功能介绍 +多数据源框架官方文档: [dynamic-datasource文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611) + +* 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 +* 支持数据库敏感配置信息 加密 ENC()。 +* 支持每个数据库独立初始化表结构schema和数据库database。 +* 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。 +* 支持 自定义注解 ,需继承DS(3.2.0+)。 +* 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。 +* 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。 +* 提供 自定义数据源来源 方案(如全从数据库加载)。 +* 提供项目启动后 动态增加移除数据源 方案。 +* 提供Mybatis环境下的 纯读写分离 方案。 +* 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。 +* 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。 +* 提供 基于seata的分布式事务方案。 +* 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。 + +### 用法说明 + +> 加载顺序 `方法 => 类 => 默认`
+ +![输入图片说明](https://foruda.gitee.com/images/1678979069737596299/abe8ae7f_1766278.png "屏幕截图") + +### 配置方式 + +![输入图片说明](https://foruda.gitee.com/images/1678979074000345758/b9238f0b_1766278.png "屏幕截图") + +### 数据库异构 + +例如: `mysql + oracle` 参考对应多数据源框架文档 [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource) + +![输入图片说明](https://foruda.gitee.com/images/1678979078387192317/2de94a78_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md new file mode 100644 index 00000000..729a3039 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/encrypt.md @@ -0,0 +1,38 @@ +# 数据加解密 +- - - +## 框架版本 >= 1.6.0 + +## 引入依赖 + +```xml + + com.ruoyi + ruoyi-common-encrypt + +``` + +## 功能说明 + +数据库 数据存储加密 查询解密功能
+支持加密算法: `BASE64` `AES` `RSA` `SM2` `SM4` + +## 注解 `@EncryptField` + +![输入图片说明](https://foruda.gitee.com/images/1675577493013639395/cd920f15_1766278.png "屏幕截图") + +## 用法说明 + +**详细用法可参考案例 TestEncryptController 测试数据库加解密功能** + +全局默认加密配置(如果注解不配置则使用全局配置) + +![输入图片说明](https://foruda.gitee.com/images/1675577674063566357/dee94786_1766278.png "屏幕截图") + +注解可自定义算法与配置 + +![输入图片说明](https://foruda.gitee.com/images/1675577725117970708/7ee7a833_1766278.png "屏幕截图") + +## 密钥生成说明 + +![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md new file mode 100644 index 00000000..5f706710 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/idempotent.md @@ -0,0 +1,29 @@ +# 防重幂等 +- - - +## 功能介绍 + +防重功能为防止两条相同的数据重复提交导致脏数据或业务错乱
+**注意: 重复提交属于小概率事件 请不要拿并发压测与之相提并论**
+框架防重功能参考 `美团GTIS防重系统` 使用 请求参数与用户Token或URL 生成全局业务ID
+有效防止 `同一个用户` 在 `限制时间` 内对 `同一个业务` 提交 `相同的数据` + +框架防重处理 `支持业务失败或异常` 快速释放限制
+业务处理成功后 会在设置时间内 限制同一条数据的提交
+**注意: 只对同一个用户的同一个接口提交相同的数据有效** + + + + +### 美团GTIS系统流程图 + +[美团 分布式系统互斥性与幂等性问题的分析与解决](https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html) + +![输入图片说明](https://foruda.gitee.com/images/1678979231862359032/34f030c5_1766278.png "屏幕截图") + +### 使用方法 + +在Controller标注 `@RepeatSubmit` 注解即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979236772683145/9fa27e5b_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678979240831458322/8e1fac4b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md new file mode 100644 index 00000000..ce089802 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/mail.md @@ -0,0 +1,15 @@ +# 邮件功能 +- - - +## 配置功能 + +修改配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1663555260932007318/fabb2bfa_1766278.png "屏幕截图") + +* `enabled` 为邮件功能开关 + +## 功能使用 + +参考 `demo` 模块 `MailController` 邮件演示案例 + +![输入图片说明](https://foruda.gitee.com/images/1663555374113593089/885b4db2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md new file mode 100644 index 00000000..3e2d92ba --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sensitive.md @@ -0,0 +1,33 @@ +# 数据脱敏 +- - - +## 功能说明 + +系统使用 `Jackson` 序列化策略 对标注了 `Sensitive` 注解的属性进行脱敏处理 + +## 使用教程 + +> 使用注解标注需要脱敏的字段 选择对应的策略 + +![输入图片说明](https://foruda.gitee.com/images/1699523591703893602/ffd6dba2_1766278.png "屏幕截图") + +* strategy 脱敏策略 +* roleKey 角色code(判断用户是否拥有角色权限) +* perms 权限code(判断用户是否拥有标识符权限) + +![输入图片说明](https://foruda.gitee.com/images/1678979315796014155/614adf91_1766278.png "屏幕截图") + +> 可再 `SensitiveStrategy` 内自定义策略 + +![输入图片说明](https://foruda.gitee.com/images/1678979319996224858/3b3e3c8b_1766278.png "屏幕截图") + +## 脱敏逻辑修改 + +> 系统使用通用接口处理是否需要脱敏 多个系统可以自定义不同的脱敏逻辑实现 + +![输入图片说明](https://foruda.gitee.com/images/1678979325448998856/b262e425_1766278.png "屏幕截图") + +> 系统默认处理逻辑为 根据角色与标识符或非管理员脱敏 可自行修改默认实现 + +![输入图片说明](https://foruda.gitee.com/images/1699523752627488891/f82f2f50_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md new file mode 100644 index 00000000..81fb345a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sms.md @@ -0,0 +1,51 @@ +# 短信模块 +- - - + +# 配置功能 + +### 版本: >= v2.1.0 + +已完成 sms4j 项目整合 文档地址: https://sms4j.com/doc3 + +配置方式 具体厂商配置扩展 可以查看sms4j文档 + +![输入图片说明](https://foruda.gitee.com/images/1705573035997239848/2ca8512d_1766278.png "屏幕截图") + +使用方式 参考文档各种写法 下方为 demo 模块提供示例 + +![输入图片说明](https://foruda.gitee.com/images/1705573001447394180/2bd726d0_1766278.png "屏幕截图") + +### 版本: v1.2.0 提供短信模块 + +短信模块采用SPI加载
+使用哪家的短信 引入哪家的依赖 即可动态加载
+目前支持: `阿里云` `腾讯云` 欢迎扩展PR其他 + +> 参考 `ruoyi-demo` pom文件写法 + +![输入图片说明](https://foruda.gitee.com/images/1678979157797419426/cc9b7444_1766278.png "屏幕截图") + +> 修改配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1678979163029635375/e5fd6e20_1766278.png "屏幕截图") + +* `enabled` 为短信功能开关 +* `endpoint` 为域名 各厂家域名固定 按照文档配置即可 +* `accessKeyId` 密钥id +* `accessKeySecret` 密钥密匙 +* `signName` 签名 +* `sdkAppId` 应用id 腾讯专用 + +## 功能使用 + +参考 `demo` 模块 `SmsController` 短信演示案例
+功能采用 `模板模式` 动态加载对应厂家的工具模板
+引入 `SmsTemplate` 即可使用 + +![输入图片说明](https://foruda.gitee.com/images/1678979168699323982/e9301e84_1766278.png "屏幕截图") + +## 重点须知 + +由于各厂家参数解析不一致 请遵守以下规则 + +![输入图片说明](https://foruda.gitee.com/images/1678979172581090456/ac1f10e8_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md new file mode 100644 index 00000000..ec51df7c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/sse.md @@ -0,0 +1,24 @@ +# SSE功能 +- - - + +## 框架版本 >= 2.2.1 + +## 配置说明 + +配置在 `ruoyi-resource` 目录下 远程调用可直接使用 `RemoteMessageService` 接口 + +![输入图片说明](https://foruda.gitee.com/images/1721986989993234455/4214cbbd_1766278.png "屏幕截图") + +* enabled 是否开启此功能 +* path 应用路径 + +## 使用方法 + +前端连接方式: `http://后端ip:端口/resource/sse?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` + +其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 + +`SseMessageUtils.sendMessage` 推送单机消息(特殊需求使用)
+`SseMessageUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
+`SseMessageUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
+`SseMessageUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md new file mode 100644 index 00000000..d0834ab8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/translation.md @@ -0,0 +1,44 @@ +# 翻译功能 +- - - +## 框架版本 >= 1.6.0 + +## 引入依赖包 + +```xml + + com.ruoyi + ruoyi-common-translation + +``` + +## 注解 + +![输入图片说明](https://foruda.gitee.com/images/1675575648043199227/d04b3e21_1766278.png "屏幕截图") + +`@Translation` 翻译注解 用于实体类字段上
+`@TranslationType` 翻译类别注解 用于实现类上标注与 `@Translation` 注解相同的 `type` 类型 实现翻译功能 + + +## 用法说明 + +默认提供功能 `用户id转账号(用户名)` `部门id转名称` `字典type转label` `ossId转url` + +![输入图片说明](https://foruda.gitee.com/images/1675575977860232549/143b74f8_1766278.png "屏幕截图") + +用户名翻译(映射翻译) 根据另一个映射字段 翻译保存到此字段 + +![输入图片说明](https://foruda.gitee.com/images/1675576044011477847/13eb9f57_1766278.png "屏幕截图") + +ossUrl翻译(直接翻译) 直接根据此字段值翻译后替换此字段值 + +![输入图片说明](https://foruda.gitee.com/images/1675576265894720924/70792f66_1766278.png "屏幕截图") + +字典翻译(其他扩展条件翻译) 根据`other`条件 自行定义如何使用 例如字典翻译`other`条件就是字典的唯一值 + +![输入图片说明](https://foruda.gitee.com/images/1675576391012282823/f95c5d78_1766278.png "屏幕截图") + +## 自定义扩展 + +实现接口 `TranslationInterface` 标注注解 `@TranslationType` 可参考框架默认实现 + +![输入图片说明](https://foruda.gitee.com/images/1676735454308997001/cfcf3590_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md new file mode 100644 index 00000000..55145bad --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/extend/websocket.md @@ -0,0 +1,39 @@ +# WebSocket功能 +- - - + +## 框架版本 >= 2.1.0 + +## 配置说明 + +配置在 `ruoyi-resource` 目录下 + +![输入图片说明](https://foruda.gitee.com/images/1688356273985385949/5e4d1de8_1766278.png "屏幕截图") + +* enabled 是否开启此功能 +* path 应用路径 +* allowedOrigins 设置访问源地址 + +**重点: 如关闭ws功能需连同前端ws开关一同关闭 不然前端启动会报错** + +![输入图片说明](https://foruda.gitee.com/images/1700644877512019497/052d2f46_1766278.png "屏幕截图") + +## 使用方法 + +前端连接方式: `ws://后端ip:端口/resource/websocket?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` + +**由于js不支持请求头传输故而采用参数传输 如支持请求头传输建议使用请求头传输** + +传输方式: +```js +headers: { + Authorization: "Bearer " + getToken(), + clientid: import.meta.env.VITE_APP_CLIENT_ID +} +``` + +其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 + +`WebSocketUtils.sendMessage` 推送单机消息(特殊需求使用)
+`WebSocketUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
+`WebSocketUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
+`WebSocketUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md new file mode 100644 index 00000000..f649197c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/framework/tree.md @@ -0,0 +1,91 @@ +# 项目结构 +- - - +## 目录结构 +v2.2.1 +~~~ +RuoYi-Cloud-Plus +├─ ruoyi-api // api模块 +│ └─ ruoyi-api-bom // api模块依赖管理 +│ └─ ruoyi-api-resource // 资源api模块 +│ └─ ruoyi-api-system // 系统api模块 +│ └─ ruoyi-api-workflow // 工作流api模块 +├─ ruoyi-auth // 认证服务 [9210] +├─ ruoyi-common // 通用模块 +│ └─ ruoyi-common-alibaba-bom // alibaba 依赖管理 +│ └─ ruoyi-common-bom // common 依赖管理 +│ └─ ruoyi-common-bus // 消息总线模块 +│ └─ ruoyi-common-core // 核心功能模块 +│ └─ ruoyi-common-dict // 字典集成模块 +│ └─ ruoyi-common-doc // 文档集成模块 +│ └─ ruoyi-common-dubbo // dubbo集成模块 +│ └─ ruoyi-common-elasticsearch // ES集成模块 +│ └─ ruoyi-common-encrypt // 数据加解密模块 +│ └─ ruoyi-common-excel // excel集成模块 +│ └─ ruoyi-common-idempotent // 幂等功能模块 +│ └─ ruoyi-common-job // job定时任务集成模块 +│ └─ ruoyi-common-json // json集成模块 +│ └─ ruoyi-common-loadbalancer // 团队负载均衡集成模块 +│ └─ ruoyi-common-log // 日志集成模块 +│ └─ ruoyi-common-logstash // elk日志集成模块 +│ └─ ruoyi-common-mail // 邮件集成模块 +│ └─ ruoyi-common-mybatis // mybatis数据库相关集成模块 +│ └─ ruoyi-common-oss // oss相关集成模块 +│ └─ ruoyi-common-prometheus // prometheus监控 +│ └─ ruoyi-common-redis // redis集成模块 +│ └─ ruoyi-common-satoken // satoken集成模块 +│ └─ ruoyi-common-seata // seata分布式事务集成模块 +│ └─ ruoyi-common-security // 框架权限鉴权集成模块 +│ └─ ruoyi-common-sensitive // 脱敏功能模块 +│ └─ ruoyi-common-sentinel // sentinel集成模块 +│ └─ ruoyi-common-skylog // skywalking日志收集模块 +│ └─ ruoyi-common-sms // 短信集成模块 +│ └─ ruoyi-common-social // 社交三方功能模块 +│ └─ ruoyi-common-sse // sse流推送模块 +│ └─ ruoyi-common-tenant // 租户功能模块 +│ └─ ruoyi-common-translation // 通用翻译功能 +│ └─ ruoyi-common-web // web服务集成模块 +│ └─ ruoyi-common-websocket // websocket服务集成模块 +├─ ruoyi-example // 例子模块 +│ └─ ruoyi-demo // 演示模块 [9401] +│ └─ ruoyi-test-mq // mq演示模块 [9402] +├─ ruoyi-gateway // 网关模块 [8080] +├─ ruoyi-modules // 功能模块 +│ └─ ruoyi-gen // 代码生成模块 [9202] +│ └─ ruoyi-job // 任务调度模块 [9203,9901] +│ └─ ruoyi-resource // 资源模块 [9204] +│ └─ ruoyi-system // 系统模块 [9201] +│ └─ ruoyi-workflow // 工作流模块 [9205] +├─ ruoyi-visual // 可视化模块 +│ └─ ruoyi-monitor // 服务监控模块 [9100] +│ └─ ruoyi-nacos // nacos服务模块 [8848,9848,9849] +│ └─ ruoyi-seata-server // seata服务模块 [7091,8091] +│ └─ ruoyi-sentinel-dashboard // sentinel控制台模块 [8718] +│ └─ ruoyi-snailjob-server // 任务调度控制台模块 [8800,17888] +├─ plus-ui // 前端框架 [80] +├─ config/nacos // nacos配置文件(需复制到nacos配置中心使用) +│ └─ sentinel-ruoyi-gateway.json // sentinel对接gateway限流配置文件 +│ └─ seata-server.properties // seata服务配置文件 +│ └─ application-common.yml // 所有应用主共享配置文件 +│ └─ datasource.yml // 所有应用共享数据源配置文件 +│ └─ ruoyi-auth.yml // auth 模块配置文件 +│ └─ ruoyi-gateway.yml // gateway 模块配置文件 +│ └─ ruoyi-gen.yml // gen 模块配置文件 +│ └─ ruoyi-job.yml // job 模块配置文件 +│ └─ ruoyi-monitor.yml // monitor 模块配置文件 +│ └─ ruoyi-resource.yml // resource 模块配置文件 +│ └─ ruoyi-sentinel-dashboard.yml // sentinel 控制台 模块配置文件 +│ └─ ruoyi-snailjob-server.yml // snailjob 控制台 模块配置文件 +│ └─ ruoyi-system.yml // systen 模块配置文件 +│ └─ ruoyi-workflow.yml // workflow 模块配置文件 +├─ config/grafana // grafana配置文件(需复制到grafana使用) +│ └─ Nacos.json // Nacos监控页面 +│ └─ SLS JVM监控大盘.json // JVM监控页面 +│ └─ Spring Boot 2.1 Statistics.json // SpringBoot监控页面 +├─ sql // sql脚本 +├─ docker // docker 配置脚本 +├─ .run // 执行脚本文件 +├─ .editorconfig // 编辑器编码格式配置 +├─ LICENSE // 开源协议 +├─ pom.xml // 公共依赖 +├─ README.md // 框架说明文件 +~~~ \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md new file mode 100644 index 00000000..290a4f9c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/home.md @@ -0,0 +1,137 @@ + +
+ +- - - +# 平台简介 +
+ +[![码云Gitee](https://gitee.com/dromara/RuoYi-Cloud-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Cloud-Plus) +[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Cloud-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Cloud-Plus) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus/blob/master/LICENSE) +[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Cloud-Plus) +
+[![RuoYi-Cloud-Plus](https://img.shields.io/badge/RuoYi_Cloud_Plus-2.2.1-success.svg)](https://gitee.com/dromara/RuoYi-Cloud-Plus) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.1-blue.svg)]() +[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() +[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() + +> RuoYi-Cloud-Plus `微服务通用权限管理系统` 重写 RuoYi-Cloud 全方位升级(不兼容原框架) + +> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
+活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 + +> 系统演示: [传送门](https://gitee.com/dromara/RuoYi-Vue-Plus/wikis/pages?sort_id=4836388&doc_id=1469725) 分布式集群版本(功能一致) + +# 本框架与RuoYi的功能差异 + +| 功能 | 本框架 | RuoYi | +|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| +| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | +| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | +| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | +| 分布式注册中心 | 采用 Alibaba Nacos 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Nacos 自行搭建纯官方版本不可靠 | +| 分布式配置中心 | 采用 Alibaba Nacos 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Nacos 自行搭建纯官方版本不可靠 | +| 服务网关 | 采用 SpringCloud Gateway 框架扩展了多种功能
例如:内网鉴权、请求体缓存、跨域配置、请求响应日志等 | 采用 SpringCloud Gateway 功能单一 | +| 负载均衡 | 采用 SpringCloud Loadbalancer 扩展支持了开发团队路由 便于多团队开发调试 | 采用 SpringCloud Loadbalancer 功能单一 | +| RPC远程调用 | 采用 全新 Apache Dubbo 3.X 历史悠远不用多说 | 采用 feign 功能有限编写方式 网络波动大 不稳定 | +| 分布式限流熔断 | 采用 Alibaba Sentinel 源码集成便于调试扩展与二次开发 框架还为其增加了各种监控 | 采用 Alibaba Sentinel 自行搭建纯官方版本不可靠 | +| 分布式事务 | 采用 Alibaba Seata 源码集成对接了Nacos与各种监控 简化了搭建部署流程 | 采用 Alibaba Seata 自行搭建纯官方版本 搭建繁琐与Nacos不挂钩 代码内使用方式怪异等 | +| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | +| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | +| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | +| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | +| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | +| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | +| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | +| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | +| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | +| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | +| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | +| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | +| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | +| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | +| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | +| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | +| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | +| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | +| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | +| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | +| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | +| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | +| 分布式日志中心 | 采用 ELK 业界成熟解决方案 实时收集所有服务的运行日志 快速发现定位问题 | 无 | +| 分布式搜索引擎 | 采用 ElasticSearch、Easy-Es 以 Mybatis-Plus 方式操作 ElasticSearch | 无 | +| 分布式消息队列 | 采用 支持 Kafka、RocketMQ、RabbitMQ 各种 延迟消息 事务消息 流消息 | 无 | +| 分布式消息总线 | 采用 SpringCloud Bus 实现事件总线 跨服务通知 支持 Kafka、RocketMQ、RabbitMQ | 无 | +| 分库分表功能 | 采用 Apache Sharding-Proxy 代理服务无入侵支持分库分表 只需编写分库分表规则即可 | 无 | +| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | +| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | +| 短信 | 支持 阿里、腾讯 只需在yml配置好厂家密钥即可使用 接口化支持扩展其他厂家 | 不支持 | +| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | +| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | +| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | +| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | +| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | +| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | +| 服务监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | +| 全方位监控报警 | 采用 Prometheus、Grafana 多样化采集 多模板大屏展示 实时报警监控 提供详细的搭建文档 | 无 | +| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | +| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | +| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | +| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | +| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | +| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | +| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | + +## 本框架与RuoYi的业务差异 + +| 业务 | 功能说明 | 本框架 | RuoYi | +|--------|-----------------------------------------|-----|------------------| +| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | +| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | +| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | +| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | +| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | +| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | +| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | +| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | +| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | +| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | +| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | +| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | +| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | +| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | +| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | +| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | +| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | + +## 演示图例 + +| | | +|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md new file mode 100644 index 00000000..19492b1e --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/1.Xinit.md @@ -0,0 +1,87 @@ +# 1.X项目初始化 +- - - +### 项目分支说明 +`master` 主分支 稳定发布分支
+`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
+`2.X` 新2.X大版本分支
+`future/*` 新功能预览分支 + +### 项目必备环境 +> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 + +* oracle jdk 8 11 (暂时不支持 17 不支持大于 jdk8_202 因为202是最后一个免费版本) +* mysql 5.7 8.0 (5.6未适配可能会有问题) +* oracle 11g 12c +* postgres 13 14 +* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) +* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 +* maven 3.6.3 3.8.X +* nodejs >= 12 +* npm 6.X 8.X (7.X确认有问题) +* nacos >= 2.X(框架1.3.0内置nacos) +* sentinel 框架内置 +* seata 框架内置 + +### 需勾选 maven 对应环境 +![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") + +### 默认 `JDK8` 如有变动 需更改以下配置 + +![输入图片说明](https://foruda.gitee.com/images/1686813181851830778/2dd7954c_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1686813189749486666/c526486c_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1686813196981178511/cd218705_1766278.png "屏幕截图") + +### sql导入 +将sql导入到与sql文件名对应的数据库(不要放到一个库下)
+ +![输入图片说明](https://foruda.gitee.com/images/1678981513725772842/8097a816_1766278.png "屏幕截图") + +### 使用内置 `ruoyi-naocs` 服务 从这开始 + +> 更改 ruoyi-nacos 数据库地址 + +![输入图片说明](https://foruda.gitee.com/images/1664422006264405180/cac5afc6_1766278.png "屏幕截图") + +**其余流程同下方步骤一致** + +### 自建 Nacos 从这开始 + +**Nacos 数据库指向 ry-config 数据库(此处重点: 此数据库为定制数据 未使用此库会无法读取配置)** + +> 将项目 `config/nacos` 下所有配置 复制到 `nacos` 内(建议手动复制内容 防止编码不一致问题) + +![输入图片说明](https://foruda.gitee.com/images/1678979826345958752/913142c9_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678979856705927770/75cc1e8c_1766278.png "屏幕截图") + +> 更改 `主pom文件` 对应环境的 `nacos` 地址 + +![输入图片说明](https://foruda.gitee.com/images/1678979881888833924/7e6a191f_1766278.png "屏幕截图") + +### 更改 `Nacos` 自定义配置 + +**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改** + +> `application-common.yml` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979889410167794/100db4ab_1766278.png "屏幕截图") + +> `datasource.yml` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979894464784408/0d020c07_1766278.png "屏幕截图") + +> `seata-server.properties` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979902433843257/12da2839_1766278.png "屏幕截图") + +### 使用内置 `ruoyi-seata-server` 服务 从这开始 + +执行 `ry-seata.sql` 文件 初始化服务端数据库
+修改 `nacos` 内的 `seata-server.properties` 的数据库地址
+启动 `ruoyi-seata-server` 服务即可 + +### 服务启动顺序说明 + +1. 必须启动基础建设: mysql redis nacos
+2. 可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启) sentinel(影响熔断限流) monitor(影响监控) xxljob(影响定时任务)
+3. 必须启动应用服务: gateway auth system
+4. 可选启动应用服务: resource(影响资源使用 文件上传 邮件 短信等) gen(代码生成) job(影响定时任务) demo(影响demo使用) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md new file mode 100644 index 00000000..bdc653bc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/deploy.md @@ -0,0 +1,118 @@ +# 应用部署 +- - - +## 版本 >= 1.3.0 + +### 请优先阅读 [idea环境配置](/ruoyi-cloud-plus/quickstart/idea_environment.md) + +## 手动部署 + +在服务器安装 `mysql` `redis` `nginx` `minio` 等其他组件 + +将项目内 `docker/` 文件夹下的文件内容 放到对应的组件内
+例如: 将项目内 `docker/nginx/nginx.conf` 配置文件 复制到 `nginx` 配置内
+将项目内 `docker/redis/redis.conf` 配置文件 复制到 `redis` 配置内
+ +并修改相关参数如 `前端页面存放位置` `后端Ip地址` 等使其生效 + +jar包部署后端服务 打包命令如下 +```mvn +mvn clean install -D maven.test.skip=true -P prod +``` +前端参考下方前端部署章节 + + +## docker 后端部署 + +### 请优先阅读 [idea环境配置](https://gitee.com/dromara/RuoYi-Cloud-Plus/wikis/pages?sort_id=5985190&doc_id=2056143) + +**重点: 一知半解的必看** +> [docker安装](https://lionli.blog.csdn.net/article/details/83153029)
+> [docker-compose安装](https://lionli.blog.csdn.net/article/details/111220320)
+> [docker网络模式讲解](https://lionli.blog.csdn.net/article/details/109603785)
+> [docker 开启端口 2375 供外部程序访问](https://lionli.blog.csdn.net/article/details/92627962) + +### 将配置使用FTP上传到根目录 +idea拖拽文件到远程目录即可上传
+![输入图片说明](https://foruda.gitee.com/images/1662109450908169859/eaac9299_1766278.png "屏幕截图") + +### 给docker分配文件夹权限 +**重点注意: 一定要确保目录 `/docker` 及其所有子目录 具有写权限 如果后续出现权限异常问题 重新执行一遍分配权限** +![输入图片说明](https://foruda.gitee.com/images/1662109847279259882/3a2202c1_1766278.png "屏幕截图") +```shell +chmod -R 777 /docker +``` +### 构建应用镜像 + +**1.需要先使用maven打包成jar包**
+![输入图片说明](https://foruda.gitee.com/images/1662110477410977621/c6931c42_1766278.png "屏幕截图") + +**2.执行构建**
+> 项目初始化后会自动生成构建镜像的运行配置
+配置好docker连接之后 运行如下即可构建对应的应用镜像 + +**重点注意: idea2024及以上版本要求必须在本地安装docker才可以执行如下操作** + +![输入图片说明](https://foruda.gitee.com/images/1662110192257483752/0f754b47_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1662120029312793237/89dee3e5_1766278.png "屏幕截图") + +**3.结构讲解**
+右键编辑 即可看到内部配置
+ +![输入图片说明](https://foruda.gitee.com/images/1662458355500139498/eaa26036_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1662458446794722159/32c086a7_1766278.png "屏幕截图") + + +### 创建基础服务 + +```shell +docker-compose up -d mysql nginx-web redis minio +``` + +### 创建中心服务(需要先构建服务镜像) + +1.X +```shell +docker-compose up -d nacos seata-server sentinel ruoyi-monitor ruoyi-xxl-job-admin +``` + +2.X +```shell +docker-compose up -d nacos seata-server sentinel ruoyi-monitor ruoyi-snailjob-server +``` + +### 创建业务服务(需要先构建服务镜像) + +```shell +docker-compose up -d ruoyi-gateway ruoyi-auth ruoyi-system ruoyi-resource +``` + +### docker其他操作(idea的docker插件 推荐使用) +![输入图片说明](https://foruda.gitee.com/images/1662458296425228696/90b4b4f8_1766278.png "屏幕截图") + + +## 前端部署 + +执行打包命令 +```shell +# 打包正式环境 +npm run build:prod +``` +打包后生成打包文件在 `ruoyi-ui/dist` 目录
+将 `dist` 目录下文件(不包含 `dist` 目录) 上传到部署服务器 `docker/nginx/html` 目录下(手动部署放入自己配置的路径即可)
+![输入图片说明](https://foruda.gitee.com/images/1662110914769648699/07f344c4_1766278.png "屏幕截图")
+重启 `nginx` 服务即可 + + +### 如需更改后端代理路径或者后端ip地址的话往下看 + +更改`nginx.conf`配置文件代理路径(注意: /开头/结尾) + +![输入图片说明](https://foruda.gitee.com/images/1660185698211067202/屏幕截图.png "屏幕截图.png") + +更改前端`.env.环境` 文件内的 `VITE_APP_BASE_API` + +![输入图片说明](https://foruda.gitee.com/images/1724318035232137124/5d035a09_1766278.png "屏幕截图") + +更改`nginx.conf`配置文件后端ip地址 + +![输入图片说明](https://foruda.gitee.com/images/1660185711265558730/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md new file mode 100644 index 00000000..8d68fa4d --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/extend_project.md @@ -0,0 +1,42 @@ +# 基于 RuoYi-Cloud-Plus 的扩展项目列表 +- - - +### 精品PR 欢迎投稿 +| 功能介绍 | PR地址 | +|-------------------------------------|------------------------------------------------------| +| 拖拽图片调整显示顺序 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/173 | +| 增加Jasypt加密库对配置文件加密 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/177 | +| 使用富文本wangeditor5替换Quill | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/213 | +| sentinel持久化nacos动态更改 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/37 | +| 集成screw数据库文档功能模块 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/42 | +| Excel导入模板增加批注支持 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/222 | +| 压缩包处理工具 支持本地文件/目录+oss文件/网络文件混合 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/44 | +| 添加websocket模块 支持satoken鉴权 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/65 | +| 数据库字段加解密(支持 base64 aes rsa sm2 sm4) | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/274 | +| 增加liquibase迁移数据库 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/299 | +| 增加OSS模块支持本地环境 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/353 | +| 扩展模块独立集成flyway | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/439 | +| 扩展模块独立集成go-view大屏看板 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/445 | +| 基于AmazonS3协议的分片上传 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/130 | +| 扩展forest http客户端 声明式http请求 二次封装像工具类 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/547 | +| 增加短链接生成工具 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/515 | +| 新增oss预签名上传工具组合使用异步客户端分片 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/522 | +| 新增规则引擎LiteFlow,SQL持久化接入,支持可视化页面 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/552 | +| 一键部署到私有Nexus仓库 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/181 | +| 服务状态监控发送邮件钉钉等 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/568 | +| 登录验证支持2FA验证 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/578 | + +### 欢迎投稿 项目介绍+项目地址 + + +| 项目介绍 | 项目地址 | +|--------------------------------|-------------------------------------------------------------------------| +| 分布式集群扩展 | https://gitee.com/dromara/RuoYi-Vue-Plus | +| Plus学习笔记(常规功能) | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-vue-plus/home | +| Plus学习笔记(微服务组件) | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-cloud-plus/home | +| 基于uniapp+TmUI从0开发 支持H5/小程序/安卓 | https://gitee.com/dapppp/ruoyi-plus-miniapp | +| 基于RuoYi-App框架二次修改使用Uniapp+Vue3 | https://gitee.com/wangying110166/ruo-yi-uni-app-plus | +| 基于RuoYi-App框架对接Plus后端 | https://gitee.com/FnTop/RuoYi-App-Plus | +| 基于vben(ant-design-vue)前端项目 | https://gitee.com/dapppp/ruoyi-plus-vben | +| 基于vue-next-admin的vue3+ts前端 | https://gitee.com/thiszhc/RuoYi-Vue3-UI | +| MybatisFlex版本 | https://gitee.com/yhan219/ruoyi-cloud-flex | + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md new file mode 100644 index 00000000..25a5fa3c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/idea_environment.md @@ -0,0 +1,38 @@ +# idea环境配置 +- - - +## 配置项目编码 +![输入图片说明](https://foruda.gitee.com/images/1662107706295343419/e27065a9_1766278.png "屏幕截图") + +## 配置运行看板 +![输入图片说明](https://foruda.gitee.com/images/1662108673306567278/8af97b47_1766278.png "屏幕截图") +### 配置spring与docker看板 +![输入图片说明](https://foruda.gitee.com/images/1662111392476935892/6b6760fb_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1662108865191892425/3c045999_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1662108877322329668/ddb6d93d_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1662108894122798039/6a53a38c_1766278.png "屏幕截图") + +## 配置服务器SSH连接 +进入 `Settings -> Tools -> SSH Configurations` 点击加号创建SSH连接配置
+填写 服务器IP 用户名 密码 端口号 点击 Test Connection 测试连接
+![输入图片说明](https://foruda.gitee.com/images/1662107776533098115/bd78467b_1766278.png "屏幕截图") +使用Terminal 工具 点击箭头找到上方创建的SSH连接配置
+选择即可进入SSH连接界面 在这里可以对服务器进行命令操作
+![输入图片说明](https://foruda.gitee.com/images/1662108010120640495/c70f9f9a_1766278.png "屏幕截图") + +## 配置服务器FTP连接 +进入 `Settings -> Build-> Deployment` 点击加号 选择SFTP 创建 FTP 连接配置
+选择之前创建好的SSH配置 点击 Test Connection 测试连接
+![输入图片说明](https://foruda.gitee.com/images/1662107899553257979/e2eeb7fd_1766278.png "屏幕截图") +在IDEA上方工具栏 找到 `Tools -> Deployment -> Browse Remote Host` 打开远程界面
+点击箭头找到我们上方配置的SFTP连接配置 即可连接到服务器的文件目录
+![输入图片说明](https://foruda.gitee.com/images/1662107974682787233/b8a601fd_1766278.png "屏幕截图") + +## 配置Docker连接 +### 可操作远程docker与构建上传docker镜像(代替原来maven docker插件) +tcp连接需要开放服务器2375端口
+ssh需要使用上方的SSH连接配置
+建议使用SSH连接
+![输入图片说明](https://foruda.gitee.com/images/1662108188005932060/75872bf8_1766278.png "屏幕截图") +配置好之后 在运行窗口会多出一个Docker图标 双击即可连接远程docker
+可以查看容器实时日志 启动 重启 停止 等操作
+![输入图片说明](https://foruda.gitee.com/images/1662108250902891875/b82d022b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md new file mode 100644 index 00000000..f6d4fadc --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/init.md @@ -0,0 +1,102 @@ +# 2.X项目初始化 +- - - +### 项目分支说明 + +`2.X` 主分支 新2.X版本 稳定发布分支
+`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
+`future/*` 新功能预览分支 + +### 项目必备环境 +> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 + +**注意: 禁止使用 `oraclejdk`(由于spring的bug导致打包运行会报错)** + +**Spring官方推荐使用JDK https://bell-sw.com/pages/downloads/** + +![输入图片说明](https://foruda.gitee.com/images/1720080025744223375/0213a652_1766278.png "屏幕截图") + +* openjdk-17/21 或 graalvm-community-jdk-17/21 [下载地址](https://github.com/graalvm/graalvm-ce-builds/releases) 版本 +* mysql 5.7 8.0 (其他版本未测试 如其他版本没问题 可以告知咱们) +* oracle >= 12c (其他版本未测试 如其他版本没问题 可以告知咱们) +* postgres 13 14 (其他版本未测试 如其他版本没问题 可以告知咱们) +* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) +* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 +* maven >= 3.8.X +* nodejs 18.18 (其他版本未测试 如其他版本没问题 可以告知咱们) +* npm >= 8.X (7.X确认有问题) +* idea 2022 2024 (一定不要使用2023后果自负 bug太多影响项目开发) +* nacos >= 2.X(框架已经内置 采用nacos官方jar包) +* sentinel 框架内置(采用sentinel官方jar包) +* seata 框架内置(采用seata官方jar包) + +### 需勾选 maven 对应环境 + +![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") + +### 默认 `JDK17` 如有变动 需更改以下配置 + +![输入图片说明](https://foruda.gitee.com/images/1678941027820943505/c688e01e_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678941120518807034/4d56fcc9_1766278.png "屏幕截图") + +### sql导入 + +将sql导入到与sql文件名对应的数据库(不要放到一个库下)
+默认数据库为mysql如需使用其他数据库 看这里 => [多数据库数据源](../framework/extend/dynamic_datasource.md)
+ +![输入图片说明](https://foruda.gitee.com/images/1717122730708924506/7f3aaecf_1766278.png "屏幕截图") + +### 使用内置 `ruoyi-naocs` 服务 从这开始 + +> 更改 ruoyi-nacos 数据库地址 + +![输入图片说明](https://foruda.gitee.com/images/1664422006264405180/cac5afc6_1766278.png "屏幕截图") + +**其余流程同下方步骤一致** + +### 自建 Nacos 从这开始 + +**Nacos 数据库指向 ry-config 数据库(此处重点: 此数据库为定制数据 未使用此库会无法读取配置)** + +> 将项目 `config/nacos` 下所有配置 复制到 `nacos` 内(建议手动复制内容 防止编码不一致问题) + +**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
+**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
+**注意: 不懂就不要乱改配置文件内容 框架内所有功能都是配置好的!!!不要画蛇添足**
+ +![输入图片说明](https://foruda.gitee.com/images/1678979826345958752/913142c9_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678979856705927770/75cc1e8c_1766278.png "屏幕截图") + +> 更改 `主pom文件` 对应环境的 `nacos` 地址 + +![输入图片说明](https://foruda.gitee.com/images/1678979881888833924/7e6a191f_1766278.png "屏幕截图") + +### 更改 `Nacos` 自定义配置 + +**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
+**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
+**忠告: 微服务配置相当复杂 请勿在不懂原理的情况下乱改**
+ +> `application-common.yml` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979889410167794/100db4ab_1766278.png "屏幕截图") + +> `datasource.yml` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979894464784408/0d020c07_1766278.png "屏幕截图") + +> `seata-server.properties` 更改 + +![输入图片说明](https://foruda.gitee.com/images/1678979902433843257/12da2839_1766278.png "屏幕截图") + +### 使用内置 `ruoyi-seata-server` 服务 从这开始 + +执行 `ry-seata.sql` 文件 初始化服务端数据库
+修改 `nacos` 内的 `seata-server.properties` 的数据库地址
+启动 `ruoyi-seata-server` 服务即可 + +### 服务启动顺序说明 + +1. 必须启动基础建设: mysql redis nacos
+2. 可选启动基础建设: minio(影响文件上传) seata(影响分布式事务 默认开启) sentinel(影响熔断限流) monitor(影响监控) snailjob(影响定时任务)
+3. 必须启动应用服务: gateway auth system
+4. 可选启动应用服务: resource(影响资源使用 websocket 文件上传 邮件 短信等) workflow(工作流) gen(代码生成) job(影响定时任务) demo(影响demo使用) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md new file mode 100644 index 00000000..907c7fc7 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/power_job_init.md @@ -0,0 +1,33 @@ +# 搭建PowerJob任务调度中心(2.X分支已废弃) +- - - +### 废弃原因 + +接到大量投诉 使用困难 用法诡异 各种问题等 + +### 配置调度中心客户端 +> 查看ruoyi-job配置文件(默认情况下无需做任何更改) +> +![输入图片说明](https://foruda.gitee.com/images/1688013407489024239/9b619e0d_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `server-address` 为调度中心地址 +* `server-name` 为调度中心服务名 +* `app-name` 为执行器组账户名(需在调度中心注册方可登录查看) + +### 启用调度中心 +**需执行 ry-job.sql 默认账号密码 `ruoyi-worker` `123456` 账号在数据库里 可以在页面修改密码** +
+ +![输入图片说明](https://foruda.gitee.com/images/1688634898607827011/8853b387_1766278.png "屏幕截图") + +> 在 `ruoyi-visual -> ruoyi-powerjob-server` 启动 +> +![输入图片说明](https://foruda.gitee.com/images/1688013606234848334/cf2028cd_1766278.png "屏幕截图") + +> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-powerjob-server服务的配置文件**) +> +![输入图片说明](https://foruda.gitee.com/images/1688013663152608235/6c5d6a9c_1766278.png "屏幕截图") + +> 也可配置邮件发送 钉钉推送 和 mongodb存储 +> +![输入图片说明](https://foruda.gitee.com/images/1687335842722317559/f875c07a_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md new file mode 100644 index 00000000..25c21ebb --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/snail_job_init.md @@ -0,0 +1,38 @@ +# 搭建SnailJob任务调度中心(2.2.0新功能) +- - - + +### 视频介绍 + +[Snail job任务调度中心:轻松掌握任务管理、重试机制和任务编排](https://www.bilibili.com/video/BV19i421m7GL/) + +### 配置调度中心客户端 +> 修改主服务配置文件 +> + +![输入图片说明](https://foruda.gitee.com/images/1716175076777941469/db565dc1_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `server.server-name` 为调度中心服务名(自动从Nacos获取服务 支持动态扩容调度中心) +* `server.address` 为调度中心地址(服务名优先 ip垫底) +* `server.port` 为调度中心通信端口 +* `token` 为组通信校验token(可在调度中心组配置更换) +* `group-name` 为执行器组 +* `namespace` 作用域(不同作用域相互隔离请勿填错) + +### 启用调度中心 +**需执行 ruoyi-job.sql 默认账号密码 `admin` `admin` 账号在数据库里 可以在页面修改密码** +
+ +![输入图片说明](https://foruda.gitee.com/images/1688634898607827011/8853b387_1766278.png "屏幕截图") + +> 在 `ruoyi-visual -> ruoyi-snailjob-server` 模块启动 +> +![输入图片说明](https://foruda.gitee.com/images/1716175119324078438/ca667a0c_1766278.png "屏幕截图") + +> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-snailjob-server服务的配置文件 支持多种不同数据库**) +> +![输入图片说明](https://foruda.gitee.com/images/1688013663152608235/6c5d6a9c_1766278.png "屏幕截图") + +### 快速入门 + +[Snailjob快速入门 基本使用介绍](https://juejin.cn/post/7412955032092442675) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md new file mode 100644 index 00000000..121a094d --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-cloud-plus/quickstart/worker_init.md @@ -0,0 +1,52 @@ +# 工作流初始化 +- - - + +### 注意事项 + +设置 RabbitMQ 配置 `application-common.yml` 配置文件 (可使用其他例如 kafka、rocketmq 详见 ruoyi-common-bus 模块) + +此功能用于跨服务同步流程与业务状态 MQ安装方式可参考文档扩展功能 + +![输入图片说明](https://foruda.gitee.com/images/1718728432072816698/47eadbb1_1766278.png "屏幕截图") + + +### 工作流使用及配置方式 + +1.找到项目中bpmn文件夹 + +![输入图片说明](https://foruda.gitee.com/images/1714211764058540441/5c8b97af_5363069.png "屏幕截图") + +2.启动项目找到流程定义通过**部署流程文件**将bpmn文件夹下**模型.zip**上传 + +![输入图片说明](https://foruda.gitee.com/images/1714211950485333575/1e2b3ff4_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212113004821592/96586e69_5363069.png "屏幕截图") + +3.导入**模型.zip**后将会出现以下列表,默认使用**leave1**,test_leave为请假申请表名称 + +![输入图片说明](https://foruda.gitee.com/images/1714212222766335759/1227bbd6_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212493602552742/9e0258b1_5363069.png "屏幕截图") + +**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** + +![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") + + +4.新增一条请假申请,提交后将会得到如下信息 + +![输入图片说明](https://foruda.gitee.com/images/1714212617432902105/3609f6ef_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212630860787365/2922d38e_5363069.png "屏幕截图") + +5.关于如何切换一个新的流程使用,当前默认使用得KEY为leave1 ,我们切换到leave2使用,我们只需点击绑定业务将表名绑定,重新发起一个新的请假申请就可以得到一个新的流程信息 + +![输入图片说明](https://foruda.gitee.com/images/1714212876442323110/4554ea95_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714213037864274694/613149f5_5363069.png "屏幕截图") + +**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** + +![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212963457174382/add768db_5363069.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md new file mode 100644 index 00000000..9fd7aad1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/_sidebar.md @@ -0,0 +1,64 @@ + +- **特别赞助** +- [![输入图片说明](https://foruda.gitee.com/images/1704162419429172656/d0521e59_1766278.png "2024-01-02=>2028-01-02")](http://ccflow.org/?frm=ryPlus) +- [![输入图片说明](https://foruda.gitee.com/images/1705569347386939952/3f187980_1766278.jpeg "2024-01-18=>2025-01-18")](http://www.shuduokeji.com) +- [![输入图片说明](https://foruda.gitee.com/images/1711681233267310022/2ffbcff2_1766278.png "2024-03-29=>2025-03-29")](https://www.jnpfsoft.com/index.html?from=plus-doc) + + +* **简介** + * [项目简介](/ruoyi-vue-plus/home.md) + * [更新日志](/ruoyi-vue-plus/changlog.md) +* **快速开始** + * [项目初始化](/ruoyi-vue-plus/quickstart/init.md) + * [5.X新功能介绍](/ruoyi-vue-plus/quickstart/5.Xnew.md) + * [4.X项目初始化](/ruoyi-vue-plus/quickstart/4.Xinit.md) + * [工作流初始化](/ruoyi-vue-plus/quickstart/worker_init.md) + * [搭建Admin监控](/ruoyi-vue-plus/quickstart/admin_init.md) + * [搭建SnailJob调度中心](/ruoyi-vue-plus/quickstart/snail_job_init.md) + * [(废弃)搭建PowerJob调度中心](/ruoyi-vue-plus/quickstart/power_job_init.md) + * [(废弃)搭建XXLJob调度中心](/ruoyi-vue-plus/quickstart/xxl_job_init.md) + * [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) + * [应用部署](/ruoyi-vue-plus/quickstart/deploy.md) + * [扩展项目](/ruoyi-vue-plus/quickstart/extend_project.md) +* **框架功能** + * [项目结构](/ruoyi-vue-plus/framework/tree.md) + * [软件架构图](/ruoyi-vue-plus/framework/architecture_diagram.md) + * 框架相关 + * [创建新模块](/ruoyi-vue-plus/framework/association/new_module.md) + * [修改包名](/ruoyi-vue-plus/framework/association/update_package_name.md) + * [接口文档](/ruoyi-vue-plus/framework/association/doc.md) + * [修改应用路径](/ruoyi-vue-plus/framework/association/update_url.md) + * [国际化](/ruoyi-vue-plus/framework/association/i18n.md) + * 基础功能 + * [系统用户相关](/ruoyi-vue-plus/framework/basic/user.md) + * [权限控制](/ruoyi-vue-plus/framework/basic/permissions_control.md) + * [导出功能](/ruoyi-vue-plus/framework/basic/export.md) + * [导入功能](/ruoyi-vue-plus/framework/basic/import.md) + * [参数校验](/ruoyi-vue-plus/framework/basic/param_check.md) + * [代码生成](/ruoyi-vue-plus/framework/basic/code_generate.md) + * [分页功能](/ruoyi-vue-plus/framework/basic/page.md) + * [OSS功能](/ruoyi-vue-plus/framework/basic/oss.md) + * [数据权限](/ruoyi-vue-plus/framework/basic/permissions.md) + * [接口放行](/ruoyi-vue-plus/framework/basic/interface_release.md) + * [多租户功能](/ruoyi-vue-plus/framework/basic/tenant.md) + * [第三方授权功能](/ruoyi-vue-plus/framework/basic/social.md) + * [客户端管理功能](/ruoyi-vue-plus/framework/basic/client.md) + * 扩展功能 + * [多数据源](/ruoyi-vue-plus/framework/extend/dynamic_datasource.md) + * [短信模块](/ruoyi-vue-plus/framework/extend/sms.md) + * [邮件功能](/ruoyi-vue-plus/framework/extend/mail.md) + * [防重幂等](/ruoyi-vue-plus/framework/extend/idempotent.md) + * [数据脱敏](/ruoyi-vue-plus/framework/extend/sensitive.md) + * [API加解密](/ruoyi-vue-plus/framework/extend/api_encrypt.md) + * [数据加解密](/ruoyi-vue-plus/framework/extend/encrypt.md) + * [翻译功能](/ruoyi-vue-plus/framework/extend/translation.md) + * [WebSocket功能](/ruoyi-vue-plus/framework/extend/websocket.md) + * [SSE功能](/ruoyi-vue-plus/framework/extend/sse.md) + * [Skywalking链路监控](/ruoyi-vue-plus/framework/extend/skywalking.md) + * [对接MaxKey单点登录](/ruoyi-vue-plus/framework/extend/maxkey.md) + * [对接TOPIAM单点登录](/ruoyi-vue-plus/framework/extend/topiam.md) + * 功能说明 + * [事务相关](/ruoyi-vue-plus/framework/explain/transaction.md) + * [单元测试](/ruoyi-vue-plus/framework/explain/test.md) + * [主键使用说明](/ruoyi-vue-plus/framework/explain/key.md) + * [关于多表查询](/ruoyi-vue-plus/framework/explain/about_join.md) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md new file mode 100644 index 00000000..ac8eb907 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/changlog.md @@ -0,0 +1,2028 @@ +# 更新日志 +- - - + +## v5.2.2 - 2024-08-26 + +### 重大改动 + +* 增加 ruoyi-common-sse 模块 支持SSE推送 比ws更轻量更稳定的推送 +* 增加 springboot snailjob 等 actuator 账号密码认证 杜绝内外网信息泄漏问题 +* 增加 重构代码生成器 集成anyline开源框架 支持400+种数据库适配 + +### 依赖升级 + +* update springboot 3.2.6 => 3.2.9 +* update snailjob 1.0.1 => 1.1.2 +* update mapstruct-plus 1.4.3 => 1.4.4 +* update hutool 5.8.27 => 5.8.31 解决hutool不兼容jakarta问题 +* update anyline 8.7.2-20240808 +* update sms4j 3.2.1 => 3.3.2 +* update redisson 3.31.0 => 3.34.1 +* update mapstruct-plus 1.3.6 => 1.4.3 +* update lombok 1.18.32 => 1.18.34 +* update easyexcel 3.3.4 => 4.0.2 +* update springdoc 2.5.0 => 2.6.0 +* update flowable 7.0.0 => 7.0.1 + +### 功能更新 + +* update 优化 去除日志部署环境判断 通过日志级别控制 +* update 优化 忽略租户与忽略数据权限支持嵌套使用(感谢 amadeus5201) +* update 优化 租户相关controller 增加租户开关配置控制是否注册 +* update 优化 移除 alibaba ttl 与线程池搭配有问题(可传递但无法清除与更新) +* update 优化 个人中心编辑 忽略数据权限 +* update 优化 兼容部分用户不想给用户分配角色与部门的场景 +* update 优化 租户套餐重名校验 +* update 优化 部门下存在岗位不允许删除 +* update 优化 角色编辑状态未校验问题 +* update 优化 用户脱敏增加编辑权限标识符 +* update 优化 代码生成器 自动适配oss翻译 +* update 优化 临时升级 undertow 版本 解决虚拟线程溢出问题 +* update 优化 支持通过配置文件关闭工作流 +* update 优化 增加mybatis-plus填充器兜底策略 +* update 优化 TenantSpringCacheManager 处理逻辑 +* update 优化 角色权限判断 +* update 优化 增加删除标志位常量优化查询代码 +* update 优化 监控使用独立web依赖 +* update 优化 更多脱敏策略(感谢 hemengji) +* update 优化 设置nginx sse相关代理参数 +* update 优化 调整默认推送使用SSE +* update 优化 Monitor监控服务通知分类打印(感谢 AprilWind) +* update 优化 限流注解 又写key又不是表达式的情况 +* update 优化 WorkflowUtils查询用户信息发送消息未查询邮件和手机号(感谢 yanzy) +* update 优化 注释掉其他数据库 jdbc 依赖 由用户手动添加 +* update 优化 oracle snailjob 兼容低版本oracle索引名称长度限制 +* update 优化 数据权限支持通过菜单标识符获取数据所有权 +* update 优化 数据权限支持自定义连接符 +* update 优化 TestDemo 删除前校验数据权限 +* update 优化 更换docker镜像底层系统 避免无字体情况 + +### 问题修复 + +* fix 修复 三方登录构建去除无用代码 +* fix 修复 多线程对同一个session发送ws消息报错问题 +* fix 修复 依赖漏洞 限制部分依赖版本 +* fix 修复 excel 基于其他字段 合并错误问题 +* fix 修复 一级缓存key未区分租户问题 +* fix 修复 id字符串格式转换错误问题 +* fix 修复 登出无法正确删除对应的租户数据问题 +* fix 修复 登录错误锁定不区分租户问题 +* fix 修复 转换模型缺少分类字段 +* fix 修复 权限标识符处理未设置成功状态问题 +* fix 修复 无法导入 bpmn 类型文件问题 + +### 前端改动 + +* update element-plus 2.7.5 => 2.7.8 +* update vue 3.4.25 => 3.4.34 +* update vite 5.2.10 => 5.2.12 +* add 增加 使用 vueuse 编写 sse 推送功能 +* update 优化 使用匹配模式简化预编译配置 +* update 优化 时间搜索组件统一 +* update 优化 oss 配置按钮 使用ossConfig权限标识符与oss权限分离 +* update 优化 类型报错问题 +* update 优化 切换租户后刷新首页 +* update 优化 实现表格行选中切换 +* update 优化 使用 vueuse 重构 websocket 实现 +* update 优化 代码生成器编辑页禁用缓存 防止同步后页面不更新问题 +* update 优化 调整默认推送使用SSE +* fix 修复 租户套餐导出路径错误问题 +* fix 修复 登出后重新登录 sse推送报错问题 + + +## v5.2.1 - 2024-07-09 + +### 功能更新 + +* update 优化 更改prod环境 snailjob状态 默认启用 +* update 优化 替换过期方法 +* update 优化 租户列表接口 避免登录之后列表被域名过滤 +* update 优化 获取用户账户方法 LoginHelper#getUsername(感谢 AprilWind) +* update 优化 用户ID查询角色列表代码实现(感谢 AprilWind) +* update 优化 大数据量下join卡顿问题 使用子查询提高性能 +* update 优化 修改路由name命名规则 防止重复路由覆盖问题(感谢 玲娜贝er) +* update 优化 修改 snailjob 默认端口 避免与系统内置端口冲突问题 +* update 优化 isTenantAdmin 空校验 +* update 优化 webscoket 配置与异常拦截 +* update 优化 更新 redis 密码策略(密码必填 升级需注意) +* update 优化 更新使用 Spring 官方推荐 JDK +* update 优化 StreamUtils 抽取 findFirst findAny 方法 +* update 优化 工作流相关代码方法 + +### 问题修复 + +* fix 修复 postgres flowable sql 缺失字段问题 +* fix 修复 新版上传未设置acl问题 +* fix 修复 get路径特殊规则 导致 actuator 泄漏问题 [issue#4f9ceb0a](https://gitee.com/dromara/RuoYi-Vue-Plus/commit/4f9ceb0a8057284a0d9d69da58df630d8bc2e84f) +* fix 修复 pg数据库 用户查询报错问题 +* fix 修复 isLogin 方法抛异常无法正常返回值问题 + +### 前端改动 + +* update 优化 工作流选人改为懒加载窗口 +* update 优化 路由name重复检查 +* update 优化 eslint 语法 +* update 优化 动态创建组件实例时, 设置路由name为组件名 解决缓存问题 +* fix 修复 由于没有await 导致执行顺序不可控 +* fix 修复 富文本编辑器 添加之后内容未清理问题 + +## v5.2.0 - 2024-06-20 + +### 重大改动 + +* 集成 flowable 增加工作流相关功能(感谢 May) +* 集成 snailjob 移除 powerjob(投诉的人太多使用成本太高)(感谢 dhb52) +* 升级 aws s3 升级到 2.X 性能大幅提升 +* 优化 数据权限 数据加密 使用预扫描mapper注解提升代码性能(感谢 老马) +* 新增 caffeine 减少将近90%的redis查询提高性能 + +### 依赖升级 + +* update springboot 3.1.7 => 3.2.6 支持虚拟线程 +* update springboot-admin 3.1.8 => 3.2.3 +* update mybatis-plus 3.5.4 => 3.5.7 适配更改代码 +* update springdoc 2.2.0 => 2.5.0 +* update easyexcel 3.3.3 => 3.3.4 +* update redisson 3.24.3 => 3.31.0 +* update lombok 1.18.30 => 1.18.32 +* update sms4j 2.2.0 => 3.2.1 支持自定义配置key 可用于多厂商多租户等 +* update satoken 1.37.0 -> 1.38.0 +* update hutool 5.8.22 => 5.8.26 +* update mapstruct-plus 1.3.5 => 1.3.6 +* update lock4j 2.2.5 => 2.2.7 +* update dynamic-ds 4.2.0 => 4.3.1 + +### 功能更新 + +* update 优化 三方登录不同域名问题 采用新方案 +* update 优化 获取aop代理的方式 减少与其他使用aop的功能冲突的概率 +* update 优化 token无效时关闭ws连接(感谢 AprilWind) +* update 优化 移除表单构建菜单(没有可用组件 用处不大以后再考虑) +* update 优化 切换动态租户 默认线程内切换(如需全局 手动传参) +* update 优化 代码生成注释,删除无用引入(感谢 AprilWind) +* update 优化 代码生成 el-radio 标签过期属性 +* update 优化 异常处理器自动配置 +* update 优化 文件下载使用对流下载降低内存使用(感谢 PhoenixL) +* update 优化 去除gc日志参数(有需要自己加) +* update 优化 拆分异常处理器 +* update 优化 常规web异常状态码 +* update 优化 设置静态资源路径防止所有请求都可以访问静态资源 +* update 优化 redis 对Long值的存储类型不同问题 +* update 优化 去除加密请求类型限制 +* update 优化 mp多租户插件注入逻辑 +* update 优化 RedisUtils 支持忽略租户 +* update 优化 更新ip地址xdb文件 +* update 优化 验证码背景色改为浅灰色 +* update 优化 mybatis依赖设置为可选依赖 避免出现不应该注入的情况 +* update 优化 GET 方法响应体支持加密 +* update 优化 excel插件合并策略 去除被合并单元格的非首行内容(感谢 司猫子) +* update 优化 下拉选接口数据权限 +* update 优化 OssFactory 获取实例锁性能 +* update 优化 使用翻译注解简化用户查询 调整用户查询逻辑 +* update 优化 框架整体提高查询性能 +* update 优化 将p6spy配置文件统一放置到 common-mybatis 插件包内 + +### 新增功能 + +* add 新增 分布式锁Lock4j异常拦截器 +* add 新增 个人中心-在线设备管理 +* add 新增 岗位编码与部门编码并将岗位调整到部门下(感谢 AprilWind) +* add 新增 BaseMapperPlus提供可选是否抛异常selectVoOne方法(感谢 秋辞未寒) +* add 新增 用户、部门、角色、岗位 下拉选接口与代码实现优化 +* add 增加 StringUtils.isVirtual 方法 +* add 增加 JustAuth 整合 TopIam 单点登录 + +### 问题修复 + +* fix 修复 websocket clientid 参数不走mvc拦截器 无法生效问题 +* fix 修复 oss未使用租户 拼接租户id null问题 +* fix 修复 用户昵称修改后未清除对应缓存问题(感谢 zhuweitung) +* fix 修复 图片预览问题(感谢 AprilWind) +* fix 修复 三方账号可以绑定多平台账号问题 +* fix 修复 主建错别字(感谢 good) +* fix 修复 兼容redis5.0出现的问题 +* fix 修复 部分浏览器无法获取加密响应头问题 +* fix 修复 用户未设置部门 登录报错问题 +* fix 修复 excel 表达式字典 下拉框导出格式错误 +* fix 修复 提升锁的作用域 并采用双重校验锁(感谢 fanc) +* fix 修复 用户登录查询部门缓存无法获取租户id问题 +* fix 修复 关闭租户功能 三方登录报错问题 + + +### 前端改动 + +* update element-plus 2.7.5 +* update vite 5.2.10 +* update vue 3.4.25 +* update vue-router 4.3.2 +* update nodejs 升级到最低 18.18.0 +* update 优化 跟密码相关的默认前端关闭防重功能 +* update 优化 点击左边菜单时页面空白或者刷新整个页面的问题 +* update 优化 el-select 与 el-input 全局样式 +* update 优化 首页打开topNav不展开菜单问题 +* update 优化 支持全局开启或关闭接口加密功能 +* update 优化 密码校验策略增加非法字符限制 +* update 优化 图片上传组件增加压缩功能支持 可自行开关(感谢 fengheguai) +* update 优化 request请求类判断请求头方式 +* update 优化 更改客户端状态接口 使用clientId传参 +* update 优化 ws开关改为常开(vite5修复了崩溃bug) +* fix 修复 移动端下 无法展开菜单问题 +* fix 修复 面板因为min width原因收缩不全 +* fix 修复 文件预览大写后缀不展示的问题(感谢 北桥) +* fix 修复 i18n无感刷新问题 +* fix 修复 websocket 非index页面刷新无法重连问题 + +## v5.1.2 - 2023-12-22 + +### 依赖升级 + +* update springboot 3.1.5 => 3.1.7 +* update mybatis-boot 3.0.2 => 3.0.3 优化依赖传递 +* update powerjob 4.3.3 => 4.3.6 +* update easyexcel 3.3.2 => 3.3.3 +* update transmittable-thread-local 2.14.2 => 2.14.4 +* update justauth 1.16.5 => 1.16.6 +* update redisson 3.24.1 => 3.24.3 修复订阅重启连接超时问题 + +### 功能更新 + +* update 优化 为 admin 模块 单独增加 ratelimiter 模块 +* update 优化 验证码接口 增加限流配置 +* update 优化 excel合并注解会根据第一合并列的结果来决定后续的列合并 (感谢 Simple) +* update 优化 SocialUtils 代码 +* update 优化 删除无用异常类 +* update 优化 补全三方登录校验国际化 +* update 优化 sms组件 预留自动配置类 +* update 更新 关于数据库的说明 +* update 优化 sms组件 预留自动配置类 +* update 优化 将 OSS配置 改为全局模式 降低使用难度 保留sql便于用户自行扩展(常规项目用不上配置分多租户) +* update 优化 细化oss配置管理权限控制 +* update 优化 开启 redisson 脚本缓存 减少网络传输 +* update 优化 删除 hikaricp 官方不推荐使用的配置 jdbc4 协议自带校验方法 +* update 优化 减少 PlusSaTokenDao 不必要的查询优化性能 +* update 优化 更新用户异常提示 使用登录账号 +* update 优化 使用登录用户判断是否登录 提高效率 +* update 优化 重构 LoginHelper 将本地存储代码操作封装 +* update 优化 getTenantId 判断是否开启多租户 +* update 优化 Dockerfile 使用shell模式 支持环境变量传入jvm参数 +* update 优化 WebSocketUtils 连接关闭改为警告 +* update 优化 excel多sheet页导出 (感谢 May) +* update 优化 删除无用接口实现 +* update 优化 jvm参数调整 全面启用zgc +* update 优化 使用动态租户重构业务对租户的逻辑 +* update 优化 TenantHelper 动态租户支持函数式方法 +* update 优化 支持多租户绑定相同的三方登录 +* update 优化 更新用户登录信息方法忽略数据权限 +* update 优化 补全三方绑定时间字段 删除无用excel注解 +* update 优化 将登录记录抽取到监听器统一处理 +* update 优化 租户插件 ignoreTable 方法支持动态租户 + +### 新增功能 + +* add 新增 RedisUtils.setObjectIfExists 如果存在则设置方法 +* add 新增 丰富RedisUtils对List Set类型的操作 +* add 新增 翻译组件 用户昵称翻译实现 +* add 新增 响应加密功能 支持注解强制加密接口数据 (感谢 MichelleChung) + +### 问题修复 + +* fix 修复 selectDictTypeByType 查询方法错误问题 +* fix 修复 一些不正常类无法加载报错问题 +* fix 修复 powerjob sql脚本针对其他数据库转义符问题 (感谢 branches) +* fix 修复 MybatisSystemException 空指针问题 +* fix 修复 excel合并注解会根据第一合并列的结果来决定后续的列合并 +* fix 修复 session 多账号共用覆盖问题 改为 tokenSession 独立存储 +* fix 修复 token 失效后 登录获取用户null问题 +* fix 修复 powerjob部署方案 高版本nginx不生效问题 +* fix 修复 OssFactory 并发多创建实例问题 +* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 + +### 前端改动 + +* update 优化 用户头像 img 变量无确定类型问题 +* update 优化 细化oss配置管理权限控制 +* update 优化 明确打包命令 +* update 优化 代码中存在的警告 +* update 优化 前端白名单页面放行逻辑 +* update 优化 页面关于权限标识符说明 +* fix 修复 append-to-body 编写错误 (感谢 Ai3_刘小龙) +* fix 关闭动态路由tab页签时不清理组件缓存 (感谢 NickLuo) +* fix 删除重复环境变量ElUploadInstance (感谢 棉花) +* fix 修复 在线用户 强推按钮点击取消控制台警告问题 +* fix 修复 字典使用 default 样式报警告问题 + +## v4.8.2 - 2023-11-27 + +### 依赖升级 + +* update springboot 2.7.17 => 2.7.18 升级到2.X最终版本(官方停更) +* update mybatis-plus 3.5.3.2 => 3.5.4 +* update springboot 2.7.14 => 2.7.17 +* update satoken 1.36.0 => 1.37.0 +* update aws-java-sdk-s3 1.12.400 => 1.12.540 +* update vue-quill 1.1.0 => 1.2.0 + +### 功能更新 + +* update 优化 页面关于权限标识符说明 +* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 +* update 优化 部门数据权限使用默认兜底方案 +* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) +* update 优化 补全代码生成 columnList 接口参数注解缺失 +* update 优化 操作日志 部门信息完善 vue3页面 +* update 优化 AddressUtils 兼容linux系统本地ip +* update 优化 操作日志 部门信息完善 (感谢 柏竹) +* update 优化 数据权限 减少二次校验查询 +* update 优化 vue3 版本用户初始密码从字典查询 +* update 优化 富文本Editor组件检验图片格式 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 全局数据存储用户编号 +* update 优化 菜单管理类型为按钮状态可选 + +### 问题修复 + +* fix 修复 OssFactory 并发多创建实例问题 +* fix 修复 demo的form字段有误 (感谢 dhb52) +* fix 修复 延迟队列在投递消息未到达时间的时候 服务死机导致重启收不到消息 +* fix 修复 数据权限优化后 update delete 报null问题 +* fix 修复 五级路由缓存无效问题 +* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 +* fix 修复 内链iframe没有传递参数问题 +* fix 修复 外链带端口出现的异常 +* fix 修复 普通角色编辑使用内置管理员code越权问题 +* fix 修复 代码生成 是否必填与数据库不匹配问题 +* fix 修复 HeaderSearch组件跳转query参数丢失问题 +* fix 修复 树结构代码生成新增方法赋值错误 (感谢 这夏天依然平凡) + +## v5.1.1 - 2023-11-14 + +### 依赖升级 + +* update springboot 3.1.3 => 3.1.5 +* update springboot 2.7.14 => 2.7.17(扩展服务) +* update springboot-admin 3.1.5 => 3.1.7 +* update satoken 1.35.0.RC => 1.37.0 +* update mybatis-plus 3.5.3.2 => 3.5.4 适配mp新版本改动 +* update dynamic-ds 4.1.3 => 4.2.0 +* update bouncycastle 1.72 => 1.76 +* update poi 5.2.3 => 5.2.4 +* update redisson 3.23.2 => 3.24.1 +* update hutool 5.8.20 => 5.8.22 +* update lombok 1.18.26 => 1.18.30(适配支持jdk21) +* update vue-quill 1.1.0 => 1.2.0 + +### 功能更新 + +* update 优化 数据权限拦截器优先判断方法是否有效 提高性能减少无用sql解析 +* update 优化 适配 maxkey 新版本 +* update 优化 @Sensitive脱敏增加角色和权限校验 (感谢 盘古给你一斧) +* update 优化 部门数据权限使用默认兜底方案 +* update 优化 更改默认日志等级为info 避免日志过多(按需开启debug) +* update 优化 登录策略代码优化(感谢 David Wei) +* update 优化 补全代码生成 columnList 接口参数注解缺失 +* update 优化 nginx 配置支持 websocket +* update 优化 notice 新增通知公告发送ws推送 +* update 优化 websocket 模块减少日志输出 增加登录推送 +* update 优化 重构登录策略增加扩展性降低复杂度 +* update 优化 addressUtils 兼容linux系统本地ip +* update 优化 补全操作日志部门数据 +* update 优化 支持数据库操作在非web环境下切换租户 +* update 优化 排除powerjob无用的依赖 减少打包30M体积 +* update 优化 删除 satoken yml 时间配置 此功能已迁移至客户端管理 +* update 优化 redis 集群模式注释说明 +* update 优化 客户端禁用限制 +* update 优化 登录日志, 在线用户展示信息(增加 客户端, 设备类型)(感谢 MichelleChung) +* update 优化 限制框架中的fastjson版本 +* update 优化 数据权限 减少二次校验查询 +* update 优化 将部门id存入token避免过度查询redis +* update 优化 增加租户ID为Null错误日志 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) +* update 优化 为 sys_grant_type 字典增加样式 +* update 优化 代码生成 页面输入框样式 +* update 优化 全业务分页查询增加排序规则避免因where条件导致乱序问题 +* update 优化 登录接口租户id被强制校验问题 +* update 优化 加密模块 支持父类统一使用加密注解(感谢 Tyler Ge) +* update 优化 将graalvm镜像更新为openjdk镜像 需要的人自行切换即可 +* update 优化 部分使用者乱设权限导致无法获取用户信息 增加权限提示 +* update 优化 表格列的显示与隐藏小组件(感谢 bestrevens) +* update 优化 增加表单构建不能使用说明 +* update 优化 富文本Editor组件检验图片格式 +* update 优化 操作日志列表新增IP地址查询 +* update 优化 菜单管理类型为按钮状态可选 +* update 优化 用户初始密码从参数配置查询 +* update 优化 通过参数键名获取键值接口的返回体(感谢 David Wei) +* update 优化 字典标签支持数组和多标签(感谢 抓蛙师) + +### 新增功能 + +* add 新增 websocket 群发功能 +* add 新增 前端接入websocket接收消息(感谢 三个三) + +### 问题修复 + +* fix 修复 oss服务无法连接 导致业务异常问题 查询不应该影响业务 +* fix 修复 租户id为null 无法匹配字符串导致的嵌套key问题 +* fix 修复 部门管理orderNum排序失效问题 +* fix 修复 外链带端口出现的异常 +* fix 修复 普通角色编辑使用内置管理员code越权问题 +* fix 修复 代码生成 是否必填与数据库不匹配问题 +* fix 修复 用户注册接口校验用户名不区分租户问题 +* fix 修复 错误增加组导致的校验不生效问题 +* fix 修复 新增校验主键id问题 +* fix 修复 powerjob 使用 nginx 部署无法访问的问题 +* fix 修复 SysUserMapper 内标签使用错误(不影响使用) +* fix 修复 新增或编辑 SysOssConfig 数据后 推送到 redis 数据不完整 +* fix 修复 树表生成查询变量使用错误 +* fix 修复 个人信息修改密码接口隐藏新旧密码参数明文(感谢 bleachtred) +* fix 修复 删除字段后 * update sql 未更新问题 +* fix 修复 三方登录支付宝source与实际支付宝业务code不匹配问题 +* fix 修复 五级路由缓存无效问题 +* fix 修复 内链iframe没有传递参数问题 +* fix 修复 绑定第三方帐号参数“wechar”更正为“wechat” (感谢 scmiot) +* fix 修复 用户注册缺失 clientid 问题 +* fix 修复 HeaderSearch组件跳转query参数丢失问题 +* fix 修复 自定义字典样式不生效的问题 +* fix 修复 login 页面 loading 未关闭问题 + +## v4.8.1 - 2023-09-25 + +### 依赖升级 + +* update springboot 2.7.15 => 2.7.16 +* update springboot-admin 2.7.10 => 2.7.11 +* update satoken 1.35.0.RC => 1.36.0 +* update lombok 1.18.26 =. 1.18.30 +* update mybatis-plus 3.5.3.1 => 3.5.3.2 +* update easyexcel 3.3.1 => 3.3.2 +* update hutool 5.8.18 => 5.8.20 + +### 功能更新 + +* update 优化 重置密码注释参数中文解释错误 +* update 优化 getTokenActivityTimeout => getTokenActiveTimeout +* update 优化字典标签支持传分隔符分隔的字符串和数组,优化渲染效果 +* update 优化 控制台debuger位置错误问题 +* update 优化 TopNav 菜单样式 +* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 +* update 优化 用户管理 只查询未禁用的部门角色岗位数据 +* update 优化 岗位如果绑定了用户则不允许禁用 +* update 优化 部门与角色如果绑定了用户则不允许禁用 +* update 优化 加密实现 使用 EncryptUtils 统一处理 +* update 优化 excel导出字典转下拉框 无需标记index自动处理 +* update 优化 excel 导出字典默认转为下拉框 +* update 优化 删除一些跟 swagger 有关的字眼 避免误解 +* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 +* update 优化 RedisCacheController 注释错误 +* update 优化 xxljob 端口随着主应用端口飘逸 避免集群冲突 +* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 + +### 问题修复 + +* fix 修复 代码生成后 vo 定义 'serialVersionUID' 字段的不可序列化类 +* fix 修复 自定义字典样式不生效的问题 +* fix 修复 布局配置失效问题 +* fix 修复 新建用户可能会存在的越权行为 +* fix 修复 字典缓存删除方法参数错误问题 +* fix 修复 修复树模板父级编码变量错误 +* fix 修复 有界队列与优先队列 错误使用问题 +* fix 修复 升级 mp 版本导致的问题 +* fix 修复 vue3 版本注册页验证码不显示问题 +* fix 修复 加密模块数据转换异常问题 +* fix 修复 动态设置 token 有效期不生效问题 +* fix 修复 token 过期登出无法清理在线用户问题 + + +## v5.1.0 - 2023-09-05 + +# 开发历程 + +* 2023年5月 开始 5.1.0 计划 历经1个月的设计与讨论 +* 2023年6月 开始着手开发 历经2个多月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 +* 2023年8月 开始公测 历经将近1个月的公测与修复工作(期间成功支持多位使用者生产使用) +* 2023年9月初 正式发布(经过多个小伙伴的生产实践 已基本可尝试生产使用) +> 关于4.X的说明 由于SpringBoot2.X与vue2.X均在11月底停止维护
+> 故而咱们vue版本4.X也无法再继续更新
+> 介于4.X的用户量特别庞大 功能也非常的稳定
+> 计划于11月底同Boot2.X一同停止更新但还会持续维护修复bug(修复的形式为直接提交到4.X分支停止发版)
+ +# 视频介绍 + +为了更好的让大家了解 5.1.0 作者录制了相关的视频 供大家快速了解上手 + +* 5.1.0 新功能与变更介绍: https://www.bilibili.com/video/BV1fj411y71X/ +* 搭建与运行: https://www.bilibili.com/video/BV1Fg4y137JK/ +* 生产环境搭建部署: https://www.bilibili.com/video/BV1mL411e7ha/ + +# 更新日志 + +### 重大更新 + +* [重大更新] 优化 相关代码 完成代码生成多数据源统一存储(感谢 WangBQ !pr349) +* [不兼容更新] 移除 原短信功能 集成更强大的 sms4j 短信工具包(感谢 友杰 !pr367) +* [不兼容更新] 对接 powerjob 实现分布式任务调度 删除原有 xxljob 原因为社区不更新功能太少只支持mysql(感谢 yhan219 !pr359) +* [重大更新] 新增 三方授权绑定登录功能 基于 justauth 支持市面上大部分三方登录(感谢 三个三 !pr370) +* [不兼容更新] 新增 客户端授权功能 不需要更改任何代码即可完成多端动态对接(感谢 Michelle.Chung !pr379) +* [重大更新] 新增 前后端接口请求加密传输 基于AES+RSA动态高强度加密(感谢 wdhcr !pr377) +* [重大更新] 新增 三方授权登录 对接 maxkey 单点登录 +* [不兼容更新] 优化 redis序列化配置 更改为通用格式(升级需清除redis所有数据) + +### 依赖升级 + +* update springboot 3.0.7 => 3.1.3 +* update springboot-admin 3.1.3 => 3.1.5 +* update springdoc 2.1.0 => 2.2.0 +* update spring-mybatis 3.0.1 => 3.0.2 +* update mybatis-plus 3.5.3.1 => 3.5.3.2 +* update easyexcel 3.2.1 => 3.3.2 +* update mapstruct-plus 1.2.3 => 1.3.5 解决修改实体类 idea不编译问题 +* update satoken 1.34.0 => 1.35.0.RC 优化过期配置 支持多端token自定义有效期 +* update dynamic-ds 3.6.1 => 4.1.3 支持 SpringBoot3 +* update sms4j 2.2.0 +* update hutool 5.8.18 => 5.8.20 +* update redisson 3.20.1 => 3.23.4 +* update lock4j 2.2.4 => 2.2.5 +* update aws-java-sdk-s3 1.12.400 => 1.12.540 +* update maven-surefire-plugin 3.0.0 => 3.1.2 + +### 功能更新 + +* update 优化 excel 导出合并 在初始化类时进行数据的处理 +* update 优化 简化 flatten 插件语法写法 +* update 优化 支持本地虚拟域名调试(感谢 代星登 !pr363) +* update 重构 将框架内的 swagger 命名更改为 springdoc 命名避免误解 +* update 重构 将系统内置配置放置到 common 包内独立加载 不允许用户随意修改 +* update 优化 切换 maven 仓库到 华为云(aliyun依赖不更新拉取不到) +* update 优化 升级 satoken 支持多端 token 自定义有效期功能 +* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 +* update 优化 在全局异常拦截器中增加两类异常处理 +* update 优化 提供powerjob完整sql脚本 降低用户使用难度 +* update 优化 StreamUtils 其他方法过滤null值(感谢 bleachtred !pr390) +* update 优化 powerjob 端口随着主应用端口飘逸 避免集群冲突 +* update 优化 角色权限支持仅本人权限查看 解决无法查看自己创建的角色问题 +* update 修改代码生成模版,日期范围统一采用addDateRange方法(感谢 LiuHao !pr397) +* update 优化 树表生成前端缺少 children 字段 +* update 优化 CryptoFilter null判断工具 +* update 优化 websocket 路径与 cloud 版本保持一致 +* update 优化 更新登录策略返回值(感谢 zlyx) +* update 修改代码生成模板,调整列表打开对话框和接口请求顺序 +* update 优化 SaInterceptor 拦截器判断 token 客户端id是否有效(感谢 zlyx !pr402) +* update 优化 excel 导出字典默认转为下拉框 +* update 优化 兼容 clientid 通过 param 传输 +* update 优化 excel导出字典转下拉框 无需标记index自动处理(感谢 一夏coco) +* update 优化 简化线程池配置 +* update 优化 屏蔽 powerjob 无用的心跳日志 +* update 优化 适配 mysql 8.0.34 升级连接机制 +* update 优化 加密实现 使用 EncryptUtils 统一处理 +* update 优化 删除字典无用状态字段(基本用不上 禁用后还会导致回显问题) +* update 优化 部门与角色如果绑定了用户则不允许禁用 +* update 优化 岗位如果绑定了用户则不允许禁用 +* update 优化 用户管理 只查询未禁用的部门角色岗位数据 +* update 优化 登录用户增加昵称返回 +* update 优化 将部门管理 负责人选项改为下拉框选择(感谢 Lionel !pr410) +* update 优化 全局异常处理器 业务异常不输出具体堆栈信息 减少无用日志存储 +* update 优化 登录用户缓存 去除冗余统一存储 +* update 优化 放宽菜单权限 角色关联菜单无需管理员 + +### 新增功能 + +* add 增加 RedisUtils 批量删除 hash key 方法 +* add 新增 Oss 上传 File 文件方法(感谢 jenn !pr362) +* add 增加 excel 导出下拉框功能 +* add 新增 RedisUtils.setObjectIfAbsent 如果不存在则设置方法 + +### 修复问题 + +* fix 修复 脱敏注解标记位置错误 +* fix 修复 OssClient 实例多租户相同key缓存覆盖问题 +* fix 修复 关闭多租户 脱敏判断问题 +* fix 修复 OssClient 切换服务 实例不正确问题(感谢 jenn !pr360) +* fix 修复 传参类型不正确导致 postgreSql 同步套餐报错问题 +* fix 修复 参数类型修改 未修改校验注解 +* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题(感谢 konbai !pr366) +* fix 修复 common-core 包使用aop注解 但未添加aop实现类导致单独使用报错问题 +* fix 修复 Mapper 多参数未加 @Param 注解问题 +* fix 修复 邮箱登录 查询值错误问题 +* fix 修复 用户篡改管理员角色标识符越权问题 +* fix 修复 字典缓存注解使用错误问题 +* fix 修复 查询部门下拉树未过滤数据权限问题 +* fix 修复 CacheName 缓存key存储错误问题 +* fix 修复 代码生成 前端添加或修改表单修改列生成问题 +* fix 修复 新增角色使用内置管理员标识符问题 +* fix 修复 代码生成 前端添加或修改表单修改列生成问题 +* fix 修复 token 过期登出无法清理在线用户问题 +* fix 修复 加密模块数据转换异常问题 +* fix 修复 可能导致异常类无法反序列化问题 +* fix 修复 代码生成 编辑按钮刷新列表问题 +* fix 修复 客户端编辑时授权类型变更未保存的问题(感谢 David Wei !pr400) +* fix 修复 有界队列与优先队列 错误使用问题 +* fix 修复 修复树模板父级编码变量错误 +* fix 修复 部署部分系统出现乱码问题 +* fix 修复 一级菜单无法显示问题 +* fix 修复 可能会存在的越权行为(感谢 丶Stone !pr416) +* fix 修复 代码生成页面参数缺少逗号问题 + +### 移除功能 + +* remove 移除原有短信功能(建议使用sms4j) +* remove 移除xxljob功能(建议使用powerjob) + + +## v4.8.0 - 2023-07-10 + +### 重大更新 + +* [重大更新] 新增 sms4j 短信融合框架整合(支持数十种短信厂商接入、发送限制、负载均衡等功能) +* [不兼容更新] 移除 原短信功能(建议使用新 sms4j 功能) +* [重要迁移] 迁移 vue3 前端到主仓库统一维护 + +### 依赖升级 + +* update springboot 2.7.11 => 2.7.13 +* update satoken 1.34.0 => 1.35.0.RC +* update easyexcel 3.2.1 => 3.3.1 +* update sms4j 2.2.0 + +### 功能更新 + +* update 优化 StreamUtils 方法过滤null值 +* update 优化 页签在Firefox浏览器被遮挡 +* update 优化 在全局异常拦截器中增加两类异常处理 +* update 优化 下载zip方法增加遮罩层(感谢@梁剑锋) +* update 优化 用户昵称非空校验 +* update 优化 修改角色如果未绑定用户则无需清理 +* update 优化 RepeatSubmitAspect 逻辑避免并发请求问题 +* update 优化 satoken 过期配置 支持多端token自定义有效期 +* update 优化 加密注解注释错误 +* update 优化 切换 maven 仓库到华为云(aliyun 不可用) +* update 优化 excel 导出存在合并项时在初始化类时进行数据的处理避免多次调用(感谢@yueye) +* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 + +### 新增功能 + +* add 新增 RedisUtils.setObjectIfAbsent 不存在则设置方法 +* add 新增 Excel 导出附带有下拉框(字典自动导出为下拉框) 可自定义多级下拉框(感谢@Emil.Zhang) +* add 新增 OssClient File 文件上传方法 +* add 增加 RedisUtils 批量删除 hash key 方法 + +### 问题修复 + +* fix 修复 新增角色使用内置管理员标识符问题 +* fix 修复 缓存监控图表 支持跟随屏幕大小自适应调整(感谢@抓蛙师) +* fix 修复 防重组件 错删注解问题 +* fix 修复 CacheName 缓存key存储错误问题 +* fix 修复 字典缓存注解使用错误问题 +* fix 修复 用户篡改管理员角色标识符越权问题 +* fix 修复 登录校验错误次数未达到上限时 错误次数缓存未设置有效时间问题 +* fix 修复 OssClient 切换服务 实例不正确问题 +* fix 修复 element ui 因版本而未被工具识别问题(感谢@梁剑锋) +* fix 修复 admin监控 切换tab页需要重复登录问题 + +## v5.0.0 - 2023-05-19 + +# 开发历程 + +* 2022年11月 开始5.X计划 历经2个月的设计与讨论 +* 2023年1月 开始着手开发 历经3个月的开发 特别感谢团队的小伙伴与一些热心的粉丝 参与功能开发与测试 +* 2023年4月 开始公测 历经将近2个月的公测与修复工作(期间成功支持多位使用者生产使用) +* 2023年5月底 正式发布 虽然已经有生产实践 但是springboot3.0与jdk17使用者还处于少数 另外5.X后续还有一些不兼容更新 求稳者建议在等一等 +* 关于4.X的说明 由于springboot2.X 与 vue2.X 匀在年底停止维护 故此4.X也将于年底同boot2一同停止维护 + +# 视频介绍 + +为了更好的让大家了解 5.X 作者录制了相关的视频 供大家快速了解上手 + +* 搭建与运行: https://www.bilibili.com/video/BV1Fg4y137JK/ +* 新功能与变更介绍: https://www.bilibili.com/video/BV1Us4y1m7ky/ +* 生产环境搭建部署: https://www.bilibili.com/video/BV1mL411e7ha/ + +# 更新日志 + +### 重大更新 + +* [不兼容升级] java 版本从 jdk 8 升级到 jdk 17 且需要使用 graalvm 运行(暂时未解决原生jdk存在的问题) +* [不兼容升级] springboot 升级 3.0 版本 +* [不兼容升级] 重构 项目模块结构 采用插件化结构 易扩展易解耦 +* [不兼容升级] com.sun.mail 更改为 jakarta.mail 修改最新写法 +* [不兼容升级] javax.servlet 替换为 jakarta.servlet 更新所有代码 +* [简化性升级] 默认开启复杂结构 resultMap 自动映射 简化xml编码(多结构实体需带上主键id) +* [数据库改动] 更新 create_by update_by 字段类型 (保存用户id) +* [数据库改动] 新增 create_dept 字段 (保存创建部门id) +* [不兼容更新] system 模块 所有实体类均使用 bo|vo 规范化 +* [重大更新] 新增 多租户功能设计 整体框架代码结构与数据库更改 +* [重大更新] 新增 mapstruct-plus 替换 BeanUtil 与 BeanCopyUtils 工具 +* [不兼容更新] 重构 登录注解接口与cloud版本统一接口路径 +* [不兼容更新] 重构 BaseMapperPlus接口 去除 `@param Mapper` 泛型 +* [不兼容更新] 移除 vue2 前端工程 全面启用 vue3 +* [重大更新] 新增 vue3 + TS 版本前端(独立仓库后续与Cloud版本共用) +* [重大更新] 增加 websocket 模块 支持token鉴权 支持分布式集群消息同步 +* [重大更新] 框架文档全面翻新 https://plus-doc.dromara.org + +### 依赖升级 + +* update java 1.8 => 17 +* update springboot 2.7.7 => 3.0.7 +* update springboot-admin 2.7.10 => 3.0.4 +* update springdoc 1.6.14 => 2.1.0 +* update lock4j 2.2.3 => 2.2.4 +* update dynamic-ds 3.5.2 => 3.6.1 +* update easyexcel 3.1.5 => 3.2.1 +* update hutool 5.8.11 => 5.8.18 +* update redisson 3.19.2 => 3.20.1 +* update lombok 1.18.24 => 1.18.26 +* update spring-boot.mybatis 2.2.2 => 3.0.1 +* update mapstruct-plus 1.2.3 +* update maven-compiler-plugin 3.10.1 => 3.11.0 +* update maven-surefire-plugin 3.0.0-M7 => 3.0.0 +* update docker mysql 8.0.31 => 8.0.33 +* update docker nginx 1.22.1 => 1.32.4 +* update docker redis 6.2.7 => 6.2.12 +* update docker minio RELEASE.2023-04-13T03-08-07Z + +### 功能更新 + +* update 适配 AsyncConfig 替换过期继承类改为实现 AsyncConfigurer 接口 +* update 适配 redis 新版本配置文件写法 +* update 适配 获取redis 监控参数接口 替换过期语法 +* update 适配 sa-token 替换新依赖 sa-token-spring-boot3-starter +* update 适配 springboot-admin 改为最新 spring-security 写法 +* update 适配 springdoc 新版本配置方式 +* update 适配 ServletUtils 更换继承 JakartaServletUtil +* update 适配 新序列化注解 +* update 优化 利用 resultMap 自动映射配置 简化 xml (非嵌套) +* update 优化 调整 system entity 实体与 controller 包结构 +* update 优化 实体类中校验注解的提示信息 +* update 优化 使用 jdk17 语法优化代码 +* update 优化 所有 properties 文件改为注解启用 +* update 更新 docker 基础镜像 graalvm java17 +* update 优化 用户头像 改为存储 ossId 使用转换模块转为 url 展示 +* update 优化 重构 CellMergeStrategy 支持多级表头修复一些小问题 整理代码结构 +* update 优化 登录流程代码注释 + +### 新增功能 + +* add 新增 flatten-maven-plugin 插件统一版本号管理 +* add 新增 ip2region 实现离线IP地址定位库 + +### 移除功能 + +* remove 移除 BeanCopyUtils 工具类 与 JDK17 不兼容 +* remove 移除 devtools 依赖 并不好用(建议直接用idea自带的热更) +* remove 移除 vue2 前端工程 统一使用 vue3 工程 + +## v4.7.0 - 2023-05-08 + +### 依赖升级 + +* update springboot 2.7.9 => 2.7.11 修复 DoS 漏洞 +* update xxljob 2.3.1 => 2.4.0 +* update minio 升级至最新版 避免低版本信息泄漏问题 +* update hutool 5.8.15 => 5.8.18 +* update redisson 3.20.0 => 3.20.1 + +### 功能更新 + +* update 优化 更改 sys_oss_config 表注释 避免误解 +* update 项目正式入驻 dromara 开源社区 更改项目地址 +* update 全新 logo 全新背景图(设计师打造) +* update 优化代码生成 同步操作使用批量处理 +* update 重写项目 readme 说明 +* update 修改controller中校验直接返回R.fail +* update 更换默认用户头像 +* update 优化 限流注解 key 支持简单 spel 表达式 +* update 优化弹窗后导航栏偏移的问题 +* update 优化$tab.closePage后存在非首页页签时不应该跳转首页 +* update delete build style +* update 优化选择图标组件 +* update 移除vue-multiselect样式 +* update 优化固定头部页签滚动条被隐藏的问题 +* update 按代码规范补全重写注解 +* update 优化 极端情况获取LoginUser可能为null问题 +* update 优化 更改系统所有服务日志配置文件命名为 logback-plus.xml 避免与其他框架默认配置冲突 +* update 优化 加解密模块 将null判断下推防止任何可能的null出现 +* update 优化 调整配置文件错误注释 +* update 优化 在线用户token获取方式 +* update 优化 用户更改角色 踢掉角色相关所有在线用户 +* update 优化 下拉图标选择组件优化:1.已选择图标高亮回显 2.滚动条采用el-scrollbar +* update 优化 Vue的DictTag组件 当value没有匹配的值时 展示空value +* update 优化 恢复翻页/切换路由滚动功能 + +### 新增功能 + +* add 新增 ip2region 实现离线IP地址定位库 +* add 增加 邮箱验证码发送接口 +* add 增加 邮箱登陆接口 +* add 增加 EncryptUtils 加解密安全工具类 可以处理base64,aes,sm4,sm2,rsa,md5,sha256加解密 +* add 增加 EncryptUtils 类中增加国密sm3的不可逆加密算法 +* add 新增 忽略数据权限写法 防止异常不执行关闭问题 + +### 问题修复 + +* fix 修复 代码生成 点选按钮不生效问题 +* fix 修复 用户密码更新无效问题 +* fix 修复 findInSet 在mysql下方法搜索非数字字段时 无引号报错问题 +* fix 修复 oracle postgres 数据库日志表索引创建错误 +* fix 角色列表关联多表sort值都一样 导致排序不稳定、临时表没有原来的主键顺序 +* fix 修复 DefaultExcelResult 单词拼写错误 +* fix 修复页面切换时布局错乱的问题 +* fix 修复tab栏“关闭其他”异常的问题 +* fix 修复 加解密拦截器 对象属性为null问题 +* fix 修复 取消oss预览状态修改 图标变化不正常问题 +* fix 修复 开启TopNav后一级菜单路由参数设置无效问题 +* fix 修复 路由跳转被阻止时vue-router内部产生报错信息问题 +* fix 修复 缓存列表:多次清除操作,提示不变的问题 + +## v4.6.0 - 2023-03-13 + +### 重大更新 + +[重大更新] add 新增 基于 Mybatis 实现数据库字段加解密功能 +[重大更新] add 新增 通用翻译注解及实现(部门名、字典、oss、用户名) + +### 依赖升级 + +* update springboot 2.7.7 => 2.7.9 +* update easyexcel 3.1.5 => 3.2.1 +* update redisson 3.19.1 => 3.20.0 +* update hutool 5.8.11 => 5.8.15 (13与14有问题勿使用) +* update springdoc 1.6.14 => 1.6.15 +* update aws-java-sdk-s3 1.12.373 => 1.12.400 +* update element-ui 2.15.10 => 2.15.12 +* update lombok 1.18.24 => 1.18.26 + +### 功能更新 + +* update 优化 实体类中校验注解的提示信息 +* update 优化 修改 oss 配置页面开关说明 避免造成误解 +* update 优化 框架代码书写格式 +* update 优化 调整连接池默认参数 +* update 优化 `DictDataMapper` 注解标注过期 推荐使用 `@Translation` 注解 +* update 优化 部门更新接口 清理缓存 +* update 优化 获取菜单数据权限接口 删除无用角色属性与逻辑 +* update 优化 调整连接池最长生命周期 防止出现警告 +* update 优化 连接池增加 `keepaliveTime` 探活参数 +* update 优化 `DataPermissionHelper` 增加 `开启/关闭` 忽略数据权限功能 +* update 重构 `OssFactory` 加载方式 改为每次比对配置做实例更新 +* update 优化 `SaToken` 自定义扩展类 改为配置类注入 便于扩展 +* update 优化 启用 `sqlserver` 高版本语法 简化sql脚本语法 +* update 优化 更新角色后踢掉所有相关的登录用户 用户量过大会导致redis阻塞卡顿(应粉丝要求) +* update 优化 翻译组件 支持返回值泛型 支持多种类型数据翻译(例如: 根据主键翻译成对象) +* update 优化 限流注解使用 `SpringEl` 表达式动态定义 Key 与 message 国际化支持 +* update 优化 限流功能 `redis key` 生成规则 以 `功能头+url+ip+key` 格式 +* update 优化 只拦截系统内存在的路径 减少不必要的拦截造成的性能消耗 +* update 优化 `tagsView` 右选框,首页不应该存在关闭左侧选项 +* update 优化 `copyright 2023` +* update 优化 监控页面图标显示 +* update 优化 日志注解支持排除指定的请求参数 +* update 优化 业务校验优化代码 +* update 优化 日志管理使用索引提升查询性能 +* update 优化 框架时间检索使用时间默认值 `00:00:00 - 23:59:59` +* update 优化 oss 预览使用 `ImagePreview` 组件 + + +### 新增功能 + +* add 新增 `BeanCopyUtils#mapToMap` 方法 +* add 新增 `StringUtils` `splitTo` 与 `splitList` 方法 优化业务代码 +* add 新增 `EasyExcel` `@ExcelEnumFormat` 枚举类数据翻译注解 + + +### 问题修复 + +* fix 修复 新版本 `Redisson` 存在与 `springboot 2.X` 的兼容性问题 +* fix 修复 vue3 模板点击删除按钮后弹框显示`[object Object]`或控制台报错的问题 +* fix 修复 接口问题开关不生效问题 +* fix 修复 前端优化文件下载出现的异常 +* fix 修复 修改密码日志存储明文问题 +* fix 修复 用户密码注解误删暴露问题 +* fix 修复 代码生成 使用 `postgreSQL` 数据库查出已删除的字段 + + +## v4.5.0 - 2023-01-12 + +### 重大更新 + +* [重大更新] 使用 spring 事件发布机制 重构登录日志与操作日志 支持多事件监听无入侵扩展 +* 例如: 可以增加一个监听者将日志上传至ES等存储 对原有逻辑无影响 + +### 依赖升级 + +* update springboot 2.7.6 => 2.7.7 +* update springboot-admin 2.7.7 => 2.7.10 +* update mybatis-plus 3.5.2 => 3.5.3.1 +* update redisson 3.18.0 => 3.19.1 +* update sa-token 1.33.0 => 1.34.0 +* update easyexcel 3.1.3 => 3.1.5 +* update springdoc 1.6.13 => 1.6.14 +* update snakeyaml 1.32 => 1.33 +* update hutool 5.8.10 => 5.8.11 +* update aws-s3 1.12.349 => 1.12.373 +* update aliyun-sms 2.0.22 => 2.0.23 +* update tencent-sms 3.1.635 => 3.1.660 +* update echarts 4.9.0 => 5.4.0 +* update vue3 element-plus 2.2.21 => 2.2.27 + +### 功能更新 + +* update 优化 BaseMapperPlus 使用 MP V3.5.3 新工具类 Db 简化批处理操作实现 +* update 优化 将环境配置放到 pom 文件上方 便于查看使用 +* update 优化 代码生成与框架主体使用相同的主键生成器 全局统一避免问题 +* update 优化 系统登录 使用单表查询校验用户 避免多次 join 查询 +* update 优化 删除 vue3 模板无用参数 +* update 优化 xss 包装器 变量命名错误 +* update 优化 重构 ExcelUtil 全导出方法支持 OutputStream 流导出 不局限于 response +* update 优化 maven 地址切换回 aliyun 仓库 +* update 优化 去除无用 guava 依赖管理 项目中已无此依赖 +* update 优化 springdoc 配置鉴权头写死问题 增加持久化鉴权头配置 +* update 优化 验证码结果使用 spel 引擎自动计算 +* update 优化 弹窗内容过多展示不全问题 +* update 优化 删除 fuse 无效选项 maxPatternLength +* update 优化 minio 安装警告 使用新版本参数 +* update 优化 使用 spring 事件机制 重构 OssConfig 缓存更新 +* update 优化 抽取 SysLoginService recordLogininfor 记录登录信息方法 简化日志记录 +* update 优化 使用 spring 事件发布机制 重构登录日志与操作日志 +* update 优化 单元格合并判断 cellValue 是否相等方法调整 +* update 优化 去除 RedisConfig 无用继承 + +### 新增功能 + +* add 增加 GET 请求提交日期参数 默认格式化配置 +* add 增加 RedisUtils 检查缓存对象是否存在方法 + +### 问题修复 + +* fix 修复 根据 key 更新参数配置报null问题 +* fix 修复 树形下拉不能默认选中 +* fix 修复 读取 generator.yml 中文乱码问题 +* fix 修复 代码生成图片/文件/单选时选择必填无法校验问题 +* fix 修复 修改参数键名时 未移除过期缓存配置 +* fix 修复 用户注册 用户类型字段书写错误 +* fix 修复 文件名包含特殊字符(+、-、*...)的文件无法下载问题 +* fix 修复 短信校验模板参数传参错误 +* fix 修复 vue3 closeSidebar 这个方法定义的参数没有解构问题 + +## v4.4.0 - 2022-11-28 + +### 重大更新 +* [重大更新] 优化支持 oss 私有库功能(数据库字段改动) #cd9c3c3f +* [重大更新] 连接池由 druid 修改为 hikari 更新相关配置(原因可看文档) #1f42bd3d +* [重大更新] 移除 tlog(不支持UI界面 使用的人太少) 建议使用 skywalking +* [重大更新] 增加 skywalking 集成 默认注释不开启(使用看文档) + +### 依赖升级 +* update springboot 2.7.5 => 2.7.6 +* update springboot-admin 2.7.6 => 2.7.7 +* update satoken 1.31.0 => 1.33.0 +* update spring-doc 1.6.12 => 1.6.13 +* update easyexcel 3.1.1 => 3.1.3 +* update hutool 5.8.8 => 5.8.10 +* update redisson 3.17.7 => 3.18.0 +* update lock4j 2.2.2 => 2.2.3 +* update s3-adk 1.12.324 => 1.12.349 +* update mysql-docker 8.0.29 => 8.0.31 + +### 功能更新 +* update 优化 oss 云厂商增加 华为obs关键字 +* update 优化 冗余的三元表达式 +* update 优化 重置时取消部门选中 +* update 优化 新增返回警告消息提示 +* update 优化 hikari 参数顺序 最常用的放上面 删除无用 druid 监控页面 +* update 优化 p6spy 排除健康检查 sql 执行记录 +* update 优化 Dockerfile 创建目录命令 +* update 优化 将空‘catch’块形参重命名为‘ignored’ +* update 优化 使用本地缓存优化 excel 导出 数据量大字典转换慢问题 +* update 优化 字典转换实现 去除字符串查找拼接优化效率 +* update 优化 减小腾讯短信引入jar包的体积 +* update 消除Vue3控制台出现的警告信息 +* update 忽略不必要的属性数据返回 +* update 替换 mysql-jdbc 最新坐标 + +### 新增功能 +* add 新增 junit5 单元测试案例 #6e8ef308 +* add 增加 sys_oss_config access_policy 桶权限类型字段 +* add 增加 4.3-4.4 更新 sql 文件 +* add 新增 字典数据映射注解 #da94e898 +* add 增加 RedisUtils 获取缓存Map的key列表 + +### 问题修复 +* fix 修复 上传png透明图片 生成头像透明部分变成黑色 +* fix 修复 sqlserver sql文件 重复主键数据问题 +* fix 修复 sqlserver 特定情况下报 ssl 证书问题 默认关闭 ssl 认证 +* fix 修复 table中更多按钮切换主题色未生效修复问题 +* fix 修复 菜单激活无法修改其填充颜色 去除某些svg图标的fill="#bfbfbf"属性 +* fix 修复 使用缓冲流 导致上传异常问题 +* fix 修复 过滤器链使用IoUtil.read方法导致request流关闭 +* fix 修复 Log注解GET请求记录不到参数问题 +* fix 修复 某些特性的环境生成代码变乱码TXT文件问题 +* fix 修复 开启TopNav没有子菜单隐藏侧边栏 +* fix 修复 回显数据字典数组异常问题 + +### 移除功能 +* remove 移除过期 Anonymous 注解与其实现代码 +* remove 移除 tlog(不支持UI界面 使用的人太少) 建议使用 skywalking + +## v4.3.1 - 2022-10-24 + +### 依赖升级 +* update springboot 2.7.3 => 2.7.5 +* update springboot-admin 2.7.4 => 2.7.6 +* update sa-token 1.30.0 => 1.31.0 +* update springdoc 1.6.11 => 1.6.12 +* update poi 5.2.2 => 5.2.3 +* update hutool 5.8.6 => 5.8.8 +* update aws-s3 1.12.300 => 1.12.324 +* update aliyun-sms 2.0.18 => 2.0.22 +* update tencent-sms 3.1.591 => 3.1.611 +* update tlog 1.4.3 => 1.5.0 安全性升级 +* update snakeyaml 1.30 => 1.32 存在漏洞 +* update redisson 3.17.6 => 3.17.7 +* update nginx 1.21.6 => 1.22.1 存在漏洞 +* update element-ui 2.15.8 => 2.15.10 +* update core-js 3.19.1 => 3.25.3 + +### 功能更新 +* update 修改 差异命名与镜像名同步 +* update 优化 通用下载方法新增config配置选项 +* update 优化 日志操作中重置按钮时重复查询的问题 +* update 优化 `@Anonymous` 注解标注过期 使用 `@SaIgnore` 替换 +* update 优化 前端可以配置多排序参数支持依次排序 +* update 优化 oss管理 支持时间排序 +* update 优化 替换 sa-token 过期配置 +* update 优化 sa-token 拦截器注册 `SaTokenConfig#addInterceptors` 排除拦截路径配置 +* update 优化 vue3说明文件 编码问题 +* update 优化 导入更新用户数据前校验数据权限 +* update 优化 `R` 类 `isError` 和 `isSuccess` 改为静态方法 +* update 优化 获取用户信息getInfo接口 使用缓存数据获取 +* update 优化 选择按钮宽度 + +### 问题修复 +* fix 修复 用户导入存在则更新不生效 +* fix 修复 日志转换非json数据导致报错 +* fix 修复 控制台SQL日志打印时间格式化问题 +* fix 修复 不同网段因reset请求头导致下载导出跨域问题 +* fix 修复 在线用户设置永不过期 被过滤问题 +* fix 修复 在线用户设置永不过期 超时时间-1推送redis无效问题 +* fix 修复 snakeyaml 漏洞 强制升级依赖版本(临时处理等boot升级) +* fix 修复 开启账号同端互斥登录 被顶掉后登出报null异常问题 +* fix 修复 Redisson 设置 `NameMapper` 导致队列功能异常问题 +* fix 修复 文件上传组件格式验证问题 +* fix 修复 内部调用缓存不生效问题 +* fix 修复 主题颜色在Drawer组件不会加载问题 +* fix 修复 小屏幕上修改头像界面布局错位的问题 +* fix 修复 内链域名特殊字符替换 合并错误导致问题 +* fix 修复 nginx 漏洞 https://www.oschina.net/news/214309 + +## v4.3.0 - 2022-09-14 + +### 重大更新 +* [重大更新] 整合 springdoc 基于 javadoc 实现无注解零入侵生成接口文档 +* [重大更新] 重写 spring-cache 实现 更人性化的操作 支持注解指定ttl等一些参数 +* [不兼容更新] 移除 swagger 所属所有功能 建议使用 springdoc +* [重大更新] 移除maven docker插件 过于老旧功能缺陷大 使用idea自带的docker插件替代 + +### 依赖升级 +* update springboot 2.6.9 => 2.7.3 +* update springboot-admin 2.7.2 => 2.7.4 +* update redisson 3.17.4 => 3.17.6 +* update hutool 5.8.3 => 5.8.6 +* update okhttp 4.9.1 => 4.10.0 +* update lock4j 2.2.1 => 2.2.2 +* update aws-java-sdk-s3 1.12.248 => 1.12.300 修复依赖安全漏洞 +* update aliyun.sms 2.0.9 => 2.0.18 +* update tencent.sms 3.1.537 => 3.1.591 +* update guava 30.0-jre => 31.1-jre +* update springdoc 1.6.9 => 1.6.11 +* update druid 1.2.11 => 1.2.12 +* update dynamic-ds 3.5.1 => 3.5.2 + +### 功能更新 +* update 优化 短信接口实现类 `@Override` 注解 +* update 优化 登出方法代码逻辑 +* update 优化 代码中的一些魔法值 +* update 优化 使用 StreamUtils 简化业务流操纵 +* update 修改 oss 客户端自定义域名 统一使用https开关控制协议头 +* update 更新 监控过时配置 WebSecurityConfigurerAdapter 改为 bean 注入 +* update 修改 生成错误注释 +* update 优化 docker 部署方式 使用 host 模式简化部署流程 降低使用成本 +* update 修改 验证码开关变量名 +* update 优化 DateColumn 支持单模板多key场景 +* update 优化 redission 处理增加前缀 +* update 优化 缓存监控 相关代码 +* update 优化 部署脚本 防止出现权限问题 +* update 优化 多个相同角色数据导致权限SQL重复问题 +* update 优化 字典数据使用store存取 +* update 优化 布局设置使用el-drawer抽屉显示 +* update 更新框架文档 专栏与视频 链接地址 +* update 优化 OSS文件上传 主动设置文件公共读 适配天翼云OSS +* update 优化 表格上右侧工具条(搜索按钮显隐&右侧样式凸出) +* update 优化 前后端多环境部署保持一致 删除无用环境文件 +* update 优化 错误登录锁定与新增解锁功能 +* update 优化 getLoginId 增加必要参数空校验 +* update 使用 SpringCache注解 优化参数管理、字典管理、在线用户等业务缓存 +* update 优化 多角色数据权限匹配规则 +* update 优化 页面内嵌iframe切换tab不刷新数据 +* update 优化 调整 oss表key 与 ossconfig的service 字段长度不匹配 +* update 优化 操作日志密码脱敏 +* update 重构 QueueUtils 抽取通用方法 统一使用 适配优先队列新用法 + +### 新功能 +* add 增加 StreamUtils 流工具 简化 stream 流操纵 +* add 新增 缓存列表菜单功能 +* add 新增 获取oss对象元数据方法 +* add 增加 QueueUtils 操作普通队列的方法 + +### 问题修复 +* fix 修复 mysql sys_notice 与 sys_config 表主键类型长度不够问题 +* fix 修复 获取 SensitiveService 空问题 增加空兼容 +* fix 修复 代码生成首字母大写问题 +* fix 修复 minio 上传自定义域名回显路径错误问题 +* fix 修复 短信功能返回实体 SysSms 序列化问题 +* fix 修复 sqlserver 更新sql错误提交 +* fix 修复 RedisUtils 并发 set ttl 错误问题 +* fix 修复 防止主键字段名与'row'或'ids'一致导致报错的问题 +* fix 修复 幂等组件 逻辑问题导致线程变量未清除 +* fix 修复 脱敏没有实现类导致返回数据异常问题 +* fix 修复 用户导出字典使用错误 +* fix 修复 用户登录与短信登录 国际化格式不一致 +* fix 修复 BaseMapperPlus 方法命令不一致问题 +* fix 修复 短信功能是否启用判断不生效BUG +* fix 修复 xxljob prod 环境配置文件 数据库ip漏改 +* fix 修复 部署脚本 cp 命令缺少参数问题 +* fix 修复 菜单管理的一些操作问题 +* fix 修复 国际化文件提交为特殊编码问题 +* fix 修复 minio配置https遇到的问题 +* fix 修复 点击删除后点击取消控制台报错问题 +* fix 修复 文件/图片上传组件 第一次上传报错导致后续上传无限loading问题 +* fix 修复 postgresql 时间查询类型转换报错问题 +* fix 修复 部门与角色 状态导出字典使用错误 +* fix 修复 openapi结构体 因springdoc缓存导致多次拼接接口路径问题 +* fix 修复 没有权限的用户编辑部门缺少数据 +* fix 修复 oss配置删除内部数据id匹配类型问题 +* fix 修复 用户导入存在则更新不生效 +* fix 修复 日志转换非json数据导致报错 + +## v4.2.0 - 2022-06-28 +### 重大更新 +* [重大更新] 增加 `ruoyi-sms` 短信模块 整合 阿里云、腾讯云 短信功能 +* [重大改动] 基于 `AWS S3` 协议重新实现 OSS模块 支持自定义域名 +* [安全性] 优化 nginx 限制外网访问内网 actuator 相关路径(建议升级) +* [不兼容] 优化 文件与图片上传组件 使用id存储回显(升级的用户需要注意 上传组件返回值变成了 ossid 便于关联) +* [不兼容] 升级 mybatis-plus 3.5.2 解决新版本兼容性问题 关键字冲突修改(新增了很多关键字 升级的需要注意 冲突的关键字建议换一个命名) + +### 依赖升级 +* update springboot-admin 2.6.6 => 2.6.9 +* update springboot-mybatis 2.2.0 => 2.2.2 +* update sa-token 1.29.0 => 1.30.0 +* update hutool 5.7.22 => 5.8.3 +* update druid 1.2.8 => 1.2.11 +* update tlog 1.3.6 => 1.4.3 +* update easyexcel 3.0.5 => 3.1.1 去除cglib 支持jdk17 +* update xxl-job 2.3.0 => 2.3.1 +* update redisson 3.17.0 => 3.17.4 +* update mybatis-plus 3.5.1 => 3.5.2 +* update poi 4.1.2 => 5.2.2 性能大幅提升 +* update docker mysql 8.0.27 => 8.0.29 +* update docker nginx 1.21.3 => 1.21.6 +* update docker redis 6.2.6 => 6.2.7 +* update docker minio 2021-10-27 => 2022-05-26 + +### 功能更新 +* update 优化 redis 序列化 使用系统自带json工具 全局统一 +* update 优化 RedisUtils 重构过期方法 +* update 完善短信验证码发送接口 +* update 优化 弹窗点击遮罩层 默认不关闭 可在 main.js 修改 +* update 调整 CacheManager 使用系统 系统序列化器 +* update 调整 图片预览组件 去除无用根目录拼接 +* update 用户管理左侧树型组件增加选中高亮保持 +* update 优化 DataPermissionHelper 上下文存储 使用 SaToken 的请求存储器 +* update 优化 用户头像上传限制只能为图片格式 +* update 优化 redis 与 jackson 使用自动装配定制器简化配置 +* update 优化 getLoginUser 获取 使用一级缓存 +* update 增加 redis 无密码使用说明 +* update 手动配置 Undertow 缓冲池 消除运行警告 +* update 优化 表单构建按钮不显示正则校验 +* update 优化 oss 回显查询 使用 redis 缓存 +* update 优化 用户列表查询 剔除密码字段 +* update 优化 验证码 登录 登出 注册 等接口 使用匿名注解放行 +* update 修改 代码生成 controller 去除查询校验 由用户自行选择是否校验 +* update 优化 ExcelUtil 工具支持合并处理器 +* update 使用 SaStorage 优化 LoginHelper 一级缓存 避免 ThreadLocal 清理不干净问题 +* update 优化 新增用户与角色信息、用户与岗位信息逻辑 +* update 优化 代码生成 业务接口 增加事务回滚 +* update 优化 logback 删除无用配置 + +### 新功能 +* add 增加 MailUtils 邮件工具 +* add 增加 RedisUtils 操作原子值方法 +* add 增加 demo 短信演示案例 +* add 增加 获取短信验证码接口 +* add 新增 SpringUtils 获取配置文件中的属性值方法 +* add 新增 Anonymous 匿名访问不鉴权注解 +* add 新增 easyexcel 单元格合并注解与处理器 +* add 增加 ExcelUtil 模板导出方法 支持 单列表/多列表 +* add 增加 Excel 模板导出 测试类 + +### 问题修复 +* fix 修复 ExcelUtil 表达式解析 参数添反导致无法解析问题 +* fix 修复 全局线程池配置 核心线程与最大线程 参数填反问题 +* fix 修复 查询未分配用户角色列表 角色无绑定用户情况下 空列表问题 +* fix 修复 sqlserver 新增数据 id 错误 +* fix 修复 token 超时时间设置 -1 导致的单位转换问题 +* fix 修复 编辑 OssConfig 在 postgres 字段重复报错 补全 remark 字段 +* fix 修复 postgres 数据库 菜单部分字段类型无法转换问题 +* fix 修复 脱敏实现逻辑问题 +* fix 修复 登录未选部门报空问题 +* fix 修复 用户注销时记录注销日志异常问题 +* fix 修复 代码生成表字段类型不匹配 导致查询不准确问题 + +## v4.1.0 - 2022-04-24 +### 重大更新 +* [重大更新] 增加应用适配 oracle +* [重大更新] 增加应用适配 SQL Server +* [重大更新] 增加应用适配 postgresql +* [重大更新] 确保更好的适配 多数据库 主键策略统一改为 雪花ID + +### 依赖升级 +* update springboot 2.6.4 => 2.6.7 修复 CVE-2022-22965 漏洞 +* update springboot-admin 2.6.2 => 2.6.6 +* update hutool 5.7.21 => 5.7.22 +* update dynamic-datasource 3.5.0 => 3.5.1 +* update redisson 3.16.8 => 3.17.0 +* update qiniu 7.9.3 => 7.9.5 +* update qcloud 5.6.68 => 5.6.72 +* update minio 8.3.7 => 8.3.8 +* update okhttp 4.9.2 => 4.9.3 + +### 功能更新 +* update 简化查询 部门、菜单、角色、用户、代码生成列表 功能 +* update 优化 部门修改子元素关系 使用批量更新 +* update 优化去除sql差异化 时间范围统一使用 between 处理 +* update 优化 RepeatSubmit 注解 支持业务处理失败 与 异常快速放行 +* update 优化 防重 与 限流 功能支持国际化消息返回 +* update 开启TopNav没有子菜单情况隐藏侧边栏 +* update 更新minio压缩配置 +* update 重命名 菜单字段 query -> query_param 解决系统关键字问题 +* update 使用 in 优化 or 提升索引命中率 +* update 优化 TreeEntity 树实体 去除未知泛型 +* update 优化菜单名称过长悬停显示标题 +* update 优化固定Header后顶部导航栏样式问题 +* update 优化 logback 日志 异步输出 +* update 全局异常处理器引入DuplicateKeyException主键冲突异常拦截 +* update topNav自定义隐藏侧边栏路由 +* update 更名 SaInterfaceImpl 为 SaPermissionImpl 完善相关注释 +* update 优化 sa-token 路由拦截器语法 增加注释 避免误操作 +* update 优化文件上传、图片上传组件 文件列表展示文件原名便于后续处理, 完善组件删除功能 +* update 优化登录失败相关部分代码结构 +* update 使用 spring cglib 替换 停止维护的 cglib +* update 简化 全局线程池配置 使用cpu核心数自动处理 +* update 移除 重复提交 配置文件全局配置 使用注解默认值替代 + +### 新功能 +* add 增加 4.0 升级 4.1 的 sql 脚本(升级需执行此sql) +* add 增加 DataBaseHelper 数据库助手 用于屏蔽多类型数据库sql语句差异 +* add 增加 短信登录 与 小程序登录 示例 +* add 增加 Mybatis 全局异常处理 开启多数据源切换 严格模式 找不到数据源报错 + +### 问题修复 +* fix 修复 数据权限 从 aop 切换到 拦截器 导致获取代理失败问题 +* fix 修复表单清除元素位置未垂直居中问题 +* fix 修复 poi 组件漏洞 与 mysql jdbc 漏洞 +* fix 修复单独访问 接口文档 请求 favicon.ico 报错问题 +* fix 修复 minio 上传, 因 socket 导致 available 获取数值不精确问题 +* fix 修复 cos_api bcprov-jdk15on 漏洞 +* fix 修复 guava 漏洞 统一依赖版本 +* fix 修复 tlog 依赖漏洞 + +## v4.0.1 - 2022-03-01 +### 依赖升级 +* update springboot 2.6.3 => 2.6.4 +* update hutool 5.7.20 => 5.7.21 +* update qiniu 7.9.2 => 7.9.3 +* update minio 8.3.5 => 8.3.7 + +### 功能更新 +* update 图片上传 文件上传 支持并发上传 +* update 组件ImageUpload支持多图同时选择上传 +* udpate 组件fileUpload支持多文件同时选择上传 +* update 优化 R 默认返回 msg +* update 增加 用户注册 用户类型默认值 +* update 增加用户登出日志 +* update 更新 多用户多设备的注释说明 +* update 优化 是否为管理员的判断 +* update 优化 页面若未匹配到字典标签则返回原字典值 +* update 调整用户登录 将日志调整到最后 防止获取不到用户警告 +* update 优化随机数生成方式 避免容易生成两个相同随机数的问题 + +### 问题修复 +* fix 修复代码生成 基于路径生成 路径为空问题 +* fix 恢复误删 `@Async` 注解线程池配置类 +* fix 修复 minio 适配 https 导致的问题 +* fix 修复分页组件请求两次问题 + +## v4.0.0 - 2022-02-18 +### 重大更新 +* [重大更新] 重写项目整体结构 数据处理下沉至Mapper符合MVC规范 减少循环依赖 +* [重磅更新] 主分支与satoken分支合并 权限统一使用 sa-token +* [重磅更新] 适配升级 SpringBoot 2.6 +* [重磅更新] EasyExcel大版本升级3.X +* [重磅更新] 移除链式调用注解 因链式调用不符合java规范 导致很多问题 +* [重磅更新] 增加 轻量级 分布式队列 支持 +* [重磅更新] 增加 数据脱敏注解 使用序列化控制脱敏 支持多种表达式 +* [重磅更新] 重构 使用 Spring 简化 oss 模块代码 +* [重磅更新] 重构 调整返回类型为 R 精简 Controller 代码 + +### 依赖升级 +* update springboot 2.5.8 => 2.6.3 +* update mybatis-plus 3.4.3.4 => 3.5.1 +* update maven-jar-plugin 3.2.0 => 3.2.2 +* update maven-war-plugin 3.2.0 => 3.2.2 +* update maven-compiler-plugin 3.1 => 3.9.0 +* update hutool 5.7.18 => 5.7.20 +* update springboot-admin 2.6.0 => 2.6.2 +* update redisson 3.16.7 => 3.16.8 +* update qiniu 7.9.0 => 7.9.2 +* update aliyun 3.13.1 => 3.14.0 +* update qcloud 5.6.58 => 5.6.68 +* update minio 8.3.4 => 8.3.5 + +### 功能更新 +* update 用户管理部门查询选择节点后分页参数初始 +* update 防重复提交标识组合(key + url + header) +* update 接口文档增加 basic 账号密码验证 +* update 用户修改减少一次角色列表关联查询 +* update 优化部门修改缩放后出现的错位问题 +* update 指定 maven 资源过滤为具体文件 防止错误过滤 +* update hutool 引入改为 bom 依赖项引入 +* update 降低开发环境 redis连接池数量 +* update 升级 springboot 2.6.X 解决 springfox 兼容性问题 +* update 优化多用户体系处理 更名 LoginUtils 为 LoginHelper 支持 LoginUser 多级缓存 +* update 优化加载字典缓存数据 +* update 数据库更改 对接多用户体系 +* update 移除掉 StringUtils 语义不明确的api方法 使用特定工具替换 +* update 优化登录、注册在接口通过`@Validated`注解进行数据基础校验 +* update 优化 查询登录用户数据 统一走缓存 +* update 优化 redisson 配置 去除掉不常用的配置 使用默认配置 +* update 用户访问控制时校验数据权限,防止越权 +* update 修改用户注册报未登录警告 +* update 调整oss预览开关 使用前端直接调用更改配置参数 +* update 使用 satoken 自带的 BCrypt 工具 替换 Security 加密工具 减少依赖 +* update 优化 TreeBuildUtils 工具 使用反射自动获取顶级父id +* update 使用 hutool Dict 优化 JsonUtils 防止类型解析异常 +* update 优化代码生成 使用新 JsonUtils.parseMap 方法 +* update 更新 所有 oss 均支持 https 配置 + +### 新功能 +* add 增加 RedisUtils 工具 hasKey 检查key存在方法 +* add 增加 监控中心 自定义事件通知 +* add 增加 3.X update 4.0 更新sql + +### 问题修复 +* fix 修复登录失效后多次请求提示多次弹窗问题 +* fix 修复 StringUtils 通配符匹配无效 +* fix 修复选项卡点击右键刷新丢失参数问题 +* fix 修复 数据权限 缓存方法名错误问题 +* fix 修复自定义组件`file-upload`无法显示第一个文件,列表显示的文件比实际文件少一个的问题 +* fix 修复因升级 sa-token 导致 doLogin 无法获取 token 问题 +* fix 修复分页组件请求两次问题 + +### 移除功能 +* remove 移除过期代码 分页工具相关 +* remove 移除过期代码 多数据源切换 +* remove 移除过期代码 数据权限 + +### 其他 +* 3.X 版本进入维护阶段 不进行更新 只修复bug 持续维护到2022年10月 +* 4.X 版本公测将近一个月 大部分bug已修复 官网主分支更改为 4.X 版本 推荐使用 + + +## v3.5.0 - 2021-12-28 +### 重大更新 +* [重大更新] 重写数据权限实现 +* [重磅更新] 重构分页 简化使用 +* [重磅更新] 用户登录 支持校验错误次数锁定登录 +* [重磅更新] 增加 jdbc 批处理参数 大幅提升批量操作性能 对原生语句与 MP 均有效 + +### 依赖升级 +* update springboot 2.5.7 => 2.5.8 升级预防 log4j2 问题 +* update springboot-admin 2.5.4 => 2.5.5 +* update hutool 5.7.16 => 5.7.18 +* update redisson 3.16.4 => 3.16.7 +* update dynamic-ds 3.4.1 => 3.5.0 +* update qiniu 7.8.0 => 7.9.0 +* update minio 8.3.3 => 8.3.4 +* update tlog 1.3.4 => 1.3.6 启用 tlog 自动配置 +* update clipboard 2.0.6 => 2.0.8 + +### 功能更新 +* update 多数据源切换标注过期 3.6.0 移除 推荐使用原生注解 +* update 通用权限服务 迁移回 ruoyi-framework 模块 +* update 使用 hutool-jwt 替换老旧 jjwt 依赖 +* update 调整 OSS 表字段内容长度 +* update LoginUser 增加角色缓存 优化角色权限代码 +* update 使用 Cglib 重构 BeanCopyUtils 性能优异 +* update 禁止所有工具类实例化 优化代码书写规范 +* update 优化查询用户的角色组、岗位组代码 +* update 更新 RedisUtils 返回客户端实例 +* update 修改 健康检查权限 改为用户放行 提高安全性 +* update hutool 工具 改为单包引入 减少无用依赖 +* update ServicePlusImpl 功能 下沉到 BaseMapperPlus +* update 去除 jdk17 标签 由于很多组件还未适配 导致一些问题 +* udpate 代码生成预览支持复制内容 +* update 用户导入提示溢出则显示滚动条 +* update 路由支持单独配置菜单或角色权限 +* update 优化web拦截器 使用原生接口处理 默认非生产环境开启 +* update 调整监控依赖 从 common 迁移到 framework + +### 新功能 +* add 新增 Vue3 分支 与 代码生成模板(由于组件还未完善 仅供学习) +* add 增加 RedisUtils 注册监听器方法 +* add 增加 自定义 Xss 校验注解 用户导入增加 Bean 校验 +* add oss下载增加 loading 层 +* add 新增图片预览组件 +* add 集成compression-webpack-plugin插件实现打包Gzip压缩 +* add 新增 SqlUtils 检查关键字方法 + +### 问题修复 +* fix 修复 集群雪花id重复问题 使用网卡信息绑定生成 +* fix 修复 count 语法异常 +* fix 修复更改密码问题 +* fix 修复sql关键字处理 防止解析器报错 +* fix 修复 TreeBuildUtils 顶节点不为 0 问题 +* fix 修复 SysOssConfig 主键类型错误 +* fix 修复代码生成 导出注解错误 +* fix 修复 redisson 集群模式 路径未匹配协议头问题 +* fix 修复打包后字体图标偶现的乱码问题 +* fix 修复版本差异导致的懒加载报错问题 +* fix 修复代码生成字典组重复问题 + +### 移除功能 +* remove 删除 jjwt 无用依赖 +* remove 移除过期 用户导入 +* remove 移除过期工具 DictUtils + +## v3.4.0 - 2021-11-29 + +### 重磅更新 +* update [重磅更新] 重构 Excel 导入 支持 Validator 校验 支持自定义监听器 +* update [重磅更新] Validator 校验框架支持国际化 + +### 依赖升级 +* update springboot 2.5.6 => 2.5.7 +* update hutool 5.7.15 => 5.7.16 +* update okhttp 4.9.1 => 4.9.2 +* update spring-boot-admin 2.5.2 => 2.5.4 +* update redisson 3.16.3 => 3.16.4 +* update tlog 1.3.3 => 1.3.4 +* update axios 0.21.0 => 0.24.0 +* update core-js 3.8.1 => 3.19.1 +* update js-cookie 2.2.1 => 3.0.1 +* update velocity 1.7 => 2.3 +* update 升级 docker 基础镜像 + +### 功能更新 +* update 基于 hutool 封装树构建工具 重构部门与菜单树结构返回 +* update 减少使用特定数据库函数 +* update 配置应用前缀路径 改为配置文件统一配置 +* update 升级 swagger 配置 使用 knife4j 增强模式 +* update 监控中心 集成监控客户端 实现自监控 +* update 调度中心 集成监控客户端 注册到监控中心 +* update 优化 tab 对象简化页签操作 +* update 解耦 LoginUser 与 SysUser 强关联 +* update 更新 RepeatSubmit 注解 aop 处理 针对特殊参数进行过滤 +* update DictUtils 字典工具类 标记过期 3.5.0 版本移除 使用 DictService 代替 +* update 抽象 DictService 通用 字典服务 +* update 抽象 ConfigService 通用 参数配置服务 +* update 基于 DictService 重构 Excel 内字典查询功能 +* update OSS 模块 整体重命名 消除歧义 +* update 更新 redis.conf 存储策略 aof 与 rdb 配置参数 +* update 初始化数据转移到 ApplicationRunner 统一处理 +* update 优化时间查询语句 + +### 新功能 +* add 增加 框架缓存懒加载 开关 +* add 新增 监控中心 Bean 初始化 startup trace 监控插件 +* add 增加 ValidatorUtils 校验框架工具 用于在非 Controller 的地方校验对象 + +### 漏洞修复 +* fix 修复 SysOss、SysOssConfig 未继承 BaseEntity 基础实体问题 +* fix 修复 xxl-job-admin 部署问题 +* fix 修复 回显数据字典键值修正 +* fix 修复 Linux 清除临时目录 导致上传找不到目录报错问题 +* fix 修复通用实体 传参无法接收问题 +* fix 修复 SysLoginController 接口文档书写错误问题 +* fix 修复 用户逻辑删除 差异问题 +* fix 修复 OSS 七牛云 token 过期未刷新问题 +* fix 修复 分页工具 排序字段 null 处理 +* fix 修复 用户导入字典使用错误 +* fix 修复 关闭 xss 功能导致可重复读 RepeatableFilter 失效 +* fix 修复 使用 this.$options.data 报错问题 +* fix 修复 代码生成复选框字典遗漏问题 +* fix 修复 重复提交不生效问题 由于概念不同 使用 RedisUtils 重构 +* fix 修复 OSS 工厂 未实例化服务更新加载问题 + +### 功能移除 +* remove 移除 quartz 相关代码与依赖 +* remove 移除 feign 相关代码与依赖 +* remove 移除 MybatisPlusRedisCache 二级缓存 + +## v3.3.0 - 2021-10-29 + +### 重磅更新 +* add [重磅更新] 增加分布式日志框架 TLog +* add [重磅更新] 增加分布式任务调度系统 Xxl-Job +* add [重大更新] 增加 ruoyi-job 任务调度模块(基于xxl-job) +* update [重大更新]全业务 增加 接口文档注解 格式化代码 + +### 依赖更新 +* update springboot 2.5.5 => 2.5.6 +* update springboot-admin 2.5.1 => 2.5.2 +* update element-ui 2.15.5 => 2.15.6 +* update hutool 5.7.13 => 5.7.15 +* update qcloud.cos 5.6.55 => 5.6.58 +* update minio 8.3.0 => 8.3.3 + +### 功能更新 +* update 更新 element 2.15.6 表格样式 +* update 优化 代码生成常量 关于 BO VO 注释 +* update 优化代码生成 导入表 列表返回 主键默认选中 +* update MybatisPlusRedisCache 标记过期 推荐使用 spring-cache +* update Quartz 标记过期 推荐迁移至新框架 xxl-job +* update Feign 标记过期 +* update 前端增加默认国际化参数 +* update 更新 Admin 监控 注释 避免错误使用 +* update Admin 监控增加日志文件输出 +* update 优化 xxl-job-admin 增加格式化日志输出与 docker 镜像 +* update 更新 xxl-job 执行器开关功能 +* update 代码生成 改为生成抽象实体 +* update 代码生成 搜索框 更新文本域生成 用于模糊查询 +* update 通用数据注入改为适配通用实体类 +* update 使用路由懒加载提升页面响应速度 +* update 迁移所有脚本文件至 script 目录 +* update swagger 组顺序配置 +* update sql 文件更新 xxljob 控制台菜单 +* update 前端增加 任务调度中心页面与环境及 nginx 配置 +* update 合并 oss.sql 至主 sql +* update 补全国际化文件(英文) +* update 更新关于全局路径设置与文档链接 +* update 删除无用 setUsername 使用自动注入 +* update RedisUtils 更新删除 hash 数据方法 + +### 漏洞修复 +* fix 修复 多数据源 aop 语法错误 +* fix 修复 子菜单无 query 参数问题 +* fix 修复 oss 配置删除时删除缓存 bug +* fix 修复无权限获取请求头 download-filename 导致文件名为空问题 + +## v3.2.0 - 2021-9-28 + +### 重大更新 +* update [重大改动]接口文档 支持分组配置 +* update [重大改动]security 路径配置抽取到配置文件 +* update [重大改动] 将 framework 与 system 模块 解耦 调整依赖结构 解决依赖冲突 +* update [重大改动]重写 防重提交实现 使用分布式锁 解决并发问题 压测通过 + +### 依赖更新 +* update springboot 2.5.4 => 2.5.5 bugfix版本 +* update mybatis-plus 3.4.3.3 => 3.4.3.4 bugfix版本 +* update redisson 3.16.2 => 3.16.3 bugfix版本 +* update easyexcel 2.2.10 => 2.2.11 +* update hutool 5.7.11 => 5.7.13 +* update file-saver 2.0.4 => 2.0.5 +* update dart-sass 1.32.0 => 1.32.13 +* update sass-loader 10.1.0 => 10.1.1 + +### 功能更新 +* update 优化代码生成 根据MP生成特性 调整导入表结构默认值合理化 +* update 将所有 云存储字样 改为 对象存储 避免误解 +* update 更新 @Cacheable 错误用法 注意事项 +* update 优化 AddressUtils 空校验处理 +* update 菜单管理支持配置路由参数 +* update 优化aop语法 使用spring自动注入注解 +* update 使用 Redisson 限流工具 重写限流实现 +* update 使用 vue-data-dict 简化数据字典使用 +* update 增加日志注解新增是否保存响应参数开关 +* update 用户未登录日志改为 warn 级别 +* update OSS模块 关于下载403报错信息优化 +* update 更新 Actuator prod 默认暴漏端点 增加暴漏 logfile 日志端点 +* update 默认适配jdk11 测试 jdk17 无异常 +* update 封装通用下载方法简化下载使用 + +### 新功能 +* add 新增通用方法简化模态/缓存使用 +* add 增加 限流演示案例 +* add 增加 redis redisson 集群配置 + +### 漏洞修复 +* fix Cron表达式生成器关闭时销毁,避免再次打开时存在上一次修改的数据 +* fix 全局限流key会多出一个"-" 将其移动到IP后面 去除多余的空格 +* fix 修复多主键代码生成bug +* fix 修复 @Cacheable 与 @DataScope 冲突问题 +* fix 修复代码生成页面数据编辑保存之后总是跳转第一页的问题 + +### 功能移除 +* remove 移除过期工具 RedisCache +* remove 移除无用配置类 ServerConfig +* remove 移除 SysUser 无用字段 salt + +## v3.1.0 - 2021-9-7 + +### 重大更新 +* add [重大改动] 过期 RedisCache 新增 RedisUtils 工具类 新增 发布订阅功能 更灵巧便于使用 +* add [重大改动] 新增 saveOrUpdateAll 方法 可完美替代 saveOrUpdateBatch 高性能 +* update [重大改动] 重写 InsertAll 方法实现 可完美替代 saveBatch 秒级插入上万数据 +* update [重大改动] 更改OSS上传通用路径生成 按照年月日分三级目录 +* update [重大改动] MP字段验证策略更改为 NOT_NULL 个别特殊字段使用注解单独处理 +* update [重大改动] 所有业务适配 RedisUtils 新工具 + +### 依赖升级 +* update springboot 2.5.3 => 2.5.4 +* update spring-boot-admin 2.5.0 => 2.5.1 +* update mybatis-plus 3.4.3 => 3.4.3.3 适配升级 (包含不兼容升级) +* update aliyun.oss 3.13.0 => 3.13.1 +* update qcloud.cos 5.6.47 => 5.6.51 +* update hutool 5.7.9 => 5.7.11 +* update maven-jar-plugin 3.1.1 => 3.2.0 +* update feign-okhttp 11.2 => 11.6 +* update redisson 3.16.1 => 3.16.2 + +### 新功能 +* add 优化 docker 增加 redis 配置文件 +* add 新增暗色菜单风格主题 +* add 菜单&部门新增展开/折叠功能 +* add 页签右键按钮添加图标 页签新增关闭左侧 + +### 功能更新 +* update 优化 OSS 模块与上传组件 异常处理 +* update 更新 jackson 配置 支持 LocalDateTime 全局格式化 +* update 优化 使用权限工具 获取用户信息 +* update 自定义可拖动弹窗宽度指令 +* update 重构 将下载excel工具提取到全局 +* update 定时任务对检查异常进行事务回滚 +* update 优化spy配置文件为 UTF8编码 解决中文注释乱码问题 +* update 修改时检查用户数据权限范围 +* update 解决 logout 写死 无法扩展路径问题 +* update 优化代码生成 导入与同步 批处理效率 +* update 修改时检查用户数据权限范围 +* update 修改代码生成字典回显样式 +* update 修改数据字典回显 +* update 优化验证码配置 使用泛型 防止错误输入 +* update 优化全局线程池配置 使用泛型 防止错误输入 +* update 使用 MP 全局配置分页溢出 +* update 代码生成器 导入表时查询 新创建表的优先排序在前面 +* update 定时任务支持在线生成cron表达式 +* update 自定义弹层溢出滚动样式 +* update 优化分页工具排序处理 +* update 优化 oss配置 使用发布订阅工具 刷新配置 +* update 代码生成 查询数据库列表 按照时间倒序 +* update 使用MP自行判断数据库类型 + +### 漏洞修复 +* fix 修复保存配置主题颜色失效问题 +* fix 修复 导出雪花id excel失真问题 +* fix 修复 druid 监控 集群模式下 无法路由到同一台服务器问题 +* fix 解决搜索校验不通过问题 +* fix 修复定时器工具编写错误问题 +* fix 修复 minio 无 perfix 问题 +* fix 修复 富文本图片路径错误问题 +* fix 修复 OSS配置清空被过滤问题 +* fix 修复 excel 导入与 class 未对应问题 +* fix 修复字典组件值为整形不显示问题 + +## v3.0.0 - 2021-8-18 + +### 重大更新 +* add [重大更新]重写 OSS 模块相关实现 支持动态配置(页面配置) +* add [重大更新]增加 jackson 超出 JS 最大数值自动转字符串(雪花id序列化)处理 +* add [重大更新]重写 防重提交拦截器 支持全局与注解自定义 拦截时间配置配置 优化逻辑 +* add [重大更新]新增是否开启用户注册功能 +* add [重大更新]增加 easyexcel 工具类 +* add [重大更新]集成 性能分析插件 p6spy 更强劲的 SQL 分析 +* add [重大更新]增加 完整国际化解决方案 +* add [重大更新]支持自定义注解实现接口限流 + +### 依赖升级 +* update feign-okhttp 11.0 => 11.2 +* update okhttp 3.19.4 => 4.9.1 +* update minio 8.2.0 => 8.3.0 +* update hutool 5.7.6 => 5.7.7 +* update element-ui 2.15.2 => 2.15.5 +* update springboot admin 2.4.3 => 2.5.0 (新增 Quartz 专属监控页) + +### 新功能 +* add 增加 admin 监控客户端开关 +* add 增加 国际化演示demo + +### 依赖更新 +* update 更新软件架构图 +* update 优化XSS跨站脚本过滤 +* update 优化BLOB下载时清除URL对象引用 +* update 更新 防重提交拦截器 demo演示案例 +* update 日常字符串校验 统一重构到 StringUtils 便于维护扩展 +* update 修改 自动注入器 用户未登录异常拦截抛出警告 返回Null +* update 重构 统一使用 流工具下载 +* update 重写 所有业务导出 适配easyexcel工具 +* update 移动文件存储业务到 system 模块 +* update 代码生成模板 适配新excel导出 +* update 将 Actuator 配置 移动到全局配置 +* update 统一镜像时区配置 移除主机时间映射 +* update 更改多数据源框架更清晰的依赖名 +* update 更新 阿里云 maven源 新地址 +* update 补全基础实体 文档注解 +* update 代码生成文档注解 增加必填判断配置 +* update 注入器 insert 增加 update 字段处理 +* update 默认首页使用keep-alive缓存 + +### 漏洞修复 +* fix 生产minio回显问题 +* fix 修复角色分配用户页面接收参数与传递参数类型不一致导致的错误 +* fix 修复代码生成 删除按钮报错 loading 不取消问题 +* fix 解决登录后浏览器后台Breadcrumb组件报错 +* fix 修复DictUtils方法报错 +* fix 头像上传 未走OSS存储问题 +* fix oss列表 jpeg 不回显问题 +* fix 修复操作日志根据状态查询异常问题 + +### 功能移除 +* remove 移除原生excel工具 +* remove 移除通用上传下载接口与配置 + +## v2.6.0 - 2021-7-28 + +### 重大更新 +* add [重大新增] 增加 OSS 对象存储模块 +* remove [重大改动] 删除 自带通用上传 接口 使用OSS模块替换 +* update [重大改动] 重写VO转换 支持深拷贝 将VO类抽象到 ServicePlus 泛型处理 +* update [重大改动] 多BO合并 使用分组校验 生成BO代码 +* update [重大改动] 重构 IServicePlus 功能 增加 BeanCopyUtils 深拷贝工具 + +### 依赖升级 +* update springboot 2.4.9 => 2.5.3 +* update hutool 5.7.4 => 5.7.6 +* update minio 8.2.2 => 8.3.0 +* update docker plugin 1.2.0 => 1.2.2 +* update redisson 3.16.0 => 3.16.1 +* update datasource 3.4.0 => 3.4.1 +* update element-ui 2.15.2 => 2.15.3 + +### 新功能 +* add 演示Demo增加自定义分页接口案例 +* add 角色&菜单新增字段属性提示信息 + +### 功能更新 +* update 更新druid配置 独立配置更明显 +* update 顶部菜单排除隐藏的默认路由 +* update 富文本新增上传文件大小限制 +* update 导入用户样式调整 +* update 顶部菜单样式调整 +* update 密码框新增显示切换密码图标 +* update 内链设置meta信息 +* update 跳转路由高亮相对应的菜单栏 + +### 漏洞修复 +* fix 修复多数据源druid全局配置缩进错误 引起无效配置问题 +* fix 修复定时任务日志执行状态显示 +* fix 修复 授权角色空数据问题 +* fix 修复 DictData 删除逻辑问题 +* fix 修复任意账户越权漏洞 + +## v2.5.2 - 2021-7-19 + +### 功能更新 +* update 优化代码生成器注释格式 + +### 漏洞修复 +* fix 回滚代码生成 批处理优化 +* fix 代码生成 queryType 重复勾选数据库无默认值问题 +* fix 修复接口单参数校验无效问题 +* fix 代码生成 queryType >= <= 标识符错误问题 +* fix 修复代码生成字典问题 +* fix 修复 thread-pool: enabled 配置不生效问题 + +### 功能移除 +* remove 删除无用文档与脚本 + +## v2.5.1 - 2021-7-13 +* update 验证码开关 转移到表 参数管理 内 +* update 使用hutool重构 判断是否url + +### 漏洞修复 + +### 功能更新 +* fix 修复 docker业务集群部署与文件上传的问题 +* fix 修复代码生成同步表结构id冲突问题 +* fix 修复代码生成选择字典 无法取消问题 +* fix 修复代码生成字典为null问题 +* fix 图片上传 多图时无法删除相应图片修复 + +### 功能移除 +* remove 删除富文本video事件 + +## v2.5.0 - 2021-7-12 + +### 依赖升级 +* update springboot 2.4.7 => 2.4.8 +* update knife4j 3.0.2 => 3.0.3 +* update hutool 5.7.2 => 5.7.4 +* update spring-boot-admin 2.4.1 => 2.4.3 +* update redisson 3.15.2 => 3.16.0 + +### 新功能 +* add 增加 docker 编排 与 shell 脚本 +* add 增加 feign 熔断 自定义结构体解析方法 与 demo 注释 +* add 用户管理新增分配角色功能 +* add 角色管理新增分配用户功能 +* add 增加spring-cache演示案例 + +### 功能更新 +* update 独立 springboot-admin 监控到扩展模块项目 +* update springboot-admin 监控 增加用户登录权限管理 +* update 优化代码生成器 批量导入 +* update 优化 增加MP注入异常拦截 +* update 关闭默认二级缓存 推荐使用 spring-cache 注解手动缓存 +* update FileUpload ImageUpload组件 支持多图片上传 +* update 优化中英文语言配置 +* update 规范maven写法 + +### 漏洞修复 +* fix redis获取map属性bug修复。 +* fix 修复 按钮loading 后端500卡死问题 +* fix 相对路径下载问题 +* fix 修复 hutool 工具返回结果不一致问题 + +## v2.4.0 - 2021-6-24 + +### 依赖升级 +* update springboot 2.3.11 => 2.4.7 +* update springboot-admin 2.3.1 => 2.4.1 +* update feign 2.2.6 => 3.0.3 +* update hutool 5.6.7 => 5.7.2 + +### 功能更新 +* update 多数据源替换成dynamic-datasource +* update 适配 jdk11 +* update 集成 Lock4j 分布式锁 +* update 移除 fastjson 增加 jackson 工具类 重写相关业务 +* update 优化 异步工厂重写 使用 spring 异步处理 +* update 全局挂载字典标签组件 +* update 日志列表支持排序操作 +* update 更新 feign demo 更清晰的用法 +* update 更新多数据源演示案例 + +### 新功能 +* add 增加 ServicePlusImpl 自动以实现类 重写移除事务注解方法 防止多数据源失效 +* add 增加 自定义 批量insert方法 +* add 增加 Swagger3 用法示例 + +### 漏洞修复 +* fix 修复地址ip地址特殊回环问题 + +## v2.3.2 - 2021-6-11 + +### 新功能 +* add redis锁工具类编写 + +### 功能更新 +* update spring-cache 整合 redisson +* update MybatisPlus整合Redis二级缓存 +* update swagger 升级为 3.0.0 使用 OAS_30 协议 +* update 优化 代码生成器 增加表单防重注解 +* update 优化 锁切面代码 key到常量类 + +### 漏洞修复 +* fix 修复相对路径上传异常问题 + +## v2.3.1 - 2021-6-4 + +### 新功能 +* add 增加 redisson 分布式锁 注解与demo案例 +* add 增加 Oracle 分支 + +### 功能更新 +* update 优化 redis 空密码兼容性 +* update 优化前端代码生成按钮增加 loading + +### 漏洞修复 +* fix 修复 redisson 不能批量删除的bug +* fix 修复表单构建选择下拉选择控制台报错问题 +* fix 修复 vo 代码生成 主键列表显示 重复生成bug +* fix 修复上传路径 win 打包编译为 win 路径, linux 报错bug + +## v2.3.0 - 2021-6-1 + +### 新功能 +* add 升级 luttuce 为 redisson 性能更强 工具更全 +* add 增加测试数据sql文件 +* add 增加demo模块 单表演示案例(包含数据权限) + +### 功能更新 +* update 完美修复 数据权限功能(支持单表多表过滤) +* update 优化代码生成模板 +* update 优化 system 模块 批量操作性能 + +## v2.2.1 - 2021-5-29 + +### 新功能 +* add 增加 security 权限框架 `@Async` 异步注解配置 + +### 功能更新 +* update 优化dataScope参数防止注入 +* update 优化参数&字典缓存操作 +* update 增加修改包名文档 +* update 文档增加演示图例 + +### 漏洞修复 +* fix 修复部门类sql符号错误 + +## v2.2.0 - 2021-5-25 + +* 同步升级 RuoYi-Vue 3.5.0 + +### 新功能 +* add 增加验证码开关 +* add 新增IE浏览器版本过低提示页面 + +### 功能更新 +* update 升级druid到最新版本v1.2.6 +* update 升级fastjson到最新版1.2.76 +* update 修改bo加入判断是否设置必填再加载必填注解 +* update 生成vue模板导出按钮点击后添加遮罩 +* update Redis设置HashKey序列化 +* update 优化Redis序列化配置 + +### 漏洞修复 +* fix 修复代码生成器中表字段取消必填无法更新问题 + +## v2.1.2 - 2021-5-21 + +### 功能更新 +* update springboot 升级 2.3.11 +* update mybatis-plus 升级 3.4.3 分页Plus对象适配更新 +* update 验证码生成更新为无符号整数计算 +* update 请求响应对象 与 分页对象 结构修改 适配接口文档配置 +* update swagger增加请求前缀 + +## v2.1.1 - 2021-5-19 + +### 功能更新 +* update 配置统一提取为 properties 配置类 +* update 分页工具 删除过期方法 +* update admin 实时监控日志 改为保留一天 + +### 漏洞修复 +* fix 修复swagger开关无法控制关闭问题 +* fix maven install 异常 + +## v2.1.0 - 2021-5-17 + +### 功能更新 +* update knife4j升级3.0.2 +* update 增强分页工具兼容性 +* update 通用Service接口 增加自定义vo转换函数 + +### 移除功能 +* remove 移除ruoyi自带服务监控(Admin已全部包含) + +## v2.0.0 - 2021-5-15 + +### 依赖升级 +* springboot 升级 2.3.10 依赖全面升级适配 + +### 新功能 +* add 增加分页工具 +* add 增加 增强Mapper 与 增强Service 重写业务适配 +* add 代码生成器 增加校验注解 + +### 功能更新 +* update 代码生成器修改为MP分页 +* update 使用 MP 分页工具 重构业务 +* update 重写文档介绍 + +### 移除功能 +* remove 移除 pagehelper 分页工具 + +### 漏洞修复 +* fix 修复代码生成 数据权限问题 + +## v1.0.2 - 2021-5-13 + +### 功能更新 +* update 更新整合打包文档 重新排版 + +### 漏洞修复 +* fix vue与boot整合打包与admin页面路由冲突 + +## v1.0.1 - 2021-5-11 + +### 依赖更新 +* update 更新banner +* update 配置转移到 yml 文件 统一管理 +* update 上传媒体类型添加视频格式 +* update 树级结构更新子节点使用replaceFirst +* update 删除操作日志记录日志 + +### 漏洞修复 +* fix 修正导入表权限标识 +* fix 文件上传时报错 + +## v1.0.0 - 2021-5-10 +* 基于 ruoyi-vue 3.4.0 发布 v1.0.0 稳定版 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md new file mode 100644 index 00000000..ef65fef3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/architecture_diagram.md @@ -0,0 +1,3 @@ +# 软件架构图 +- - - +![输入图片说明](https://foruda.gitee.com/images/1722569328704494018/e84442b6_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md new file mode 100644 index 00000000..06e62dc5 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/doc.md @@ -0,0 +1,89 @@ +# 接口文档 +- - - +## 版本 >= `4.3.0` +## 说明 + +由于 `springfox` 与 `knife4j` 均停止维护 bug众多
+故从 `4.3.0` 开始 迁移到 `springdoc` 框架
+基于 `javadoc` 无注解零入侵生成规范的 `openapi` 结构体
+由于框架自带文档UI功能单一扩展性差 故移除自带UI 建议使用外置文档工具 + +## 文档工具使用 +由于框架采用 `openapi` 行业规范 故市面上大部分的框架均支持 可自行选择
+例如: `apifox` `apipost` `postman` `torna` `knife4j` 等 根据对应工具的文档接入即可 + +## Swagger升级SpringDoc指南 + +常见功能如下 其他功能自行挖掘
+**注意: `javadoc` 只能替换基础功能 特殊功能还需要使用注解实现** + +| swagger | springdoc | javadoc | +|----------------------------------|---------------------------------|--------------------| +| @Api(name = "xxx") | @Tag(name = "xxx") | java类注释第一行 | +| @Api(description= "xxx") | @Tag(description= "xxx") | java类注释 | +| @ApiOperation | @Operation | java方法注释 | +| @ApiIgnore | @Hidden | 无 | +| @ApiParam | @Parameter | java方法@param参数注释 | +| @ApiImplicitParam | @Parameter | java方法@param参数注释 | +| @ApiImplicitParams | @Parameters | 多个@param参数注释 | +| @ApiModel | @Schema | java实体类注释 | +| @ApiModelProperty | @Schema | java属性注释 | +| @ApiModelProperty(hidden = true) | @Schema(accessMode = READ_ONLY) | 无 | +| @ApiResponse | @ApiResponse | java方法@return返回值注释 | + +# 建议使用 `Apifox`(常见问题有其他对接方式) + +官网连接: [https://www.apifox.cn/](https://www.apifox.cn/)
+视频教程: [springdoc与apifox配合使用](https://www.bilibili.com/video/BV1mr4y1j75M?p=8&vd_source=8f52c77be3233dbdd1c5e332d4d45bfb) + +![输入图片说明](https://foruda.gitee.com/images/1678976476639902970/f1617b40_1766278.png "屏幕截图") + +支持 文档编写 接口调试 Mock 接口压测 自动化测试 等一系列功能 + +### 接入框架 + +> 1.下载或使用web在线版 创建一个自己的项目 + +![输入图片说明](https://foruda.gitee.com/images/1678976502850663851/7bbd8728_1766278.png "屏幕截图") + +> 2.进入项目 选择项目设置 找到自动同步 + +![输入图片说明](https://foruda.gitee.com/images/1678976508918240326/6a4a61a8_1766278.png "屏幕截图") + +> 3.根据项目内所有文档组完成所有数据源创建(拉取后端`openapi`结构体)
+数据源URL格式 `http://后端ip:端口/v3/api-docs/组名`
+项目内所需:
+`http://localhost:8080/v3/api-docs/1.演示模块`
+`http://localhost:8080/v3/api-docs/2.通用模块`
+`http://localhost:8080/v3/api-docs/3.系统模块`
+`http://localhost:8080/v3/api-docs/4.代码生成模块`
+也可不分组统一导入: `http://localhost:8080/v3/api-docs`
+ +![输入图片说明](https://foruda.gitee.com/images/1678976514385097727/05c7e0a6_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1686626073422245046/df4b6a54_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678976527495742967/79836e7f_1766278.png "屏幕截图") + +> 4.选择 接口管理 项目概览 点击立即导入 并等待导入完成
+后续会根据策略每3个小时自动导入一次
+每次重新进入apifox也会自动同步一次
+后端有改动也可以手动点击导入
+ +![输入图片说明](https://foruda.gitee.com/images/1678976534677430926/f32c64c5_1766278.png "屏幕截图") + +> 5.(注意版本号)设置鉴权 选择接口管理 项目概览 找到Auth 按照如下配置 + +**版本号: >= 5.X** + +![输入图片说明](https://foruda.gitee.com/images/1690966897370710566/6a688aea_1766278.png "屏幕截图") + +**版本号: 4.X** + +![输入图片说明](https://foruda.gitee.com/images/1678976539608390075/77246461_1766278.png "屏幕截图") + +> key对应项目配置 默认为 `Authorization` + +![输入图片说明](https://foruda.gitee.com/images/1678976544342001474/c2ff85d3_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678976549237304743/bcdfadda_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md new file mode 100644 index 00000000..4052979a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/i18n.md @@ -0,0 +1,33 @@ +# 国际化方案 +- - - +* 前端国际化参考 [ruoyi前端国际化文档](http://doc.ruoyi.vip/ruoyi-vue/document/htsc.html#前端国际化流程)
+* 后端国际化(2.7.0 以上增加) +* 3.4.0 以上支持 `Validator` 校验框架 +* 参考 `demo` 模块 `TestI18nController` 国际化演示案例 + 在 `Header` 请求头 增加上下文语言参数 `content-language` 参数需与国际化配置文件后缀对应 + 如 `zh_CN` `en_US` 等
+ +![输入图片说明](https://foruda.gitee.com/images/1678976722892396585/60917594_1766278.png "屏幕截图") + +## 获取 `code` 对应国际化内容 + +![输入图片说明](https://foruda.gitee.com/images/1678976728533100954/0ab8e36a_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976733019209506/a16574d6_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976738409745057/a073b425_1766278.png "屏幕截图") + +## 使用 `Validator` 框架校验 `controller` 参数返回国际化 + +`controller` 校验接口参数 需要在类增加 `@Validated` 注解
+![输入图片说明](https://foruda.gitee.com/images/1678976741834729507/6c19b9cc_1766278.png "屏幕截图")
+参数对应校验注解 使用 `{code}` 形式标注使用国际化处理
+![输入图片说明](https://foruda.gitee.com/images/1678976746093285542/ad0989db_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976750822808564/56bd60d7_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976754755107198/b89bf173_1766278.png "屏幕截图") + +## 使用 `Validator` 框架校验 `Bean` 返回国际化 + +`Bean` 校验需要在接口校验 `Bean` 参数使用 `@Validated` 注解
+![输入图片说明](https://foruda.gitee.com/images/1678976761015767874/729da3bc_1766278.png "屏幕截图")
+`Bean` 内属性校验注解 使用 `{code}` 形式标注使用国际化处理
+![输入图片说明](https://foruda.gitee.com/images/1678976765122587920/0b1027af_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976769965314387/0c416ede_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md new file mode 100644 index 00000000..87b992aa --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/new_module.md @@ -0,0 +1,15 @@ +# 关于如何创建新模块 +- - - +* 参考ruoyi-demo模块 +* 需要改动: 父pom 与 admin模块pom + +![输入图片说明](https://foruda.gitee.com/images/1719814203987728184/6940ecf8_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1719814254968294155/70fe6d77_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1719814280768521481/14fb11cd_1766278.png "屏幕截图") + +### 注意事项 +如果是两个不同包名的模块 需要修改如下配置 + +![输入图片说明](https://foruda.gitee.com/images/1719813861680271619/82435586_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1692006501957936219/059f8526_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md new file mode 100644 index 00000000..2dcab848 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_package_name.md @@ -0,0 +1,33 @@ +# 关于修改包名 +- - - + +**注意: 老包名为 com.ruoyi** + +## 1.随便找个地方新建 org.dromara 包 +![输入图片说明](https://foruda.gitee.com/images/1708491220807198688/b95c0c34_1766278.png "屏幕截图") + +## 2.在包上右键选择 refactor -> rename 选择 All Directories +![输入图片说明](https://foruda.gitee.com/images/1683276891079076405/79808b22_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1708491697128844860/1e87ad39_1766278.png "屏幕截图") + +**因为dromara组织下有很多依赖导致idea无法识别完整包名** +
+![输入图片说明](https://foruda.gitee.com/images/1708490576909691001/692e5b37_1766278.png "屏幕截图") + +**需要先将dromara修改为 例如: ruoyi 然后重复上述步骤 这样就可以整包修改了** +
+![输入图片说明](https://foruda.gitee.com/images/1708490906933084793/ff104cd7_1766278.png "屏幕截图") + +## 3.使用IDEA全局替换 org.dromara 替换为 com.xxx + +![输入图片说明](https://foruda.gitee.com/images/1708491055347995519/dedda0d1_1766278.png "屏幕截图") + +**注意: 由于dromara组织下项目很多 非本框架的依赖模块 请勿修改 例如上图中的 org.dromara.sms4j** + +## 4.如有需要 将所有模块名逐一修改即可 + +## 5.修改完成后需查看所有common包下模块spi文件是否修改正确 + +**老版本idea或者未按照教程修改包名可能导致文件丢包问题** + +![输入图片说明](https://foruda.gitee.com/images/1708491365841192006/8bc337c2_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md new file mode 100644 index 00000000..0f5f106b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/association/update_url.md @@ -0,0 +1,26 @@ +# 修改应用路径 +- - - +## 修改后端路径 + +更改 `application.yml` 的 `server.servlet.context-path` 即可更改后端容器路径 + +![输入图片说明](https://foruda.gitee.com/images/1724316662536650741/41d534b1_1766278.png "屏幕截图") + +与之对应前端 `dev`环境 需更改 `vite.config.ts` 的代理路径 + +![输入图片说明](https://foruda.gitee.com/images/1724316844091667249/9b0badc5_1766278.png "屏幕截图") + +`prod` 生产环境需修改 `nginx.conf` 后端代理路径 + +![输入图片说明](https://foruda.gitee.com/images/1661823876773225117/f1f912a9_1766278.png "屏幕截图") + +## 修改前端路径 +### 注意: 3.4.0 提供便捷更改方式 +直接修改对应环境的 `.env.环境` 文件内的 `VITE_APP_CONTEXT_PATH` 应用访问路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1661824572484410642/14265f05_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1724317049535973756/0a2cc43b_1766278.png "屏幕截图") + +生产环境 `nginx.conf` 与之对应修改即可
+**注意: 文件真实目录为 `/usr/share/nginx/html/admin/index.html` 此功能一般为多项目部署需要 故会增加一层目录 如不需要可以自行修改**
+![输入图片说明](https://foruda.gitee.com/images/1678976662194341301/2720b7e9_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md new file mode 100644 index 00000000..bec103d8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/client.md @@ -0,0 +1,85 @@ +# 客户端管理功能 +- - - +## 版本 >= 5.X + +## 客户端管理页面 + +![输入图片说明](https://foruda.gitee.com/images/1690961819029076660/c44374ac_4959041.png "屏幕截图") + +### 客户端管理字段说明 +| 字段名称 | 取值说明 | 注意事项 | +|----------------|----------------------------|--------------------------------| +| 客户端id | 由后端生成,用于前端登录校验以及接口数据加密 | 无法修改,不要删除默认数据,否则会报错 | +| 客户端key | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | +| 客户端秘钥 | 前端自定义 | 无法修改,不要删除默认数据,否则会报错 | +| 授权类型 | 密码认证、短信认证、邮件认证、小程序认证、第三方认证 | 根据授权类型判断当前客户端是否支持该登录方式 | +| 设备类型 | PC端、APP端 | | +| Token活跃超时时间 | 自定义 | 指定时间无操作则过期(单位:秒),默认30分钟(1800秒) | +| Token固定超时时间 | 自定义 | 指定时间必定过期(单位:秒),默认七天(604800秒) | + +### 前后端使用新的客户端id + +步骤如下: +1. 前端管理页面生成新的客户端id。 +2. 将新的客户端id复制到前端配置文件。 + +![输入图片说明](https://foruda.gitee.com/images/1690962894318847386/133d2f90_4959041.png "屏幕截图") + +## 新增自定义客户端 + +### 步骤一:新增客户端数据(例如增加小程序端) + +![输入图片说明](https://foruda.gitee.com/images/1690965463070099188/baeb4441_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1690965508836621042/df06248f_4959041.png "屏幕截图") + +### 步骤二:配置前端请求头信息 + +需要在全局请求头 header 中增加 cientid
+确保客户端所有请求都携带此id 可参考项目 `request.ts` + +![输入图片说明](https://foruda.gitee.com/images/1690965768235114596/980b88d2_4959041.png "屏幕截图") + +`VITE_APP_CLIENT_ID` 即配置文件中的客户端id。 + +**重点:不同客户端登录获取到的token不同与其他端不互通(例如: app登录获取到的token无法用于pc端接口查询)** + +## 新增自定义登录方式授权类型 + +**重点说明: 不要单独增加登录接口 系统全局统一只有一个登录接口 只需增加不同的鉴权方式即可** + +如何调试使用登录看这里 -> [关于登录调试步骤](/questions/login_step.md) + +### 步骤一:新增字典数据 + +![输入图片说明](https://foruda.gitee.com/images/1690968849418013624/3b28417e_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1690968865819397010/64529fad_4959041.png "屏幕截图") + +### 步骤二:新增/修改客户端数据 + +### 步骤三:后端新增认证策略 + +新增策略实现类实现 `IAuthStrategy` 接口。
+ +![输入图片说明](https://foruda.gitee.com/images/1690972828588111954/7614a4c5_4959041.png "屏幕截图") + +参照已有策略实现类实现自定义参数校验登录方法逻辑。
+ +![输入图片说明](https://foruda.gitee.com/images/1718951146945578143/789c80e4_1766278.png "屏幕截图") + +**注意修改 `@Service` 名称保证规范性** + +![输入图片说明](https://foruda.gitee.com/images/1718951179571300385/8db730b9_1766278.png "屏幕截图") + +`LoginBody` 校验参数(可自定义)
+ +![输入图片说明](https://foruda.gitee.com/images/1718951237123374392/f7840db2_1766278.png "屏幕截图") + +例如 扩展小程序登录参数 只需要继承 `LoginBody
+ +![输入图片说明](https://foruda.gitee.com/images/1718951283931895761/e6348be5_1766278.png "屏幕截图")` + +校验分组(可自定义)
+ +![输入图片说明](https://foruda.gitee.com/images/1718951343601334215/8ef404b4_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md new file mode 100644 index 00000000..e20e09ac --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/code_generate.md @@ -0,0 +1,85 @@ +# 代码生成 +- - - +## 功能介绍 + +### 数据源配置 + +![输入图片说明](https://foruda.gitee.com/images/1678976867341325193/a2be0608_1766278.png "屏幕截图") + +**>= 4.1.0版本 项目适配多种类型数据库 可以在代码生成页面切换**
+ +> 填写对应的数据源名称 点击搜索按钮 即可切换到对应的数据源
+ +![输入图片说明](https://foruda.gitee.com/images/1678976876081856486/4ef4841c_1766278.png "屏幕截图") + +**>= 5.2.2版本 项目支持100+种数据库适配 在代码生成模块增加对应的数据库依赖即可**
+ +![输入图片说明](https://foruda.gitee.com/images/1722396530340741054/3914eb72_1766278.png "屏幕截图") + +### 导入数据表 + +> 点击导入按钮 会加载系统数据库所有的表
+ +![输入图片说明](https://foruda.gitee.com/images/1678976880393939803/3ecf1dcc_1766278.png "屏幕截图") + +> 选择需要的表 点击确定即可
+ +![输入图片说明](https://foruda.gitee.com/images/1678976885370716109/4834faa5_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976891856866728/853420d9_1766278.png "屏幕截图") + +### 编辑表生成结构 + +> 点击表对应的编辑按钮
+ +![输入图片说明](https://foruda.gitee.com/images/1678976899111822310/aeaa33f9_1766278.png "屏幕截图") + +> 更改要生成表的数据
+ +![输入图片说明](https://foruda.gitee.com/images/1678976903345795925/4326f6ee_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678976908897387614/4cdf939b_1766278.png "屏幕截图") + +### 生成条件影响 + +![输入图片说明](https://foruda.gitee.com/images/1678976913809284051/24da09b0_1766278.png "屏幕截图") + + +* `插入` `编辑` 影响生成 BO 类 与 前端添加编辑页面 是否有该字段 +* `列表` 影响生成 VO 类 与 前端列表页面展示 是否有该字段 +* `查询` 影响 前端页面是否有该字段的搜索框 与 后端代码是否生成对应的查询条件 +* `查询方式` 影响生成查询条件的类型 +* `必填` 影响 BO 类 与 页面是否强制校验 +* `显示类型` 影响生成页面使用何种展示组件 +* `字典类型` 影响页面是否生成与字典的关联 + +### 树表配置 + +> 编辑表生成信息 生成模板为 `树表` 填写对应数据即可
+ +![输入图片说明](https://foruda.gitee.com/images/1678976917918548901/f5886c5c_1766278.png "屏幕截图") + +### 主子表说明 + +框架不支持也不推荐使用主子表
+原因一般业务场景 基本都是一对N表 多表关联场景
+还有一些 主 => 子 <= 主 场景 需求很复杂 很少有单纯主子表场景出现
+另外主子表关联 很容易出现 笛卡尔积 或者数据错乱等问题 需要自行sql调优场景
+所以建议大家都按照 单表生成 自行编写业务逻辑 + +### 预览功能 + +> 配置好生成信息后 可以点击预览按钮
+ +![输入图片说明](https://foruda.gitee.com/images/1678976924411765532/2e9747df_1766278.png "屏幕截图") + +> 系统会根据已经配置好的数据 生成对应的代码预览
+> 可以再此处观察代码的生成结构和数据是否正确等
+ +![输入图片说明](https://foruda.gitee.com/images/1678976945982406065/ca7383bb_1766278.png "屏幕截图") + + +### 代码结构同步 + +> 实际开发中 难免会有表结构更改的需求
+> 这时可以使用 同步功能 点击同步按钮 即可与实时数据库表进行字段同步
+ +![输入图片说明](https://foruda.gitee.com/images/1678976952919156537/3c47c078_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md new file mode 100644 index 00000000..1dd01c17 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/export.md @@ -0,0 +1,249 @@ +# 导出功能 + +- - - + +在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导出操作(即写 Excel)。 + +[EasyExcel 文档地址](https://easyexcel.opensource.alibaba.com/) + +## 导出功能使用流程说明 + +### 步骤一:定义导出实体对象 + +以框架中 `SysUserExportVo` 为例: + +```Java + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + // ....................... + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; +``` + +> 说明:
+> 1. 使用 `@ExcelProperty` 注解标注需要导出的属性。 +> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 +> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 + +### 步骤二:使用导出方法 + +以框架中 `SysUserController#export` 方法为例: + +```Java + /** + * 导出用户列表 + */ + @PostMapping("/export") + public void export(SysUserBo user, HttpServletResponse response) { + // 根据参数查询导出的用户列表数据 + List list = userService.selectUserList(user); + // 将列表转换为导出对象列表 + List listVo = MapstructUtils.convert(list, SysUserExportVo.class); + // 导出方法 + ExcelUtil.exportExcel(listVo, "用户数据", SysUserExportVo.class, response); + } +``` + +> 说明:
+> 使用 `ExcelUtil.exportExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导出对象集合,Excel sheet 表名称,导出对象类型,response。 + +## 框架工具使用说明 + +### 1:字典转换器 + +字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 + +使用方式一: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; +``` + +使用方式二: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") + private String sex; +``` + +`@ExcelDictFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|------------------|--------|-----|-----------------------------------| +| dictType | String | "" | 字典的type值 (如: sys_user_sex) | +| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | +| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | + +### 2:枚举转换器 + +字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 + +使用方式: + +```Java + /** + * 用户类型 + *

+ * 使用ExcelEnumFormat注解需要进行下拉选的部分 + */ + @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) + @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") + private String userStatus; +``` + +`@ExcelEnumFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|-----------|------------|------|------------------------------| +| enumClass | Enum Class | - | 字典枚举类型 | +| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | +| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | + +### 3:合并单元格 + +`@CellMerge` 注解用于合并相同的列数据,需要结合 `CellMergeStrategy` 策略使用,标注在需要转换的属性上。 + +使用方式: + +步骤一:在属性标注 `@CellMerge` 注解: +```Java + /** + * 部门id + */ + @CellMerge + @ExcelProperty(value = "部门id") + private Long deptId; +``` + +`@CellMerge` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|---------|----------|-----|------------------------------| +| index | int | -1 | 合并列的下标,建议使用默认值 | +| mergeBy | String[] | {} | 合并需要依赖的其他字段名称(基于这个字段内容做合并条件) | + +步骤二:导出方法开启合并: +```Java + /** + * 导出测试单表列表 + */ + @PostMapping("/export") + public void export(@Validated TestDemoBo bo, HttpServletResponse response) { + List list = testDemoService.queryList(bo); + // 参数 true 表示开启合并单元格策略 + ExcelUtil.exportExcel(list, "测试单表", TestDemoVo.class, true, response); + } +``` +![输入图片说明](https://foruda.gitee.com/images/1700128921644543994/e8d4704f_1766278.png "屏幕截图") + +### 4:复杂 Excel 导出示例 +`TestExcelController` 提供了几种导出示例,如果需要可以参照相应方法进行导出。 + +#### 4.1:单列表多数据导出(模板导出) + +模板内容: + +![输入图片说明](https://foruda.gitee.com/images/1700124852002972562/d9f57a8c_4959041.png "屏幕截图") + +模板位置:`ruoyi-modules/ruoyi-demo/src/main/resources/excel/` + +导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700124885532359879/0d011d05_4959041.png "屏幕截图") + +#### 4.2:多列表多数据导出(模板导出) + +模板内容: + +![输入图片说明](https://foruda.gitee.com/images/1700125025931981176/105dbaaa_4959041.png "屏幕截图") + +模板位置:`ruoyi-modules/ruoyi-demo/src/main/resources/excel/` + +导出示例代码:参考 demo 模块 `TestExcelController` 模板写法请查看 `EasyExcel` 文档 + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700125054011300002/71869c1d_4959041.png "屏幕截图") + +#### 4.3:导出下拉框 + +`ExcelDictFormat` 注解指定的字典项默认都会转换成下拉框 + +自定义导出省市区下拉框示例代码:参考 demo 模块 `TestExcelController` + +导出结果: + +![输入图片说明](https://foruda.gitee.com/images/1700125265411678973/7f767719_4959041.png "屏幕截图") + +## Easy Excel 常用注解 + +`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解,自定义注解会结合转换器一起进行说明。 + +| 类型 | 注解名称 | 使用举例 | 说明 | +|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| +| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | +| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | +| 样式注解 | @ColumnWidth | @ColumnWidth(value=值) | 设置列宽 | +| 样式注解 | @ContentFontStyle | @ContentFontStyle(color=颜色) | 可以设置字体类型,颜色,粗细,是否斜体,下划线等,具体可查看注解 `@ContentFontStyle` | +| 样式注解 | @ContentLoopMerge | @ContentLoopMerge(eachRow=行值, columnExtend=列值) | 设置循环合并的区域 | +| 样式注解 | @ContentRowHeight | @ContentRowHeight(value=值) | 设置内容行高 | +| 样式注解 | @ContentStyle | - | 设置单元格样式,具体可查看注解 `@ContentStyle` | +| 样式注解 | @HeadFontStyle | @HeadFontStyle(color=颜色) | 设置表头字体格式,类似 `@ContentFontStyle`,具体可查看注解 `@HeadFontStyle` | +| 样式注解 | @HeadRowHeight | @HeadRowHeight(value=值) | 设置表头行高 | +| 样式注解 | @HeadStyle | - | 设置表头样式,具体可查看注解 `@HeadStyle` | +| 样式注解 | @OnceAbsoluteMerge | @OnceAbsoluteMerge(firstRowIndex=开始行下标, lastRowIndex=结束行下标, firstColumnIndex=开始列下标, lastColumnIndex=结束列下标) | 根据设置值合并单元格 | +| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | +| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | +| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | + +## 扩展说明 + +### 自定义转换器实现 + +由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 +以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 + +字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 + +_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ + +#### 实现方式 + +自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") + +转换方法 `ExcelDictConvert#convertToExcelData` : + +![输入图片说明](https://foruda.gitee.com/images/1700104426131801297/72931ef0_4959041.png "屏幕截图") + +## 更多功能 + +更多导出功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/api/write)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md new file mode 100644 index 00000000..f1bbca7d --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/import.md @@ -0,0 +1,202 @@ +# 导入功能 +- - - + +在本框架中引入了 `Easy Excel` 依赖(对 `Apache POI`进行了封装以及扩展),可以对数据进行导入操作(即读 Excel)。 + +## 导入功能使用流程说明 + +### 步骤一:定义导入实体对象 + +以框架中 `SysUserImportVo` 为例: + +```java + /** + * 用户ID + */ + @ExcelProperty(value = "用户序号") + private Long userId; + + // ....................... + + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; + + /** + * 帐号状态(0正常 1停用) + */ + @ExcelProperty(value = "帐号状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_normal_disable") + private String status; +``` + +> 说明:
+> 1. 使用 `@ExcelProperty` 注解标注需要导入的属性。 +> 2. 注解 `@ExcelProperty` 中 `value` 属性代表表格头部标题字段,`converter` 代表使用的转换器,后面会详细说明。 +> 3. 注解 `@ExcelDictFormat` 为自定义注解,与自定义转换器结合使用,同样在后面进行详细说明。 +> 4. 对象禁止使用链式注解 `@Accessors(chain = true)`,会找不到set方法。 + +### 步骤二:使用导入方法 + +以框架中 `SysUserController#importData` 方法为例: + +```Java + /** + * 导入数据 + * + * @param file 导入文件 + * @param updateSupport 是否更新已存在数据 + */ + @Log(title = "用户管理", businessType = BusinessType.IMPORT) + @SaCheckPermission("system:user:import") + @PostMapping(value = "/importData", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + public R importData(@RequestPart("file") MultipartFile file, boolean updateSupport) throws Exception { + // 导入方法 + ExcelResult result = ExcelUtil.importExcel(file.getInputStream(), SysUserImportVo.class, new SysUserImportListener(updateSupport)); + return R.ok(result.getAnalysis()); + } +``` +> 说明:
+> 使用 `ExcelUtil.importExcel` 方法完成导出功能,上述 Demo 传入参数分别是:导入文件流,导入对象类型,导入监听器 `SysUserImportListener`。 + +## 框架工具使用说明 + +### 1:字典转换器 + +字典转换器 `ExcelDictConvert` 与自定义注解 `@ExcelDictFormat` 结合使用,标注在需要转换的属性上。 + +使用方式一: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(dictType = "sys_user_sex") + private String sex; +``` + +使用方式二: + +```Java + /** + * 用户性别 + */ + @ExcelProperty(value = "用户性别", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp="0=男,1=女,2=未知", separator=",") + private String sex; +``` + +`@ExcelDictFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|------------------|--------|-----|-----------------------------------| +| dictType | String | "" | 字典的type值 (如: sys_user_sex) | +| readConverterExp | String | "" | 读取内容转表达式 (如: 0=男,1=女,2=未知) | +| separator | String | "," | 与 readConverterExp 属性结合使用,表达式的分隔符 | + +### 2:枚举转换器 + +字典转换器 `ExcelEnumConvert` 与自定义注解 `@ExcelEnumFormat` 结合使用,标注在需要转换的属性上。 + +使用方式: + +```Java + /** + * 用户类型 + *

+ * 使用ExcelEnumFormat注解需要进行下拉选的部分 + */ + @ExcelProperty(value = "用户类型", index = 1, converter = ExcelEnumConvert.class) + @ExcelEnumFormat(enumClass = UserStatus.class, textField = "info") + private String userStatus; +``` + +`@ExcelEnumFormat` 注解属性说明: + +| 属性名称 | 属性类型 | 默认值 | 说明 | +|-----------|------------|------|------------------------------| +| enumClass | Enum Class | - | 字典枚举类型 | +| codeField | String | code | 字典枚举类中对应的 code 属性名称,默认为 code | +| textField | String | text | 字典枚举类中对应的 text 属性名称,默认为 text | + + +### 3:导入监听器 + +#### 3.1:ExcelListener 监听器接口 + +`ExcelListener` 扩展了 `ReadListener` 接口,增加了获取结果方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700181723794469524/99bf83c9_4959041.png "屏幕截图") + +#### 3.2:DefaultExcelListener 默认监听器 + +`DefaultExcelListener` 默认监听器在读 Excel 时调用,主要对数据进行校验、解析、异常处理、返回结果等。导入操作时如果没有特别指定则使用该监听器。 + +#### 3.3:SysUserImportListener 用户导入监听器 + +`SysUserImportListener` 用户导入监听器是在用户导入时调用的监听器。 + +该监听器重写了 `invoke` 反射接口,对导入的用户数据进行了校验;重写了 `getExcelResult` 获取结果接口,返回结果数据。 + +#### 3.4:ExportDemoListener 带下拉框的导入监听器 + +`ExportDemoListener` 是对带有下拉框的 Excel 进行处理的导入监听器。 + +## Easy Excel 常用注解 + +`Easy Excel` 提供了丰富的注解可以对导出对象进行定制化操作,这里的注解说明针对的是原生注解。 + +| 类型 | 注解名称 | 使用举例 | 说明 | +|-------|-------------------------|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------| +| 格式化注解 | @DateTimeFormat | @DateTimeFormat(value=格式化值) | 对字符串进行日期格式化 (参照 `java.text.SimpleDateFormat` 书写即可) | +| 格式化注解 | @NumberFormat | @NumberFormat(value=格式化值, roundingMode=舍入模式) | 对字符串进行数值格式化 (参照 `java.text.DecimalFormat` 书写即可, `roundingMode` 默认 `RoundingMode.HALF_UP`) | +| 属性注解 | @ExcelIgnore | @ExcelIgnore | 导出忽略该字段 | +| 属性注解 | @ExcelIgnoreUnannotated | @ExcelIgnoreUnannotated | 默认不管加不加 `@ExcelProperty` 的注解的所有字段都会参与读写,加了 `@ExcelIgnoreUnannotated` 注解以后,不加 `@ExcelProperty` 注解的字段就不会参与 | +| 属性注解 | @ExcelProperty | @ExcelProperty(value=值, order=排序值, index=下标, converter=转换器) | 默认按照对象属性顺序导出,如果设置了 `order` 以及 `index`,优先级 `index` > `order` > 默认;converter 可以自定义 | + +## 扩展使用 + +### 扩展一:自定义转换器实现 + +由于业务需要,原生注解不一定能够符合需要,因而衍生出了自定义转换器。能够实现定制化的内容转换需要。 +以下以框架中的字典转换器 `ExcelDictConvert` 为例进行说明。 + +字典转换器 `ExcelDictConvert`,字典转换器使用了自定义注解 `@ExcelDictFormat` 配合使用。 + +_**注:自定义转换器并非一定需要自定义注解,也可以针对已有的注解进行自定义转换实现。**_ + +#### 实现方式 + +自定义转换器需要实现 `com.alibaba.excel.converters.Converter` 接口,实现接口中的方法。 + +![输入图片说明](https://foruda.gitee.com/images/1700104014304819918/33eb0c42_4959041.png "屏幕截图") + +转换方法 `ExcelDictConvert#convertToJavaData` : + +![输入图片说明](https://foruda.gitee.com/images/1700182975516396213/d3c020f9_4959041.png "屏幕截图") + +### 扩展二:自定义监听器实现 + +自定义监听器主要用于在读取解析 Excel 数据时进行自定义操作。 +以下以框架中的用户导入监听器 `SysUserImportListener` 为例进行说明。 + +#### 实现方式 +1. 继承分析事件监听器 `AnalysisEventListener` 以及实现 Excel 监听器 `ExcelListener`。 + +![输入图片说明](https://foruda.gitee.com/images/1700184652693497753/09333dac_4959041.png "屏幕截图") + +2. 显示使用构造函数,否则将导致空指针。 + +![输入图片说明](https://foruda.gitee.com/images/1700184759075616584/cf05b0ed_4959041.png "屏幕截图") + +3. 实现 `invoke` 方法,对数据进行解析操作,可以在此方法对数据进行合法性判断。 + +4. 实现 `getExcelResult` 方法,对结果进行操作,例如返回成功、失败的统计数据。 + +## 更多功能 + +更多导入功能使用可以参照 `Easy Excel` [官方文档](https://easyexcel.opensource.alibaba.com/docs/current/quickstart/read)。 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md new file mode 100644 index 00000000..a3e6e6b6 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/interface_release.md @@ -0,0 +1,25 @@ +# 接口放行 +- - - +## 使用方式 + +在配置文件填写路径放行
+![输入图片说明](https://foruda.gitee.com/images/1678979039071447990/8b272aba_1766278.png "屏幕截图") + +### 注解放行 +版本 4.3.1 以上 建议使用 `@SaIgnore` 忽略注解
+ +支持在类或方法上放行
+**注意: 动态路径会解析成通配符 请设计好接口路径避免问题** + +**例如: `/get/{userId}` 会解析成 `/get/*`**
+![输入图片说明](https://foruda.gitee.com/images/1666595109409104199/5b7d75c7_1766278.png "屏幕截图") + +## 注意事项 + +接口放行后不需要token即可访问
+但是没有token也就无法获取用户信息与鉴权 + +### 解决方案 +删除接口上的鉴权注解
+删除接口内获取用户信息功能
+删除数据库实体类 自动注入 `createBy` `updateBy` 因为会获取用户数据 \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md new file mode 100644 index 00000000..47484ab2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/oss.md @@ -0,0 +1,124 @@ +# 关于OSS模块使用 +- - - +## 重点注意事项 + +`桶/存储区域` 系统会根据配置自行创建分配权限
+~~如手动配置需要设置 `公有读` 权限 否则文件无法访问~~(`aliyun` 还需开通跨域配置)
+4.4.0 版本支持配置`公有/私有`权限(`aliyun` 还需开通跨域配置)
+访问站点 后严禁携带其他 `url` 例如: `/`, `/ruoyi` 等
+**阿里云与腾讯云SDK访问站点中不能包含桶名 系统会自动处理**
+**minio 站点不允许使用 localhost 请使用 127.0.0.1**
+**访问站点与自定义域名 都不要包含 `http` `https` 前缀 设置`https`请使用选项处理** + +## 代码使用 + +> 参考 `SysOssService.upload` 用法
+> 使用 `OssFactory.instance()` 获取当前启用的 `OssClient` 实例
+> 进行功能调用 获取返回值后 存储到对应的业务表 + +![输入图片说明](https://foruda.gitee.com/images/1678978345529639839/d350ec0b_1766278.png "屏幕截图") + + +## 功能配置 + +### 配置OSS + +> 进入 `系统管理 -> 文件管理 -> 配置管理` 填写对应的OSS服务相关配置
+ +![输入图片说明](https://foruda.gitee.com/images/1678978349820700551/1f91a237_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978354387669856/3a91a3a9_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978358019307086/0c2523e4_1766278.png "屏幕截图") + +**重点说明** + +> 云厂商只需修改 `访问站点`对应的域 切勿乱改(云厂商强烈建议绑定自定义域名使用 七牛云必须绑定[官方规定])
+ +![输入图片说明](https://foruda.gitee.com/images/1678978362358100362/5c2c4d20_1766278.png "屏幕截图") + +> 七牛云 访问站点
+ + +![输入图片说明](https://foruda.gitee.com/images/1678978366254745764/e93a65ff_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978369853348732/79e8950e_1766278.png "屏幕截图") + +> 阿里云 访问站点 + +![输入图片说明](https://foruda.gitee.com/images/1678978373981462025/56a70398_1766278.png "屏幕截图") + +> 腾讯云 访问站点 + +![输入图片说明](https://foruda.gitee.com/images/1678978378697093134/785517f3_1766278.png "屏幕截图") + +### MinIO 使用 https访问站点 + +**注意:S3 API 签名计算算法不支持托管 MinIO Server API 的代理方案** + +[ minio https 配置方式](https://blog.csdn.net/Michelle_Zhong/article/details/126484358) + +### 切换OSS + +> 再配置列表点击 `状态` 按钮开启即可(注意: 只能开启一个OSS默认配置)
+> 手动使用 `OssFactory.instance("configKey")`
+ +![输入图片说明](https://foruda.gitee.com/images/1678978383700118702/7f3fa0c5_1766278.png "屏幕截图") + +### 扩展分类 + +> 如有文件分类 建议创建多个 oss配置 进行切换存储
+ +例如: 创建一个 图片存储的 oss配置
+指定唯一的 `configKey` 与 `前缀目录` 或 直接使用独立的`桶`
+独立桶的特点 可以自定义访问权限
+例如: 创建一个私有文件存储桶 不对外开放
+ +![输入图片说明](https://foruda.gitee.com/images/1678978389139754119/140be1df_1766278.png "屏幕截图") + +> 指定需要使用的配置
+> 使用 `OssFactory.instance("image")` 获取的 `OssClient` 会加载上图的配置 从而达到上传不同的目录或桶 + + +![输入图片说明](https://foruda.gitee.com/images/1678978397550123641/1b536881_1766278.png "屏幕截图") + + +### 上传图片或文件 + +> 进入 `系统管理 -> 文件管理` 点击 `上传文件` 或 `上传图片` 根据选项选择即可 会对应上传到配置开启的OSS内
+ +![输入图片说明](https://foruda.gitee.com/images/1678978401028132972/445d058e_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978404388284503/5459da29_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978408761764835/c81651fc_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978412748494539/7bae621f_1766278.png "屏幕截图") + +### 列表展示 + +> 默认展示图片(可预览) 文件会展示路径
+ +![输入图片说明](https://foruda.gitee.com/images/1678978416327601385/af1ecb3b_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678978422249633007/19d68eaa_1766278.png "屏幕截图") + +> 可以点击 `预览禁用启用` 按钮对是否展示进行更改 + +![输入图片说明](https://foruda.gitee.com/images/1678978426017014926/4f7fa3f3_1766278.png "屏幕截图") + +> 点击禁用后 图片会变成路径展示 + +![输入图片说明](https://foruda.gitee.com/images/1678978429692592556/0231d778_1766278.png "屏幕截图") + +> 也可再 `参数设置` 更改预览状态 将 `OSS预览列表资源` 改为 `false` 即可关闭预览 + +![输入图片说明](https://foruda.gitee.com/images/1678978433769403801/7d480e76_1766278.png "屏幕截图") + +### 删除功能 + +> 点击列表上方或后方 `删除` 按钮 会根据OSS服务商类型 调用对应的删除(注意: 需确保对应的服务商配置正确)
+> 可勾选多服务商类型的文件进行删除 系统会自动判断 + +![输入图片说明](https://foruda.gitee.com/images/1678978438265941745/f32edc72_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678978441938542080/43ed7c3d_1766278.png "屏幕截图") + +### 下载功能 + +> 点击列表后方对应资源的 `下载` 按钮 根据需求填写文件名 点击确认即可完成下载 + +![输入图片说明](https://foruda.gitee.com/images/1678978448927336261/409af888_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678978452761792483/ed0a4a72_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md new file mode 100644 index 00000000..97b6c525 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/page.md @@ -0,0 +1,32 @@ +# 分页功能 +- - - +## 对应版本 + +> 3.5.0 版本 + +## 重点说明 + +> 项目使用 `mybatis-plus` 分页插件 实现分页功能 大致用法与 MP 一致 [MP分页文档](https://baomidou.com/pages/97710a/)
+> 项目已配置分页合理化 页数溢出 例如: 一共5页 查了第6页 默认返回第一页
+ +![输入图片说明](https://foruda.gitee.com/images/1678977804058241635/b5cb362d_1766278.png "屏幕截图") + +## 代码用法 + +> `Controller` 使用 `PageQuery` 接收分页参数 具体参数参考 `PageQuery` + +![输入图片说明](https://foruda.gitee.com/images/1678977844048821356/1f994221_1766278.png "屏幕截图") + +> 构建 `Mybatis-Plus` 分页对象
+> 使用 `PageQuery#build()` 方法 可快速(基于当前对象数据)构建 `MP` 分页对象 + +![输入图片说明](https://foruda.gitee.com/images/1678977862816976499/b82c1638_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678977876194578744/eaa7b854_1766278.png "屏幕截图")
+ +具体用法与 `MP` 一致 + +> 自定义 `SQL` 方法分页
+> 只需在 `Mapper` 方法第一个参数和返回值 重点: 第一个参数 标注分页对象 + +![输入图片说明](https://foruda.gitee.com/images/1678977898181729571/6e102731_1766278.png "屏幕截图")
+![输入图片说明](https://foruda.gitee.com/images/1678977906788451483/70979292_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md new file mode 100644 index 00000000..95ee19d8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/param_check.md @@ -0,0 +1,158 @@ +# 参数校验 +- - - + +参数校验在日常开发中十分常见,在本框架中引入了 `spring-boot-starter-validation` 依赖,底层基于 `hibernate-validator`,可以对参数进行校验。 + +## 参数校验使用 + +### 方法一:使用 `@Validated` 注解 + +#### 步骤一:标注 `@Validated` + +`@Validated` 可以标注在类上,或者是参数前。 + +```Java +/** 标注在类上 **/ +@Validated +@RestController +@RequestMapping("/auth") +public class AuthController { + + @PostMapping("/login") + public R login(@RequestBody LoginBody body) { + // ... + } + +} +``` + +```Java +/** 标注在参数前 **/ +@PostMapping +public R add(@Validated @RequestBody SysUserBo user) { + // ... +} +``` + +#### 步骤二:标注校验注解 + +在参数中加入校验注解。 + +```Java +public class SysUserBo { + + @NotBlank(message = "用户账号不能为空") + @Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") + private String userName; + + @NotBlank(message = "用户昵称不能为空") + @Size(min = 0, max = 30, message = "用户昵称长度不能超过{max}个字符") + private String nickName; + + @Email(message = "邮箱格式不正确") + @Size(min = 0, max = 50, message = "邮箱长度不能超过{max}个字符") + private String email; + +} +``` + +常见校验注解见文末附表。 + +_注:message 支持 EL 表达式,{max} 直接读取前面的参数值。_ + +### 方法二:使用校验工具类 `ValidatorUtils` + +`org.dromara.common.core.utils.ValidatorUtils` + +![输入图片说明](https://foruda.gitee.com/images/1700050047426137432/206bd032_4959041.png "屏幕截图") + +使用方式 1:校验所有带有校验注解的属性 + +```Java +// 校验所有带有校验注解的属性 +ValidatorUtils.validate(object); +``` + +使用方式 2:按照分组校验属性(可以传多个分组) + +```Java +// 按照分组校验属性(可以传多个分组) +ValidatorUtils.validate(object, group); +``` + +## 扩展使用 + +### 扩展一:自定义校验注解 + +除了已有的校验注解以外,可以结合业务进行自定义。 + +以框架中的 `@Xss` 注解为例进行说明。 + +```Java +@Xss(message = "用户账号不能包含脚本字符") +@NotBlank(message = "用户账号不能为空") +@Size(min = 0, max = 30, message = "用户账号长度不能超过{max}个字符") +private String userName; +``` + +#### 1:新增 `@Xss` 注解 + +`org.dromara.common.core.xss.Xss` + +![输入图片说明](https://foruda.gitee.com/images/1700048074014527096/b4e230c2_4959041.png "屏幕截图") + +#### 2:自定义校验器 + +自定义校验器实现 `jakarta.validation.ConstraintValidator` 接口。 + +`org.dromara.common.core.xss.XssValidator` + +![输入图片说明](https://foruda.gitee.com/images/1700048474563719650/f9172bdc_4959041.png "屏幕截图") + +### 扩展二:自定义分组校验 + +同一个对象在不同的请求中需要校验的参数不同,则可以使用分组校验。 + +#### 1:自定义分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049439236073123/9e0d2e16_4959041.png "屏幕截图") + +#### 2:`@Validated` 注解指定分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049302803077030/c2a985aa_4959041.png "屏幕截图") + +#### 3:校验注解中指定分组 + +![输入图片说明](https://foruda.gitee.com/images/1700049205699437759/96babbd6_4959041.png "屏幕截图") + +## 附录:常用校验注解 + +| 注解 | 使用(只列举特殊参数值) | 参数类型 | 说明 | +|------------------|--------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------| +| @AssertFalse | @AssertFalse | boolean / Boolean | 元素值必须为 false | +| @AssertTrue | @AssertTrue | boolean / Boolean | 元素值必须为 true | +| @DecimalMax | @DecimalMax(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | +| @DecimalMin | @DecimalMin(value=值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | +| @Digits | @Digits(integer=整数位值, fraction=小数位值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 元素必须符合整数位以及小数位范围值 | +| @Email | @Email(regexp=正则表达式, flags=标志) | CharSequence | 元素是否符合正则表达式(正则表达式非必传) | +| @Future | @Future | - java.util.Date
- java.util.Calendar
- java.time.Instant
- java.time.LocalDate
- java.time.LocalDateTime
- java.time.LocalTime
- java.time.MonthDay
- java.time.OffsetDateTime
- java.time.OffsetTime
- java.time.Year
- java.time.YearMonth
- java.time.ZonedDateTime
- java.time.chrono.HijrahDate
- java.time.chrono.JapaneseDate
- java.time.chrono.MinguoDate
- java.time.chrono.ThaiBuddhistDate | 元素必须是未来的时刻、日期或时间 | +| @FutureOrPresent | @FutureOrPresent | 同 @Future | 元素必须是当前或未来的时刻、日期或时间 | +| @Length | @Length(min=最小值, max=最大值) | - CharSequence | 验证字符串是否在包含的 min 和 max 之间 | +| @Max | @Max(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须小于或等于指定的最大值 | +| @Min | @Min(value=值) | - BigDecimal
- BigInteger
- byte, short, int, long 及其包装类 | 元素必须是一个数字,其值必须大于或等于指定的最小值 | +| @Negative | @Negative | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的负数(即 0 被视为无效值) | +| @NegativeOrZero | @NegativeOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为负数或 0 | +| @NotBlank | @NotBlank | CharSequence | 元素不能为 null,并且必须至少包含一个非空白字符 | +| @NotEmpty | @NotEmpty | - CharSequence
- Collection
- Map
- Array | 元素不能为 null 或空集合 | +| @NotNull | @NotNull | 不限类型 | 元素不能为 null | +| @Null | @Null | 不限类型 | 元素必须为 null | +| @Past | @Past | 同 @Future | 元素必须是过去的瞬间、日期或时间 | +| @PastOrPresent | @PastOrPresent | 同 @Future | 元素必须是过去或现在的瞬间、日期或时间 | +| @Pattern | @Pattern(regexp=正则表达式, flags=标志) | CharSequence | 元素必须与指定的正则表达式匹配(正则表达式遵循 Java 正则表达式约定) | +| @Positive | @Positive | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须是一个严格的正数(即 0 被视为无效值) | +| @PositiveOrZero | @PositiveOrZero | - BigDecimal
- BigInteger
- byte,short,int,long,float,double 及其包装类 | 元素必须为正数或 0 | +| @Range | @Range(min=最小值, max=最大值) | - BigDecimal
- BigInteger
- CharSequence
- byte, short, int, long 及其包装类 | 验证元素是否在包含的 min 和 max 之间 | +| @Size | @Size(min=最小值, max=最大值) | - CharSequence
- Collection
- Map
- Array | 验证元素是否在包含的 min 和 max 之间 | +| @Valid | @Valid | 对象 | 级联验证 | + +更多注解可参考包: `org.hibernate.validator` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md new file mode 100644 index 00000000..384b7749 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions.md @@ -0,0 +1,144 @@ +# 关于数据权限 +- - - +* 参考 demo 模块用法(需导入 test.sql 文件) + +### 新版数据权限功能: +1.支持自动注入 sql 数据过滤
+2.查询、更新、删除 限制
+3.支持自定义数据字段过滤
+4.模板支持 spel 语法实现动态 Bean 处理
+5.支持与菜单权限标识符联合使用(5.2.X新功能) + +### 数据权限相关代码 + +| 类 | 说明 | 功能 | +|-------------------------------|-----------------|----------------------------------------| +| DataScopeType | 数据权限模板定义 | 用于定义数据权限模板 | +| DataPermission | 数据权限组注解 | 用于标注开启数据权限 (默认过滤部门权限) | +| DataColumn | 具体的数据权限字段标注 | 用于替换数据权限模板内的 key 变量 | +| PlusDataPermissionInterceptor | 数据权限 sql 拦截器 | 用于拦截所有 sql 检查是否标注了 `DataPermission` 注解 | +| PlusDataPermissionHandler | 数据权限处理器 | 用于处理被拦截到的 sql 为其添加数据权限过滤条件 | +| DataPermissionHelper | 数据权限助手 | 操作数据权限上下文变量 | +| SysDataScopeService | 自定义 Bean 处理数据权限 | 用于自定义扩展 | + +## 忽略数据权限 + +1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: +``` +@InterceptorIgnore(dataPermission = "true") +``` + +2.如果需要在业务层忽略数据权限,可调用以下方法: +``` +# 无返回值 +DataPermissionHelper.ignore(() -> { 业务代码 }); +# 有返回值 +Class result = DataPermissionHelper.ignore(() -> { return 业务代码 }); +``` + +### 使用方式 `参考demo模块` +数据权限体系 `用户 -> 多角色 => 角色 -> 单数据权限` +> 例子: 用户A 拥有两个角色
+> 角色A 部门经理 可查看 本部门及以下部门的数据
+> 角色B 兼职开发 可查看 仅自己的数据 + +> 创建角色 test1 为 本部门及以下 + +![输入图片说明](https://foruda.gitee.com/images/1678978669666831574/b51ed0a3_1766278.png "屏幕截图") + +> 创建角色 test2 为 仅本人 + +![输入图片说明](https://foruda.gitee.com/images/1678978674159035056/69cf32ad_1766278.png "屏幕截图") + +> 将其分配给用户 test + +![输入图片说明](https://foruda.gitee.com/images/1678978680492570269/a47b6afc_1766278.png "屏幕截图") + +### 编写列表查询(注意: 数据权限注解只能在 Mapper 层使用) + +> 标注数据权限注解 `dept_id` 为过滤部门字段 `user_id` 为过滤创建用户 + +![输入图片说明](https://foruda.gitee.com/images/1678978687179608427/d6b83c30_1766278.png "屏幕截图") + +### 重点注意: 如下情况不生效 + +> 有自定义实现方法 最终执行的mapper不是这个方法 所以无法生效 +> +> 解决方案: 一直往下点 找到最终的执行mapper重写即可 + +![输入图片说明](https://foruda.gitee.com/images/1678978692558777291/78b0a3dd_1766278.png "屏幕截图") + +### 编写数据权限模板 + +![输入图片说明](https://foruda.gitee.com/images/1678978697141183499/cfc1cb6a_1766278.png "屏幕截图") + +1.`code` 为关联角色的数据权限 `code`
+2.`sqlTemplate` 为 sql 模板
+`#{#deptName}` 为模板变量 对应权限注解的 `key`
+`#{@sdss}` 为模板 Bean 调用 调用其 Bean 的处理方法
+3.`elseSql` 为兜底 sql 处理当前角色与标注的注解 无对应的情况
+例如 数据权限为仅本人 且 方法并未标注具体过滤注解 则 填充 `1 = 0` 使条件不满足 不允许查看
+更详细用法可以参考 `DataScopeType` 注释 + +### 测试代码 + +> 使用 `管理员` 用户优先测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978703250082481/e93a68a5_1766278.png "屏幕截图") + +> 使用 `test` 用户测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978710644676604/d7f80487_1766278.png "屏幕截图") + +> 使用 `test` 删除一条不属于自己的数据 +> sql执行为不满足条件 不允许删除 + +![输入图片说明](https://foruda.gitee.com/images/1678978715711122947/441d61f7_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678978720298532619/a35b1147_1766278.png "屏幕截图") + + +> 使用 `test` 修改与删除同理
+> 具体实现为 更新和删除方法 标注数据权限注解 + +![输入图片说明](https://foruda.gitee.com/images/1678978725329242504/a70491a1_1766278.png "屏幕截图") + +### 自定义SQL模板 + +> 1.首先在角色管理 数据权限下拉框 添加自定义模板
+> 为什么不放置到系统字典问题: 因数据权限与模板绑定 不应随意改动 最好事先定义好 + +![输入图片说明](https://foruda.gitee.com/images/1678978730563169865/3459ee17_1766278.png "屏幕截图") + +> 2.代码 `DataScopeType` 自定义一个SQL模板 + +![输入图片说明](https://foruda.gitee.com/images/1678978735588305505/3f030c67_1766278.png "屏幕截图") + +> 3.标注权限注解 + +![输入图片说明](https://foruda.gitee.com/images/1678978742259837391/eabe5caa_1766278.png "屏幕截图") + +> 4.设置数据权限变量 + +![输入图片说明](https://foruda.gitee.com/images/1678978746778429543/e211201f_1766278.png "屏幕截图") + +> 5.测试 + +![输入图片说明](https://foruda.gitee.com/images/1678978751875467640/7d210cf4_1766278.png "屏幕截图") + +### mybatis-plus 原生方法 增加数据权限过滤 + +> 首先查看需要重写的方法源码 重点`方法源码` `方法源码` `方法源码`
+> 例如重写 `selectPage` 方法
+ +![输入图片说明](https://foruda.gitee.com/images/1678978757955000897/8315695c_1766278.png "屏幕截图") + +> 复制源码到自己的 `Mapper` 并增加数据权限注解 注意左边出现重写图标 即为重写成功
+ +![输入图片说明](https://foruda.gitee.com/images/1678978763224011694/bbea25a1_1766278.png "屏幕截图") + +### 支持类标注 + +> 获取规则 `方法 > 类` 注意: 类标注后 所有方法(包括父类方法) 都会进行数据权限过滤 + +![输入图片说明](https://foruda.gitee.com/images/1678978767336534896/fb13ee99_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md new file mode 100644 index 00000000..fa3a079c --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/permissions_control.md @@ -0,0 +1,180 @@ +# 权限控制 +- - - + +本文采用 `Sa-Token` 框架实现权限控制。[官方文档传送门](https://sa-token.cc/doc.html#/) + +## 权限校验 +权限校验指的是校验用户是否拥有访问某个 API 的能力。 + +通常情况下,一个 API 对应一个权限码,如果用户具备当前 API 的权限码,即代表有能力访问该 API。 + +### 1:权限标识 +在本系统中,每一个菜单功能都有对应的权限标识,可以在菜单管理中进行设置。 + +> 注: +> 1. 前后端的权限标识要保持一致。 +> 2. 权限标识可以使用通配符`*`。 + +![输入图片说明](https://foruda.gitee.com/images/1701086497939145368/133fb327_4959041.png "屏幕截图") + + +### 2:校验方法 +#### 2.1:使用 `@SaCheckPermission` 注解进行校验 +`@SaCheckPermission` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 + +- 单个权限校验: + +```Java +@SaCheckPermission("system:user:list") +``` + +- 多个权限校验(或模式,满足任意一个权限即可): + +```Java +@SaCheckPermission( + value = { + "system:user:list", + "system:user:query" + }, + mode = SaMode.OR +) +``` + +- 多个权限校验(与模式,必须满足所有权限): + +```Java +@SaCheckPermission( + value = { + "system:user:list", + "system:user:query" + }, + mode = SaMode.AND +) +``` + +#### 2.2:使用 `StpUtil` 工具类校验 +`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 + +- 判断当前用户是否拥有某个权限(返回 `boolean`): + +```Java +StpUtil.hasPermission("system:user:list"); +``` + +- 单个权限校验: + +```Java +StpUtil.checkPermission("system:user:list"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +- 多个权限校验(或模式,满足任意一个权限即可): + +```Java +StpUtil.checkPermissionOr("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +- 多个权限校验(与模式,必须满足所有权限): + +```Java +StpUtil.checkPermissionAnd("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotPermissionException` + +## 角色校验 +角色校验指的是校验用户是否拥有某个指定角色。 + +### 1:权限标识 +在本系统中,每个角色都拥有唯一的权限字符。 + +除了超级管理员角色外,其他角色的权限字符可以通过角色管理进行设置。 + +![输入图片说明](https://foruda.gitee.com/images/1701085080527279823/3255961d_4959041.png "屏幕截图") + +### 2:校验方法 +#### 2.1:使用 `@SaCheckRole` 注解校验 +`@SaCheckRole` 注解是由 `Sa-Token` 框架提供的角色校验注解,可以标注在方法上或类上。 + +- 单个角色校验 + +```Java +@SaCheckRole("superadmin") +``` + +- 多个角色校验(或模式,满足任意一个角色即可): + +```Java +@SaCheckRole( + value = { + "superadmin", + "admin" + }, + mode = SaMode.OR +) +``` + +- 多个角色校验(与模式,必须满足所有角色): + +```Java +@SaCheckRole( + value = { + "superadmin", + "admin" + }, + mode = SaMode.AND +) +``` + +#### 2.2:使用 `StpUtil` 工具类校验 +`StpUtil` 工具类是由 `Sa-Token` 框架提供的权限工具类,提供了常用的校验方法。 + +- 判断当前用户是否拥有某个角色(返回 `boolean`): + +```Java +StpUtil.hasRole("superadmin") +``` + +- 单个权限校验: + +```Java +StpUtil.checkRole("system:user:list"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +- 多个权限校验(或模式,满足任意一个角色即可): + +```Java +StpUtil.checkRoleOr("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +- 多个权限校验(与模式,必须满足所有角色): + +```Java +StpUtil.checkRoleAnd("system:user:list", "system:user:query"); +``` +如果验证未通过,则抛出异常: `NotRoleException` + +## 角色权限双重 `OR` 校验 +除了分开校验以外,权限和角色也可以进行组合,表示备选校验。 + +简单举个例子: + +假设某个 API 的权限码为 `system:user:list`,角色 `admin` 可以调用,则可以这样写: + +```Java +@SaCheckPermission(value = "system:user:list", orRole = "admin") +``` + +以上权限只需要满足任意一项即可。更多写法可以参考 `Sa-Token` [官方文档](https://sa-token.cc/doc.html#/use/at-check?id=_4%e3%80%81%e8%a7%92%e8%89%b2%e6%9d%83%e9%99%90%e5%8f%8c%e9%87%8d-or%e6%a0%a1%e9%aa%8c)。 + +## 当前用户的所有权限 +本系统中实现了 `StpInterface` 接口,可以对用户的权限以及角色进行管理,并且可以根据不同的用户类型进行设置。 + +具体参考类:`org.dromara.common.satoken.core.service.SaPermissionImpl` + +## 忽略权限校验 +请参考文档:[接口放行](/ruoyi-vue-plus/framework/basic/interface_release?id=接口放行) + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md new file mode 100644 index 00000000..a004434b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/social.md @@ -0,0 +1,68 @@ +# 第三方授权功能 +- - - +## 版本 >= 5.X + +## 前置说明 +1. 该功能基于 `JustAuth` 实现,支持多家平台实现第三方授权登录。 +2. 以 `Gitee` 授权登录为例进行本功能的使用说明。 +3. 其他第三方授权配置信息获取方式可参考 `JustAuth` [官方文档](https://www.justauth.cn/guide/)。
+ + ![输入图片说明](https://foruda.gitee.com/images/1690937097426867003/91d80587_4959041.png "屏幕截图") + +## 第三方授权配置 + +### 申请三方应用(以gitee为例) + +![输入图片说明](https://foruda.gitee.com/images/1700641775779304627/1cf1b56f_1766278.png "屏幕截图") + +### 更改后端配置 `application-dev.yml` + +![输入图片说明](https://foruda.gitee.com/images/1690936741844431943/580f8998_4959041.png "屏幕截图") + +**注:内网地址无法回调,请使用外网可以访问的地址。** + +![输入图片说明](https://foruda.gitee.com/images/1690940457570856867/ce22df18_4959041.png "屏幕截图") + +### 更改前端配置 `login.vue` + +![输入图片说明](https://foruda.gitee.com/images/1690937306197173754/5c1ece29_4959041.png "屏幕截图") + +## 授权登录(未绑定第三方平台) + +### 步骤一:个人中心授权第三方应用 + +![输入图片说明](https://foruda.gitee.com/images/1690938449386201097/ea375106_4959041.png "屏幕截图") + +### 步骤二:同意授权 + +![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") + +顶部出现授权成功,并跳转到系统首页。
+ +![输入图片说明](https://foruda.gitee.com/images/1690938559178527841/563168e4_4959041.png "屏幕截图")
+ +![输入图片说明](https://foruda.gitee.com/images/1690938636375977741/8ceb77cf_4959041.png "屏幕截图") + +查看第三方应用可看到授权成功的个人信息。
+ +![输入图片说明](https://foruda.gitee.com/images/1690938725512311321/5532a2a9_4959041.png "屏幕截图") + +## 授权登录(已绑定第三方平台) + +### 步骤一:点击登录页面图标 + +![输入图片说明](https://foruda.gitee.com/images/1690938908352243992/fd044381_4959041.png "屏幕截图") + +### 步骤二:同意授权 + +![输入图片说明](https://foruda.gitee.com/images/1690938522418523183/81b327bf_4959041.png "屏幕截图") + +## 解除授权绑定 + +### 步骤一:个人中心点击解绑第三方应用 + +![输入图片说明](https://foruda.gitee.com/images/1690939087877969002/4ef324e7_4959041.png "屏幕截图") + +### 步骤二:点击确定完成解绑 + +![输入图片说明](https://foruda.gitee.com/images/1690939108017661775/7236088d_4959041.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md new file mode 100644 index 00000000..33953086 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/tenant.md @@ -0,0 +1,121 @@ +# 多租户功能 +- - - +## 版本 >= 5.X + +## 前置说明(重要) +1. 本框架多租户功能的实现是基于 [MyBatis-Plus 多租户插件](https://baomidou.com/pages/aef2f2/#tenantlineinnerinterceptor) 的,只支持最简单的隔离。 +2. 本系统默认开启多租户功能。 +3. 多租户业务表建表需要加上租户id `tenant_id`,可参考其他系统表。 +4. 非多租户表可在配置文件进行配置排除。 +5. 只有超级管理员支持切换租户。 + +## 多租户使用流程(先说结论再展开!) +0. 开启多租户配置(系统默认已经开启) +1. 登录界面(可以选择不同租户) +> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 +2. 设置多租户套餐 +3. 新增/修改租户(需要选择套餐) +4. 切换租户(仅超级管理员可操作) + +## 多租户配置 +`application.yml`
+ +> 开关 `enable` 节点不用废话。
+> 如果不需要过滤租户的表可在 `excludes` 节点下添加。 + +**注意: 如果已经基于租户模式启动了程序 关闭租户必须删除mysql与redis内的相关数据重新导入sql** + +![输入图片说明](https://foruda.gitee.com/images/1680168468127690787/2cd3279e_4959041.png "屏幕截图") + +## 忽略租户 + +1.如果需要指定单独 SQL 不开启过滤,可在对应的 Mapper 接口添加如下忽略注解: +``` +@InterceptorIgnore(tenantLine = "true", dataPermission = "false") +``` +**此处注意事项 使用此注解如果需要开启数据权限 dataPermission = "false" 必须添加 mp的注解默认是忽略数据权限的 会导致数据权限失效** + +2.如果需要在业务层忽略多租户,可调用以下方法(推荐使用): +``` +# 无返回值 +TenantHelper.ignore(() -> { 业务代码 }); +# 有返回值 +Class result = TenantHelper.ignore(() -> { return 业务代码 }); +``` + +## 动态切换租户 + +**仅适用于特殊需求业务(例如: 创建租户时, 对该租户操作一些数据, 或者需要去其他租户查一些数据等) 禁止乱用后果自负** + +``` +# 无返回值 +TenantHelper.dynamic(租户id, () -> { 业务代码 }); +# 有返回值 +Class result = TenantHelper.dynamic(租户id, () -> { return 业务代码 }); +``` + +## 登录界面 + +![输入图片说明](https://foruda.gitee.com/images/1680173982933030545/bca146d7_4959041.png "屏幕截图") + +> 注:如果为租户设置了绑定域名,则只能选择当前域名相关的租户列表。 + +## 租户套餐管理 +### 租户套餐新增 +![输入图片说明](https://foruda.gitee.com/images/1680174317475230288/352957a1_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680174602877523112/fc194f17_4959041.png "屏幕截图") + +> 注: +> 1、先新增套餐再新增租户,因为租户新增之后无法修改所选套餐。 +> 2、租户所关联的套餐如果后续有修改可以进行同步。 + + +## 租户管理 +### 默认租户 +> 注:默认租户无法修改 + +![输入图片说明](https://foruda.gitee.com/images/1680174738913576400/b6aca11a_4959041.png "屏幕截图") + +### 新增租户 +#### 填写表单 +![输入图片说明](https://foruda.gitee.com/images/1680174945220618443/f7181b51_4959041.png "屏幕截图") + +#### 选择新增的租户套餐 +![输入图片说明](https://foruda.gitee.com/images/1680174991869792688/0dbaadd6_4959041.png "屏幕截图") + +#### 新增完成 +![输入图片说明](https://foruda.gitee.com/images/1680175033853525725/42e64b4d_4959041.png "屏幕截图") + +#### 登录租户 +![输入图片说明](https://foruda.gitee.com/images/1680176145378931134/e05f347e_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176208161104366/44a935f1_4959041.png "屏幕截图") + +### 修改租户 +#### 配置域名 +![输入图片说明](https://foruda.gitee.com/images/1680175251192690133/141fa6a6_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680175431036971650/db522d39_4959041.png "屏幕截图") + +#### 没有配置域名 +![输入图片说明](https://foruda.gitee.com/images/1680175541165540240/95e211f7_4959041.png "屏幕截图") + +#### 强调一下:这不是bug! +> 注:域名的配置就是为了绑定特定租户! + +### 同步套餐 +应用场景:租户套餐进行了修改,配置的菜单需要同步到特定租户。 +(不是所有租户都有更新套餐的权利, 这是跟钱挂钩的) + +> 点一下按钮的事,图略。 + +## 切换租户(仅超级管理员) +> 注:管理员切换租户不是切换用户,切换的只是数据,管理员拥有所有权限。 + +![输入图片说明](https://foruda.gitee.com/images/1680176324802967804/5c5d6fc3_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176431031189788/0c3f924c_4959041.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1680176496555243569/624ec677_4959041.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md new file mode 100644 index 00000000..b665ac5a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/basic/user.md @@ -0,0 +1,85 @@ +# 系统用户相关 +- - - + +> 框架采用sa-token控制权限 并对sa-token的api做了一定的业务封装
+ +## 用户登录 + +> 参考自带多种登录实现 不限制用户数据来源 只需要构建 LoginUser 即可完成登录
+> 例如: `同表不同类型` `不同表` `同表+扩展表`
+ +![输入图片说明](https://foruda.gitee.com/images/1699590555824776931/63d493fc_1766278.png "屏幕截图") + +## 获取用户信息 + +> 完成登录后会生成登录token返回给前端 前端需要再请求头携带token 后端方可获取到对应的用户信息 + +请求头传递格式: `Authorization: Bearer token` + +后端获取用户信息: +```java +LoginUser user = LoginHelper.getLoginUser(); +``` + +## 获取用户信息(基于token) +```java +LoginUser user = LoginHelper.getLoginUser(token); +``` + +## 获取登录用户id +```java +Long userId = LoginHelper.getUserId(); +``` + +## 获取登录用户账户名 +```java +String username = LoginHelper.getUsername(); +``` + +## 获取登录用户所属租户id +```java +String tenantId = LoginHelper.getTenantId(); +``` + +## 获取登录用户所属部门id +```java +Long deptId = LoginHelper.getDeptId(); +``` + +## 获取登录用户类型 +```java +UserType userType = LoginHelper.getUserType(); +``` + +## 获取登录用户其他扩展属性 +```java +Object obj = LoginHelper.getExtra(key); +``` + +## 设置登录用户其他扩展属性 + +参考登录设置 `clientId` 属性 + +![输入图片说明](https://foruda.gitee.com/images/1699591164562734430/42730add_1766278.png "屏幕截图") + +## 判断用户是否为超级管理员 + +```java +// 判断当前登录用户 +boolean b = LoginHelper.isSuperAdmin(); +// 判断用户基于id +boolean b = LoginHelper.isSuperAdmin(userId); +``` + +## 判断用户是否为租户管理员 + +```java +// 判断当前登录用户 +boolean b = LoginHelper.isTenantAdmin(); +// 判断用户基于角色组 +boolean b = LoginHelper.isSuperAdmin(rolePermission); +``` + +## 其他更多操作 +[Sa-Token 官方文档 - 登录认证](https://sa-token.cc/doc.html#/use/login-auth) + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md new file mode 100644 index 00000000..593129e8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/about_join.md @@ -0,0 +1,14 @@ +# 关于多表查询 +- - - +## 建议单表查询 + +文章连接: [大连接查询分解好处](https://java.isture.com/db/mysql/mysql-x-optimize-decompose-connection.html) +文章连接: [如何用mp多表查询性能测试](https://developer.aliyun.com/article/858927) + +![输入图片说明](https://foruda.gitee.com/images/1678979482724037085/1e74f3e1_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1666336728402711844/52788205_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1666336945935088277/f60e3288_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1666336954686520161/c6c83adc_1766278.png "屏幕截图") + +**(上图出自 <高性能MySql>)** \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md new file mode 100644 index 00000000..3ec55fec --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/key.md @@ -0,0 +1,19 @@ +# 主键使用说明 +- - - +## 关于如何使用分布式id或雪花id + +参考 `MybatisPlusConfig` 如需自定义 修改 `Bean` 实现即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979401707903546/e25f6c06_1766278.png "屏幕截图") + +框架默认集成 雪花ID 只需全局更改 主键类型即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979411517764918/1470df04_1766278.png "屏幕截图") + +如单表使用 可单独配置注解 + +![输入图片说明](https://foruda.gitee.com/images/1678979416033986923/2a4c3736_1766278.png "屏幕截图") + +### 重点说明 +* 由于雪花id位数过长 `Long` 类型在前端会失真 +* 框架已配置序列化方案 超越 `JS` 最大值自动转字符串 参考 `BigNumberSerializer` 类 (3.0.0 及以上新增) \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md new file mode 100644 index 00000000..c6dbfe99 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/test.md @@ -0,0 +1,6 @@ +# 单元测试 +- - - +## 参考文章 +[SpringBoot 2.X 整合 JUnit5 及全方位使用手册](https://lionli.blog.csdn.net/article/details/127576604) +## 参考代码(4.4.0新增) +![输入图片说明](https://foruda.gitee.com/images/1666973091281055549/6e8f58c3_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md new file mode 100644 index 00000000..dfad76f8 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/explain/transaction.md @@ -0,0 +1,45 @@ +# 事务相关 +- - - +若依文档对事务注解的描述 [关于事务](https://doc.ruoyi.vip/ruoyi/document/htsc.html#%E4%BA%8B%E5%8A%A1%E7%AE%A1%E7%90%86) 以下对多数据源事务做补充: + +## 多后端多数据源事务 + +框架支持对接 `seata` 保证分布式多数据源事务
+详情参考多数据源框架文档连接: https://www.kancloud.cn/tracy5546/dynamic-datasource/2268607 + +## 本地多数据源事务 +请使用 `@DSTransactional` 注解 会代理 `@DS` 注解切换后的数据源事务做回滚处理
+只要 `@DSTransactional` 注解下任一环节发生异常,则全局多数据源事务回滚。
+如果BC上也有 `@DSTransactional` 会有影响吗?答:没有影响的。 + +```java +//如AService调用BService和CService的方法,A,B,C分别对应不同数据源。 + +public class AService { + + @DS("a")//如果a是默认数据源则不需要DS注解。 + @DSTransactional + public void dosomething(){ + BService.dosomething(); + CService.dosomething(); + } +} + +public class BService { + + @DS("b") + public void dosomething(){ + //dosomething + } +} + +public class CService { + + @DS("c") + public void dosomething(){ + //dosomething + } +} +``` + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md new file mode 100644 index 00000000..fc56df31 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/api_encrypt.md @@ -0,0 +1,38 @@ +# 数据加解密 +- - - + +## 1:API 加密注解 `@ApiEncrypt` +1. 对于标注了 `@ApiEncrypt` 注解的接口,请求参数都必须进行加密。 +2. 注解的参数 `response` 为响应加密标识,默认 `false` 不加密,为 `true` 表示响应加密。 +3. 加密解密逻辑由过滤器实现,详情可参考 `org.dromara.common.encrypt.filter.CryptoFilter`。 + +## 2:API 加密配置 +`application.yml` + +![输入图片说明](https://foruda.gitee.com/images/1701131796468961065/83c464cd_4959041.png "屏幕截图") + +`.env.development` / `.env.production` + +![输入图片说明](https://foruda.gitee.com/images/1709533252413969800/1d0dff25_1766278.png "屏幕截图") + +> 注: +> 1. 公私钥与前端配置文件互为配对,如果需要更换请一同更换。 +> 2. 后端公钥对应前端私钥;后端私钥对应前端公钥。 + +## 3:前端开启加密 +如果需要开启 API 加密,则需要修改 `request` 的 `headers` 内容: +```Javascript +headers: { + isEncrypt: true +} +``` + +![输入图片说明](https://foruda.gitee.com/images/1701137141916998346/5e839bbe_4959041.png "屏幕截图") + +## 4.关于请求响应参数加解密说明 + +如何加解密请求响应参数看这里 -> [关于请求响应参数解密](/questions/api_encrypt.md) + +## 密钥生成说明 + +![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md new file mode 100644 index 00000000..1e81b5e0 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/dynamic_datasource.md @@ -0,0 +1,45 @@ +# 多数据源 +- - - + +### 框架默认 mysql 其他数据库使用说明 + +找到 `ruoyi-admin` 模块在 pom 文件内增加对应的jdbc依赖 + +![输入图片说明](https://foruda.gitee.com/images/1721098535176969987/d42870ca_1766278.png "屏幕截图") + + +### 关于多数据源事务 具体参考 `事务相关` 文档说明 + +### 多数据源框架功能介绍 +多数据源框架官方文档: [dynamic-datasource文档](https://www.kancloud.cn/tracy5546/dynamic-datasource/2264611) + +* 支持 数据源分组 ,适用于多种场景 纯粹多库 读写分离 一主多从 混合模式。 +* 支持数据库敏感配置信息 加密 ENC()。 +* 支持每个数据库独立初始化表结构schema和数据库database。 +* 支持无数据源启动,支持懒加载数据源(需要的时候再创建连接)。 +* 支持 自定义注解 ,需继承DS(3.2.0+)。 +* 提供并简化对Druid,HikariCp,BeeCp,Dbcp2的快速集成。 +* 提供对Mybatis-Plus,Quartz,ShardingJdbc,P6sy,Jndi等组件的集成方案。 +* 提供 自定义数据源来源 方案(如全从数据库加载)。 +* 提供项目启动后 动态增加移除数据源 方案。 +* 提供Mybatis环境下的 纯读写分离 方案。 +* 提供使用 spel动态参数 解析数据源方案。内置spel,session,header,支持自定义。 +* 支持 多层数据源嵌套切换 。(ServiceA >>> ServiceB >>> ServiceC)。 +* 提供 基于seata的分布式事务方案。 +* 提供 本地多数据源事务方案。 附:不能和原生spring事务混用。 + +### 用法说明 + +> 加载顺序 `方法 => 类 => 默认`
+ +![输入图片说明](https://foruda.gitee.com/images/1678979069737596299/abe8ae7f_1766278.png "屏幕截图") + +### 配置方式 + +![输入图片说明](https://foruda.gitee.com/images/1678979074000345758/b9238f0b_1766278.png "屏幕截图") + +### 数据库异构 + +例如: `mysql + oracle` 参考对应多数据源框架文档 [dynamic-ds文档](https://www.kancloud.cn/tracy5546/dynamic-datasource) + +![输入图片说明](https://foruda.gitee.com/images/1678979078387192317/2de94a78_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md new file mode 100644 index 00000000..19d726cd --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/encrypt.md @@ -0,0 +1,28 @@ +# 数据加解密 +- - - +## 框架版本 >= 4.6.0 +## 功能说明 + +数据库 数据存储加密 查询解密功能
+支持加密算法: `BASE64` `AES` `RSA` `SM2` `SM4` + +## 注解 `@EncryptField` + +![输入图片说明](https://foruda.gitee.com/images/1675577493013639395/cd920f15_1766278.png "屏幕截图") + +## 用法说明 + +**详细用法可参考案例 TestEncryptController 测试数据库加解密功能** + +全局默认加密配置(如果注解不配置则使用全局配置) + +![输入图片说明](https://foruda.gitee.com/images/1675577674063566357/dee94786_1766278.png "屏幕截图") + +注解可自定义算法与配置 + +![输入图片说明](https://foruda.gitee.com/images/1675577725117970708/7ee7a833_1766278.png "屏幕截图") + +## 密钥生成说明 + +![输入图片说明](https://foruda.gitee.com/images/1675577852271308699/9b30258e_1766278.png "屏幕截图") + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md new file mode 100644 index 00000000..46c7f423 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/idempotent.md @@ -0,0 +1,29 @@ +# 防重幂等 +- - - +### 功能介绍 + +防重功能为防止两条相同的数据重复提交导致脏数据或业务错乱
+**注意: 重复提交属于小概率事件 请不要拿并发压测与之相提并论**
+框架防重功能参考 `美团GTIS防重系统` 使用 请求参数与用户Token或URL 生成全局业务ID
+有效防止 `同一个用户` 在 `限制时间` 内对 `同一个业务` 提交 `相同的数据` + +框架防重处理 `支持业务失败或异常` 快速释放限制
+业务处理成功后 会在设置时间内 限制同一条数据的提交
+**注意: 只对同一个用户的同一个接口提交相同的数据有效** + + + + +### 美团GTIS系统流程图 + +[美团 分布式系统互斥性与幂等性问题的分析与解决](https://tech.meituan.com/2016/09/29/distributed-system-mutually-exclusive-idempotence-cerberus-gtis.html) + +![输入图片说明](https://foruda.gitee.com/images/1678979231862359032/34f030c5_1766278.png "屏幕截图") + +### 使用方法 + +在Controller标注 `@RepeatSubmit` 注解即可 + +![输入图片说明](https://foruda.gitee.com/images/1678979236772683145/9fa27e5b_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678979240831458322/8e1fac4b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md new file mode 100644 index 00000000..6e7413ed --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/mail.md @@ -0,0 +1,17 @@ +# 邮件功能 +- - - +## 配置功能 + +版本: v4.2.0 提供邮件功能 + +修改配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1663555260932007318/fabb2bfa_1766278.png "屏幕截图") + +* `enabled` 为邮件功能开关 + +## 功能使用 + +参考 `demo` 模块 `MailController` 邮件演示案例 + +![输入图片说明](https://foruda.gitee.com/images/1663555374113593089/885b4db2_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md new file mode 100644 index 00000000..a0b51d24 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/maxkey.md @@ -0,0 +1,20 @@ +# 对接 MaxKey 单点登录 +- - - + +# 安装 MaxKey 应用服务 + +参考 MaxKey 官方文档安装 [MaxKey安装部署](http://www.maxkey.top/doc/docs/intro/) + +# 配置应用 OAuth2.0 认证注册 + +![输入图片说明](https://foruda.gitee.com/images/1693377802128677240/0927270a_1766278.png "屏幕截图") + +# 配置后端服务 + +找到框架 `application-环境.yml` 配置文件 + +修改 `maxkey` 对应的 `client-id` 与 `client-secret` + +![输入图片说明](https://foruda.gitee.com/images/1693378118762354596/2f02c8a3_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1693378168538263792/24476d2a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md new file mode 100644 index 00000000..3e2d92ba --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sensitive.md @@ -0,0 +1,33 @@ +# 数据脱敏 +- - - +## 功能说明 + +系统使用 `Jackson` 序列化策略 对标注了 `Sensitive` 注解的属性进行脱敏处理 + +## 使用教程 + +> 使用注解标注需要脱敏的字段 选择对应的策略 + +![输入图片说明](https://foruda.gitee.com/images/1699523591703893602/ffd6dba2_1766278.png "屏幕截图") + +* strategy 脱敏策略 +* roleKey 角色code(判断用户是否拥有角色权限) +* perms 权限code(判断用户是否拥有标识符权限) + +![输入图片说明](https://foruda.gitee.com/images/1678979315796014155/614adf91_1766278.png "屏幕截图") + +> 可再 `SensitiveStrategy` 内自定义策略 + +![输入图片说明](https://foruda.gitee.com/images/1678979319996224858/3b3e3c8b_1766278.png "屏幕截图") + +## 脱敏逻辑修改 + +> 系统使用通用接口处理是否需要脱敏 多个系统可以自定义不同的脱敏逻辑实现 + +![输入图片说明](https://foruda.gitee.com/images/1678979325448998856/b262e425_1766278.png "屏幕截图") + +> 系统默认处理逻辑为 根据角色与标识符或非管理员脱敏 可自行修改默认实现 + +![输入图片说明](https://foruda.gitee.com/images/1699523752627488891/f82f2f50_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md new file mode 100644 index 00000000..283eb221 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/skywalking.md @@ -0,0 +1,20 @@ +# Skywalking链路监控 +- - - +## skywalking服务搭建 + +参考文章: https://lionli.blog.csdn.net/article/details/127656534
+多种搭建方式 也可以参考百度 + +## 代码改动 + +https://gitee.com/dromara/RuoYi-Vue-Plus/commit/4d02466fed4f3ea012a80c3359cde9af0737141f
+根据上方commit提交记录 开启注释掉的代码 + +## 本地使用 + +参考文章: https://lionli.blog.csdn.net/article/details/127656534 + +## docker部署使用 + +完成上方代码改动 将下载好的 `agent` 探针 放入服务器 `/docker/skywalking/agent/` 目录下 赋予所有权限即可
+![输入图片说明](https://foruda.gitee.com/images/1669032573170837535/d9901f53_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md new file mode 100644 index 00000000..a2308ecd --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sms.md @@ -0,0 +1,51 @@ +# 短信模块 +- - - + +# 配置功能 + +### 版本: >= v5.1.0 + +已完成 sms4j 项目整合 文档地址: https://sms4j.com/doc3 + +配置方式 具体厂商配置扩展 可以查看sms4j文档 + +![输入图片说明](https://foruda.gitee.com/images/1705573035997239848/2ca8512d_1766278.png "屏幕截图") + +使用方式 参考文档各种写法 下方为 demo 模块提供示例 + +![输入图片说明](https://foruda.gitee.com/images/1705573001447394180/2bd726d0_1766278.png "屏幕截图") + +### 版本: v4.2.0 提供短信模块 + +短信模块采用SPI加载
+使用哪家的短信 引入哪家的依赖 即可动态加载
+目前支持: `阿里云` `腾讯云` 欢迎扩展PR其他 + +> 参考 `ruoyi-demo` pom文件写法 + +![输入图片说明](https://foruda.gitee.com/images/1678979157797419426/cc9b7444_1766278.png "屏幕截图") + +> 修改配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1678979163029635375/e5fd6e20_1766278.png "屏幕截图") + +* `enabled` 为短信功能开关 +* `endpoint` 为域名 各厂家域名固定 按照文档配置即可 +* `accessKeyId` 密钥id +* `accessKeySecret` 密钥密匙 +* `signName` 签名 +* `sdkAppId` 应用id 腾讯专用 + +## 功能使用 + +参考 `demo` 模块 `SmsController` 短信演示案例
+功能采用 `模板模式` 动态加载对应厂家的工具模板
+引入 `SmsTemplate` 即可使用 + +![输入图片说明](https://foruda.gitee.com/images/1678979168699323982/e9301e84_1766278.png "屏幕截图") + +## 重点须知 + +由于各厂家参数解析不一致 请遵守以下规则 + +![输入图片说明](https://foruda.gitee.com/images/1678979172581090456/ac1f10e8_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md new file mode 100644 index 00000000..8a738329 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/sse.md @@ -0,0 +1,22 @@ +# SSE功能 +- - - + +## 框架版本 >= 5.2.2 + +## 配置说明 + +![输入图片说明](https://foruda.gitee.com/images/1721986820599622433/1abe5d60_1766278.png "屏幕截图") + +* enabled 是否开启此功能 +* path 应用路径 + +## 使用方法 + +前端连接方式: `http://后端ip:端口/resource/sse?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` + +其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 + +`SseMessageUtils.sendMessage` 推送单机消息(特殊需求使用)
+`SseMessageUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
+`SseMessageUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
+`SseMessageUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md new file mode 100644 index 00000000..4778d0f9 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/topiam.md @@ -0,0 +1,30 @@ +# 对接 TOPIAM 单点登录 +- - - + +# 安装 TOPIAM 应用服务 + +参考 TOPIAM 官方文档安装 [TOPIAM安装部署](https://eiam.topiam.cn/docs/deployment/) + +# 配置 OIDC 应用 + +在 `登录 Redirect URI` 中填写 `http://localhost:80/oauth/callback?source=topiam` + +# 配置后端服务 + +找到框架 `application-环境.yml` 配置文件 + +修改 `topiam` 对应的 `client-id` 与 `client-secret` + +```yaml +justauth: + # 前端外网访问地址 + address: http://localhost:80 + type: + topiam: + # topiam 服务器地址,可在【应用配置信息】中找到 + server-url: http://127.0.0.1:1989/api/v1/authorize/y0q************spq***********8ol + client-id: 449c4*********937************759 + client-secret: ac7***********1e0************28d + redirect-uri: ${justauth.address}/social-callback?source=topiam + scopes: [openid] +``` \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md new file mode 100644 index 00000000..547b15ff --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/translation.md @@ -0,0 +1,34 @@ +# 翻译功能 +- - - +## 框架版本 >= 4.6.0 +## 注解 + +![输入图片说明](https://foruda.gitee.com/images/1675575648043199227/d04b3e21_1766278.png "屏幕截图") + +`@Translation` 翻译注解 用于实体类字段上
+`@TranslationType` 翻译类别注解 用于实现类上标注与 `@Translation` 注解相同的 `type` 类型 实现翻译功能 + + +## 用法说明 + +默认提供功能 `用户id转账号(用户名)` `部门id转名称` `字典type转label` `ossId转url` + +![输入图片说明](https://foruda.gitee.com/images/1675575977860232549/143b74f8_1766278.png "屏幕截图") + +用户名翻译(映射翻译) 根据另一个映射字段 翻译保存到此字段 + +![输入图片说明](https://foruda.gitee.com/images/1675576044011477847/13eb9f57_1766278.png "屏幕截图") + +ossUrl翻译(直接翻译) 直接根据此字段值翻译后替换此字段值 + +![输入图片说明](https://foruda.gitee.com/images/1675576265894720924/70792f66_1766278.png "屏幕截图") + +字典翻译(其他扩展条件翻译) 根据`other`条件 自行定义如何使用 例如字典翻译`other`条件就是字典的唯一值 + +![输入图片说明](https://foruda.gitee.com/images/1675576391012282823/f95c5d78_1766278.png "屏幕截图") + +## 自定义扩展 + +实现接口 `TranslationInterface` 标注注解 `@TranslationType` 可参考框架默认实现 + +![输入图片说明](https://foruda.gitee.com/images/1676735436673932715/c3caa8d7_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md new file mode 100644 index 00000000..9e74e1e3 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/extend/websocket.md @@ -0,0 +1,37 @@ +# WebSocket功能 +- - - + +## 框架版本 >= 5.1.0 + +## 配置说明(默认关闭 推送建议使用SSE) + +![输入图片说明](https://foruda.gitee.com/images/1688356273985385949/5e4d1de8_1766278.png "屏幕截图") + +* enabled 是否开启此功能 +* path 应用路径 +* allowedOrigins 设置访问源地址 + +**重点: 如关闭ws功能需连同前端ws开关一同关闭 不然前端启动会报错** + +![输入图片说明](https://foruda.gitee.com/images/1700644877512019497/052d2f46_1766278.png "屏幕截图") + +## 使用方法 + +前端连接方式: `ws://后端ip:端口/resource/websocket?clientid=import.meta.env.VITE_APP_CLIENT_ID&Authorization=Bearer eyJ0eXAiO......` + +**由于js不支持请求头传输故而采用参数传输 如支持请求头传输建议使用请求头传输** + +传输方式: +```js +headers: { + Authorization: "Bearer " + getToken(), + clientid: import.meta.env.VITE_APP_CLIENT_ID +} +``` + +其中 `Authorization` 为请求token需要登录后获取 连接成功之后 与框架内其他获取登录用户方式一致 + +`WebSocketUtils.sendMessage` 推送单机消息(特殊需求使用)
+`WebSocketUtils.subscribeMessage` 订阅分布式消息(框架初始化已订阅)
+`WebSocketUtils.publishMessage` 发布分布式消息(推荐使用 所有集群内寻找到接收人)
+`WebSocketUtils.publishAll` 群发消息给所有连接人
\ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md new file mode 100644 index 00000000..329cce21 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/framework/tree.md @@ -0,0 +1,61 @@ +# 目录结构 +- - - +v5.2.2 +~~~ +RuoYi-Vue-Plus +├─ ruoyi-admin // 管理模块 [8080,28080] +│ └─ RuoYiApplication // 启动类 +│ └─ RuoYiServletInitializer // 容器部署初始化类 +│ └─ resources // 资源文件 +│ └─ i18n/messages.properties // 国际化配置文件 +│ └─ application.yml // 框架总配置文件 +│ └─ application-dev.yml // 开发环境配置文件 +│ └─ application-prod.yml // 生产环境配置文件 +│ └─ banner.txt // 框架启动图标 +│ └─ logback-plus.xml // 日志配置文件 +│ └─ ip2region.xdb // IP区域地址库 +├─ ruoyi-extend // 扩展模块 +│ └─ ruoyi-monitor-admin // admin监控模块 [9090] +│ └─ ruoyi-snailjob-server // 任务调度中心模块 [8800,17888] +├─ ruoyi-common // 通用模块 +│ └─ ruoyi-common-bom // common依赖包管理 +│ └─ ruoyi-common-core // 核心模块 +│ └─ ruoyi-common-doc // 系统接口模块 +│ └─ ruoyi-common-encrypt // 数据加解密模块 +│ └─ ruoyi-common-excel // excel模块 +│ └─ ruoyi-common-idempotent // 幂等功能模块 +│ └─ ruoyi-common-job // 定时任务模块 +│ └─ ruoyi-common-json // 序列化模块 +│ └─ ruoyi-common-log // 日志模块 +│ └─ ruoyi-common-mail // 邮件模块 +│ └─ ruoyi-common-mybatis // 数据库模块 +│ └─ ruoyi-common-oss // oss服务模块 +│ └─ ruoyi-common-ratelimiter // 限流功能模块 +│ └─ ruoyi-common-redis // 缓存服务模块 +│ └─ ruoyi-common-satoken // satoken模块 +│ └─ ruoyi-common-security // 安全模块 +│ └─ ruoyi-common-sensitive // 脱敏模块 +│ └─ ruoyi-common-sms // 短信模块 +│ └─ ruoyi-common-social // 社交三方模块 +│ └─ ruoyi-common-sse // sse流推送模块 +│ └─ ruoyi-common-tenant // 租户模块 +│ └─ ruoyi-common-translation // 通用翻译模块 +│ └─ ruoyi-common-web // web模块 +│ └─ ruoyi-common-websocket // websocket服务集成模块 +├─ ruoyi-modules // 模块组 +│ └─ ruoyi-demo // 演示模块 +│ └─ ruoyi-generator // 代码生成模块 +│ └─ ruoyi-job // 任务调度服务 +│ └─ ruoyi-system // 业务模块 +│ └─ ruoyi-workflow // 工作流模块 +├─ plus-ui // 前端框架 [80] +├─ script // 系统脚本包 +│ └─ bin // 运行脚本包 +│ └─ docker // docker相关脚本 +│ └─ sql // sql脚本 +├─ .run // 执行脚本文件 +├─ .editorconfig // 编辑器编码格式配置 +├─ LICENSE // 开源协议 +├─ pom.xml // 公共依赖 +├─ README.md // 框架说明文件 +~~~ \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md new file mode 100644 index 00000000..ff4de9ef --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/home.md @@ -0,0 +1,127 @@ + +
+ +- - - +# 平台简介 +
+ +[![码云Gitee](https://gitee.com/dromara/RuoYi-Vue-Plus/badge/star.svg?theme=blue)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![GitHub](https://img.shields.io/github/stars/dromara/RuoYi-Vue-Plus.svg?style=social&label=Stars)](https://github.com/dromara/RuoYi-Vue-Plus) +[![License](https://img.shields.io/badge/License-MIT-blue.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus/blob/master/LICENSE) +[![使用IntelliJ IDEA开发维护](https://img.shields.io/badge/IntelliJ%20IDEA-提供支持-blue.svg)](https://www.jetbrains.com/?from=RuoYi-Vue-Plus) +
+[![RuoYi-Vue-Plus](https://img.shields.io/badge/RuoYi_Vue_Plus-5.2.2-success.svg)](https://gitee.com/dromara/RuoYi-Vue-Plus) +[![Spring Boot](https://img.shields.io/badge/Spring%20Boot-3.2-blue.svg)]() +[![JDK-17](https://img.shields.io/badge/JDK-17-green.svg)]() +[![JDK-21](https://img.shields.io/badge/JDK-21-green.svg)]() + +> RuoYi-Vue-Plus 是重写 RuoYi-Vue 针对 `分布式集群与多租户` 场景全方位升级(不兼容原框架) + +> 项目代码、文档 均开源免费可商用 遵循开源协议在项目中保留开源协议文件即可
+活到老写到老 为兴趣而开源 为学习而开源 为让大家真正可以学到技术而开源 + +# 本框架与RuoYi的功能差异 + +| 功能 | 本框架 | RuoYi | +|-------------|-------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------| +| 前端项目 | 采用 Vue3 + TS + ElementPlus 重写 | 基于Vue2/Vue3 + JS | +| 后端项目结构 | 采用插件化 + 扩展包形式 结构解耦 易于扩展 | 模块相互注入耦合严重难以扩展 | +| 后端代码风格 | 严格遵守Alibaba规范与项目统一配置的代码格式化 | 代码书写与常规结构不同阅读障碍大 | +| Web容器 | 采用 Undertow 基于 XNIO 的高性能容器 | 采用 Tomcat | +| 权限认证 | 采用 Sa-Token、Jwt 静态使用功能齐全 低耦合 高扩展 | Spring Security 配置繁琐扩展性极差 | +| 权限注解 | 采用 Sa-Token 支持注解 登录校验、角色校验、权限校验、二级认证校验、HttpBasic校验、忽略校验
角色与权限校验支持多种条件 如 `AND` `OR` 或 `权限 OR 角色` 等复杂表达式 | 只支持是否存在匹配 | +| 三方鉴权 | 采用 JustAuth 第三方登录组件 支持微信、钉钉等数十种三方认证 | 无 | +| 关系数据库支持 | 原生支持 MySQL、Oracle、PostgreSQL、SQLServer
可同时使用异构切换(支持其他 mybatis-plus 支持的所有数据库 只需要增加jdbc依赖即可使用 达梦金仓等均有成功案例) | 支持 Mysql、Oracle 不支持同时使用、不支持异构切换 | +| 缓存数据库 | 支持 Redis 5-7 支持大部分新功能特性 如 分布式限流、分布式队列 | Redis 简单 get set 支持 | +| Redis客户端 | 采用 Redisson Redis官方推荐 基于Netty的客户端工具
支持Redis 90%以上的命令 底层优化规避很多不正确的用法 例如: keys被转换为scan
支持单机、哨兵、单主集群、多主集群等模式 | Lettuce + RedisTemplate 支持模式少 工具使用繁琐
连接池采用 common-pool Bug多经常性出问题 | +| 缓存注解 | 采用 Spring-Cache 注解 对其扩展了实现支持了更多功能
例如 过期时间 最大空闲时间 组最大长度等 只需一个注解即可完成数据自动缓存 | 需手动编写Redis代码逻辑 | +| ORM框架 | 采用 Mybatis-Plus 基于对象几乎不用写SQL全java操作 功能强大插件众多
例如多租户插件 分页插件 乐观锁插件等等 | 采用 Mybatis 基于XML需要手写SQL | +| SQL监控 | 采用 p6spy 可输出完整SQL与执行时间监控 | log输出 需手动拼接sql与参数无法快速查看调试问题 | +| 数据分页 | 采用 Mybatis-Plus 分页插件
框架对其进行了扩展 对象化分页对象 支持多种方式传参 支持前端多排序 复杂排序 | 采用 PageHelper 仅支持单查询分页 参数只能从param传 只能单排序 功能扩展性差 体验不好 | +| 数据权限 | 采用 Mybatis-Plus 插件 自行分析拼接SQL 无感式过滤
只需为Mapper设置好注解条件 支持多种自定义 不限于部门角色 | 采用 注解+aop 实现 基于部门角色 生成的sql兼容性差 不支持其他业务扩展
生成sql后需手动拼接到具体业务sql上 对于多个Mapper查询不起作用 | +| 数据脱敏 | 采用 注解 + jackson 序列化期间脱敏 支持不同模块不同的脱敏条件
支持多种策略 如身份证、手机号、地址、邮箱、银行卡等 可自行扩展 | 无 | +| 数据加解密 | 采用 注解 + mybatis 拦截器 对存取数据期间自动加解密
支持多种策略 如BASE64、AES、RSA、SM2、SM4等 | 无 | +| 接口传输加密 | 采用 动态 AES + RSA 加密请求 body 每一次请求秘钥都不同大幅度降低可破解性 | 无 | +| 数据翻译 | 采用 注解 + jackson 序列化期间动态修改数据 数据进行翻译
支持多种模式: `映射翻译` `直接翻译` `其他扩展条件翻译` 接口化两步即可完成自定义扩展 内置多种翻译实现 | 无 | +| 多数据源框架 | 采用 dynamic-datasource 支持市面大部分数据库
通过yml配置即可动态管理异构不同种类的数据库 也可通过前端页面添加数据源
支持spel表达式从请求头参数等条件切换数据源 | 基于 druid 手动编写代码配置数据源 配置繁琐 支持性差 | +| 多数据源事务 | 采用 dynamic-datasource 支持多数据源不同种类的数据库事务回滚 | 不支持 | +| 数据库连接池 | 采用 HikariCP Spring官方内置连接池 配置简单 以性能与稳定性闻名天下 | 采用 druid bug众多 社区维护差 活跃度低 配置众多繁琐性能一般 | +| 数据库主键 | 采用 雪花ID 基于时间戳的 有序增长 唯一ID 再也不用为分库分表 数据合并主键冲突重复而发愁 | 采用 数据库自增ID 支持数据量有限 不支持多数据源主键唯一 | +| WebSocket协议 | 基于 Spring 封装的 WebSocket 协议 扩展了Token鉴权与分布式会话同步 不再只是基于单机的废物 | 无 | +| SSE推送 | 采用 Spring SSE 实现 扩展了Token鉴权与分布式会话同步 | 无 | +| 序列化 | 采用 Jackson Spring官方内置序列化 靠谱!!! | 采用 fastjson bugjson 远近闻名 | +| 分布式幂等 | 参考美团GTIS防重系统简化实现(细节可看文档) | 手动编写注解基于aop实现 | +| 分布式锁 | 采用 Lock4j 底层基于 Redisson | 无 | +| 分布式任务调度 | 采用 SnailJob 天生支持分布式 统一的管理中心 支持多种数据库 支持分片重试DAG任务流等 | 采用 Quartz 基于数据库锁性能差 集群需要做很多配置与改造 | +| 文件存储 | 采用 Minio 分布式文件存储 天生支持多机、多硬盘、多分片、多副本存储
支持权限管理 安全可靠 文件可加密存储 | 采用 本机文件存储 文件裸漏 易丢失泄漏 不支持集群有单点效应 | +| 云存储 | 采用 AWS S3 协议客户端 支持 七牛、阿里、腾讯 等一切支持S3协议的厂家 | 不支持 | +| 短信 | 采用 sms4j 短信融合包 支持数十种短信厂家 只需在yml配置好厂家密钥即可使用 可多厂家共用 | 不支持 | +| 邮件 | 采用 mail-api 通用协议支持大部分邮件厂商 | 不支持 | +| 接口文档 | 采用 SpringDoc、javadoc 无注解零入侵基于java注释
只需把注释写好 无需再写一大堆的文档注解了 | 采用 Springfox 已停止维护 需要编写大量的注解来支持文档生成 | +| 校验框架 | 采用 Validation 支持注解与工具类校验 注解支持国际化 | 仅支持注解 且注解不支持国际化 | +| Excel框架 | 采用 Alibaba EasyExcel 基于插件化
框架对其增加了很多功能 例如 自动合并相同内容 自动排列布局 字典翻译等 | 基于 POI 手写实现 功能有限 复杂 扩展性差 | +| 工作流支持 | 支持各种复杂审批 转办 委派 加减签 会签 或签 票签 等功能 | 无 | +| 工具类框架 | 采用 Hutool、Lombok 上百种工具覆盖90%的使用需求 基于注解自动生成 get set 等简化框架大量代码 | 手写工具稳定性差易出问题 工具数量有限 代码臃肿需自己手写 get set 等 | +| 监控框架 | 采用 SpringBoot-Admin 基于SpringBoot官方 actuator 探针机制
实时监控服务状态 框架还为其扩展了在线日志查看监控 | 无 | +| 链路追踪 | 采用 Apache SkyWalking 还在为请求不知道去哪了 到哪出了问题而烦恼吗
用了它即可实时查看请求经过的每一处每一个节点 | 无 | +| 代码生成器 | 只需设计好表结构 一键生成所有crud代码与页面
降低80%的开发量 把精力都投入到业务设计上
框架为其适配MP、SpringDoc规范化代码 同时支持动态多数据源代码生成 | 代码生成原生结构 只支持单数据源生成 | +| 部署方式 | 支持 Docker 编排 一键搭建所有环境 让开发人员从此不再为搭建环境而烦恼 | 原生jar部署 其他环境需手动下载安装 自行搭建 | +| 项目路径修改 | 提供详细的修改方案文档 并为其做了一些改动 非常简单即可修改成自己想要的 | 需要做很多改造 文档说明有限 | +| 国际化 | 基于请求头动态返回不同语种的文本内容 开发难度低 有对应的工具类 支持大部分注解内容国际化 | 只提供基础功能 其他需自行编写扩展 | +| 代码单例测试 | 提供单例测试 使用方式编写方法与maven多环境单测插件 | 只提供基础功能 其他需自行编写扩展 | +| Demo案例 | 提供框架功能的实际使用案例 单独一个模块提供了很多很全 | 无 | + + +## 本框架与RuoYi的业务差异 + +| 业务 | 功能说明 | 本框架 | RuoYi | +|--------|----------------------------------------------------------------------|-----|------------------| +| 租户管理 | 系统内租户的管理 如:租户套餐、过期时间、用户数量、企业信息等 | 支持 | 无 | +| 租户套餐管理 | 系统内租户所能使用的套餐管理 如:套餐内所包含的菜单等 | 支持 | 无 | +| 客户端管理 | 系统内对接的所有客户端管理 如: pc端、小程序端等
支持动态授权登录方式 如: 短信登录、密码登录等 支持动态控制token时效 | 支持 | 无 | +| 用户管理 | 用户的管理配置 如:新增用户、分配用户所属部门、角色、岗位等 | 支持 | 支持 | +| 部门管理 | 配置系统组织机构(公司、部门、小组) 树结构展现支持数据权限 | 支持 | 支持 | +| 岗位管理 | 配置系统用户所属担任职务 | 支持 | 支持 | +| 菜单管理 | 配置系统菜单、操作权限、按钮权限标识等 | 支持 | 支持 | +| 角色管理 | 角色菜单权限分配、设置角色按机构进行数据范围权限划分 | 支持 | 支持 | +| 字典管理 | 对系统中经常使用的一些较为固定的数据进行维护 | 支持 | 支持 | +| 参数管理 | 对系统动态配置常用参数 | 支持 | 支持 | +| 通知公告 | 系统通知公告信息发布维护 | 支持 | 支持 | +| 操作日志 | 系统正常操作日志记录和查询 系统异常信息日志记录和查询 | 支持 | 支持 | +| 登录日志 | 系统登录日志记录查询包含登录异常 | 支持 | 支持 | +| 文件管理 | 系统文件展示、上传、下载、删除等管理 | 支持 | 无 | +| 文件配置管理 | 系统文件上传、下载所需要的配置信息动态添加、修改、删除等管理 | 支持 | 无 | +| 在线用户管理 | 已登录系统的在线用户信息监控与强制踢出操作 | 支持 | 支持 | +| 定时任务 | 运行报表、任务管理(添加、修改、删除)、日志管理、执行器管理等 | 支持 | 仅支持任务与日志管理 | +| 代码生成 | 多数据源前后端代码的生成(java、html、xml、sql)支持CRUD下载 | 支持 | 仅支持单数据源 | +| 系统接口 | 根据业务代码自动生成相关的api接口文档 | 支持 | 支持 | +| 服务监控 | 监视集群系统CPU、内存、磁盘、堆栈、在线日志、Spring相关配置等 | 支持 | 仅支持单机CPU、内存、磁盘监控 | +| 缓存监控 | 对系统的缓存信息查询,命令统计等。 | 支持 | 支持 | +| 在线构建器 | 拖动表单元素生成相应的HTML代码。 | 支持 | 支持 | +| 使用案例 | 系统的一些功能案例 | 支持 | 不支持 | + + +## 演示图例 + +| | | +|--------------------------------------------------------------------------------------------|--------------------------------------------------------------------------------------------| +| ![输入图片说明](https://foruda.gitee.com/images/1680077524361362822/270bb429_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077619939771291/989bf9b6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077681751513929/1c27c5bd_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680077721559267315/74d63e23_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680077765638904515/1b75d4a6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078026375951297/eded7a4b_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078237104531207/0eb1b6a7_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078254306078709/5931e22f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078287971528493/0b9af60a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078308138770249/8d3b6696_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078352553634393/db5ef880_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078378238393374/601e4357_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078414983206024/2aae27c1_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078446738419874/ecce7d59_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078475971341775/149e8634_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078491666717143/3fadece7_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078558863188826/fb8ced2a_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078574561685461/ae68a0b2_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078594932772013/9d8bfec6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078626493093532/fcfe4ff6_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078643608812515/0295bd4f_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078685196286463/d7612c81_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078703877318597/56fce0bc_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078716586545643/b6dbd68f_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078734103217688/eb1e6aa6_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078759131415480/73c525d8_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078779416197879/75e3ed02_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078802329118061/77e10915_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078893627848351/34a1c342_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078928175016986/f126ec4a_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078941718318363/b68a0f72_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680078963175518631/3bb769a1_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680078982294090567/b31c343d_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079000642440444/77ca82a9_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079020995074177/03b7d52e_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079039367822173/76811806_1766278.png "屏幕截图") | +| ![输入图片说明](https://foruda.gitee.com/images/1680079274333484664/4dfdc7c0_1766278.png "屏幕截图") | ![输入图片说明](https://foruda.gitee.com/images/1680079290467458224/d6715fcf_1766278.png "屏幕截图") | + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md new file mode 100644 index 00000000..73a6dbc4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/4.Xinit.md @@ -0,0 +1,67 @@ +# 4.X项目初始化 +- - - +### 项目分支说明 +`4.X` 主分支 4.X版本 稳定发布分支
+`fast` 单体分支 功能与主分支相同 结构为单模块
+`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
+`future/*` 新功能预览分支
+ +### 项目必备环境 +> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 +* oracle jdk 8 11 (暂时不支持 17 不支持大于 jdk8_202 因为202是最后一个免费版本) +* mysql 5.7 8.0 (5.6未适配可能会有问题) +* oracle 11g 12c +* postgres 13 14 +* sqlserver 2017 2019 +* redis 5.X 6.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/tporadowski/redis)) +* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 +* maven 3.6.3 3.8.X +* nodejs >= 12 < 18 +* npm 6.X 8.X (7.X确认有问题) + +### 3.2.0及以上 只需勾选对应环境即可 +![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") + +### 默认 `JDK1.8` 如有变动 需更改以下配置 + +![输入图片说明](https://foruda.gitee.com/images/1681017282888708602/09da902f_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1681017287160367631/3a033268_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1681017292933832275/0bdf875e_1766278.png "屏幕截图") + +### sql导入 + +请按照以下顺序依次导入 + +![输入图片说明](https://foruda.gitee.com/images/1681017239000759855/ad43a5b2_1766278.png "屏幕截图") + +默认为 `mysql` 其他数据库需导入对应的sql文件 + +![输入图片说明](https://foruda.gitee.com/images/1681017245687923510/1b444bc4_1766278.png "屏幕截图") + +**多数据库仅支持主应用 扩展应用需自行适配(例如: xxl-job仅支持mysql)** + +### 服务启动顺序说明 + +1. 必须启动基础建设: mysql redis admin
+2. 可选启动基础建设: minio(影响文件上传) monitor(影响监控) xxljob(影响定时任务)
+ +![输入图片说明](https://foruda.gitee.com/images/1678976302776168895/7333341c_1766278.png "屏幕截图") + +* `MonitorAdminApplication` 为 Admin监控服务(非必要 可参考对应文档关闭) +* `XxlJobAdminApplication` 为 任务调度中心服务(非必要 可参考对应文档关闭) +* `RuoYiApplication` 为 主应用服务 +> 需优先启动 `MonitorAdminApplication` 与 `XxlJobAdminApplication` 具体配置方式参考对应文档 +> 最后启动 主服务 `RuoYiApplication` + +### 主服务配置方式 + +在勾选对应环境的配置文件内 填写 mysql 与 redis 配置信息 + +![输入图片说明](https://foruda.gitee.com/images/1678941357316005626/70559736_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1681017185596156350/d4607b5b_1766278.png "屏幕截图") + +其他数据库配置 按照系统自带的配置更改即可 + +![输入图片说明](https://foruda.gitee.com/images/1678941444707120259/b274592a_1766278.png "屏幕截图") + + diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md new file mode 100644 index 00000000..a966adad --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/5.Xnew.md @@ -0,0 +1,5 @@ +### 视频讲解 + +[RuoYi-Vue-Plus 5.0.0 新功能与变更介绍](https://www.bilibili.com/video/BV1Us4y1m7ky/) + +[RuoYi-Vue-Plus 5.1.0 新功能与变更介绍](https://www.bilibili.com/video/BV1fj411y71X/) diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md new file mode 100644 index 00000000..0a317a83 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/admin_init.md @@ -0,0 +1,32 @@ +# 搭建Admin监控 +- - - +### 配置监控客户端 + +> 修改主服务配置文件 + +![输入图片说明](https://foruda.gitee.com/images/1678941504260707700/68ab99e5_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `url` 为监控中心地址 +* `username 与 password` 为监控中心的账号密码 + +### 启用监控中心 +在 `扩展项目 -> 监控模块` 启动 + +![输入图片说明](https://foruda.gitee.com/images/1678976327174539378/df97e36e_1766278.png "屏幕截图") + +在监控模块对应的 `yml` 配置文件 可设置登录的账号密码与访问路径 + +![输入图片说明](https://foruda.gitee.com/images/1678941572583282843/28117457_1766278.png "屏幕截图") + +### 前端修改admin监控访问路径 +`dev`环境 默认使用 `.env.development` 配置文件内地址 + +![输入图片说明](https://foruda.gitee.com/images/1678941607472644388/460e8eea_1766278.png "屏幕截图") + +`prod`环境 使用 `.env.production` 本机路由 + +![输入图片说明](https://foruda.gitee.com/images/1678941644784144830/6293ab1c_1766278.png "屏幕截图") +故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1678981483900657668/31fd1aad_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md new file mode 100644 index 00000000..37e184c4 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/deploy.md @@ -0,0 +1,126 @@ +# 应用部署 +- - - +## 版本 >= 4.3.0 + +### 请优先阅读 [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) + +## 手动部署 + +在服务器安装 `mysql` `redis` `nginx` `minio` + +将项目内 `script/docker/nginx/nginx.conf` 配置文件 复制到 `nginx` 配置内
+将项目内 `script/docker/redis/redis.conf` 配置文件 复制到 `redis` 配置内 + +并修改相关参数如 `前端页面存放位置` `后端Ip地址` 等使其生效 + +jar包部署后端服务 打包命令如下 + +3.2.0及以上 +```mvn +mvn clean package -D maven.test.skip=true -P prod +``` +服务器需创建临时文件存储目录与配置文件对应(无此目录上传文件会报错) + +![输入图片说明](https://foruda.gitee.com/images/1659951373949149804/屏幕截图.png "屏幕截图.png") + +前端参考下方前端部署章节 + +## 部署视频 + +[RuoYi-Vue-Plus 5.0 生产环境搭建部署](https://www.bilibili.com/video/BV1mL411e7ha/) + +## docker 后端部署 + +### 请优先阅读 [idea环境配置](/ruoyi-vue-plus/quickstart/idea_environment.md) + +**重点: 一知半解的必看** +> [docker安装](https://lionli.blog.csdn.net/article/details/83153029)
+> [docker-compose安装](https://lionli.blog.csdn.net/article/details/111220320)
+> [docker网络模式讲解](https://lionli.blog.csdn.net/article/details/109603785)
+> [docker 开启端口 2375 供外部程序访问](https://lionli.blog.csdn.net/article/details/92627962) + +### 将配置使用FTP上传到根目录 +idea拖拽文件到远程目录即可上传 + +![输入图片说明](https://foruda.gitee.com/images/1662109450908169859/eaac9299_1766278.png "屏幕截图") + +### 给docker分配文件夹权限 +**重点注意: 一定要确保目录 `/docker` 及其所有子目录 具有写权限 如果后续出现权限异常问题 重新执行一遍分配权限** + +![输入图片说明](https://foruda.gitee.com/images/1662109847279259882/3a2202c1_1766278.png "屏幕截图") +```shell +chmod -R 777 /docker +``` +### 构建应用镜像 + +**1.需要先使用maven打包成jar包** + +![输入图片说明](https://foruda.gitee.com/images/1662110477410977621/c6931c42_1766278.png "屏幕截图") + +**2.执行构建** +> 项目初始化后会自动生成构建镜像的运行配置
+> 配置好docker连接之后 运行如下即可构建对应的应用镜像 + +**重点注意: idea2024及以上版本要求必须在本地安装docker才可以执行如下操作** + +![输入图片说明](https://foruda.gitee.com/images/1662110192257483752/0f754b47_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1662120004773449909/9fdef59c_1766278.png "屏幕截图") + +**3.结构讲解** +右键编辑 即可看到内部配置 + +![输入图片说明](https://foruda.gitee.com/images/1662458355500139498/eaa26036_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1662458446794722159/32c086a7_1766278.png "屏幕截图") + + +### 创建基础服务 + +```shell +docker-compose up -d mysql nginx-web redis minio +``` + +### 创建业务服务(需要先构建服务镜像) + +4.X +```shell +docker-compose up -d ruoyi-monitor-admin ruoyi-xxl-job-admin ruoyi-server1 ruoyi-server2 +``` + +5.X +```shell +docker-compose up -d ruoyi-monitor-admin ruoyi-snailjob-server ruoyi-server1 ruoyi-server2 +``` + +### docker其他操作(idea的docker插件 推荐使用) +![输入图片说明](https://foruda.gitee.com/images/1662458271941863770/cd180a04_1766278.png "屏幕截图") + +## 前端部署 + +执行打包命令 +```shell +# 打包正式环境 +npm run build:prod +``` +打包后生成打包文件在 `ruoyi-ui/dist` 目录 +将 `dist` 目录下文件(不包含 `dist` 目录) 上传到部署服务器 `docker/nginx/html` 目录下(手动部署放入自己配置的路径即可) + +![输入图片说明](https://foruda.gitee.com/images/1662110914769648699/07f344c4_1766278.png "屏幕截图") + +重启 `nginx` 服务即可 + + +### 如需更改后端代理路径或者后端ip地址的话往下看 + +更改`nginx.conf`配置文件代理路径(注意: /开头/结尾) + +![输入图片说明](https://foruda.gitee.com/images/1660185698211067202/屏幕截图.png "屏幕截图.png") + +更改前端`.env.环境` 文件内的 `VITE_APP_BASE_API` + +![输入图片说明](https://foruda.gitee.com/images/1724318035232137124/5d035a09_1766278.png "屏幕截图") + +更改`nginx.conf`配置文件后端ip地址 + +![输入图片说明](https://foruda.gitee.com/images/1660185711265558730/屏幕截图.png "屏幕截图.png") diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md new file mode 100644 index 00000000..0c6f33ac --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/extend_project.md @@ -0,0 +1,49 @@ +# 基于 RuoYi-Vue-Plus 的扩展项目列表 +- - - +### 精品PR 欢迎投稿 +| 功能介绍 | PR地址 | +|-------------------------------------|------------------------------------------------------| +| 拖拽图片调整显示顺序 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/173 | +| 增加Jasypt加密库对配置文件加密 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/177 | +| 使用富文本wangeditor5替换Quill | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/213 | +| 集成screw数据库文档功能模块 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/42 | +| Excel导入模板增加批注支持 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/222 | +| 压缩包处理工具 支持本地文件/目录+oss文件/网络文件混合 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/44 | +| 添加websocket模块 支持satoken鉴权 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/65 | +| 数据库字段加解密(支持 base64 aes rsa sm2 sm4) | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/274 | +| 增加liquibase迁移数据库 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/299 | +| 增加OSS模块支持本地环境 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/353 | +| 扩展模块独立集成flyway | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/439 | +| 扩展模块独立集成go-view大屏看板 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/445 | +| 基于AmazonS3协议的分片上传 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/130 | +| 扩展forest http客户端 声明式http请求 二次封装像工具类 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/547 | +| 增加短链接生成工具 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/515 | +| 新增oss预签名上传工具组合使用异步客户端分片 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/522 | +| 新增规则引擎LiteFlow,SQL持久化接入,支持可视化页面 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/552 | +| 一键部署到私有Nexus仓库 | https://gitee.com/dromara/RuoYi-Cloud-Plus/pulls/181 | +| 服务状态监控发送邮件钉钉等 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/568 | +| 登录验证支持2FA验证 | https://gitee.com/dromara/RuoYi-Vue-Plus/pulls/578 | + +### 项目介绍+项目地址 欢迎投稿 + + +| 项目介绍 | 项目地址 | +|--------------------------------|---------------------------------------------------------------------------| +| 微服务扩展 | https://gitee.com/dromara/RuoYi-Cloud-Plus | +| Plus学习笔记 | https://zhonglingyuxiu1028.github.io/zlyx-space/#/ruoyi-vue-plus/home | +| 基于uniapp+TmUI从0开发 支持H5/小程序/安卓 | https://gitee.com/dapppp/ruoyi-plus-miniapp | +| 基于RuoYi-App框架二次修改使用Uniapp+Vue3 | https://gitee.com/wangying110166/ruo-yi-uni-app-plus | +| 基于RuoYi-App框架对接Plus后端 | https://gitee.com/FnTop/RuoYi-App-Plus | +| 基于vben(ant-design-vue)前端项目 | https://gitee.com/dapppp/ruoyi-plus-vben | +| 基于vue-next-admin的vue3+ts前端 | https://gitee.com/thiszhc/RuoYi-Vue3-UI | +| 集成GoView版本 | https://gitee.com/kdwqjwgqxx/RuoYi-Vue-Plus-GoView | +| mybatis-flex版本 | https://gitee.com/dataprince/ruoyi-flex | +| blog博客系统 | https://gitee.com/kalashok-pan/zhi-blog-plus | +| tdengine时序数据库扩展 | https://gitee.com/zhangbg/ruoyi-plus-tdengine | +| 重构项目结构(参考springboot源码) | https://gitee.com/denghuafeng/ruoyi-boot-plus | +| Activiti扩展 | https://gitee.com/sgs98/RuoYi-Vue-Plus-Activiti | +| flowable扩展 | https://gitee.com/sgs98/RuoYi-Vue-Plus-Flowable | +| flowable扩展 | https://gitee.com/KonBAI-Q/ruoyi-flowable-plus | +| mybatis-flex版本 | https://gitee.com/yhan219/ruoyi-vue-flex | +| weblog博客系统 | https://gitee.com/fu-zhanshuai/fzshuai-weblog | +| Annlcc博客 | https://gitee.com/ahcode/ann-blog-plus | \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md new file mode 100644 index 00000000..5995e0ff --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/idea_environment.md @@ -0,0 +1,50 @@ +# idea环境配置 +- - - +## 配置项目编码 +![输入图片说明](https://foruda.gitee.com/images/1662107706295343419/e27065a9_1766278.png "屏幕截图") + +## 配置运行看板 +![输入图片说明](https://foruda.gitee.com/images/1662108673306567278/8af97b47_1766278.png "屏幕截图") +### 配置spring与docker看板 +![输入图片说明](https://foruda.gitee.com/images/1662111392476935892/6b6760fb_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1662108865191892425/3c045999_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1662108877322329668/ddb6d93d_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1662108894122798039/6a53a38c_1766278.png "屏幕截图") + +## 配置服务器SSH连接 +进入 `Settings -> Tools -> SSH Configurations` 点击加号创建SSH连接配置
+填写 服务器IP 用户名 密码 端口号 点击 Test Connection 测试连接 + +![输入图片说明](https://foruda.gitee.com/images/1662107776533098115/bd78467b_1766278.png "屏幕截图") + +使用Terminal 工具 点击箭头找到上方创建的SSH连接配置
+选择即可进入SSH连接界面 在这里可以对服务器进行命令操作 + +![输入图片说明](https://foruda.gitee.com/images/1662108010120640495/c70f9f9a_1766278.png "屏幕截图") + +## 配置服务器FTP连接 +进入 `Settings -> Build-> Deployment` 点击加号 选择SFTP 创建 FTP 连接配置
+选择之前创建好的SSH配置 点击 Test Connection 测试连接 + +![输入图片说明](https://foruda.gitee.com/images/1662107899553257979/e2eeb7fd_1766278.png "屏幕截图") + +在IDEA上方工具栏 找到 `Tools -> Deployment -> Browse Remote Host` 打开远程界面
+点击箭头找到我们上方配置的SFTP连接配置 即可连接到服务器的文件目录 + +![输入图片说明](https://foruda.gitee.com/images/1662107974682787233/b8a601fd_1766278.png "屏幕截图") + +## 配置Docker连接 +### 可操作远程docker与构建上传docker镜像(代替原来maven docker插件) +tcp连接需要开放服务器2375端口
+ssh需要使用上方的SSH连接配置
+建议使用SSH连接 + +![输入图片说明](https://foruda.gitee.com/images/1662108188005932060/75872bf8_1766278.png "屏幕截图") + +配置好之后 在运行窗口会多出一个Docker图标 双击即可连接远程docker
+可以查看容器实时日志 启动 重启 停止 等操作 + +![输入图片说明](https://foruda.gitee.com/images/1662108250902891875/b82d022b_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md new file mode 100644 index 00000000..dba09058 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/init.md @@ -0,0 +1,73 @@ +# 5.X项目初始化 +- - - +### 项目分支说明 + +`5.X` 主分支 5.X版本 稳定发布分支
+`dev` 开发分支 代码随时更新 不推荐使用 经测试后会发布到主分支
+`future/*` 新功能预览分支
+ +### 项目必备环境 +> 推荐使用 `docker` 安装 项目内置 `docker` 编排文件 + +**注意: 禁止使用 `oraclejdk`(由于spring的bug导致打包运行会报错)** + +**Spring官方推荐使用JDK https://bell-sw.com/pages/downloads/** + +![输入图片说明](https://foruda.gitee.com/images/1720080025744223375/0213a652_1766278.png "屏幕截图") + +* openjdk-17/21 或 graalvm-community-jdk-17/21 [下载地址](https://github.com/graalvm/graalvm-ce-builds/releases) 版本 +* mysql 5.7 8.0 (其他版本未测试 如其他版本没问题 可以告知咱们) +* oracle >= 12c (其他版本未测试 如其他版本没问题 可以告知咱们) +* postgres 13 14 (其他版本未测试 如其他版本没问题 可以告知咱们) +* sqlserver 2017 2019 (其他版本未测试 如其他版本没问题 可以告知咱们) +* redis 5.X 6.X 7.X 由于框架大量使用了redis特性 版本必须 >= 5.X ([win redis 下载地址](https://github.com/zkteco-home/redis-windows)) +* minio 本地文件存储 或 阿里云 腾讯云 七牛云等一切支持S3协议的云存储 +* maven >= 3.8.X +* nodejs >= 18.18 (其他版本未测试 如其他版本没问题 可以告知咱们) +* npm >= 8.X (7.X确认有问题) +* idea 2022 2024 (一定不要使用2023后果自负 bug太多影响项目开发) + +### 搭建视频 + +[RuoYi-Vue-Plus 5.0 搭建与运行](https://www.bilibili.com/video/BV1Fg4y137JK/) + +### 勾选maven对应环境 +![输入图片说明](https://foruda.gitee.com/images/1678976284045210056/a2f28d33_1766278.png "屏幕截图") + +### 默认 `JDK17` 如有变动 需更改以下配置 + +![输入图片说明](https://foruda.gitee.com/images/1678941027820943505/c688e01e_1766278.png "屏幕截图") +![输入图片说明](https://foruda.gitee.com/images/1678941120518807034/4d56fcc9_1766278.png "屏幕截图") + +### sql导入 + +请按照以下顺序依次导入 默认为 `mysql` 其他数据库需导入对应的sql文件
+如需使用其他数据库 看这里 => [多数据库数据源](../framework/extend/dynamic_datasource.md)
+ +![输入图片说明](https://foruda.gitee.com/images/1725853192789853346/a0d3f0b7_1766278.png "屏幕截图") + +### 服务启动顺序说明 + +1. 必须启动基础建设: mysql redis admin
+2. 可选启动基础建设: minio(影响文件上传) monitor(影响监控) snailjob(影响定时任务)
+ +![输入图片说明](https://foruda.gitee.com/images/1716175484919688429/8b9a79b7_1766278.png "屏幕截图") + +* `MonitorAdminApplication` 为 Admin监控服务(非必要 可参考对应文档关闭 [搭建Admin监控](/ruoyi-vue-plus/quickstart/admin_init.md)) +* `SnailJobServerApplication` 为 任务调度中心服务(非必要 可参考对应文档关闭 [搭建调度中心](/ruoyi-vue-plus/quickstart/snail_job_init.md)) +* `DromaraApplication` 为 主应用服务 +> 需优先启动 `MonitorAdminApplication` 与 `SnailJobServerApplication` 具体配置方式参考对应文档
+> 最后启动 主服务 `DromaraApplication`
+> 工作流相关初始化使用 [工作流初始化](/ruoyi-vue-plus/quickstart/worker_init.md) + +### 主服务配置方式 + +在勾选对应环境的配置文件内 填写 mysql 与 redis 配置信息 + +![输入图片说明](https://foruda.gitee.com/images/1678941357316005626/70559736_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1678941405169571070/0d06a955_1766278.png "屏幕截图") + +其他数据库配置 按照系统自带的配置更改即可 + +![输入图片说明](https://foruda.gitee.com/images/1678941444707120259/b274592a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md new file mode 100644 index 00000000..863971b1 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/power_job_init.md @@ -0,0 +1,48 @@ +# 搭建PowerJob任务调度中心(5.X分支已废弃) +- - - +### 废弃原因 + +接到大量投诉 使用困难 用法诡异 各种问题等 + +### 配置调度中心客户端 +> 修改主服务配置文件 +> + +![输入图片说明](https://foruda.gitee.com/images/1687656939847353725/951c1af7_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1687335574708412835/41d6c9d7_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `server-address` 为调度中心地址 +* `app-name` 为执行器组账户名(需在调度中心注册方可登录查看) + +### 启用调度中心 +**需执行 powerjob.sql 默认账号密码 `ruoyi-worker` `123456` 账号在数据库里 可以在页面修改密码** +
+ +![输入图片说明](https://foruda.gitee.com/images/1688634469876143273/c89455c0_1766278.png "屏幕截图") + +> 在 `扩展项目 -> powerjob-server模块` 启动 +> +![输入图片说明](https://foruda.gitee.com/images/1687335752250147336/17abe410_1766278.png "屏幕截图") + +> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-powerjob-server服务的配置文件**) +> +![输入图片说明](https://foruda.gitee.com/images/1687335802095066722/569d92be_1766278.png "屏幕截图") + +> 也可配置邮件发送 钉钉推送 和 mongodb存储 +> +![输入图片说明](https://foruda.gitee.com/images/1687335842722317559/f875c07a_1766278.png "屏幕截图") + +### 前端修改任务调度中心访问路径 +`dev`环境 默认使用 `.env.development` 配置文件内地址 + +![输入图片说明](https://foruda.gitee.com/images/1687335909698376722/7efa7539_1766278.png "屏幕截图") + +`prod`环境 使用 `.env.production` 本机路由 + +![输入图片说明](https://foruda.gitee.com/images/1687335937599399056/dd769ef5_1766278.png "屏幕截图") + +故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1687335979933648639/6a43b749_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md new file mode 100644 index 00000000..4c6d353b --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/snail_job_init.md @@ -0,0 +1,52 @@ +# 搭建SnailJob任务调度中心(5.2.0新功能) +- - - + +### 视频介绍 + +[Snail job任务调度中心:轻松掌握任务管理、重试机制和任务编排](https://www.bilibili.com/video/BV19i421m7GL/) + +### 配置调度中心客户端 +> 修改主服务配置文件 +> + +![输入图片说明](https://foruda.gitee.com/images/1687656939847353725/951c1af7_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1716174758437043952/de28db71_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `server.address` 为调度中心地址 +* `server.port` 为调度中心通信端口 +* `token` 为组通信校验token(可在调度中心组配置更换) +* `group-name` 为执行器组 +* `namespace` 作用域(不同作用域相互隔离请勿填错) + +### 启用调度中心 +**需执行 snail_job.sql 默认账号密码 `admin` `admin` 账号在数据库里 可以在页面修改密码** +
+ +![输入图片说明](https://foruda.gitee.com/images/1714355875395308961/adc21668_1766278.png "屏幕截图") + +> 在 `ruoyi-extend -> ruoyi-snailjob-server` 模块启动 +> +![输入图片说明](https://foruda.gitee.com/images/1716174842485474283/78cec86d_1766278.png "屏幕截图") + +> 需修改配置文件数据库连接地址(**注意: 此处为ruoyi-snailjob-server服务的配置文件 支持多种不同数据库**) +> +![输入图片说明](https://foruda.gitee.com/images/1714356048711590477/13289085_1766278.png "屏幕截图") + +### 快速入门 + +[Snailjob快速入门 基本使用介绍](https://juejin.cn/post/7412955032092442675) + +### 前端修改任务调度中心访问路径 +`dev`环境 默认使用 `.env.development` 配置文件内地址 + +![输入图片说明](https://foruda.gitee.com/images/1716174933143893408/58d47bbc_1766278.png "屏幕截图") + +`prod`环境 使用 `.env.production` 本机路由 + +![输入图片说明](https://foruda.gitee.com/images/1716174973454805690/0d6f20fb_1766278.png "屏幕截图") + +故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1716174998979181179/2f9e4e4a_1766278.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md new file mode 100644 index 00000000..da09117a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/worker_init.md @@ -0,0 +1,43 @@ +# 工作流初始化 +- - - + +### 工作流使用及配置方式 + +1.找到项目中script下bpmn文件夹 + +![输入图片说明](https://foruda.gitee.com/images/1714211764058540441/5c8b97af_5363069.png "屏幕截图") + +2.启动项目找到流程定义通过**部署流程文件**将bpmn文件夹下**模型.zip**上传 + +![输入图片说明](https://foruda.gitee.com/images/1714211950485333575/1e2b3ff4_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212113004821592/96586e69_5363069.png "屏幕截图") + +3.导入**模型.zip**后将会出现以下列表,默认使用**leave1**,test_leave为请假申请表名称 + +![输入图片说明](https://foruda.gitee.com/images/1714212222766335759/1227bbd6_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212493602552742/9e0258b1_5363069.png "屏幕截图") + +**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** + +![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") + + +4.新增一条请假申请,提交后将会得到如下信息 + +![输入图片说明](https://foruda.gitee.com/images/1714212617432902105/3609f6ef_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212630860787365/2922d38e_5363069.png "屏幕截图") + +5.关于如何切换一个新的流程使用,当前默认使用得KEY为leave1 ,我们切换到leave2使用,我们只需点击绑定业务将表名绑定,重新发起一个新的请假申请就可以得到一个新的流程信息 + +![输入图片说明](https://foruda.gitee.com/images/1714212876442323110/4554ea95_5363069.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714213037864274694/613149f5_5363069.png "屏幕截图") + +**此处表名由来与表单源码内编写的表名保持一致方可互相绑定** + +![输入图片说明](https://foruda.gitee.com/images/1716447357161482917/2c9b1639_1766278.png "屏幕截图") + +![输入图片说明](https://foruda.gitee.com/images/1714212963457174382/add768db_5363069.png "屏幕截图") \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md new file mode 100644 index 00000000..f2751e9f --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/ruoyi-vue-plus/quickstart/xxl_job_init.md @@ -0,0 +1,43 @@ +# 搭建Xxl-Job任务调度中心(5.X分支已废弃) +- - - +### 废弃原因 + +长时间不维护 社区冰点 不支持jdk17 不支持boot3 不支持其他数据库等 + +### 配置调度中心客户端 +> 修改主服务配置文件 +> +![输入图片说明](https://foruda.gitee.com/images/1678941760168414366/b81e023b_1766278.png "屏幕截图") + +* `enabled` 可启用或关闭客户端注册 +* `admin-addresses` 为调度中心地址 +* `access-token` 为调度中心交互鉴权token +* `executor` 为执行器配置 一个客户端为一个执行器 可配置执行器集群 使用分片任务处理 + +### 启用调度中心 +**默认账号密码 `admin` `123456` 账号在数据库里 可以在页面修改密码** + +> 在 `扩展项目 -> xxl-job-admin模块` 启动 +> +![输入图片说明](https://foruda.gitee.com/images/1678976353500205883/058fef13_1766278.png "屏幕截图") + +> 需修改配置文件数据库连接地址(**注意: 此处为xxl-job-admin服务的配置文件**) +> +![输入图片说明](https://foruda.gitee.com/images/1678941813423551656/04c32a5b_1766278.png "屏幕截图") + +> 也可配置邮件发送 +> +![输入图片说明](https://foruda.gitee.com/images/1678941825447455298/1baa5e43_1766278.png "屏幕截图") + +### 前端修改任务调度中心访问路径 +`dev`环境 默认使用 `.env.development` 配置文件内地址 + +![输入图片说明](https://foruda.gitee.com/images/1678976378255854583/8cdbf4e3_1766278.png "屏幕截图") + +`prod`环境 使用 `.env.production` 本机路由 + +![输入图片说明](https://foruda.gitee.com/images/1678976382819019066/96288331_1766278.png "屏幕截图") + +故而 `prod` 环境只需更改 `nginx` 反向代理路径即可 + +![输入图片说明](https://foruda.gitee.com/images/1678976386764602366/55894f85_1766278.png "屏幕截图") diff --git a/ruoyi-admin/src/main/resources/static/static/css/vue.css b/ruoyi-admin/src/main/resources/static/static/css/vue.css new file mode 100644 index 00000000..847f385a --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/css/vue.css @@ -0,0 +1 @@ +@import url("https://fonts.googleapis.com/css?family=Roboto+Mono|Source+Sans+Pro:300,400,600");*{-webkit-font-smoothing:antialiased;-webkit-overflow-scrolling:touch;-webkit-tap-highlight-color:rgba(0,0,0,0);-webkit-text-size-adjust:none;-webkit-touch-callout:none;box-sizing:border-box}body:not(.ready){overflow:hidden}body:not(.ready) .app-nav,body:not(.ready)>nav,body:not(.ready) [data-cloak]{display:none}div#app{font-size:30px;font-weight:lighter;margin:40vh auto;text-align:center}div#app:empty:before{content:"Loading..."}img.emoji{height:1.2em}img.emoji,span.emoji{vertical-align:middle}span.emoji{font-family:Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-size:1.2em}.progress{background-color:#42b983;background-color:var(--theme-color,#42b983);height:2px;left:0;position:fixed;right:0;top:0;transition:width .2s,opacity .4s;width:0;z-index:999999}.search .search-keyword,.search a:hover{color:#42b983;color:var(--theme-color,#42b983)}.search .search-keyword{font-style:normal;font-weight:700}body,html{height:100%}body{-moz-osx-font-smoothing:grayscale;-webkit-font-smoothing:antialiased;color:#34495e;font-family:Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:15px;letter-spacing:0;margin:0;overflow-x:hidden}img{max-width:100%}a[disabled]{cursor:not-allowed;opacity:.6}kbd{border:1px solid #ccc;border-radius:3px;display:inline-block;font-size:12px!important;line-height:12px;margin-bottom:3px;padding:3px 5px;vertical-align:middle}li input[type=checkbox]{margin:0 .2em .25em 0;vertical-align:middle}.app-nav{margin:25px 60px 0 0;position:absolute;right:0;text-align:right;z-index:10}.app-nav.no-badge{margin-right:25px}.app-nav p{margin:0}.app-nav>a{margin:0 1rem;padding:5px 0}.app-nav li,.app-nav ul{display:inline-block;list-style:none;margin:0}.app-nav a{color:inherit;font-size:16px;text-decoration:none;transition:color .3s}.app-nav a.active,.app-nav a:hover{color:#42b983;color:var(--theme-color,#42b983)}.app-nav a.active{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983)}.app-nav li{display:inline-block;margin:0 1rem;padding:5px 0;position:relative;cursor:pointer}.app-nav li ul{background-color:#fff;border:1px solid;border-color:#ddd #ddd #ccc;border-radius:4px;box-sizing:border-box;display:none;max-height:calc(100vh - 61px);overflow-y:auto;padding:10px 0;position:absolute;right:-15px;text-align:left;top:100%;white-space:nowrap}.app-nav li ul li{display:block;font-size:14px;line-height:1rem;margin:8px 14px;white-space:nowrap}.app-nav li ul a{display:block;font-size:inherit;margin:0;padding:0}.app-nav li ul a.active{border-bottom:0}.app-nav li:hover ul{display:block}.github-corner{border-bottom:0;position:fixed;right:0;text-decoration:none;top:0;z-index:1}.github-corner:hover .octo-arm{animation:octocat-wave .56s ease-in-out}.github-corner svg{color:#fff;fill:#42b983;fill:var(--theme-color,#42b983);height:80px;width:80px}main{display:block;position:relative;width:100vw;height:100%;z-index:0}main.hidden{display:none}.anchor{display:inline-block;text-decoration:none;transition:all .3s}.anchor span{color:#34495e}.anchor:hover{text-decoration:underline}.sidebar{border-right:1px solid rgba(0,0,0,.07);overflow-y:auto;padding:40px 0 0;position:absolute;top:0;bottom:0;left:0;transition:transform .25s ease-out;width:300px;z-index:20}.sidebar>h1{margin:0 auto 1rem;font-size:1.5rem;font-weight:300;text-align:center}.sidebar>h1 a{color:inherit;text-decoration:none}.sidebar>h1 .app-nav{display:block;position:static}.sidebar .sidebar-nav{line-height:2em;padding-bottom:40px}.sidebar li.collapse .app-sub-sidebar{display:none}.sidebar ul{margin:0 0 0 15px;padding:0}.sidebar li>p{font-weight:700;margin:0}.sidebar ul,.sidebar ul li{list-style:none}.sidebar ul li a{border-bottom:none;display:block}.sidebar ul li ul{padding-left:20px}.sidebar::-webkit-scrollbar{width:4px}.sidebar::-webkit-scrollbar-thumb{background:transparent;border-radius:4px}.sidebar:hover::-webkit-scrollbar-thumb{background:hsla(0,0%,53.3%,.4)}.sidebar:hover::-webkit-scrollbar-track{background:hsla(0,0%,53.3%,.1)}.sidebar-toggle{background-color:transparent;background-color:hsla(0,0%,100%,.8);border:0;outline:none;padding:10px;position:absolute;bottom:0;left:0;text-align:center;transition:opacity .3s;width:284px;z-index:30;cursor:pointer}.sidebar-toggle:hover .sidebar-toggle-button{opacity:.4}.sidebar-toggle span{background-color:#42b983;background-color:var(--theme-color,#42b983);display:block;margin-bottom:4px;width:16px;height:2px}body.sticky .sidebar,body.sticky .sidebar-toggle{position:fixed}.content{padding-top:60px;position:absolute;top:0;right:0;bottom:0;left:300px;transition:left .25s ease}.markdown-section{margin:0 auto;max-width:80%;padding:30px 15px 40px;position:relative}.markdown-section>*{box-sizing:border-box;font-size:inherit}.markdown-section>:first-child{margin-top:0!important}.markdown-section hr{border:none;border-bottom:1px solid #eee;margin:2em 0}.markdown-section iframe{border:1px solid #eee;width:1px;min-width:100%}.markdown-section table{border-collapse:collapse;border-spacing:0;display:block;margin-bottom:1rem;overflow:auto;width:100%}.markdown-section th{font-weight:700}.markdown-section td,.markdown-section th{border:1px solid #ddd;padding:6px 13px}.markdown-section tr{border-top:1px solid #ccc}.markdown-section p.tip,.markdown-section tr:nth-child(2n){background-color:#f8f8f8}.markdown-section p.tip{border-bottom-right-radius:2px;border-left:4px solid #f66;border-top-right-radius:2px;margin:2em 0;padding:12px 24px 12px 30px;position:relative}.markdown-section p.tip:before{background-color:#f66;border-radius:100%;color:#fff;content:"!";font-family:Dosis,Source Sans Pro,Helvetica Neue,Arial,sans-serif;font-size:14px;font-weight:700;left:-12px;line-height:20px;position:absolute;height:20px;width:20px;text-align:center;top:14px}.markdown-section p.tip code{background-color:#efefef}.markdown-section p.tip em{color:#34495e}.markdown-section p.warn{background:rgba(66,185,131,.1);border-radius:2px;padding:1rem}.markdown-section ul.task-list>li{list-style-type:none}body.close .sidebar{transform:translateX(-300px)}body.close .sidebar-toggle{width:auto}body.close .content{left:0}@media print{.app-nav,.github-corner,.sidebar,.sidebar-toggle{display:none}}@media screen and (max-width:768px){.github-corner,.sidebar,.sidebar-toggle{position:fixed}.app-nav{margin-top:16px}.app-nav li ul{top:30px}main{height:auto;min-height:100vh;overflow-x:hidden}.sidebar{left:-300px;transition:transform .25s ease-out}.content{left:0;max-width:100vw;position:static;padding-top:20px;transition:transform .25s ease}.app-nav,.github-corner{transition:transform .25s ease-out}.sidebar-toggle{background-color:transparent;width:auto;padding:30px 30px 10px 10px}body.close .sidebar{transform:translateX(300px)}body.close .sidebar-toggle{background-color:hsla(0,0%,100%,.8);transition:background-color 1s;width:284px;padding:10px}body.close .content{transform:translateX(300px)}body.close .app-nav,body.close .github-corner{display:none}.github-corner:hover .octo-arm{animation:none}.github-corner .octo-arm{animation:octocat-wave .56s ease-in-out}}@keyframes octocat-wave{0%,to{transform:rotate(0)}20%,60%{transform:rotate(-25deg)}40%,80%{transform:rotate(10deg)}}section.cover{position:relative;align-items:center;background-position:50%;background-repeat:no-repeat;background-size:cover;min-height:100vh;width:100%;display:none}section.cover.show{display:flex}section.cover.has-mask .mask{background-color:#fff;opacity:.8;position:absolute;top:0;bottom:0;width:100%}section.cover .cover-main{flex:1;margin:0 16px;text-align:center;position:relative}section.cover a{color:inherit}section.cover a,section.cover a:hover{text-decoration:none}section.cover p{line-height:1.5rem;margin:1em 0}section.cover h1{color:inherit;font-size:2.5rem;font-weight:300;margin:.625rem 0 2.5rem;position:relative;text-align:center}section.cover h1 a{display:block}section.cover h1 small{bottom:-.4375rem;font-size:1rem;position:absolute}section.cover blockquote{font-size:1.5rem;text-align:center}section.cover ul{line-height:1.8;list-style-type:none;margin:1em auto;max-width:500px;padding:0}section.cover .cover-main>p:last-child a{border-radius:2rem;border:1px solid #42b983;border-color:var(--theme-color,#42b983);box-sizing:border-box;color:#42b983;color:var(--theme-color,#42b983);display:inline-block;font-size:1.05rem;letter-spacing:.1rem;margin:.5rem 1rem;padding:.75em 2rem;text-decoration:none;transition:all .15s ease}section.cover .cover-main>p:last-child a:last-child{background-color:#42b983;background-color:var(--theme-color,#42b983);color:#fff}section.cover .cover-main>p:last-child a:last-child:hover{color:inherit;opacity:.8}section.cover .cover-main>p:last-child a:hover{color:inherit}section.cover blockquote>p>a{border-bottom:2px solid #42b983;border-bottom:2px solid var(--theme-color,#42b983);transition:color .3s}section.cover blockquote>p>a:hover{color:#42b983;color:var(--theme-color,#42b983)}.sidebar,body{background-color:#fff}.sidebar{color:#364149}.sidebar li{margin:6px 0}.sidebar ul li a{color:#505d6b;font-size:14px;font-weight:400;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.sidebar ul li a:hover{text-decoration:underline}.sidebar ul li ul{padding:0}.sidebar ul li.active>a{border-right:2px solid;color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.app-sub-sidebar li:before{content:"-";padding-right:4px;float:left}.markdown-section h1,.markdown-section h2,.markdown-section h3,.markdown-section h4,.markdown-section strong{color:#2c3e50;font-weight:600}.markdown-section a{color:#42b983;color:var(--theme-color,#42b983);font-weight:600}.markdown-section h1{font-size:2rem;margin:0 0 1rem}.markdown-section h2{font-size:1.75rem;margin:45px 0 .8rem}.markdown-section h3{font-size:1.5rem;margin:40px 0 .6rem}.markdown-section h4{font-size:1.25rem}.markdown-section h5{font-size:1rem}.markdown-section h6{color:#777;font-size:1rem}.markdown-section figure,.markdown-section p{margin:1.2em 0}.markdown-section ol,.markdown-section p,.markdown-section ul{line-height:1.6rem;word-spacing:.05rem}.markdown-section ol,.markdown-section ul{padding-left:1.5rem}.markdown-section blockquote{border-left:4px solid #42b983;border-left:4px solid var(--theme-color,#42b983);color:#858585;margin:2em 0;padding-left:20px}.markdown-section blockquote p{font-weight:600;margin-left:0}.markdown-section iframe{margin:1em 0}.markdown-section em{color:#7f8c8d}.markdown-section code,.markdown-section output:after,.markdown-section pre{font-family:Roboto Mono,Monaco,courier,monospace}.markdown-section code,.markdown-section pre{background-color:#f8f8f8}.markdown-section output,.markdown-section pre{margin:1.2em 0;position:relative}.markdown-section output,.markdown-section pre>code{border-radius:2px;display:block}.markdown-section output:after,.markdown-section pre>code{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial}.markdown-section code{border-radius:2px;color:#e96900;margin:0 2px;padding:3px 5px;white-space:pre-wrap}.markdown-section>:not(h1):not(h2):not(h3):not(h4):not(h5):not(h6) code{font-size:.8rem}.markdown-section pre{padding:0 1.4rem;line-height:1.5rem;overflow:auto;word-wrap:normal}.markdown-section pre>code{color:#525252;font-size:.8rem;padding:2.2em 5px;line-height:inherit;margin:0 2px;max-width:inherit;overflow:inherit;white-space:inherit}.markdown-section output{padding:1.7rem 1.4rem;border:1px dotted #ccc}.markdown-section output>:first-child{margin-top:0}.markdown-section output>:last-child{margin-bottom:0}.markdown-section code:after,.markdown-section code:before,.markdown-section output:after,.markdown-section output:before{letter-spacing:.05rem}.markdown-section output:after,.markdown-section pre:after{color:#ccc;font-size:.6rem;font-weight:600;height:15px;line-height:15px;padding:5px 10px 0;position:absolute;right:0;text-align:right;top:0;content:attr(data-lang)}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#8e908c}.token.namespace{opacity:.7}.token.boolean,.token.number{color:#c76b29}.token.punctuation{color:#525252}.token.property{color:#c08b30}.token.tag{color:#2973b7}.token.string{color:#42b983;color:var(--theme-color,#42b983)}.token.selector{color:#6679cc}.token.attr-name{color:#2973b7}.language-css .token.string,.style .token.string,.token.entity,.token.url{color:#22a2c9}.token.attr-value,.token.control,.token.directive,.token.unit{color:#42b983;color:var(--theme-color,#42b983)}.token.function,.token.keyword{color:#e96900}.token.atrule,.token.regex,.token.statement{color:#22a2c9}.token.placeholder,.token.variable{color:#3d8fd1}.token.deleted{text-decoration:line-through}.token.inserted{border-bottom:1px dotted #202746;text-decoration:none}.token.italic{font-style:italic}.token.bold,.token.important{font-weight:700}.token.important{color:#c94922}.token.entity{cursor:help}code .token{-moz-osx-font-smoothing:initial;-webkit-font-smoothing:initial;min-height:1.5rem;position:relative;left:auto} \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/image/favicon.ico b/ruoyi-admin/src/main/resources/static/static/image/favicon.ico new file mode 100644 index 00000000..3f919d85 Binary files /dev/null and b/ruoyi-admin/src/main/resources/static/static/image/favicon.ico differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/logo.png b/ruoyi-admin/src/main/resources/static/static/image/logo.png new file mode 100644 index 00000000..306851c1 Binary files /dev/null and b/ruoyi-admin/src/main/resources/static/static/image/logo.png differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png b/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png new file mode 100644 index 00000000..cc697e6d Binary files /dev/null and b/ruoyi-admin/src/main/resources/static/static/image/ruoyicloudplus.png differ diff --git a/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png b/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png new file mode 100644 index 00000000..d0eba10d Binary files /dev/null and b/ruoyi-admin/src/main/resources/static/static/image/ruoyivueplus.png differ diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js new file mode 100644 index 00000000..02a83a31 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/docsify-copy-code.min.js @@ -0,0 +1,9 @@ +/*! + * docsify-copy-code + * v3.0.0 + * https://github.com/jperasmus/docsify-copy-code + * (c) 2017-2023 JP Erasmus + * MIT license + */ +!function(){"use strict";function e(o){return e="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},e(o)}!function(e,o){void 0===o&&(o={});var t=o.insertAt;if(e&&"undefined"!=typeof document){var n=document.head||document.getElementsByTagName("head")[0],c=document.createElement("style");c.type="text/css","top"===t&&n.firstChild?n.insertBefore(c,n.firstChild):n.appendChild(c),c.styleSheet?c.styleSheet.cssText=e:c.appendChild(document.createTextNode(e))}}(".docsify-copy-code-button,.docsify-copy-code-button>span{cursor:pointer;transition:all .25s ease}.docsify-copy-code-button{background:grey;background:var(--theme-color,grey);border:0;border-radius:0;color:#fff;font-size:1em;opacity:0;outline:0;overflow:visible;padding:.65em .8em;position:absolute;right:0;top:0;z-index:1}.docsify-copy-code-button>span{background:inherit;border-radius:3px;pointer-events:none}.docsify-copy-code-button>.error,.docsify-copy-code-button>.success{font-size:.825em;opacity:0;padding:.5em .65em;position:absolute;right:0;top:50%;transform:translateY(-50%);z-index:-100}.docsify-copy-code-button.error>.error,.docsify-copy-code-button.success>.success{opacity:1;right:100%;transform:translate(-25%,-50%)}.docsify-copy-code-button:focus,pre:hover .docsify-copy-code-button{opacity:1}.docsify-copy-code-button>[aria-live]{height:1px;left:-10000px;overflow:hidden;position:absolute;top:auto;width:1px}"),document.querySelector('link[href*="docsify-copy-code"]')&&console.warn("[Deprecation] Link to external docsify-copy-code stylesheet is no longer necessary."),window.DocsifyCopyCodePlugin={init:function(){return function(e,o){e.ready((function(){console.warn("[Deprecation] Manually initializing docsify-copy-code using window.DocsifyCopyCodePlugin.init() is no longer necessary.")}))}}},window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(o,t){var n={buttonText:"Copy to clipboard",errorText:"Error",successText:"Copied"};o.doneEach((function(){var o=Array.from(document.querySelectorAll("pre[data-lang]"));t.config.copyCode&&Object.keys(n).forEach((function(o){var c=t.config.copyCode[o];"string"==typeof c?n[o]=c:"object"===e(c)&&Object.keys(c).some((function(e){var t=location.href.indexOf(e)>-1;return n[o]=t?c[e]:n[o],t}))}));var c=['"].join("");o.forEach((function(e){e.insertAdjacentHTML("beforeend",c)}))})),o.mounted((function(){var e=document.querySelector(".content");e&&e.addEventListener("click",(function(e){if(e.target.classList.contains("docsify-copy-code-button")){var o="BUTTON"===e.target.tagName?e.target:e.target.parentNode,t=document.createRange(),c=o.parentNode.querySelector("code"),i=o.querySelector("[aria-live]"),r=window.getSelection();t.selectNode(c),r&&(r.removeAllRanges(),r.addRange(t));try{document.execCommand("copy")&&(o.classList.add("success"),i.innerText=n.successText,setTimeout((function(){o.classList.remove("success"),i.innerText=""}),1e3))}catch(e){console.error("docsify-copy-code: ".concat(e)),o.classList.add("error"),i.innerText=n.errorText,setTimeout((function(){o.classList.remove("error"),i.innerText=""}),1e3)}(r=window.getSelection())&&("function"==typeof r.removeRange?r.removeRange(t):"function"==typeof r.removeAllRanges&&r.removeAllRanges())}}))}))}].concat(window.$docsify.plugins||[])}(); +//# sourceMappingURL=docsify-copy-code.min.js.map \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js new file mode 100644 index 00000000..b4262116 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/docsify-footer.min.js @@ -0,0 +1,4 @@ +parcelRequire=function(e,r,t,n){var i,o="function"==typeof parcelRequire&&parcelRequire,u="function"==typeof require&&require;function f(t,n){if(!r[t]){if(!e[t]){var i="function"==typeof parcelRequire&&parcelRequire;if(!n&&i)return i(t,!0);if(o)return o(t,!0);if(u&&"string"==typeof t)return u(t);var c=new Error("Cannot find module '"+t+"'");throw c.code="MODULE_NOT_FOUND",c}p.resolve=function(r){return e[t][1][r]||r},p.cache={};var l=r[t]=new f.Module(t);e[t][0].call(l.exports,p,l,l.exports,this)}return r[t].exports;function p(e){return f(p.resolve(e))}}f.isParcelRequire=!0,f.Module=function(e){this.id=e,this.bundle=f,this.exports={}},f.modules=e,f.cache=r,f.parent=o,f.register=function(r,t){e[r]=[function(e,r){r.exports=t},{}]};for(var c=0;c ul > li"),c("p",e)),this.hyperlink=m(t))}var b=function(){return'
'},k=function(t,e){a=e,r=t.route.path,o={},["previousText","nextText"].forEach(function(n){var i=a[n];"string"==typeof i?o[n]=i:Object.keys(i).some(function(t){var e=r&&-1\n \n
\n \n \n \n '+i+'\n
\n
'+t.prev.name+"
\n ",t.prev&&e.crossChapterText&&'
'+t.prev.chapterName+"
",t.prev&&"
\n \n ",t.next&&'\n \n "].filter(Boolean).join("")};window.$docsify=window.$docsify||{},window.$docsify.plugins=[function(t,e){var n=d({},(e.config,{previousText:"PREVIOUS",nextText:"NEXT",crossChapter:!1,crossChapterText:!1}),e.config.pagination||{});function i(){var t=c("."+h);t&&(t.innerHTML=k(function(t,e){e=e.crossChapter;try{var n=t.router.toURL(t.route.path),i=g(c.all(".sidebar-nav li a")).filter(function(t){return!s(t,".section-link")}),a=i.find(x(n)),r=g((p(a,"ul")||{}).children).filter(function(t){return"LI"===t.tagName.toUpperCase()}),o=e?i.findIndex(x(n)):r.findIndex(function(t){t=m(t);return t&&x(n,t)}),l=e?i:r;return{route:t.route,prev:new y(l[o-1]).toJSON(),next:new y(l[o+1]).toJSON()}}catch(t){return{route:{}}}}(e,n),n))}t.afterEach(function(t){return t+b()}),t.doneEach(i)}].concat(window.$docsify.plugins||[])}); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js new file mode 100644 index 00000000..c5ed3ca2 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/docsify-scroll-to-top.min.js @@ -0,0 +1 @@ +var CONFIG={auto:true,text:"Top",right:15,bottom:15,offset:500};var install=function(hook,vm){var opts=vm.config.scrollToTop||CONFIG;CONFIG.auto=opts.auto&&typeof opts.auto==="boolean"?opts.auto:CONFIG.auto;CONFIG.text=opts.text&&typeof opts.text==="string"?opts.text:CONFIG.text;CONFIG.right=opts.right&&typeof opts.right==="number"?opts.right:CONFIG.right;CONFIG.bottom=opts.bottom&&typeof opts.bottom==="number"?opts.bottom:CONFIG.bottom;CONFIG.offset=opts.offset&&typeof opts.offset==="number"?opts.offset:CONFIG.offset;var onScroll=function(e){if(!CONFIG.auto){return}var offset=window.document.documentElement.scrollTop;var $scrollBtn=Docsify.dom.find("span.scroll-to-top");$scrollBtn.style.display=offset>=CONFIG.offset?"block":"none"};hook.mounted(function(){var scrollBtn=document.createElement("span");scrollBtn.className="scroll-to-top";scrollBtn.style.display=CONFIG.auto?"none":"block";scrollBtn.style.overflow="hidden";scrollBtn.style.position="fixed";scrollBtn.style.right=CONFIG.right+"px";scrollBtn.style.bottom=CONFIG.bottom+"px";scrollBtn.style.width="50px";scrollBtn.style.height="50px";scrollBtn.style.background="white";scrollBtn.style.color="#666";scrollBtn.style.border="1px solid #ddd";scrollBtn.style.borderRadius="4px";scrollBtn.style.lineHeight="42px";scrollBtn.style.fontSize="16px";scrollBtn.style.textAlign="center";scrollBtn.style.boxShadow="0px 0px 6px #eee";scrollBtn.style.cursor="pointer";var textNode=document.createTextNode(CONFIG.text);scrollBtn.appendChild(textNode);document.body.appendChild(scrollBtn);window.addEventListener("scroll",onScroll);scrollBtn.onclick=function(e){e.stopPropagation();var step=window.scrollY/15;var scroll=function(){window.scrollTo(0,window.scrollY-step);if(window.scrollY>0){setTimeout(scroll,15)}};scroll()}})};$docsify.plugins=[].concat(install,$docsify.plugins); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js b/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js new file mode 100644 index 00000000..18e85aa9 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/docsify.min.js @@ -0,0 +1 @@ +!function(){function c(i){var o=Object.create(null);return function(e){var n=f(e)?e:JSON.stringify(e);return o[n]||(o[n]=i(e))}}var a=c(function(e){return e.replace(/([A-Z])/g,function(e){return"-"+e.toLowerCase()})}),u=Object.prototype.hasOwnProperty,m=Object.assign||function(e){for(var n=arguments,i=1;i=e||n.classList.contains("hidden")?S(h,"add","sticky"):S(h,"remove","sticky"))}function ee(e,n,o,i){var t=[];null!=(n=l(n))&&(t=k(n,"a"));var a,r=decodeURI(e.toURL(e.getCurrentPath()));return t.sort(function(e,n){return n.href.length-e.href.length}).forEach(function(e){var n=decodeURI(e.getAttribute("href")),i=o?e.parentNode:e;e.title=e.title||e.innerText,0!==r.indexOf(n)||a?S(i,"remove","active"):(a=e,S(i,"add","active"))}),i&&(v.title=a?a.title||a.innerText+" - "+J:J),a}function ne(e,n){for(var i=0;ithis.end&&e>=this.next}[this.direction]}},{key:"_defaultEase",value:function(e,n,i,o){return(e/=o/2)<1?i/2*e*e+n:-i/2*(--e*(e-2)-1)+n}}]),re);function re(){var e=0c){n=n||p;break}n=p}!n||(r=fe[ve(e,n.getAttribute("data-id"))])&&r!==a&&(a&&a.classList.remove("active"),r.classList.add("active"),a=r,!pe&&h.classList.contains("sticky")&&(e=i.clientHeight,r=a.offsetTop+a.clientHeight+40,a=a.offsetTop>=t.scrollTop&&r<=t.scrollTop+e,i.scrollTop=a?t.scrollTop:+r"']/),xe=/[&<>"']/g,Se=/[<>"']|&(?!#?\w+;)/,Ae=/[<>"']|&(?!#?\w+;)/g,$e={"&":"&","<":"<",">":">",'"':""","'":"'"};var ze=/&(#(?:\d+)|(?:#x[0-9A-Fa-f]+)|(?:\w+));?/gi;function Fe(e){return e.replace(ze,function(e,n){return"colon"===(n=n.toLowerCase())?":":"#"===n.charAt(0)?"x"===n.charAt(1)?String.fromCharCode(parseInt(n.substring(2),16)):String.fromCharCode(+n.substring(1)):""})}var Ee=/(^|[^\[])\^/g;var Re=/[^\w:]/g,Te=/^$|^[a-z][a-z0-9+.-]*:|^[?#]/i;var Ce={},je=/^[^:]+:\/*[^/]*$/,Le=/^([^:]+:)[\s\S]*$/,Oe=/^([^:]+:\/*[^/]*)[\s\S]*$/;function qe(e,n){Ce[" "+e]||(je.test(e)?Ce[" "+e]=e+"/":Ce[" "+e]=Pe(e,"/",!0));var i=-1===(e=Ce[" "+e]).indexOf(":");return"//"===n.substring(0,2)?i?n:e.replace(Le,"$1")+n:"/"===n.charAt(0)?i?n:e.replace(Oe,"$1")+n:e+n}function Pe(e,n,i){var o=e.length;if(0===o)return"";for(var t=0;tn)i.splice(n);else for(;i.length>=1,e+=e;return i+e},We=we.defaults,Xe=Be,Qe=Ze,Je=Me,Ke=Ve;function en(e,n,i){var o=n.href,t=n.title?Je(n.title):null,n=e[1].replace(/\\([\[\]])/g,"$1");return"!"!==e[0].charAt(0)?{type:"link",raw:i,href:o,title:t,text:n}:{type:"image",raw:i,href:o,title:t,text:Je(n)}}var nn=function(){function e(e){this.options=e||We}return e.prototype.space=function(e){e=this.rules.block.newline.exec(e);if(e)return 1=i.length?e.slice(i.length):e}).join("\n")}(i,n[3]||"");return{type:"code",raw:i,lang:n[2]&&n[2].trim(),text:e}}},e.prototype.heading=function(e){var n=this.rules.block.heading.exec(e);if(n){var i=n[2].trim();return/#$/.test(i)&&(e=Xe(i,"#"),!this.options.pedantic&&e&&!/ $/.test(e)||(i=e.trim())),{type:"heading",raw:n[0],depth:n[1].length,text:i}}},e.prototype.nptable=function(e){e=this.rules.block.nptable.exec(e);if(e){var n={type:"table",header:Qe(e[1].replace(/^ *| *\| *$/g,"")),align:e[2].replace(/^ *|\| *$/g,"").split(/ *\| */),cells:e[3]?e[3].replace(/\n$/,"").split("\n"):[],raw:e[0]};if(n.header.length===n.align.length){for(var i=n.align.length,o=0;o ?/gm,"");return{type:"blockquote",raw:n[0],text:e}}},e.prototype.list=function(e){e=this.rules.block.list.exec(e);if(e){for(var n,i,o,t,a,r=e[0],c=e[2],u=1s[1].length:o[1].length>s[0].length||3/i.test(e[0])&&(n=!1),!i&&/^<(pre|code|kbd|script)(\s|>)/i.test(e[0])?i=!0:i&&/^<\/(pre|code|kbd|script)(\s|>)/i.test(e[0])&&(i=!1),{type:this.options.sanitize?"text":"html",raw:e[0],inLink:n,inRawBlock:i,text:this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]}},e.prototype.link=function(e){var n=this.rules.inline.link.exec(e);if(n){e=n[2].trim();if(!this.options.pedantic&&/^$/.test(e))return;var i=Xe(e.slice(0,-1),"\\");if((e.length-i.length)%2==0)return}else{var o=Ke(n[2],"()");-1$/.test(e)?i.slice(1):i.slice(1,-1):i)&&i.replace(this.rules.inline._escapes,"$1"),title:o&&o.replace(this.rules.inline._escapes,"$1")},n[0])}},e.prototype.reflink=function(e,n){if((i=this.rules.inline.reflink.exec(e))||(i=this.rules.inline.nolink.exec(e))){var e=(i[2]||i[1]).replace(/\s+/g," ");if((e=n[e.toLowerCase()])&&e.href)return en(i,e,i[0]);var i=i[0].charAt(0);return{type:"text",raw:i,text:i}}},e.prototype.strong=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.strong.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="**"===o[0]?this.rules.inline.strong.endAst:this.rules.inline.strong.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.strong.middle.exec(n.slice(0,o.index+3)))return{type:"strong",raw:e.slice(0,t[0].length),text:e.slice(2,t[0].length-2)}}},e.prototype.em=function(e,n,i){void 0===i&&(i="");var o=this.rules.inline.em.start.exec(e);if(o&&(!o[1]||o[1]&&(""===i||this.rules.inline.punctuation.exec(i)))){n=n.slice(-1*e.length);var t,a="*"===o[0]?this.rules.inline.em.endAst:this.rules.inline.em.endUnd;for(a.lastIndex=0;null!=(o=a.exec(n));)if(t=this.rules.inline.em.middle.exec(n.slice(0,o.index+2)))return{type:"em",raw:e.slice(0,t[0].length),text:e.slice(1,t[0].length-1)}}},e.prototype.codespan=function(e){var n=this.rules.inline.code.exec(e);if(n){var i=n[2].replace(/\n/g," "),o=/[^ ]/.test(i),e=/^ /.test(i)&&/ $/.test(i);return o&&e&&(i=i.substring(1,i.length-1)),i=Je(i,!0),{type:"codespan",raw:n[0],text:i}}},e.prototype.br=function(e){e=this.rules.inline.br.exec(e);if(e)return{type:"br",raw:e[0]}},e.prototype.del=function(e){e=this.rules.inline.del.exec(e);if(e)return{type:"del",raw:e[0],text:e[2]}},e.prototype.autolink=function(e,n){e=this.rules.inline.autolink.exec(e);if(e){var i,n="@"===e[2]?"mailto:"+(i=Je(this.options.mangle?n(e[1]):e[1])):i=Je(e[1]);return{type:"link",raw:e[0],text:i,href:n,tokens:[{type:"text",raw:i,text:i}]}}},e.prototype.url=function(e,n){var i,o,t,a;if(i=this.rules.inline.url.exec(e)){if("@"===i[2])t="mailto:"+(o=Je(this.options.mangle?n(i[0]):i[0]));else{for(;a=i[0],i[0]=this.rules.inline._backpedal.exec(i[0])[0],a!==i[0];);o=Je(i[0]),t="www."===i[1]?"http://"+o:o}return{type:"link",raw:i[0],text:o,href:t,tokens:[{type:"text",raw:o,text:o}]}}},e.prototype.inlineText=function(e,n,i){e=this.rules.inline.text.exec(e);if(e){i=n?this.options.sanitize?this.options.sanitizer?this.options.sanitizer(e[0]):Je(e[0]):e[0]:Je(this.options.smartypants?i(e[0]):e[0]);return{type:"text",raw:e[0],text:i}}},e}(),Ze=De,Ve=Ne,De=Ue,Ne={newline:/^(?: *(?:\n|$))+/,code:/^( {4}[^\n]+(?:\n(?: *(?:\n|$))*)?)+/,fences:/^ {0,3}(`{3,}(?=[^`\n]*\n)|~{3,})([^\n]*)\n(?:|([\s\S]*?)\n)(?: {0,3}\1[~`]* *(?:\n+|$)|$)/,hr:/^ {0,3}((?:- *){3,}|(?:_ *){3,}|(?:\* *){3,})(?:\n+|$)/,heading:/^ {0,3}(#{1,6})(?=\s|$)(.*)(?:\n+|$)/,blockquote:/^( {0,3}> ?(paragraph|[^\n]*)(?:\n|$))+/,list:/^( {0,3})(bull) [\s\S]+?(?:hr|def|\n{2,}(?! )(?! {0,3}bull )\n*|\s*$)/,html:"^ {0,3}(?:<(script|pre|style)[\\s>][\\s\\S]*?(?:[^\\n]*\\n+|$)|comment[^\\n]*(\\n+|$)|<\\?[\\s\\S]*?(?:\\?>\\n*|$)|\\n*|$)|\\n*|$)|)[\\s\\S]*?(?:\\n{2,}|$)|<(?!script|pre|style)([a-z][\\w-]*)(?:attribute)*? */?>(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$)|(?=[ \\t]*(?:\\n|$))[\\s\\S]*?(?:\\n{2,}|$))",def:/^ {0,3}\[(label)\]: *\n? *]+)>?(?:(?: +\n? *| *\n *)(title))? *(?:\n+|$)/,nptable:Ze,table:Ze,lheading:/^([^\n]+)\n {0,3}(=+|-+) *(?:\n+|$)/,_paragraph:/^([^\n]+(?:\n(?!hr|heading|lheading|blockquote|fences|list|html| +\n)[^\n]+)*)/,text:/^[^\n]+/,_label:/(?!\s*\])(?:\\[\[\]]|[^\[\]])+/,_title:/(?:"(?:\\"?|[^"\\])*"|'[^'\n]*(?:\n[^'\n]+)*\n?'|\([^()]*\))/};Ne.def=Ve(Ne.def).replace("label",Ne._label).replace("title",Ne._title).getRegex(),Ne.bullet=/(?:[*+-]|\d{1,9}[.)])/,Ne.item=/^( *)(bull) ?[^\n]*(?:\n(?! *bull ?)[^\n]*)*/,Ne.item=Ve(Ne.item,"gm").replace(/bull/g,Ne.bullet).getRegex(),Ne.listItemStart=Ve(/^( *)(bull)/).replace("bull",Ne.bullet).getRegex(),Ne.list=Ve(Ne.list).replace(/bull/g,Ne.bullet).replace("hr","\\n+(?=\\1?(?:(?:- *){3,}|(?:_ *){3,}|(?:\\* *){3,})(?:\\n+|$))").replace("def","\\n+(?="+Ne.def.source+")").getRegex(),Ne._tag="address|article|aside|base|basefont|blockquote|body|caption|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option|p|param|section|source|summary|table|tbody|td|tfoot|th|thead|title|tr|track|ul",Ne._comment=/|$)/,Ne.html=Ve(Ne.html,"i").replace("comment",Ne._comment).replace("tag",Ne._tag).replace("attribute",/ +[a-zA-Z:_][\w.:-]*(?: *= *"[^"\n]*"| *= *'[^'\n]*'| *= *[^\s"'=<>`]+)?/).getRegex(),Ne.paragraph=Ve(Ne._paragraph).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("|lheading","").replace("blockquote"," {0,3}>").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.blockquote=Ve(Ne.blockquote).replace("paragraph",Ne.paragraph).getRegex(),Ne.normal=De({},Ne),Ne.gfm=De({},Ne.normal,{nptable:"^ *([^|\\n ].*\\|.*)\\n {0,3}([-:]+ *\\|[-| :]*)(?:\\n((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)",table:"^ *\\|(.+)\\n {0,3}\\|?( *[-:]+[-| :]*)(?:\\n *((?:(?!\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\n|$))*)\\n*|$)"}),Ne.gfm.nptable=Ve(Ne.gfm.nptable).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.gfm.table=Ve(Ne.gfm.table).replace("hr",Ne.hr).replace("heading"," {0,3}#{1,6} ").replace("blockquote"," {0,3}>").replace("code"," {4}[^\\n]").replace("fences"," {0,3}(?:`{3,}(?=[^`\\n]*\\n)|~{3,})[^\\n]*\\n").replace("list"," {0,3}(?:[*+-]|1[.)]) ").replace("html",")|<(?:script|pre|style|!--)").replace("tag",Ne._tag).getRegex(),Ne.pedantic=De({},Ne.normal,{html:Ve("^ *(?:comment *(?:\\n|\\s*$)|<(tag)[\\s\\S]+? *(?:\\n{2,}|\\s*$)|\\s]*)*?/?> *(?:\\n{2,}|\\s*$))").replace("comment",Ne._comment).replace(/tag/g,"(?!(?:a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)\\b)\\w+(?!:|[^\\w\\s@]*@)\\b").getRegex(),def:/^ *\[([^\]]+)\]: *]+)>?(?: +(["(][^\n]+[")]))? *(?:\n+|$)/,heading:/^(#{1,6})(.*)(?:\n+|$)/,fences:Ze,paragraph:Ve(Ne.normal._paragraph).replace("hr",Ne.hr).replace("heading"," *#{1,6} *[^\n]").replace("lheading",Ne.lheading).replace("blockquote"," {0,3}>").replace("|fences","").replace("|list","").replace("|html","").getRegex()});Ze={escape:/^\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/,autolink:/^<(scheme:[^\s\x00-\x1f<>]*|email)>/,url:Ze,tag:"^comment|^|^<[a-zA-Z][\\w-]*(?:attribute)*?\\s*/?>|^<\\?[\\s\\S]*?\\?>|^|^",link:/^!?\[(label)\]\(\s*(href)(?:\s+(title))?\s*\)/,reflink:/^!?\[(label)\]\[(?!\s*\])((?:\\[\[\]]?|[^\[\]\\])+)\]/,nolink:/^!?\[(?!\s*\])((?:\[[^\[\]]*\]|\\[\[\]]|[^\[\]])*)\](?:\[\])?/,reflinkSearch:"reflink|nolink(?!\\()",strong:{start:/^(?:(\*\*(?=[*punctuation]))|\*\*)(?![\s])|__/,middle:/^\*\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*\*$|^__(?![\s])((?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?)__$/,endAst:/[^punctuation\s]\*\*(?!\*)|[punctuation]\*\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]__(?!_)(?:(?=[punctuation*\s])|$)/},em:{start:/^(?:(\*(?=[punctuation]))|\*)(?![*\s])|_/,middle:/^\*(?:(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)|\*(?:(?!overlapSkip)(?:[^*]|\\\*)|overlapSkip)*?\*)+?\*$|^_(?![_\s])(?:(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)|_(?:(?!overlapSkip)(?:[^_]|\\_)|overlapSkip)*?_)+?_$/,endAst:/[^punctuation\s]\*(?!\*)|[punctuation]\*(?!\*)(?:(?=[punctuation_\s]|$))/,endUnd:/[^\s]_(?!_)(?:(?=[punctuation*\s])|$)/},code:/^(`+)([^`]|[^`][\s\S]*?[^`])\1(?!`)/,br:/^( {2,}|\\)\n(?!\s*$)/,del:Ze,text:/^(`+|[^`])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\?@\\[\\]`^{|}~"};Ze.punctuation=Ve(Ze.punctuation).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze._blockSkip="\\[[^\\]]*?\\]\\([^\\)]*?\\)|`[^`]*?`|<[^>]*?>",Ze._overlapSkip="__[^_]*?__|\\*\\*\\[^\\*\\]*?\\*\\*",Ze._comment=Ve(Ne._comment).replace("(?:--\x3e|$)","--\x3e").getRegex(),Ze.em.start=Ve(Ze.em.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.middle=Ve(Ze.em.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.em.endAst=Ve(Ze.em.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.em.endUnd=Ve(Ze.em.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.start=Ve(Ze.strong.start).replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.middle=Ve(Ze.strong.middle).replace(/punctuation/g,Ze._punctuation).replace(/overlapSkip/g,Ze._overlapSkip).getRegex(),Ze.strong.endAst=Ve(Ze.strong.endAst,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.strong.endUnd=Ve(Ze.strong.endUnd,"g").replace(/punctuation/g,Ze._punctuation).getRegex(),Ze.blockSkip=Ve(Ze._blockSkip,"g").getRegex(),Ze.overlapSkip=Ve(Ze._overlapSkip,"g").getRegex(),Ze._escapes=/\\([!"#$%&'()*+,\-./:;<=>?@\[\]\\^_`{|}~])/g,Ze._scheme=/[a-zA-Z][a-zA-Z0-9+.-]{1,31}/,Ze._email=/[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/,Ze.autolink=Ve(Ze.autolink).replace("scheme",Ze._scheme).replace("email",Ze._email).getRegex(),Ze._attribute=/\s+[a-zA-Z:_][\w.:-]*(?:\s*=\s*"[^"]*"|\s*=\s*'[^']*'|\s*=\s*[^\s"'=<>`]+)?/,Ze.tag=Ve(Ze.tag).replace("comment",Ze._comment).replace("attribute",Ze._attribute).getRegex(),Ze._label=/(?:\[(?:\\.|[^\[\]\\])*\]|\\.|`[^`]*`|[^\[\]\\`])*?/,Ze._href=/<(?:\\.|[^\n<>\\])+>|[^\s\x00-\x1f]*/,Ze._title=/"(?:\\"?|[^"\\])*"|'(?:\\'?|[^'\\])*'|\((?:\\\)?|[^)\\])*\)/,Ze.link=Ve(Ze.link).replace("label",Ze._label).replace("href",Ze._href).replace("title",Ze._title).getRegex(),Ze.reflink=Ve(Ze.reflink).replace("label",Ze._label).getRegex(),Ze.reflinkSearch=Ve(Ze.reflinkSearch,"g").replace("reflink",Ze.reflink).replace("nolink",Ze.nolink).getRegex(),Ze.normal=De({},Ze),Ze.pedantic=De({},Ze.normal,{strong:{start:/^__|\*\*/,middle:/^__(?=\S)([\s\S]*?\S)__(?!_)|^\*\*(?=\S)([\s\S]*?\S)\*\*(?!\*)/,endAst:/\*\*(?!\*)/g,endUnd:/__(?!_)/g},em:{start:/^_|\*/,middle:/^()\*(?=\S)([\s\S]*?\S)\*(?!\*)|^_(?=\S)([\s\S]*?\S)_(?!_)/,endAst:/\*(?!\*)/g,endUnd:/_(?!_)/g},link:Ve(/^!?\[(label)\]\((.*?)\)/).replace("label",Ze._label).getRegex(),reflink:Ve(/^!?\[(label)\]\s*\[([^\]]*)\]/).replace("label",Ze._label).getRegex()}),Ze.gfm=De({},Ze.normal,{escape:Ve(Ze.escape).replace("])","~|])").getRegex(),_extended_email:/[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/,url:/^((?:ftp|https?):\/\/|www\.)(?:[a-zA-Z0-9\-]+\.?)+[^\s<]*|^email/,_backpedal:/(?:[^?!.,:;*_~()&]+|\([^)]*\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_~)]+(?!$))+/,del:/^(~~?)(?=[^\s~])([\s\S]*?[^\s~])\1(?=[^~]|$)/,text:/^([`~]+|[^`~])(?:(?= {2,}\n)|[\s\S]*?(?:(?=[\\'+(i?e:gn(e,!0))+"\n":"
"+(i?e:gn(e,!0))+"
\n"},e.prototype.blockquote=function(e){return"
\n"+e+"
\n"},e.prototype.html=function(e){return e},e.prototype.heading=function(e,n,i,o){return this.options.headerIds?"'+e+"\n":""+e+"\n"},e.prototype.hr=function(){return this.options.xhtml?"
\n":"
\n"},e.prototype.list=function(e,n,i){var o=n?"ol":"ul";return"<"+o+(n&&1!==i?' start="'+i+'"':"")+">\n"+e+"\n"},e.prototype.listitem=function(e){return"
  • "+e+"
  • \n"},e.prototype.checkbox=function(e){return" "},e.prototype.paragraph=function(e){return"

    "+e+"

    \n"},e.prototype.table=function(e,n){return"\n\n"+e+"\n"+(n=n&&""+n+"")+"
    \n"},e.prototype.tablerow=function(e){return"\n"+e+"\n"},e.prototype.tablecell=function(e,n){var i=n.header?"th":"td";return(n.align?"<"+i+' align="'+n.align+'">':"<"+i+">")+e+"\n"},e.prototype.strong=function(e){return""+e+""},e.prototype.em=function(e){return""+e+""},e.prototype.codespan=function(e){return""+e+""},e.prototype.br=function(){return this.options.xhtml?"
    ":"
    "},e.prototype.del=function(e){return""+e+""},e.prototype.link=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;e='"},e.prototype.image=function(e,n,i){if(null===(e=dn(this.options.sanitize,this.options.baseUrl,e)))return i;i=''+i+'":">"},e.prototype.text=function(e){return e},e}(),ln=function(){function e(){}return e.prototype.strong=function(e){return e},e.prototype.em=function(e){return e},e.prototype.codespan=function(e){return e},e.prototype.del=function(e){return e},e.prototype.html=function(e){return e},e.prototype.text=function(e){return e},e.prototype.link=function(e,n,i){return""+i},e.prototype.image=function(e,n,i){return""+i},e.prototype.br=function(){return""},e}(),vn=function(){function e(){this.seen={}}return e.prototype.serialize=function(e){return e.toLowerCase().trim().replace(/<[!\/a-z].*?>/gi,"").replace(/[\u2000-\u206F\u2E00-\u2E7F\\'!"#$%&()*+,./:;<=>?@[\]^`{|}~]/g,"").replace(/\s/g,"-")},e.prototype.getNextSafeSlug=function(e,n){var i=e,o=0;if(this.seen.hasOwnProperty(i))for(o=this.seen[e];i=e+"-"+ ++o,this.seen.hasOwnProperty(i););return n||(this.seen[e]=o,this.seen[i]=0),i},e.prototype.slug=function(e,n){void 0===n&&(n={});e=this.serialize(e);return this.getNextSafeSlug(e,n.dryrun)},e}(),hn=we.defaults,_n=Ie,mn=function(){function i(e){this.options=e||hn,this.options.renderer=this.options.renderer||new sn,this.renderer=this.options.renderer,this.renderer.options=this.options,this.textRenderer=new ln,this.slugger=new vn}return i.parse=function(e,n){return new i(n).parse(e)},i.parseInline=function(e,n){return new i(n).parseInline(e)},i.prototype.parse=function(e,n){void 0===n&&(n=!0);for(var i,o,t,a,r,c,u,f,p,d,g,s,l,v,h,_="",m=e.length,b=0;bAn error occurred:

    "+wn(e.message+"",!0)+"
    ";throw e}}xn.options=xn.setOptions=function(e){return bn(xn.defaults,e),yn(xn.defaults),xn},xn.getDefaults=Me,xn.defaults=we,xn.use=function(a){var n,e=bn({},a);if(a.renderer){var i,r=xn.defaults.renderer||new sn;for(i in a.renderer)!function(o){var t=r[o];r[o]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.renderer[o].apply(r,e);return i=!1===i?t.apply(r,e):i}}(i);e.renderer=r}if(a.tokenizer){var t,c=xn.defaults.tokenizer||new nn;for(t in a.tokenizer)!function(){var o=c[t];c[t]=function(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];var i=a.tokenizer[t].apply(c,e);return i=!1===i?o.apply(c,e):i}}();e.tokenizer=c}a.walkTokens&&(n=xn.defaults.walkTokens,e.walkTokens=function(e){a.walkTokens(e),n&&n(e)}),xn.setOptions(e)},xn.walkTokens=function(e,n){for(var i=0,o=e;iAn error occurred:

    "+wn(e.message+"",!0)+"
    ";throw e}},xn.Parser=mn,xn.parser=mn.parse,xn.Renderer=sn,xn.TextRenderer=ln,xn.Lexer=fn,xn.lexer=fn.lex,xn.Tokenizer=nn,xn.Slugger=vn;var Sn=xn.parse=xn;function An(e,i){if(void 0===i&&(i='
      {inner}
    '),!e||!e.length)return"";var o="";return e.forEach(function(e){var n=e.title.replace(/(<([^>]+)>)/g,"");o+='
  • '+e.title+"
  • ",e.children&&(o+=An(e.children,i))}),i.replace("{inner}",o)}function $n(e,n){return'

    '+n.slice(5).trim()+"

    "}function zn(e,o){var t=[],a={};return e.forEach(function(e){var n=e.level||1,i=n-1;o?@[\]^`{|}~]/g;function Rn(e){return e.toLowerCase()}function Tn(e){if("string"!=typeof e)return"";var n=e.trim().replace(/[A-Z]+/g,Rn).replace(/<[^>]+>/g,"").replace(En,"").replace(/\s/g,"-").replace(/-+/g,"-").replace(/^(\d)/,"_$1"),e=Fn[n],e=u.call(Fn,n)?e+1:0;return n=(Fn[n]=e)?n+"-"+e:n}Tn.clear=function(){Fn={}};var Cn={baseURL:"https://github.githubassets.com/images/icons/emoji/",data:{100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accessibility:"accessibility.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",dependabot:"dependabot.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fishsticks:"fishsticks.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"}};function jn(e,t){return e.replace(/<(code|pre|script|template)[^>]*?>[\s\S]+?<\/(code|pre|script|template)>/g,function(e){return e.replace(/:/g,"__colon__")}).replace(//g,function(e){return e.replace(/:/g,"__colon__")}).replace(/([a-z]{2,}:)?\/\/[^\s'">)]+/gi,function(e){return e.replace(/:/g,"__colon__")}).replace(/:([a-z0-9_\-+]+?):/g,function(e,n){return i=e,o=n,e=t,n=Cn.data[o],i,i=n?e&&/unicode/.test(n)?''+n.replace("unicode/","").replace(/\.png.*/,"").split("-").map(function(e){return"&#x"+e+";"}).join("‍").concat("︎")+"":''+o+'':i;var i,o}).replace(/__colon__/g,":")}function Ln(e){var o={};return{str:e=(e=void 0===e?"":e)&&e.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,i){return-1===n.indexOf(":")?(o[n]=i&&i.replace(/"/g,"")||!0,""):e}).trim(),config:o}}function On(e){return(e=void 0===e?"":e).replace(/(<\/?a.*?>)/gi,"")}var qn,Pn=be(function(e){var u,f,p,d,n,g=function(u){var i=/(?:^|\s)lang(?:uage)?-([\w-]+)(?=\s|$)/i,n=0,e={},R={manual:u.Prism&&u.Prism.manual,disableWorkerMessageHandler:u.Prism&&u.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof T?new T(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,"&").replace(/=r.reach);m+=_.value.length,_=_.next){var b=_.value;if(i.length>n.length)return;if(!(b instanceof T)){var k,w=1;if(l){if(!(k=C(h,m,n,s))||k.index>=n.length)break;var y=k.index,x=k.index+k[0].length,S=m;for(S+=_.value.length;S<=y;)_=_.next,S+=_.value.length;if(S-=_.value.length,m=S,_.value instanceof T)continue;for(var A=_;A!==i.tail&&(Sr.reach&&(r.reach=E);b=_.prev;z&&(b=j(i,b,z),m+=z.length),L(i,b,w);$=new T(c,g?R.tokenize($,g):$,v,$);_=j(i,b,$),F&&j(i,_,F),1r.reach&&(r.reach=E.reach))}}}}}(e,t,n,t.head,0),function(e){var n=[],i=e.head.next;for(;i!==e.tail;)n.push(i.value),i=i.next;return n}(t)},hooks:{all:{},add:function(e,n){var i=R.hooks.all;i[e]=i[e]||[],i[e].push(n)},run:function(e,n){var i=R.hooks.all[e];if(i&&i.length)for(var o,t=0;o=i[t++];)o(n)}},Token:T};function T(e,n,i,o){this.type=e,this.content=n,this.alias=i,this.length=0|(o||"").length}function C(e,n,i,o){e.lastIndex=n;i=e.exec(i);return i&&o&&i[1]&&(o=i[1].length,i.index+=o,i[0]=i[0].slice(o)),i}function a(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function j(e,n,i){var o=n.next,i={value:i,prev:n,next:o};return n.next=i,o.prev=i,e.length++,i}function L(e,n,i){for(var o=n.next,t=0;t"+t.content+""},!u.document)return u.addEventListener&&(R.disableWorkerMessageHandler||u.addEventListener("message",function(e){var n=JSON.parse(e.data),i=n.language,e=n.code,n=n.immediateClose;u.postMessage(R.highlight(e,R.languages[i],i)),n&&u.close()},!1)),R;var o=R.util.currentScript();function t(){R.manual||R.highlightAll()}return o&&(R.filename=o.src,o.hasAttribute("data-manual")&&(R.manual=!0)),R.manual||("loading"===(e=document.readyState)||"interactive"===e&&o&&o.defer?document.addEventListener("DOMContentLoaded",t):window.requestAnimationFrame?window.requestAnimationFrame(t):window.setTimeout(t,16)),R}("undefined"!=typeof window?window:"undefined"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{});e.exports&&(e.exports=g),void 0!==me&&(me.Prism=g),g.languages.markup={comment:{pattern://,greedy:!0},prolog:{pattern:/<\?[\s\S]+?\?>/,greedy:!0},doctype:{pattern:/"'[\]]|"[^"]*"|'[^']*')+(?:\[(?:[^<"'\]]|"[^"]*"|'[^']*'|<(?!!--)|)*\]\s*)?>/i,greedy:!0,inside:{"internal-subset":{pattern:/(^[^\[]*\[)[\s\S]+(?=\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/"[^"]*"|'[^']*'/,greedy:!0},punctuation:/^$|[[\]]/,"doctype-tag":/^DOCTYPE/i,name:/[^\s<>'"]+/}},cdata:{pattern://i,greedy:!0},tag:{pattern:/<\/?(?!\d)[^\s>\/=$<%]+(?:\s(?:\s*[^\s>\/=]+(?:\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))|(?=[\s/>])))+)?\s*\/?>/,greedy:!0,inside:{tag:{pattern:/^<\/?[^\s>\/]+/,inside:{punctuation:/^<\/?/,namespace:/^[^\s>\/:]+:/}},"special-attr":[],"attr-value":{pattern:/=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:"attr-equals"},{pattern:/^(\s*)["']|["']$/,lookbehind:!0}]}},punctuation:/\/?>/,"attr-name":{pattern:/[^\s>\/]+/,inside:{namespace:/^[^\s>\/:]+:/}}}},entity:[{pattern:/&[\da-z]{1,8};/i,alias:"named-entity"},/&#x?[\da-f]{1,8};/i]},g.languages.markup.tag.inside["attr-value"].inside.entity=g.languages.markup.entity,g.languages.markup.doctype.inside["internal-subset"].inside=g.languages.markup,g.hooks.add("wrap",function(e){"entity"===e.type&&(e.attributes.title=e.content.replace(/&/,"&"))}),Object.defineProperty(g.languages.markup.tag,"addInlined",{value:function(e,n){var i={};i["language-"+n]={pattern:/(^$)/i,lookbehind:!0,inside:g.languages[n]},i.cdata=/^$/i;i={"included-cdata":{pattern://i,inside:i}};i["language-"+n]={pattern:/[\s\S]+/,inside:g.languages[n]};n={};n[e]={pattern:RegExp(/(<__[^>]*>)(?:))*\]\]>|(?!)/.source.replace(/__/g,function(){return e}),"i"),lookbehind:!0,greedy:!0,inside:i},g.languages.insertBefore("markup","cdata",n)}}),Object.defineProperty(g.languages.markup.tag,"addAttribute",{value:function(e,n){g.languages.markup.tag.inside["special-attr"].push({pattern:RegExp(/(^|["'\s])/.source+"(?:"+e+")"+/\s*=\s*(?:"[^"]*"|'[^']*'|[^\s'">=]+(?=[\s>]))/.source,"i"),lookbehind:!0,inside:{"attr-name":/^[^\s=]+/,"attr-value":{pattern:/=[\s\S]+/,inside:{value:{pattern:/(^=\s*(["']|(?!["'])))\S[\s\S]*(?=\2$)/,lookbehind:!0,alias:[n,"language-"+n],inside:g.languages[n]},punctuation:[{pattern:/^=/,alias:"attr-equals"},/"|'/]}}}})}}),g.languages.html=g.languages.markup,g.languages.mathml=g.languages.markup,g.languages.svg=g.languages.markup,g.languages.xml=g.languages.extend("markup",{}),g.languages.ssml=g.languages.xml,g.languages.atom=g.languages.xml,g.languages.rss=g.languages.xml,function(e){var n=/(?:"(?:\\(?:\r\n|[\s\S])|[^"\\\r\n])*"|'(?:\\(?:\r\n|[\s\S])|[^'\\\r\n])*')/;e.languages.css={comment:/\/\*[\s\S]*?\*\//,atrule:{pattern:RegExp("@[\\w-](?:"+/[^;{\s"']|\s+(?!\s)/.source+"|"+n.source+")*?"+/(?:;|(?=\s*\{))/.source),inside:{rule:/^@[\w-]+/,"selector-function-argument":{pattern:/(\bselector\s*\(\s*(?![\s)]))(?:[^()\s]|\s+(?![\s)])|\((?:[^()]|\([^()]*\))*\))+(?=\s*\))/,lookbehind:!0,alias:"selector"},keyword:{pattern:/(^|[^\w-])(?:and|not|only|or)(?![\w-])/,lookbehind:!0}}},url:{pattern:RegExp("\\burl\\((?:"+n.source+"|"+/(?:[^\\\r\n()"']|\\[\s\S])*/.source+")\\)","i"),greedy:!0,inside:{function:/^url/i,punctuation:/^\(|\)$/,string:{pattern:RegExp("^"+n.source+"$"),alias:"url"}}},selector:{pattern:RegExp("(^|[{}\\s])[^{}\\s](?:[^{};\"'\\s]|\\s+(?![\\s{])|"+n.source+")*(?=\\s*\\{)"),lookbehind:!0},string:{pattern:n,greedy:!0},property:{pattern:/(^|[^-\w\xA0-\uFFFF])(?!\s)[-_a-z\xA0-\uFFFF](?:(?!\s)[-\w\xA0-\uFFFF])*(?=\s*:)/i,lookbehind:!0},important:/!important\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\()/i,lookbehind:!0},punctuation:/[(){};:,]/},e.languages.css.atrule.inside.rest=e.languages.css;e=e.languages.markup;e&&(e.tag.addInlined("style","css"),e.tag.addAttribute("style","css"))}(g),g.languages.clike={comment:[{pattern:/(^|[^\\])\/\*[\s\S]*?(?:\*\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\:])\/\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/(["'])(?:\\(?:\r\n|[\s\S])|(?!\1)[^\\\r\n])*\1/,greedy:!0},"class-name":{pattern:/(\b(?:class|extends|implements|instanceof|interface|new|trait)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\b/,boolean:/\b(?:false|true)\b/,function:/\b\w+(?=\()/,number:/\b0x[\da-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:e[+-]?\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\+\+?|&&?|\|\|?|[?*/~^%]/,punctuation:/[{}[\];(),.:]/},g.languages.javascript=g.languages.extend("clike",{"class-name":[g.languages.clike["class-name"],{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$A-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\})\s*)catch\b/,lookbehind:!0},{pattern:/(^|[^.]|\.\.\.\s*)\b(?:as|assert(?=\s*\{)|async(?=\s*(?:function\b|\(|[$\w\xA0-\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\s*(?:\{|$))|for|from(?=\s*(?:['"]|$))|function|(?:get|set)(?=\s*(?:[#\[$\w\xA0-\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\b/,lookbehind:!0}],function:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*(?:\.\s*(?:apply|bind|call)\s*)?\()/,number:{pattern:RegExp(/(^|[^\w$])/.source+"(?:"+/NaN|Infinity/.source+"|"+/0[bB][01]+(?:_[01]+)*n?/.source+"|"+/0[oO][0-7]+(?:_[0-7]+)*n?/.source+"|"+/0[xX][\dA-Fa-f]+(?:_[\dA-Fa-f]+)*n?/.source+"|"+/\d+(?:_\d+)*n/.source+"|"+/(?:\d+(?:_\d+)*(?:\.(?:\d+(?:_\d+)*)?)?|\.\d+(?:_\d+)*)(?:[Ee][+-]?\d+(?:_\d+)*)?/.source+")"+/(?![\w$])/.source),lookbehind:!0},operator:/--|\+\+|\*\*=?|=>|&&=?|\|\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\.{3}|\?\?=?|\?\.?|[~:]/}),g.languages.javascript["class-name"][0].pattern=/(\b(?:class|extends|implements|instanceof|interface|new)\s+)[\w.\\]+/,g.languages.insertBefore("javascript","keyword",{regex:{pattern:RegExp(/((?:^|[^$\w\xA0-\uFFFF."'\])\s]|\b(?:return|yield))\s*)/.source+/\//.source+"(?:"+/(?:\[(?:[^\]\\\r\n]|\\.)*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}/.source+"|"+/(?:\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.|\[(?:[^[\]\\\r\n]|\\.)*\])*\])*\]|\\.|[^/\\\[\r\n])+\/[dgimyus]{0,7}v[dgimyus]{0,7}/.source+")"+/(?=(?:\s|\/\*(?:[^*]|\*(?!\/))*\*\/)*(?:$|[\r\n,.;:})\]]|\/\/))/.source),lookbehind:!0,greedy:!0,inside:{"regex-source":{pattern:/^(\/)[\s\S]+(?=\/[a-z]*$)/,lookbehind:!0,alias:"language-regex",inside:g.languages.regex},"regex-delimiter":/^\/|\/$/,"regex-flags":/^[a-z]+$/}},"function-variable":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*[=:]\s*(?:async\s*)?(?:\bfunction\b|(?:\((?:[^()]|\([^()]*\))*\)|(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)\s*=>))/,alias:"function"},parameter:[{pattern:/(function(?:\s+(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*)?\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\))/,lookbehind:!0,inside:g.languages.javascript},{pattern:/(^|[^$\w\xA0-\uFFFF])(?!\s)[_$a-z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*=>)/i,lookbehind:!0,inside:g.languages.javascript},{pattern:/(\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*=>)/,lookbehind:!0,inside:g.languages.javascript},{pattern:/((?:\b|\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\w\xA0-\uFFFF]))(?:(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*)\(\s*|\]\s*\(\s*)(?!\s)(?:[^()\s]|\s+(?![\s)])|\([^()]*\))+(?=\s*\)\s*\{)/,lookbehind:!0,inside:g.languages.javascript}],constant:/\b[A-Z](?:[A-Z_]|\dx?)*\b/}),g.languages.insertBefore("javascript","string",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:"comment"},"template-string":{pattern:/`(?:\\[\s\S]|\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}|(?!\$\{)[^\\`])*`/,greedy:!0,inside:{"template-punctuation":{pattern:/^`|`$/,alias:"string"},interpolation:{pattern:/((?:^|[^\\])(?:\\{2})*)\$\{(?:[^{}]|\{(?:[^{}]|\{[^}]*\})*\})+\}/,lookbehind:!0,inside:{"interpolation-punctuation":{pattern:/^\$\{|\}$/,alias:"punctuation"},rest:g.languages.javascript}},string:/[\s\S]+/}},"string-property":{pattern:/((?:^|[,{])[ \t]*)(["'])(?:\\(?:\r\n|[\s\S])|(?!\2)[^\\\r\n])*\2(?=\s*:)/m,lookbehind:!0,greedy:!0,alias:"property"}}),g.languages.insertBefore("javascript","operator",{"literal-property":{pattern:/((?:^|[,{])[ \t]*)(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*(?=\s*:)/m,lookbehind:!0,alias:"property"}}),g.languages.markup&&(g.languages.markup.tag.addInlined("script","javascript"),g.languages.markup.tag.addAttribute(/on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)/.source,"javascript")),g.languages.js=g.languages.javascript,void 0!==g&&"undefined"!=typeof document&&(Element.prototype.matches||(Element.prototype.matches=Element.prototype.msMatchesSelector||Element.prototype.webkitMatchesSelector),u={js:"javascript",py:"python",rb:"ruby",ps1:"powershell",psm1:"powershell",sh:"bash",bat:"batch",h:"c",tex:"latex"},d="pre[data-src]:not(["+(f="data-src-status")+'="loaded"]):not(['+f+'="'+(p="loading")+'"])',g.hooks.add("before-highlightall",function(e){e.selector+=", "+d}),g.hooks.add("before-sanity-check",function(e){var t,n,i,o,a,r,c=e.element;c.matches(d)&&(e.code="",c.setAttribute(f,p),(t=c.appendChild(document.createElement("CODE"))).textContent="Loading…",i=c.getAttribute("data-src"),"none"===(e=e.language)&&(n=(/\.(\w+)$/.exec(i)||[,"none"])[1],e=u[n]||n),g.util.setLanguage(t,e),g.util.setLanguage(c,e),(n=g.plugins.autoloader)&&n.loadLanguages(e),i=i,o=function(e){c.setAttribute(f,"loaded");var n,i,o=function(e){if(i=/^\s*(\d+)\s*(?:(,)\s*(?:(\d+)\s*)?)?$/.exec(e||"")){var n=Number(i[1]),e=i[2],i=i[3];return e?i?[n,Number(i)]:[n,void 0]:[n,n]}}(c.getAttribute("data-range"));o&&(n=e.split(/\r\n?|\n/g),i=o[0],o=null==o[1]?n.length:o[1],i<0&&(i+=n.length),i=Math.max(0,Math.min(i-1,n.length)),o<0&&(o+=n.length),o=Math.max(0,Math.min(o,n.length)),e=n.slice(i,o).join("\n"),c.hasAttribute("data-start")||c.setAttribute("data-start",String(i+1))),t.textContent=e,g.highlightElement(t)},a=function(e){c.setAttribute(f,"failed"),t.textContent=e},(r=new XMLHttpRequest).open("GET",i,!0),r.onreadystatechange=function(){4==r.readyState&&(r.status<400&&r.responseText?o(r.responseText):400<=r.status?a("✖ Error "+r.status+" while fetching file: "+r.statusText):a("✖ Error: File does not exist or is empty"))},r.send(null))}),n=!(g.plugins.fileHighlight={highlight:function(e){for(var n,i=(e||document).querySelectorAll(d),o=0;n=i[o++];)g.highlightElement(n)}}),g.fileHighlight=function(){n||(console.warn("Prism.fileHighlight is deprecated. Use `Prism.plugins.fileHighlight.highlight` instead."),n=!0),g.plugins.fileHighlight.highlight.apply(this,arguments)})});function Mn(e,n){return"___"+e.toUpperCase()+n+"___"}qn=Prism,Object.defineProperties(qn.languages["markup-templating"]={},{buildPlaceholders:{value:function(o,t,e,a){var r;o.language===t&&(r=o.tokenStack=[],o.code=o.code.replace(e,function(e){if("function"==typeof a&&!a(e))return e;for(var n,i=r.length;-1!==o.code.indexOf(n=Mn(t,i));)++i;return r[i]=e,n}),o.grammar=qn.languages.markup)}},tokenizePlaceholders:{value:function(f,p){var d,g;f.language===p&&f.tokenStack&&(f.grammar=qn.languages[p],d=0,g=Object.keys(f.tokenStack),function e(n){for(var i=0;i=g.length);i++){var o,t,a,r,c,u=n[i];"string"==typeof u||u.content&&"string"==typeof u.content?(t=g[d],a=f.tokenStack[t],o="string"==typeof u?u:u.content,c=Mn(p,t),-1<(r=o.indexOf(c))&&(++d,t=o.substring(0,r),a=new qn.Token(p,qn.tokenize(a,f.grammar),"language-"+p,a),r=o.substring(r+c.length),c=[],t&&c.push.apply(c,e([t])),c.push(a),r&&c.push.apply(c,e([r])),"string"==typeof u?n.splice.apply(n,[i,1].concat(c)):u.content=c)):u.content&&e(u.content)}return n}(f.tokens))}}});function In(t,e){var a=this;this.config=t,this.router=e,this.cacheTree={},this.toc=[],this.cacheTOC={},this.linkTarget=t.externalLinkTarget||"_blank",this.linkRel="_blank"===this.linkTarget?t.externalLinkRel||"noopener":"",this.contentBase=e.getBasePath();var n=this._initRenderer();this.heading=n.heading;var r=o(e=t.markdown||{})?e(Sn,n):(Sn.setOptions(m(e,{renderer:m(n,e.renderer)})),Sn);this._marked=r,this.compile=function(i){var o=!0,e=c(function(e){o=!1;var n="";return i&&(n=f(i)?r(i):r.parser(i),n=t.noEmoji?n:jn(n,t.nativeEmoji),Tn.clear(),n)})(i),n=a.router.parse().file;return o?a.toc=a.cacheTOC[n]:a.cacheTOC[n]=[].concat(a.toc),e}}var Nn={},Hn={markdown:function(e){return{url:e}},mermaid:function(e){return{url:e}},iframe:function(e,n){return{html:'"}},video:function(e,n){return{html:'"}},audio:function(e,n){return{html:'"}},code:function(e,n){var i=e.match(/\.(\w+)$/);return{url:e,lang:i="md"===(i=n||i&&i[1])?"markdown":i}}};In.prototype.compileEmbed=function(e,n){var i,o,t=Ln(n),a=t.str,t=t.config;if(n=a,t.include)return R(e)||(e=q(this.contentBase,C(this.router.getCurrentPath()),e)),t.type&&(o=Hn[t.type])?(i=o.call(this,e,n)).type=t.type:(o="code",/\.(md|markdown)/.test(e)?o="markdown":/\.mmd/.test(e)?o="mermaid":/\.html?/.test(e)?o="iframe":/\.(mp4|ogg)/.test(e)?o="video":/\.mp3/.test(e)&&(o="audio"),(i=Hn[o].call(this,e,n)).type=o),i.fragment=t.fragment,i},In.prototype._matchNotCompileLink=function(e){for(var n=this.config.noCompileLinks||[],i=0;i/g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore} --\x3e",""),e.title=On(o),e.ignoreSubHeading=!0),/{docsify-ignore}/g.test(o)&&(o=o.replace("{docsify-ignore}",""),e.title=On(o),e.ignoreSubHeading=!0),//g.test(o)&&(o=o.replace("\x3c!-- {docsify-ignore-all} --\x3e",""),e.title=On(o),e.ignoreAllSubs=!0),/{docsify-ignore-all}/g.test(o)&&(o=o.replace("{docsify-ignore-all}",""),e.title=On(o),e.ignoreAllSubs=!0);i=Tn(t.id||o),t=a.toURL(a.getCurrentPath(),{id:i});return e.slug=t,g.toc.push(e),"'+o+""},t.code={renderer:e}.renderer.code=function(e,n){var i=Pn.languages[n=void 0===n?"markup":n]||Pn.languages.markup;return'
    '+Pn.highlight(e.replace(/@DOCSIFY_QM@/g,"`"),i,n)+"
    "},t.link=(i=(n={renderer:e,router:a,linkTarget:n,linkRel:i,compilerClass:g}).renderer,c=n.router,u=n.linkTarget,n.linkRel,f=n.compilerClass,i.link=function(e,n,i){var o=[],t=Ln(n=void 0===n?"":n),a=t.str,t=t.config;return u=t.target||u,r="_blank"===u?f.config.externalLinkRel||"noopener":"",n=a,R(e)||f._matchNotCompileLink(e)||t.ignore?(R(e)||"./"!==e.slice(0,2)||(e=document.URL.replace(/\/(?!.*\/).*/,"/").replace("#/./","")+e),o.push(0===e.indexOf("mailto:")?"":'target="'+u+'"'),o.push(0!==e.indexOf("mailto:")&&""!==r?' rel="'+r+'"':"")):(e===f.config.homepage&&(e="README"),e=c.toURL(e,null,c.getCurrentPath())),t.disabled&&(o.push("disabled"),e="javascript:void(0)"),t.class&&o.push('class="'+t.class+'"'),t.id&&o.push('id="'+t.id+'"'),n&&o.push('title="'+n+'"'),'"+i+""}),t.paragraph={renderer:e}.renderer.paragraph=function(e){e=/^!>/.test(e)?$n("tip",e):/^\?>/.test(e)?$n("warn",e):"

    "+e+"

    ";return e},t.image=(o=(i={renderer:e,contentBase:o,router:a}).renderer,p=i.contentBase,d=i.router,o.image=function(e,n,i){var o=e,t=[],a=Ln(n),r=a.str,a=a.config;return n=r,a["no-zoom"]&&t.push("data-no-zoom"),n&&t.push('title="'+n+'"'),a.size&&(n=(r=a.size.split("x"))[0],(r=r[1])?t.push('width="'+n+'" height="'+r+'"'):t.push('width="'+n+'"')),a.class&&t.push('class="'+a.class+'"'),a.id&&t.push('id="'+a.id+'"'),R(e)||(o=q(p,C(d.getCurrentPath()),e)),0":''+i+'"}),t.list={renderer:e}.renderer.list=function(e,n,i){n=n?"ol":"ul";return"<"+n+" "+[/
  • /.test(e.split('class="task-list"')[0])?'class="task-list"':"",i&&1"+e+""},t.listitem={renderer:e}.renderer.listitem=function(e){return/^(]*>)/.test(e)?'
  • ":"
  • "+e+"
  • "},e.origin=t,e},In.prototype.sidebar=function(e,n){var i=this.toc,o=this.router.getCurrentPath(),t="";if(e)t=this.compile(e);else{for(var a=0;a{inner}");this.cacheTree[o]=n}return t},In.prototype.subSidebar=function(e){if(e){var n=this.router.getCurrentPath(),i=this.cacheTree,o=this.toc;o[0]&&o[0].ignoreAllSubs&&o.splice(0),o[0]&&1===o[0].level&&o.shift();for(var t=0;t\n'+e+"\n"}]).links={}:(n=[{type:"html",text:e}]).links={}),a({token:t,embedToken:n}),++u>=c&&a({})}}(n);n.embed.url?X(n.embed.url).then(o):o(n.embed.html)}}({compile:i,embedTokens:c,fetch:n},function(e){var n,i=e.embedToken,e=e.token;e?(n=e.index,p.forEach(function(e){n>e.start&&(n+=e.length)}),m(f,i.links),r=r.slice(0,n).concat(i,r.slice(n+1)),p.push({start:n,length:i.length-1})):(Bn[t]=r.concat(),r.links=Bn[t].links=f,o(r))})}function Yn(e,n,i){var o,t,a,r;return n="function"==typeof i?i(n):"string"==typeof i?(a=[],r=0,(o=i).replace(V,function(n,e,i){a.push(o.substring(r,i-1)),r=i+=n.length+1,a.push(t&&t[n]||function(e){return("00"+("string"==typeof Y[n]?e[Y[n]]():Y[n](e))).slice(-n.length)})}),r!==o.length&&a.push(o.substring(r)),function(e){for(var n="",i=0,o=e||new Date;i404 - Not found","Vue"in window)for(var a=0,r=k(".markdown-section > *").filter(n);ascript").filter(function(e){return!/template/.test(e.type)})[0])||(e=e.innerText.trim())&&new Function(e)()),"Vue"in window){var u,f,p=[],d=Object.keys(i.vueComponents||{});2===t&&d.length&&d.forEach(function(e){window.Vue.options.components[e]||window.Vue.component(e,i.vueComponents[e])}),!Un&&i.vueGlobalOptions&&"function"==typeof i.vueGlobalOptions.data&&(Un=i.vueGlobalOptions.data()),p.push.apply(p,Object.keys(i.vueMounts||{}).map(function(e){return[b(o,e),i.vueMounts[e]]}).filter(function(e){var n=e[0];e[1];return n})),(i.vueGlobalOptions||d.length)&&(u=/{{2}[^{}]*}{2}/,f=/<[^>/]+\s([@:]|v-)[\w-:.[\]]+[=>\s]/,p.push.apply(p,k(".markdown-section > *").filter(function(i){return!p.some(function(e){var n=e[0];e[1];return n===i})}).filter(function(e){return e.tagName.toLowerCase()in(i.vueComponents||{})||e.querySelector(d.join(",")||null)||u.test(e.outerHTML)||f.test(e.outerHTML)}).map(function(e){var n=m({},i.vueGlobalOptions||{});return Un&&(n.data=function(){return Un}),[e,n]})));for(var g=0,s=p;g([^<]*?)

    $'))&&("color"===n[2]?o.style.background=n[1]+(n[3]||""):(e=n[1],S(o,"add","has-mask"),R(n[1])||(e=q(this.router.getBasePath(),n[1])),o.style.backgroundImage="url("+e+")",o.style.backgroundSize="cover",o.style.backgroundPosition="center center"),i=i.replace(n[0],"")),this._renderTo(".cover-main",i),K()):S(o,"remove","show")},n.prototype._updateRender=function(){var e,n,i,o;e=this,n=l(".app-name-link"),i=e.config.nameLink,o=e.route.path,n&&(f(e.config.nameLink)?n.setAttribute("href",i):"object"==typeof i&&(e=Object.keys(i).filter(function(e){return-1':"")),e.coverpage&&(f+=(o=", 100%, 85%",'
    \x3c!--cover--\x3e
    ')),e.logo&&(o=/^data:image/.test(e.logo),n=/(?:http[s]?:)?\/\//.test(e.logo),i=/^\./.test(e.logo),o||n||i||(e.logo=q(this.router.getBasePath(),e.logo))),f+=(i=(n=e).name||"","
    "+('')+'
    \x3c!--main--\x3e
    '),this._renderTo(u,f,!0)):this.rendered=!0,e.mergeNavbar&&s?p=b(".sidebar"):(c.classList.add("app-nav"),e.repo||c.classList.add("no-badge")),e.loadNavbar&&y(p,c),e.themeColor&&(v.head.appendChild(w("div","").firstElementChild),a=e.themeColor,window.CSS&&window.CSS.supports&&window.CSS.supports("(--v:red)")||(e=k("style:not(.inserted),link"),[].forEach.call(e,function(e){"STYLE"===e.nodeName?Q(e,a):"LINK"===e.nodeName&&(e=e.getAttribute("href"),/\.css$/.test(e)&&X(e).then(function(e){e=w("style",e);_.appendChild(e),Q(e,a)}))}))),this._updateRender(),S(h,"ready")},n}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.routes=function(){return this.config.routes||{}},n.prototype.matchVirtualRoute=function(t){var a=this.routes(),r=Object.keys(a),c=function(){return null};function u(){var e=r.shift();if(!e)return c(null);var n=A(o=(i="^",0===(o=e).indexOf(i)?o:"^"+o),"$")?o:o+"$",i=t.match(n);if(!i)return u();var o=a[e];if("string"==typeof o)return c(o);if("function"!=typeof o)return u();n=o,e=Xn(),o=e[0];return(0,e[1])(function(e){return"string"==typeof e?c(e):!1===e?c(null):u()}),n.length<=2?o(n(t,i)):n(t,i,o)}return{then:function(e){c=e,u()}}},n}(function(i){function e(){for(var e=[],n=arguments.length;n--;)e[n]=arguments[n];i.apply(this,e),this.route={}}return i&&(e.__proto__=i),((e.prototype=Object.create(i&&i.prototype)).constructor=e).prototype.updateRender=function(){this.router.normalize(),this.route=this.router.parse(),h.setAttribute("data-page",this.route.file)},e.prototype.initRouter=function(){var n=this,e=this.config,e=new("history"===(e.routerMode||"hash")&&t?D:H)(e);this.router=e,this.updateRender(),U=this.route,e.onchange(function(e){n.updateRender(),n._updateRender(),U.path!==n.route.path?(n.$fetch(d,n.$resetEvents.bind(n,e.source)),U=n.route):n.$resetEvents(e.source)})},e}(function(e){function n(){e.apply(this,arguments)}return e&&(n.__proto__=e),((n.prototype=Object.create(e&&e.prototype)).constructor=n).prototype.initLifecycle=function(){var i=this;this._hooks={},this._lifecycle={},["init","mounted","beforeEach","afterEach","doneEach","ready"].forEach(function(e){var n=i._hooks[e]=[];i._lifecycle[e]=function(e){return n.push(e)}})},n.prototype.callHook=function(e,t,a){void 0===a&&(a=d);var r=this._hooks[e],c=this.config.catchPluginErrors,u=function(n){var e=r[n];if(n>=r.length)a(t);else if("function"==typeof e){var i="Docsify plugin error";if(2===e.length)try{e(t,function(e){t=e,u(n+1)})}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}else try{var o=e(t);t=void 0===o?t:o,u(n+1)}catch(e){if(!c)throw e;console.error(i,e),u(n+1)}}else u(n+1)};u(0)},n}(we))))))));function Kn(e,n,i){return Qn&&Qn.abort&&Qn.abort(),Qn=X(e,!0,i)}window.Docsify={util:Me,dom:n,get:X,slugify:Tn,version:"4.13.1"},window.DocsifyCompiler=In,window.marked=Sn,window.Prism=Pn,e(function(e){return new Jn})}(); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js b/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js new file mode 100644 index 00000000..89151602 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/emoji.min.js @@ -0,0 +1 @@ +!function(){var o="https://github.githubassets.com/images/icons/emoji/",i={100:"unicode/1f4af.png?v8",1234:"unicode/1f522.png?v8","+1":"unicode/1f44d.png?v8","-1":"unicode/1f44e.png?v8","1st_place_medal":"unicode/1f947.png?v8","2nd_place_medal":"unicode/1f948.png?v8","3rd_place_medal":"unicode/1f949.png?v8","8ball":"unicode/1f3b1.png?v8",a:"unicode/1f170.png?v8",ab:"unicode/1f18e.png?v8",abacus:"unicode/1f9ee.png?v8",abc:"unicode/1f524.png?v8",abcd:"unicode/1f521.png?v8",accept:"unicode/1f251.png?v8",accessibility:"accessibility.png?v8",accordion:"unicode/1fa97.png?v8",adhesive_bandage:"unicode/1fa79.png?v8",adult:"unicode/1f9d1.png?v8",aerial_tramway:"unicode/1f6a1.png?v8",afghanistan:"unicode/1f1e6-1f1eb.png?v8",airplane:"unicode/2708.png?v8",aland_islands:"unicode/1f1e6-1f1fd.png?v8",alarm_clock:"unicode/23f0.png?v8",albania:"unicode/1f1e6-1f1f1.png?v8",alembic:"unicode/2697.png?v8",algeria:"unicode/1f1e9-1f1ff.png?v8",alien:"unicode/1f47d.png?v8",ambulance:"unicode/1f691.png?v8",american_samoa:"unicode/1f1e6-1f1f8.png?v8",amphora:"unicode/1f3fa.png?v8",anatomical_heart:"unicode/1fac0.png?v8",anchor:"unicode/2693.png?v8",andorra:"unicode/1f1e6-1f1e9.png?v8",angel:"unicode/1f47c.png?v8",anger:"unicode/1f4a2.png?v8",angola:"unicode/1f1e6-1f1f4.png?v8",angry:"unicode/1f620.png?v8",anguilla:"unicode/1f1e6-1f1ee.png?v8",anguished:"unicode/1f627.png?v8",ant:"unicode/1f41c.png?v8",antarctica:"unicode/1f1e6-1f1f6.png?v8",antigua_barbuda:"unicode/1f1e6-1f1ec.png?v8",apple:"unicode/1f34e.png?v8",aquarius:"unicode/2652.png?v8",argentina:"unicode/1f1e6-1f1f7.png?v8",aries:"unicode/2648.png?v8",armenia:"unicode/1f1e6-1f1f2.png?v8",arrow_backward:"unicode/25c0.png?v8",arrow_double_down:"unicode/23ec.png?v8",arrow_double_up:"unicode/23eb.png?v8",arrow_down:"unicode/2b07.png?v8",arrow_down_small:"unicode/1f53d.png?v8",arrow_forward:"unicode/25b6.png?v8",arrow_heading_down:"unicode/2935.png?v8",arrow_heading_up:"unicode/2934.png?v8",arrow_left:"unicode/2b05.png?v8",arrow_lower_left:"unicode/2199.png?v8",arrow_lower_right:"unicode/2198.png?v8",arrow_right:"unicode/27a1.png?v8",arrow_right_hook:"unicode/21aa.png?v8",arrow_up:"unicode/2b06.png?v8",arrow_up_down:"unicode/2195.png?v8",arrow_up_small:"unicode/1f53c.png?v8",arrow_upper_left:"unicode/2196.png?v8",arrow_upper_right:"unicode/2197.png?v8",arrows_clockwise:"unicode/1f503.png?v8",arrows_counterclockwise:"unicode/1f504.png?v8",art:"unicode/1f3a8.png?v8",articulated_lorry:"unicode/1f69b.png?v8",artificial_satellite:"unicode/1f6f0.png?v8",artist:"unicode/1f9d1-1f3a8.png?v8",aruba:"unicode/1f1e6-1f1fc.png?v8",ascension_island:"unicode/1f1e6-1f1e8.png?v8",asterisk:"unicode/002a-20e3.png?v8",astonished:"unicode/1f632.png?v8",astronaut:"unicode/1f9d1-1f680.png?v8",athletic_shoe:"unicode/1f45f.png?v8",atm:"unicode/1f3e7.png?v8",atom:"atom.png?v8",atom_symbol:"unicode/269b.png?v8",australia:"unicode/1f1e6-1f1fa.png?v8",austria:"unicode/1f1e6-1f1f9.png?v8",auto_rickshaw:"unicode/1f6fa.png?v8",avocado:"unicode/1f951.png?v8",axe:"unicode/1fa93.png?v8",azerbaijan:"unicode/1f1e6-1f1ff.png?v8",b:"unicode/1f171.png?v8",baby:"unicode/1f476.png?v8",baby_bottle:"unicode/1f37c.png?v8",baby_chick:"unicode/1f424.png?v8",baby_symbol:"unicode/1f6bc.png?v8",back:"unicode/1f519.png?v8",bacon:"unicode/1f953.png?v8",badger:"unicode/1f9a1.png?v8",badminton:"unicode/1f3f8.png?v8",bagel:"unicode/1f96f.png?v8",baggage_claim:"unicode/1f6c4.png?v8",baguette_bread:"unicode/1f956.png?v8",bahamas:"unicode/1f1e7-1f1f8.png?v8",bahrain:"unicode/1f1e7-1f1ed.png?v8",balance_scale:"unicode/2696.png?v8",bald_man:"unicode/1f468-1f9b2.png?v8",bald_woman:"unicode/1f469-1f9b2.png?v8",ballet_shoes:"unicode/1fa70.png?v8",balloon:"unicode/1f388.png?v8",ballot_box:"unicode/1f5f3.png?v8",ballot_box_with_check:"unicode/2611.png?v8",bamboo:"unicode/1f38d.png?v8",banana:"unicode/1f34c.png?v8",bangbang:"unicode/203c.png?v8",bangladesh:"unicode/1f1e7-1f1e9.png?v8",banjo:"unicode/1fa95.png?v8",bank:"unicode/1f3e6.png?v8",bar_chart:"unicode/1f4ca.png?v8",barbados:"unicode/1f1e7-1f1e7.png?v8",barber:"unicode/1f488.png?v8",baseball:"unicode/26be.png?v8",basecamp:"basecamp.png?v8",basecampy:"basecampy.png?v8",basket:"unicode/1f9fa.png?v8",basketball:"unicode/1f3c0.png?v8",basketball_man:"unicode/26f9-2642.png?v8",basketball_woman:"unicode/26f9-2640.png?v8",bat:"unicode/1f987.png?v8",bath:"unicode/1f6c0.png?v8",bathtub:"unicode/1f6c1.png?v8",battery:"unicode/1f50b.png?v8",beach_umbrella:"unicode/1f3d6.png?v8",bear:"unicode/1f43b.png?v8",bearded_person:"unicode/1f9d4.png?v8",beaver:"unicode/1f9ab.png?v8",bed:"unicode/1f6cf.png?v8",bee:"unicode/1f41d.png?v8",beer:"unicode/1f37a.png?v8",beers:"unicode/1f37b.png?v8",beetle:"unicode/1fab2.png?v8",beginner:"unicode/1f530.png?v8",belarus:"unicode/1f1e7-1f1fe.png?v8",belgium:"unicode/1f1e7-1f1ea.png?v8",belize:"unicode/1f1e7-1f1ff.png?v8",bell:"unicode/1f514.png?v8",bell_pepper:"unicode/1fad1.png?v8",bellhop_bell:"unicode/1f6ce.png?v8",benin:"unicode/1f1e7-1f1ef.png?v8",bento:"unicode/1f371.png?v8",bermuda:"unicode/1f1e7-1f1f2.png?v8",beverage_box:"unicode/1f9c3.png?v8",bhutan:"unicode/1f1e7-1f1f9.png?v8",bicyclist:"unicode/1f6b4.png?v8",bike:"unicode/1f6b2.png?v8",biking_man:"unicode/1f6b4-2642.png?v8",biking_woman:"unicode/1f6b4-2640.png?v8",bikini:"unicode/1f459.png?v8",billed_cap:"unicode/1f9e2.png?v8",biohazard:"unicode/2623.png?v8",bird:"unicode/1f426.png?v8",birthday:"unicode/1f382.png?v8",bison:"unicode/1f9ac.png?v8",black_cat:"unicode/1f408-2b1b.png?v8",black_circle:"unicode/26ab.png?v8",black_flag:"unicode/1f3f4.png?v8",black_heart:"unicode/1f5a4.png?v8",black_joker:"unicode/1f0cf.png?v8",black_large_square:"unicode/2b1b.png?v8",black_medium_small_square:"unicode/25fe.png?v8",black_medium_square:"unicode/25fc.png?v8",black_nib:"unicode/2712.png?v8",black_small_square:"unicode/25aa.png?v8",black_square_button:"unicode/1f532.png?v8",blond_haired_man:"unicode/1f471-2642.png?v8",blond_haired_person:"unicode/1f471.png?v8",blond_haired_woman:"unicode/1f471-2640.png?v8",blonde_woman:"unicode/1f471-2640.png?v8",blossom:"unicode/1f33c.png?v8",blowfish:"unicode/1f421.png?v8",blue_book:"unicode/1f4d8.png?v8",blue_car:"unicode/1f699.png?v8",blue_heart:"unicode/1f499.png?v8",blue_square:"unicode/1f7e6.png?v8",blueberries:"unicode/1fad0.png?v8",blush:"unicode/1f60a.png?v8",boar:"unicode/1f417.png?v8",boat:"unicode/26f5.png?v8",bolivia:"unicode/1f1e7-1f1f4.png?v8",bomb:"unicode/1f4a3.png?v8",bone:"unicode/1f9b4.png?v8",book:"unicode/1f4d6.png?v8",bookmark:"unicode/1f516.png?v8",bookmark_tabs:"unicode/1f4d1.png?v8",books:"unicode/1f4da.png?v8",boom:"unicode/1f4a5.png?v8",boomerang:"unicode/1fa83.png?v8",boot:"unicode/1f462.png?v8",bosnia_herzegovina:"unicode/1f1e7-1f1e6.png?v8",botswana:"unicode/1f1e7-1f1fc.png?v8",bouncing_ball_man:"unicode/26f9-2642.png?v8",bouncing_ball_person:"unicode/26f9.png?v8",bouncing_ball_woman:"unicode/26f9-2640.png?v8",bouquet:"unicode/1f490.png?v8",bouvet_island:"unicode/1f1e7-1f1fb.png?v8",bow:"unicode/1f647.png?v8",bow_and_arrow:"unicode/1f3f9.png?v8",bowing_man:"unicode/1f647-2642.png?v8",bowing_woman:"unicode/1f647-2640.png?v8",bowl_with_spoon:"unicode/1f963.png?v8",bowling:"unicode/1f3b3.png?v8",bowtie:"bowtie.png?v8",boxing_glove:"unicode/1f94a.png?v8",boy:"unicode/1f466.png?v8",brain:"unicode/1f9e0.png?v8",brazil:"unicode/1f1e7-1f1f7.png?v8",bread:"unicode/1f35e.png?v8",breast_feeding:"unicode/1f931.png?v8",bricks:"unicode/1f9f1.png?v8",bride_with_veil:"unicode/1f470-2640.png?v8",bridge_at_night:"unicode/1f309.png?v8",briefcase:"unicode/1f4bc.png?v8",british_indian_ocean_territory:"unicode/1f1ee-1f1f4.png?v8",british_virgin_islands:"unicode/1f1fb-1f1ec.png?v8",broccoli:"unicode/1f966.png?v8",broken_heart:"unicode/1f494.png?v8",broom:"unicode/1f9f9.png?v8",brown_circle:"unicode/1f7e4.png?v8",brown_heart:"unicode/1f90e.png?v8",brown_square:"unicode/1f7eb.png?v8",brunei:"unicode/1f1e7-1f1f3.png?v8",bubble_tea:"unicode/1f9cb.png?v8",bucket:"unicode/1faa3.png?v8",bug:"unicode/1f41b.png?v8",building_construction:"unicode/1f3d7.png?v8",bulb:"unicode/1f4a1.png?v8",bulgaria:"unicode/1f1e7-1f1ec.png?v8",bullettrain_front:"unicode/1f685.png?v8",bullettrain_side:"unicode/1f684.png?v8",burkina_faso:"unicode/1f1e7-1f1eb.png?v8",burrito:"unicode/1f32f.png?v8",burundi:"unicode/1f1e7-1f1ee.png?v8",bus:"unicode/1f68c.png?v8",business_suit_levitating:"unicode/1f574.png?v8",busstop:"unicode/1f68f.png?v8",bust_in_silhouette:"unicode/1f464.png?v8",busts_in_silhouette:"unicode/1f465.png?v8",butter:"unicode/1f9c8.png?v8",butterfly:"unicode/1f98b.png?v8",cactus:"unicode/1f335.png?v8",cake:"unicode/1f370.png?v8",calendar:"unicode/1f4c6.png?v8",call_me_hand:"unicode/1f919.png?v8",calling:"unicode/1f4f2.png?v8",cambodia:"unicode/1f1f0-1f1ed.png?v8",camel:"unicode/1f42b.png?v8",camera:"unicode/1f4f7.png?v8",camera_flash:"unicode/1f4f8.png?v8",cameroon:"unicode/1f1e8-1f1f2.png?v8",camping:"unicode/1f3d5.png?v8",canada:"unicode/1f1e8-1f1e6.png?v8",canary_islands:"unicode/1f1ee-1f1e8.png?v8",cancer:"unicode/264b.png?v8",candle:"unicode/1f56f.png?v8",candy:"unicode/1f36c.png?v8",canned_food:"unicode/1f96b.png?v8",canoe:"unicode/1f6f6.png?v8",cape_verde:"unicode/1f1e8-1f1fb.png?v8",capital_abcd:"unicode/1f520.png?v8",capricorn:"unicode/2651.png?v8",car:"unicode/1f697.png?v8",card_file_box:"unicode/1f5c3.png?v8",card_index:"unicode/1f4c7.png?v8",card_index_dividers:"unicode/1f5c2.png?v8",caribbean_netherlands:"unicode/1f1e7-1f1f6.png?v8",carousel_horse:"unicode/1f3a0.png?v8",carpentry_saw:"unicode/1fa9a.png?v8",carrot:"unicode/1f955.png?v8",cartwheeling:"unicode/1f938.png?v8",cat:"unicode/1f431.png?v8",cat2:"unicode/1f408.png?v8",cayman_islands:"unicode/1f1f0-1f1fe.png?v8",cd:"unicode/1f4bf.png?v8",central_african_republic:"unicode/1f1e8-1f1eb.png?v8",ceuta_melilla:"unicode/1f1ea-1f1e6.png?v8",chad:"unicode/1f1f9-1f1e9.png?v8",chains:"unicode/26d3.png?v8",chair:"unicode/1fa91.png?v8",champagne:"unicode/1f37e.png?v8",chart:"unicode/1f4b9.png?v8",chart_with_downwards_trend:"unicode/1f4c9.png?v8",chart_with_upwards_trend:"unicode/1f4c8.png?v8",checkered_flag:"unicode/1f3c1.png?v8",cheese:"unicode/1f9c0.png?v8",cherries:"unicode/1f352.png?v8",cherry_blossom:"unicode/1f338.png?v8",chess_pawn:"unicode/265f.png?v8",chestnut:"unicode/1f330.png?v8",chicken:"unicode/1f414.png?v8",child:"unicode/1f9d2.png?v8",children_crossing:"unicode/1f6b8.png?v8",chile:"unicode/1f1e8-1f1f1.png?v8",chipmunk:"unicode/1f43f.png?v8",chocolate_bar:"unicode/1f36b.png?v8",chopsticks:"unicode/1f962.png?v8",christmas_island:"unicode/1f1e8-1f1fd.png?v8",christmas_tree:"unicode/1f384.png?v8",church:"unicode/26ea.png?v8",cinema:"unicode/1f3a6.png?v8",circus_tent:"unicode/1f3aa.png?v8",city_sunrise:"unicode/1f307.png?v8",city_sunset:"unicode/1f306.png?v8",cityscape:"unicode/1f3d9.png?v8",cl:"unicode/1f191.png?v8",clamp:"unicode/1f5dc.png?v8",clap:"unicode/1f44f.png?v8",clapper:"unicode/1f3ac.png?v8",classical_building:"unicode/1f3db.png?v8",climbing:"unicode/1f9d7.png?v8",climbing_man:"unicode/1f9d7-2642.png?v8",climbing_woman:"unicode/1f9d7-2640.png?v8",clinking_glasses:"unicode/1f942.png?v8",clipboard:"unicode/1f4cb.png?v8",clipperton_island:"unicode/1f1e8-1f1f5.png?v8",clock1:"unicode/1f550.png?v8",clock10:"unicode/1f559.png?v8",clock1030:"unicode/1f565.png?v8",clock11:"unicode/1f55a.png?v8",clock1130:"unicode/1f566.png?v8",clock12:"unicode/1f55b.png?v8",clock1230:"unicode/1f567.png?v8",clock130:"unicode/1f55c.png?v8",clock2:"unicode/1f551.png?v8",clock230:"unicode/1f55d.png?v8",clock3:"unicode/1f552.png?v8",clock330:"unicode/1f55e.png?v8",clock4:"unicode/1f553.png?v8",clock430:"unicode/1f55f.png?v8",clock5:"unicode/1f554.png?v8",clock530:"unicode/1f560.png?v8",clock6:"unicode/1f555.png?v8",clock630:"unicode/1f561.png?v8",clock7:"unicode/1f556.png?v8",clock730:"unicode/1f562.png?v8",clock8:"unicode/1f557.png?v8",clock830:"unicode/1f563.png?v8",clock9:"unicode/1f558.png?v8",clock930:"unicode/1f564.png?v8",closed_book:"unicode/1f4d5.png?v8",closed_lock_with_key:"unicode/1f510.png?v8",closed_umbrella:"unicode/1f302.png?v8",cloud:"unicode/2601.png?v8",cloud_with_lightning:"unicode/1f329.png?v8",cloud_with_lightning_and_rain:"unicode/26c8.png?v8",cloud_with_rain:"unicode/1f327.png?v8",cloud_with_snow:"unicode/1f328.png?v8",clown_face:"unicode/1f921.png?v8",clubs:"unicode/2663.png?v8",cn:"unicode/1f1e8-1f1f3.png?v8",coat:"unicode/1f9e5.png?v8",cockroach:"unicode/1fab3.png?v8",cocktail:"unicode/1f378.png?v8",coconut:"unicode/1f965.png?v8",cocos_islands:"unicode/1f1e8-1f1e8.png?v8",coffee:"unicode/2615.png?v8",coffin:"unicode/26b0.png?v8",coin:"unicode/1fa99.png?v8",cold_face:"unicode/1f976.png?v8",cold_sweat:"unicode/1f630.png?v8",collision:"unicode/1f4a5.png?v8",colombia:"unicode/1f1e8-1f1f4.png?v8",comet:"unicode/2604.png?v8",comoros:"unicode/1f1f0-1f1f2.png?v8",compass:"unicode/1f9ed.png?v8",computer:"unicode/1f4bb.png?v8",computer_mouse:"unicode/1f5b1.png?v8",confetti_ball:"unicode/1f38a.png?v8",confounded:"unicode/1f616.png?v8",confused:"unicode/1f615.png?v8",congo_brazzaville:"unicode/1f1e8-1f1ec.png?v8",congo_kinshasa:"unicode/1f1e8-1f1e9.png?v8",congratulations:"unicode/3297.png?v8",construction:"unicode/1f6a7.png?v8",construction_worker:"unicode/1f477.png?v8",construction_worker_man:"unicode/1f477-2642.png?v8",construction_worker_woman:"unicode/1f477-2640.png?v8",control_knobs:"unicode/1f39b.png?v8",convenience_store:"unicode/1f3ea.png?v8",cook:"unicode/1f9d1-1f373.png?v8",cook_islands:"unicode/1f1e8-1f1f0.png?v8",cookie:"unicode/1f36a.png?v8",cool:"unicode/1f192.png?v8",cop:"unicode/1f46e.png?v8",copyright:"unicode/00a9.png?v8",corn:"unicode/1f33d.png?v8",costa_rica:"unicode/1f1e8-1f1f7.png?v8",cote_divoire:"unicode/1f1e8-1f1ee.png?v8",couch_and_lamp:"unicode/1f6cb.png?v8",couple:"unicode/1f46b.png?v8",couple_with_heart:"unicode/1f491.png?v8",couple_with_heart_man_man:"unicode/1f468-2764-1f468.png?v8",couple_with_heart_woman_man:"unicode/1f469-2764-1f468.png?v8",couple_with_heart_woman_woman:"unicode/1f469-2764-1f469.png?v8",couplekiss:"unicode/1f48f.png?v8",couplekiss_man_man:"unicode/1f468-2764-1f48b-1f468.png?v8",couplekiss_man_woman:"unicode/1f469-2764-1f48b-1f468.png?v8",couplekiss_woman_woman:"unicode/1f469-2764-1f48b-1f469.png?v8",cow:"unicode/1f42e.png?v8",cow2:"unicode/1f404.png?v8",cowboy_hat_face:"unicode/1f920.png?v8",crab:"unicode/1f980.png?v8",crayon:"unicode/1f58d.png?v8",credit_card:"unicode/1f4b3.png?v8",crescent_moon:"unicode/1f319.png?v8",cricket:"unicode/1f997.png?v8",cricket_game:"unicode/1f3cf.png?v8",croatia:"unicode/1f1ed-1f1f7.png?v8",crocodile:"unicode/1f40a.png?v8",croissant:"unicode/1f950.png?v8",crossed_fingers:"unicode/1f91e.png?v8",crossed_flags:"unicode/1f38c.png?v8",crossed_swords:"unicode/2694.png?v8",crown:"unicode/1f451.png?v8",cry:"unicode/1f622.png?v8",crying_cat_face:"unicode/1f63f.png?v8",crystal_ball:"unicode/1f52e.png?v8",cuba:"unicode/1f1e8-1f1fa.png?v8",cucumber:"unicode/1f952.png?v8",cup_with_straw:"unicode/1f964.png?v8",cupcake:"unicode/1f9c1.png?v8",cupid:"unicode/1f498.png?v8",curacao:"unicode/1f1e8-1f1fc.png?v8",curling_stone:"unicode/1f94c.png?v8",curly_haired_man:"unicode/1f468-1f9b1.png?v8",curly_haired_woman:"unicode/1f469-1f9b1.png?v8",curly_loop:"unicode/27b0.png?v8",currency_exchange:"unicode/1f4b1.png?v8",curry:"unicode/1f35b.png?v8",cursing_face:"unicode/1f92c.png?v8",custard:"unicode/1f36e.png?v8",customs:"unicode/1f6c3.png?v8",cut_of_meat:"unicode/1f969.png?v8",cyclone:"unicode/1f300.png?v8",cyprus:"unicode/1f1e8-1f1fe.png?v8",czech_republic:"unicode/1f1e8-1f1ff.png?v8",dagger:"unicode/1f5e1.png?v8",dancer:"unicode/1f483.png?v8",dancers:"unicode/1f46f.png?v8",dancing_men:"unicode/1f46f-2642.png?v8",dancing_women:"unicode/1f46f-2640.png?v8",dango:"unicode/1f361.png?v8",dark_sunglasses:"unicode/1f576.png?v8",dart:"unicode/1f3af.png?v8",dash:"unicode/1f4a8.png?v8",date:"unicode/1f4c5.png?v8",de:"unicode/1f1e9-1f1ea.png?v8",deaf_man:"unicode/1f9cf-2642.png?v8",deaf_person:"unicode/1f9cf.png?v8",deaf_woman:"unicode/1f9cf-2640.png?v8",deciduous_tree:"unicode/1f333.png?v8",deer:"unicode/1f98c.png?v8",denmark:"unicode/1f1e9-1f1f0.png?v8",department_store:"unicode/1f3ec.png?v8",dependabot:"dependabot.png?v8",derelict_house:"unicode/1f3da.png?v8",desert:"unicode/1f3dc.png?v8",desert_island:"unicode/1f3dd.png?v8",desktop_computer:"unicode/1f5a5.png?v8",detective:"unicode/1f575.png?v8",diamond_shape_with_a_dot_inside:"unicode/1f4a0.png?v8",diamonds:"unicode/2666.png?v8",diego_garcia:"unicode/1f1e9-1f1ec.png?v8",disappointed:"unicode/1f61e.png?v8",disappointed_relieved:"unicode/1f625.png?v8",disguised_face:"unicode/1f978.png?v8",diving_mask:"unicode/1f93f.png?v8",diya_lamp:"unicode/1fa94.png?v8",dizzy:"unicode/1f4ab.png?v8",dizzy_face:"unicode/1f635.png?v8",djibouti:"unicode/1f1e9-1f1ef.png?v8",dna:"unicode/1f9ec.png?v8",do_not_litter:"unicode/1f6af.png?v8",dodo:"unicode/1f9a4.png?v8",dog:"unicode/1f436.png?v8",dog2:"unicode/1f415.png?v8",dollar:"unicode/1f4b5.png?v8",dolls:"unicode/1f38e.png?v8",dolphin:"unicode/1f42c.png?v8",dominica:"unicode/1f1e9-1f1f2.png?v8",dominican_republic:"unicode/1f1e9-1f1f4.png?v8",door:"unicode/1f6aa.png?v8",doughnut:"unicode/1f369.png?v8",dove:"unicode/1f54a.png?v8",dragon:"unicode/1f409.png?v8",dragon_face:"unicode/1f432.png?v8",dress:"unicode/1f457.png?v8",dromedary_camel:"unicode/1f42a.png?v8",drooling_face:"unicode/1f924.png?v8",drop_of_blood:"unicode/1fa78.png?v8",droplet:"unicode/1f4a7.png?v8",drum:"unicode/1f941.png?v8",duck:"unicode/1f986.png?v8",dumpling:"unicode/1f95f.png?v8",dvd:"unicode/1f4c0.png?v8","e-mail":"unicode/1f4e7.png?v8",eagle:"unicode/1f985.png?v8",ear:"unicode/1f442.png?v8",ear_of_rice:"unicode/1f33e.png?v8",ear_with_hearing_aid:"unicode/1f9bb.png?v8",earth_africa:"unicode/1f30d.png?v8",earth_americas:"unicode/1f30e.png?v8",earth_asia:"unicode/1f30f.png?v8",ecuador:"unicode/1f1ea-1f1e8.png?v8",egg:"unicode/1f95a.png?v8",eggplant:"unicode/1f346.png?v8",egypt:"unicode/1f1ea-1f1ec.png?v8",eight:"unicode/0038-20e3.png?v8",eight_pointed_black_star:"unicode/2734.png?v8",eight_spoked_asterisk:"unicode/2733.png?v8",eject_button:"unicode/23cf.png?v8",el_salvador:"unicode/1f1f8-1f1fb.png?v8",electric_plug:"unicode/1f50c.png?v8",electron:"electron.png?v8",elephant:"unicode/1f418.png?v8",elevator:"unicode/1f6d7.png?v8",elf:"unicode/1f9dd.png?v8",elf_man:"unicode/1f9dd-2642.png?v8",elf_woman:"unicode/1f9dd-2640.png?v8",email:"unicode/1f4e7.png?v8",end:"unicode/1f51a.png?v8",england:"unicode/1f3f4-e0067-e0062-e0065-e006e-e0067-e007f.png?v8",envelope:"unicode/2709.png?v8",envelope_with_arrow:"unicode/1f4e9.png?v8",equatorial_guinea:"unicode/1f1ec-1f1f6.png?v8",eritrea:"unicode/1f1ea-1f1f7.png?v8",es:"unicode/1f1ea-1f1f8.png?v8",estonia:"unicode/1f1ea-1f1ea.png?v8",ethiopia:"unicode/1f1ea-1f1f9.png?v8",eu:"unicode/1f1ea-1f1fa.png?v8",euro:"unicode/1f4b6.png?v8",european_castle:"unicode/1f3f0.png?v8",european_post_office:"unicode/1f3e4.png?v8",european_union:"unicode/1f1ea-1f1fa.png?v8",evergreen_tree:"unicode/1f332.png?v8",exclamation:"unicode/2757.png?v8",exploding_head:"unicode/1f92f.png?v8",expressionless:"unicode/1f611.png?v8",eye:"unicode/1f441.png?v8",eye_speech_bubble:"unicode/1f441-1f5e8.png?v8",eyeglasses:"unicode/1f453.png?v8",eyes:"unicode/1f440.png?v8",face_exhaling:"unicode/1f62e-1f4a8.png?v8",face_in_clouds:"unicode/1f636-1f32b.png?v8",face_with_head_bandage:"unicode/1f915.png?v8",face_with_spiral_eyes:"unicode/1f635-1f4ab.png?v8",face_with_thermometer:"unicode/1f912.png?v8",facepalm:"unicode/1f926.png?v8",facepunch:"unicode/1f44a.png?v8",factory:"unicode/1f3ed.png?v8",factory_worker:"unicode/1f9d1-1f3ed.png?v8",fairy:"unicode/1f9da.png?v8",fairy_man:"unicode/1f9da-2642.png?v8",fairy_woman:"unicode/1f9da-2640.png?v8",falafel:"unicode/1f9c6.png?v8",falkland_islands:"unicode/1f1eb-1f1f0.png?v8",fallen_leaf:"unicode/1f342.png?v8",family:"unicode/1f46a.png?v8",family_man_boy:"unicode/1f468-1f466.png?v8",family_man_boy_boy:"unicode/1f468-1f466-1f466.png?v8",family_man_girl:"unicode/1f468-1f467.png?v8",family_man_girl_boy:"unicode/1f468-1f467-1f466.png?v8",family_man_girl_girl:"unicode/1f468-1f467-1f467.png?v8",family_man_man_boy:"unicode/1f468-1f468-1f466.png?v8",family_man_man_boy_boy:"unicode/1f468-1f468-1f466-1f466.png?v8",family_man_man_girl:"unicode/1f468-1f468-1f467.png?v8",family_man_man_girl_boy:"unicode/1f468-1f468-1f467-1f466.png?v8",family_man_man_girl_girl:"unicode/1f468-1f468-1f467-1f467.png?v8",family_man_woman_boy:"unicode/1f468-1f469-1f466.png?v8",family_man_woman_boy_boy:"unicode/1f468-1f469-1f466-1f466.png?v8",family_man_woman_girl:"unicode/1f468-1f469-1f467.png?v8",family_man_woman_girl_boy:"unicode/1f468-1f469-1f467-1f466.png?v8",family_man_woman_girl_girl:"unicode/1f468-1f469-1f467-1f467.png?v8",family_woman_boy:"unicode/1f469-1f466.png?v8",family_woman_boy_boy:"unicode/1f469-1f466-1f466.png?v8",family_woman_girl:"unicode/1f469-1f467.png?v8",family_woman_girl_boy:"unicode/1f469-1f467-1f466.png?v8",family_woman_girl_girl:"unicode/1f469-1f467-1f467.png?v8",family_woman_woman_boy:"unicode/1f469-1f469-1f466.png?v8",family_woman_woman_boy_boy:"unicode/1f469-1f469-1f466-1f466.png?v8",family_woman_woman_girl:"unicode/1f469-1f469-1f467.png?v8",family_woman_woman_girl_boy:"unicode/1f469-1f469-1f467-1f466.png?v8",family_woman_woman_girl_girl:"unicode/1f469-1f469-1f467-1f467.png?v8",farmer:"unicode/1f9d1-1f33e.png?v8",faroe_islands:"unicode/1f1eb-1f1f4.png?v8",fast_forward:"unicode/23e9.png?v8",fax:"unicode/1f4e0.png?v8",fearful:"unicode/1f628.png?v8",feather:"unicode/1fab6.png?v8",feelsgood:"feelsgood.png?v8",feet:"unicode/1f43e.png?v8",female_detective:"unicode/1f575-2640.png?v8",female_sign:"unicode/2640.png?v8",ferris_wheel:"unicode/1f3a1.png?v8",ferry:"unicode/26f4.png?v8",field_hockey:"unicode/1f3d1.png?v8",fiji:"unicode/1f1eb-1f1ef.png?v8",file_cabinet:"unicode/1f5c4.png?v8",file_folder:"unicode/1f4c1.png?v8",film_projector:"unicode/1f4fd.png?v8",film_strip:"unicode/1f39e.png?v8",finland:"unicode/1f1eb-1f1ee.png?v8",finnadie:"finnadie.png?v8",fire:"unicode/1f525.png?v8",fire_engine:"unicode/1f692.png?v8",fire_extinguisher:"unicode/1f9ef.png?v8",firecracker:"unicode/1f9e8.png?v8",firefighter:"unicode/1f9d1-1f692.png?v8",fireworks:"unicode/1f386.png?v8",first_quarter_moon:"unicode/1f313.png?v8",first_quarter_moon_with_face:"unicode/1f31b.png?v8",fish:"unicode/1f41f.png?v8",fish_cake:"unicode/1f365.png?v8",fishing_pole_and_fish:"unicode/1f3a3.png?v8",fishsticks:"fishsticks.png?v8",fist:"unicode/270a.png?v8",fist_left:"unicode/1f91b.png?v8",fist_oncoming:"unicode/1f44a.png?v8",fist_raised:"unicode/270a.png?v8",fist_right:"unicode/1f91c.png?v8",five:"unicode/0035-20e3.png?v8",flags:"unicode/1f38f.png?v8",flamingo:"unicode/1f9a9.png?v8",flashlight:"unicode/1f526.png?v8",flat_shoe:"unicode/1f97f.png?v8",flatbread:"unicode/1fad3.png?v8",fleur_de_lis:"unicode/269c.png?v8",flight_arrival:"unicode/1f6ec.png?v8",flight_departure:"unicode/1f6eb.png?v8",flipper:"unicode/1f42c.png?v8",floppy_disk:"unicode/1f4be.png?v8",flower_playing_cards:"unicode/1f3b4.png?v8",flushed:"unicode/1f633.png?v8",fly:"unicode/1fab0.png?v8",flying_disc:"unicode/1f94f.png?v8",flying_saucer:"unicode/1f6f8.png?v8",fog:"unicode/1f32b.png?v8",foggy:"unicode/1f301.png?v8",fondue:"unicode/1fad5.png?v8",foot:"unicode/1f9b6.png?v8",football:"unicode/1f3c8.png?v8",footprints:"unicode/1f463.png?v8",fork_and_knife:"unicode/1f374.png?v8",fortune_cookie:"unicode/1f960.png?v8",fountain:"unicode/26f2.png?v8",fountain_pen:"unicode/1f58b.png?v8",four:"unicode/0034-20e3.png?v8",four_leaf_clover:"unicode/1f340.png?v8",fox_face:"unicode/1f98a.png?v8",fr:"unicode/1f1eb-1f1f7.png?v8",framed_picture:"unicode/1f5bc.png?v8",free:"unicode/1f193.png?v8",french_guiana:"unicode/1f1ec-1f1eb.png?v8",french_polynesia:"unicode/1f1f5-1f1eb.png?v8",french_southern_territories:"unicode/1f1f9-1f1eb.png?v8",fried_egg:"unicode/1f373.png?v8",fried_shrimp:"unicode/1f364.png?v8",fries:"unicode/1f35f.png?v8",frog:"unicode/1f438.png?v8",frowning:"unicode/1f626.png?v8",frowning_face:"unicode/2639.png?v8",frowning_man:"unicode/1f64d-2642.png?v8",frowning_person:"unicode/1f64d.png?v8",frowning_woman:"unicode/1f64d-2640.png?v8",fu:"unicode/1f595.png?v8",fuelpump:"unicode/26fd.png?v8",full_moon:"unicode/1f315.png?v8",full_moon_with_face:"unicode/1f31d.png?v8",funeral_urn:"unicode/26b1.png?v8",gabon:"unicode/1f1ec-1f1e6.png?v8",gambia:"unicode/1f1ec-1f1f2.png?v8",game_die:"unicode/1f3b2.png?v8",garlic:"unicode/1f9c4.png?v8",gb:"unicode/1f1ec-1f1e7.png?v8",gear:"unicode/2699.png?v8",gem:"unicode/1f48e.png?v8",gemini:"unicode/264a.png?v8",genie:"unicode/1f9de.png?v8",genie_man:"unicode/1f9de-2642.png?v8",genie_woman:"unicode/1f9de-2640.png?v8",georgia:"unicode/1f1ec-1f1ea.png?v8",ghana:"unicode/1f1ec-1f1ed.png?v8",ghost:"unicode/1f47b.png?v8",gibraltar:"unicode/1f1ec-1f1ee.png?v8",gift:"unicode/1f381.png?v8",gift_heart:"unicode/1f49d.png?v8",giraffe:"unicode/1f992.png?v8",girl:"unicode/1f467.png?v8",globe_with_meridians:"unicode/1f310.png?v8",gloves:"unicode/1f9e4.png?v8",goal_net:"unicode/1f945.png?v8",goat:"unicode/1f410.png?v8",goberserk:"goberserk.png?v8",godmode:"godmode.png?v8",goggles:"unicode/1f97d.png?v8",golf:"unicode/26f3.png?v8",golfing:"unicode/1f3cc.png?v8",golfing_man:"unicode/1f3cc-2642.png?v8",golfing_woman:"unicode/1f3cc-2640.png?v8",gorilla:"unicode/1f98d.png?v8",grapes:"unicode/1f347.png?v8",greece:"unicode/1f1ec-1f1f7.png?v8",green_apple:"unicode/1f34f.png?v8",green_book:"unicode/1f4d7.png?v8",green_circle:"unicode/1f7e2.png?v8",green_heart:"unicode/1f49a.png?v8",green_salad:"unicode/1f957.png?v8",green_square:"unicode/1f7e9.png?v8",greenland:"unicode/1f1ec-1f1f1.png?v8",grenada:"unicode/1f1ec-1f1e9.png?v8",grey_exclamation:"unicode/2755.png?v8",grey_question:"unicode/2754.png?v8",grimacing:"unicode/1f62c.png?v8",grin:"unicode/1f601.png?v8",grinning:"unicode/1f600.png?v8",guadeloupe:"unicode/1f1ec-1f1f5.png?v8",guam:"unicode/1f1ec-1f1fa.png?v8",guard:"unicode/1f482.png?v8",guardsman:"unicode/1f482-2642.png?v8",guardswoman:"unicode/1f482-2640.png?v8",guatemala:"unicode/1f1ec-1f1f9.png?v8",guernsey:"unicode/1f1ec-1f1ec.png?v8",guide_dog:"unicode/1f9ae.png?v8",guinea:"unicode/1f1ec-1f1f3.png?v8",guinea_bissau:"unicode/1f1ec-1f1fc.png?v8",guitar:"unicode/1f3b8.png?v8",gun:"unicode/1f52b.png?v8",guyana:"unicode/1f1ec-1f1fe.png?v8",haircut:"unicode/1f487.png?v8",haircut_man:"unicode/1f487-2642.png?v8",haircut_woman:"unicode/1f487-2640.png?v8",haiti:"unicode/1f1ed-1f1f9.png?v8",hamburger:"unicode/1f354.png?v8",hammer:"unicode/1f528.png?v8",hammer_and_pick:"unicode/2692.png?v8",hammer_and_wrench:"unicode/1f6e0.png?v8",hamster:"unicode/1f439.png?v8",hand:"unicode/270b.png?v8",hand_over_mouth:"unicode/1f92d.png?v8",handbag:"unicode/1f45c.png?v8",handball_person:"unicode/1f93e.png?v8",handshake:"unicode/1f91d.png?v8",hankey:"unicode/1f4a9.png?v8",hash:"unicode/0023-20e3.png?v8",hatched_chick:"unicode/1f425.png?v8",hatching_chick:"unicode/1f423.png?v8",headphones:"unicode/1f3a7.png?v8",headstone:"unicode/1faa6.png?v8",health_worker:"unicode/1f9d1-2695.png?v8",hear_no_evil:"unicode/1f649.png?v8",heard_mcdonald_islands:"unicode/1f1ed-1f1f2.png?v8",heart:"unicode/2764.png?v8",heart_decoration:"unicode/1f49f.png?v8",heart_eyes:"unicode/1f60d.png?v8",heart_eyes_cat:"unicode/1f63b.png?v8",heart_on_fire:"unicode/2764-1f525.png?v8",heartbeat:"unicode/1f493.png?v8",heartpulse:"unicode/1f497.png?v8",hearts:"unicode/2665.png?v8",heavy_check_mark:"unicode/2714.png?v8",heavy_division_sign:"unicode/2797.png?v8",heavy_dollar_sign:"unicode/1f4b2.png?v8",heavy_exclamation_mark:"unicode/2757.png?v8",heavy_heart_exclamation:"unicode/2763.png?v8",heavy_minus_sign:"unicode/2796.png?v8",heavy_multiplication_x:"unicode/2716.png?v8",heavy_plus_sign:"unicode/2795.png?v8",hedgehog:"unicode/1f994.png?v8",helicopter:"unicode/1f681.png?v8",herb:"unicode/1f33f.png?v8",hibiscus:"unicode/1f33a.png?v8",high_brightness:"unicode/1f506.png?v8",high_heel:"unicode/1f460.png?v8",hiking_boot:"unicode/1f97e.png?v8",hindu_temple:"unicode/1f6d5.png?v8",hippopotamus:"unicode/1f99b.png?v8",hocho:"unicode/1f52a.png?v8",hole:"unicode/1f573.png?v8",honduras:"unicode/1f1ed-1f1f3.png?v8",honey_pot:"unicode/1f36f.png?v8",honeybee:"unicode/1f41d.png?v8",hong_kong:"unicode/1f1ed-1f1f0.png?v8",hook:"unicode/1fa9d.png?v8",horse:"unicode/1f434.png?v8",horse_racing:"unicode/1f3c7.png?v8",hospital:"unicode/1f3e5.png?v8",hot_face:"unicode/1f975.png?v8",hot_pepper:"unicode/1f336.png?v8",hotdog:"unicode/1f32d.png?v8",hotel:"unicode/1f3e8.png?v8",hotsprings:"unicode/2668.png?v8",hourglass:"unicode/231b.png?v8",hourglass_flowing_sand:"unicode/23f3.png?v8",house:"unicode/1f3e0.png?v8",house_with_garden:"unicode/1f3e1.png?v8",houses:"unicode/1f3d8.png?v8",hugs:"unicode/1f917.png?v8",hungary:"unicode/1f1ed-1f1fa.png?v8",hurtrealbad:"hurtrealbad.png?v8",hushed:"unicode/1f62f.png?v8",hut:"unicode/1f6d6.png?v8",ice_cream:"unicode/1f368.png?v8",ice_cube:"unicode/1f9ca.png?v8",ice_hockey:"unicode/1f3d2.png?v8",ice_skate:"unicode/26f8.png?v8",icecream:"unicode/1f366.png?v8",iceland:"unicode/1f1ee-1f1f8.png?v8",id:"unicode/1f194.png?v8",ideograph_advantage:"unicode/1f250.png?v8",imp:"unicode/1f47f.png?v8",inbox_tray:"unicode/1f4e5.png?v8",incoming_envelope:"unicode/1f4e8.png?v8",india:"unicode/1f1ee-1f1f3.png?v8",indonesia:"unicode/1f1ee-1f1e9.png?v8",infinity:"unicode/267e.png?v8",information_desk_person:"unicode/1f481.png?v8",information_source:"unicode/2139.png?v8",innocent:"unicode/1f607.png?v8",interrobang:"unicode/2049.png?v8",iphone:"unicode/1f4f1.png?v8",iran:"unicode/1f1ee-1f1f7.png?v8",iraq:"unicode/1f1ee-1f1f6.png?v8",ireland:"unicode/1f1ee-1f1ea.png?v8",isle_of_man:"unicode/1f1ee-1f1f2.png?v8",israel:"unicode/1f1ee-1f1f1.png?v8",it:"unicode/1f1ee-1f1f9.png?v8",izakaya_lantern:"unicode/1f3ee.png?v8",jack_o_lantern:"unicode/1f383.png?v8",jamaica:"unicode/1f1ef-1f1f2.png?v8",japan:"unicode/1f5fe.png?v8",japanese_castle:"unicode/1f3ef.png?v8",japanese_goblin:"unicode/1f47a.png?v8",japanese_ogre:"unicode/1f479.png?v8",jeans:"unicode/1f456.png?v8",jersey:"unicode/1f1ef-1f1ea.png?v8",jigsaw:"unicode/1f9e9.png?v8",jordan:"unicode/1f1ef-1f1f4.png?v8",joy:"unicode/1f602.png?v8",joy_cat:"unicode/1f639.png?v8",joystick:"unicode/1f579.png?v8",jp:"unicode/1f1ef-1f1f5.png?v8",judge:"unicode/1f9d1-2696.png?v8",juggling_person:"unicode/1f939.png?v8",kaaba:"unicode/1f54b.png?v8",kangaroo:"unicode/1f998.png?v8",kazakhstan:"unicode/1f1f0-1f1ff.png?v8",kenya:"unicode/1f1f0-1f1ea.png?v8",key:"unicode/1f511.png?v8",keyboard:"unicode/2328.png?v8",keycap_ten:"unicode/1f51f.png?v8",kick_scooter:"unicode/1f6f4.png?v8",kimono:"unicode/1f458.png?v8",kiribati:"unicode/1f1f0-1f1ee.png?v8",kiss:"unicode/1f48b.png?v8",kissing:"unicode/1f617.png?v8",kissing_cat:"unicode/1f63d.png?v8",kissing_closed_eyes:"unicode/1f61a.png?v8",kissing_heart:"unicode/1f618.png?v8",kissing_smiling_eyes:"unicode/1f619.png?v8",kite:"unicode/1fa81.png?v8",kiwi_fruit:"unicode/1f95d.png?v8",kneeling_man:"unicode/1f9ce-2642.png?v8",kneeling_person:"unicode/1f9ce.png?v8",kneeling_woman:"unicode/1f9ce-2640.png?v8",knife:"unicode/1f52a.png?v8",knot:"unicode/1faa2.png?v8",koala:"unicode/1f428.png?v8",koko:"unicode/1f201.png?v8",kosovo:"unicode/1f1fd-1f1f0.png?v8",kr:"unicode/1f1f0-1f1f7.png?v8",kuwait:"unicode/1f1f0-1f1fc.png?v8",kyrgyzstan:"unicode/1f1f0-1f1ec.png?v8",lab_coat:"unicode/1f97c.png?v8",label:"unicode/1f3f7.png?v8",lacrosse:"unicode/1f94d.png?v8",ladder:"unicode/1fa9c.png?v8",lady_beetle:"unicode/1f41e.png?v8",lantern:"unicode/1f3ee.png?v8",laos:"unicode/1f1f1-1f1e6.png?v8",large_blue_circle:"unicode/1f535.png?v8",large_blue_diamond:"unicode/1f537.png?v8",large_orange_diamond:"unicode/1f536.png?v8",last_quarter_moon:"unicode/1f317.png?v8",last_quarter_moon_with_face:"unicode/1f31c.png?v8",latin_cross:"unicode/271d.png?v8",latvia:"unicode/1f1f1-1f1fb.png?v8",laughing:"unicode/1f606.png?v8",leafy_green:"unicode/1f96c.png?v8",leaves:"unicode/1f343.png?v8",lebanon:"unicode/1f1f1-1f1e7.png?v8",ledger:"unicode/1f4d2.png?v8",left_luggage:"unicode/1f6c5.png?v8",left_right_arrow:"unicode/2194.png?v8",left_speech_bubble:"unicode/1f5e8.png?v8",leftwards_arrow_with_hook:"unicode/21a9.png?v8",leg:"unicode/1f9b5.png?v8",lemon:"unicode/1f34b.png?v8",leo:"unicode/264c.png?v8",leopard:"unicode/1f406.png?v8",lesotho:"unicode/1f1f1-1f1f8.png?v8",level_slider:"unicode/1f39a.png?v8",liberia:"unicode/1f1f1-1f1f7.png?v8",libra:"unicode/264e.png?v8",libya:"unicode/1f1f1-1f1fe.png?v8",liechtenstein:"unicode/1f1f1-1f1ee.png?v8",light_rail:"unicode/1f688.png?v8",link:"unicode/1f517.png?v8",lion:"unicode/1f981.png?v8",lips:"unicode/1f444.png?v8",lipstick:"unicode/1f484.png?v8",lithuania:"unicode/1f1f1-1f1f9.png?v8",lizard:"unicode/1f98e.png?v8",llama:"unicode/1f999.png?v8",lobster:"unicode/1f99e.png?v8",lock:"unicode/1f512.png?v8",lock_with_ink_pen:"unicode/1f50f.png?v8",lollipop:"unicode/1f36d.png?v8",long_drum:"unicode/1fa98.png?v8",loop:"unicode/27bf.png?v8",lotion_bottle:"unicode/1f9f4.png?v8",lotus_position:"unicode/1f9d8.png?v8",lotus_position_man:"unicode/1f9d8-2642.png?v8",lotus_position_woman:"unicode/1f9d8-2640.png?v8",loud_sound:"unicode/1f50a.png?v8",loudspeaker:"unicode/1f4e2.png?v8",love_hotel:"unicode/1f3e9.png?v8",love_letter:"unicode/1f48c.png?v8",love_you_gesture:"unicode/1f91f.png?v8",low_brightness:"unicode/1f505.png?v8",luggage:"unicode/1f9f3.png?v8",lungs:"unicode/1fac1.png?v8",luxembourg:"unicode/1f1f1-1f1fa.png?v8",lying_face:"unicode/1f925.png?v8",m:"unicode/24c2.png?v8",macau:"unicode/1f1f2-1f1f4.png?v8",macedonia:"unicode/1f1f2-1f1f0.png?v8",madagascar:"unicode/1f1f2-1f1ec.png?v8",mag:"unicode/1f50d.png?v8",mag_right:"unicode/1f50e.png?v8",mage:"unicode/1f9d9.png?v8",mage_man:"unicode/1f9d9-2642.png?v8",mage_woman:"unicode/1f9d9-2640.png?v8",magic_wand:"unicode/1fa84.png?v8",magnet:"unicode/1f9f2.png?v8",mahjong:"unicode/1f004.png?v8",mailbox:"unicode/1f4eb.png?v8",mailbox_closed:"unicode/1f4ea.png?v8",mailbox_with_mail:"unicode/1f4ec.png?v8",mailbox_with_no_mail:"unicode/1f4ed.png?v8",malawi:"unicode/1f1f2-1f1fc.png?v8",malaysia:"unicode/1f1f2-1f1fe.png?v8",maldives:"unicode/1f1f2-1f1fb.png?v8",male_detective:"unicode/1f575-2642.png?v8",male_sign:"unicode/2642.png?v8",mali:"unicode/1f1f2-1f1f1.png?v8",malta:"unicode/1f1f2-1f1f9.png?v8",mammoth:"unicode/1f9a3.png?v8",man:"unicode/1f468.png?v8",man_artist:"unicode/1f468-1f3a8.png?v8",man_astronaut:"unicode/1f468-1f680.png?v8",man_beard:"unicode/1f9d4-2642.png?v8",man_cartwheeling:"unicode/1f938-2642.png?v8",man_cook:"unicode/1f468-1f373.png?v8",man_dancing:"unicode/1f57a.png?v8",man_facepalming:"unicode/1f926-2642.png?v8",man_factory_worker:"unicode/1f468-1f3ed.png?v8",man_farmer:"unicode/1f468-1f33e.png?v8",man_feeding_baby:"unicode/1f468-1f37c.png?v8",man_firefighter:"unicode/1f468-1f692.png?v8",man_health_worker:"unicode/1f468-2695.png?v8",man_in_manual_wheelchair:"unicode/1f468-1f9bd.png?v8",man_in_motorized_wheelchair:"unicode/1f468-1f9bc.png?v8",man_in_tuxedo:"unicode/1f935-2642.png?v8",man_judge:"unicode/1f468-2696.png?v8",man_juggling:"unicode/1f939-2642.png?v8",man_mechanic:"unicode/1f468-1f527.png?v8",man_office_worker:"unicode/1f468-1f4bc.png?v8",man_pilot:"unicode/1f468-2708.png?v8",man_playing_handball:"unicode/1f93e-2642.png?v8",man_playing_water_polo:"unicode/1f93d-2642.png?v8",man_scientist:"unicode/1f468-1f52c.png?v8",man_shrugging:"unicode/1f937-2642.png?v8",man_singer:"unicode/1f468-1f3a4.png?v8",man_student:"unicode/1f468-1f393.png?v8",man_teacher:"unicode/1f468-1f3eb.png?v8",man_technologist:"unicode/1f468-1f4bb.png?v8",man_with_gua_pi_mao:"unicode/1f472.png?v8",man_with_probing_cane:"unicode/1f468-1f9af.png?v8",man_with_turban:"unicode/1f473-2642.png?v8",man_with_veil:"unicode/1f470-2642.png?v8",mandarin:"unicode/1f34a.png?v8",mango:"unicode/1f96d.png?v8",mans_shoe:"unicode/1f45e.png?v8",mantelpiece_clock:"unicode/1f570.png?v8",manual_wheelchair:"unicode/1f9bd.png?v8",maple_leaf:"unicode/1f341.png?v8",marshall_islands:"unicode/1f1f2-1f1ed.png?v8",martial_arts_uniform:"unicode/1f94b.png?v8",martinique:"unicode/1f1f2-1f1f6.png?v8",mask:"unicode/1f637.png?v8",massage:"unicode/1f486.png?v8",massage_man:"unicode/1f486-2642.png?v8",massage_woman:"unicode/1f486-2640.png?v8",mate:"unicode/1f9c9.png?v8",mauritania:"unicode/1f1f2-1f1f7.png?v8",mauritius:"unicode/1f1f2-1f1fa.png?v8",mayotte:"unicode/1f1fe-1f1f9.png?v8",meat_on_bone:"unicode/1f356.png?v8",mechanic:"unicode/1f9d1-1f527.png?v8",mechanical_arm:"unicode/1f9be.png?v8",mechanical_leg:"unicode/1f9bf.png?v8",medal_military:"unicode/1f396.png?v8",medal_sports:"unicode/1f3c5.png?v8",medical_symbol:"unicode/2695.png?v8",mega:"unicode/1f4e3.png?v8",melon:"unicode/1f348.png?v8",memo:"unicode/1f4dd.png?v8",men_wrestling:"unicode/1f93c-2642.png?v8",mending_heart:"unicode/2764-1fa79.png?v8",menorah:"unicode/1f54e.png?v8",mens:"unicode/1f6b9.png?v8",mermaid:"unicode/1f9dc-2640.png?v8",merman:"unicode/1f9dc-2642.png?v8",merperson:"unicode/1f9dc.png?v8",metal:"unicode/1f918.png?v8",metro:"unicode/1f687.png?v8",mexico:"unicode/1f1f2-1f1fd.png?v8",microbe:"unicode/1f9a0.png?v8",micronesia:"unicode/1f1eb-1f1f2.png?v8",microphone:"unicode/1f3a4.png?v8",microscope:"unicode/1f52c.png?v8",middle_finger:"unicode/1f595.png?v8",military_helmet:"unicode/1fa96.png?v8",milk_glass:"unicode/1f95b.png?v8",milky_way:"unicode/1f30c.png?v8",minibus:"unicode/1f690.png?v8",minidisc:"unicode/1f4bd.png?v8",mirror:"unicode/1fa9e.png?v8",mobile_phone_off:"unicode/1f4f4.png?v8",moldova:"unicode/1f1f2-1f1e9.png?v8",monaco:"unicode/1f1f2-1f1e8.png?v8",money_mouth_face:"unicode/1f911.png?v8",money_with_wings:"unicode/1f4b8.png?v8",moneybag:"unicode/1f4b0.png?v8",mongolia:"unicode/1f1f2-1f1f3.png?v8",monkey:"unicode/1f412.png?v8",monkey_face:"unicode/1f435.png?v8",monocle_face:"unicode/1f9d0.png?v8",monorail:"unicode/1f69d.png?v8",montenegro:"unicode/1f1f2-1f1ea.png?v8",montserrat:"unicode/1f1f2-1f1f8.png?v8",moon:"unicode/1f314.png?v8",moon_cake:"unicode/1f96e.png?v8",morocco:"unicode/1f1f2-1f1e6.png?v8",mortar_board:"unicode/1f393.png?v8",mosque:"unicode/1f54c.png?v8",mosquito:"unicode/1f99f.png?v8",motor_boat:"unicode/1f6e5.png?v8",motor_scooter:"unicode/1f6f5.png?v8",motorcycle:"unicode/1f3cd.png?v8",motorized_wheelchair:"unicode/1f9bc.png?v8",motorway:"unicode/1f6e3.png?v8",mount_fuji:"unicode/1f5fb.png?v8",mountain:"unicode/26f0.png?v8",mountain_bicyclist:"unicode/1f6b5.png?v8",mountain_biking_man:"unicode/1f6b5-2642.png?v8",mountain_biking_woman:"unicode/1f6b5-2640.png?v8",mountain_cableway:"unicode/1f6a0.png?v8",mountain_railway:"unicode/1f69e.png?v8",mountain_snow:"unicode/1f3d4.png?v8",mouse:"unicode/1f42d.png?v8",mouse2:"unicode/1f401.png?v8",mouse_trap:"unicode/1faa4.png?v8",movie_camera:"unicode/1f3a5.png?v8",moyai:"unicode/1f5ff.png?v8",mozambique:"unicode/1f1f2-1f1ff.png?v8",mrs_claus:"unicode/1f936.png?v8",muscle:"unicode/1f4aa.png?v8",mushroom:"unicode/1f344.png?v8",musical_keyboard:"unicode/1f3b9.png?v8",musical_note:"unicode/1f3b5.png?v8",musical_score:"unicode/1f3bc.png?v8",mute:"unicode/1f507.png?v8",mx_claus:"unicode/1f9d1-1f384.png?v8",myanmar:"unicode/1f1f2-1f1f2.png?v8",nail_care:"unicode/1f485.png?v8",name_badge:"unicode/1f4db.png?v8",namibia:"unicode/1f1f3-1f1e6.png?v8",national_park:"unicode/1f3de.png?v8",nauru:"unicode/1f1f3-1f1f7.png?v8",nauseated_face:"unicode/1f922.png?v8",nazar_amulet:"unicode/1f9ff.png?v8",neckbeard:"neckbeard.png?v8",necktie:"unicode/1f454.png?v8",negative_squared_cross_mark:"unicode/274e.png?v8",nepal:"unicode/1f1f3-1f1f5.png?v8",nerd_face:"unicode/1f913.png?v8",nesting_dolls:"unicode/1fa86.png?v8",netherlands:"unicode/1f1f3-1f1f1.png?v8",neutral_face:"unicode/1f610.png?v8",new:"unicode/1f195.png?v8",new_caledonia:"unicode/1f1f3-1f1e8.png?v8",new_moon:"unicode/1f311.png?v8",new_moon_with_face:"unicode/1f31a.png?v8",new_zealand:"unicode/1f1f3-1f1ff.png?v8",newspaper:"unicode/1f4f0.png?v8",newspaper_roll:"unicode/1f5de.png?v8",next_track_button:"unicode/23ed.png?v8",ng:"unicode/1f196.png?v8",ng_man:"unicode/1f645-2642.png?v8",ng_woman:"unicode/1f645-2640.png?v8",nicaragua:"unicode/1f1f3-1f1ee.png?v8",niger:"unicode/1f1f3-1f1ea.png?v8",nigeria:"unicode/1f1f3-1f1ec.png?v8",night_with_stars:"unicode/1f303.png?v8",nine:"unicode/0039-20e3.png?v8",ninja:"unicode/1f977.png?v8",niue:"unicode/1f1f3-1f1fa.png?v8",no_bell:"unicode/1f515.png?v8",no_bicycles:"unicode/1f6b3.png?v8",no_entry:"unicode/26d4.png?v8",no_entry_sign:"unicode/1f6ab.png?v8",no_good:"unicode/1f645.png?v8",no_good_man:"unicode/1f645-2642.png?v8",no_good_woman:"unicode/1f645-2640.png?v8",no_mobile_phones:"unicode/1f4f5.png?v8",no_mouth:"unicode/1f636.png?v8",no_pedestrians:"unicode/1f6b7.png?v8",no_smoking:"unicode/1f6ad.png?v8","non-potable_water":"unicode/1f6b1.png?v8",norfolk_island:"unicode/1f1f3-1f1eb.png?v8",north_korea:"unicode/1f1f0-1f1f5.png?v8",northern_mariana_islands:"unicode/1f1f2-1f1f5.png?v8",norway:"unicode/1f1f3-1f1f4.png?v8",nose:"unicode/1f443.png?v8",notebook:"unicode/1f4d3.png?v8",notebook_with_decorative_cover:"unicode/1f4d4.png?v8",notes:"unicode/1f3b6.png?v8",nut_and_bolt:"unicode/1f529.png?v8",o:"unicode/2b55.png?v8",o2:"unicode/1f17e.png?v8",ocean:"unicode/1f30a.png?v8",octocat:"octocat.png?v8",octopus:"unicode/1f419.png?v8",oden:"unicode/1f362.png?v8",office:"unicode/1f3e2.png?v8",office_worker:"unicode/1f9d1-1f4bc.png?v8",oil_drum:"unicode/1f6e2.png?v8",ok:"unicode/1f197.png?v8",ok_hand:"unicode/1f44c.png?v8",ok_man:"unicode/1f646-2642.png?v8",ok_person:"unicode/1f646.png?v8",ok_woman:"unicode/1f646-2640.png?v8",old_key:"unicode/1f5dd.png?v8",older_adult:"unicode/1f9d3.png?v8",older_man:"unicode/1f474.png?v8",older_woman:"unicode/1f475.png?v8",olive:"unicode/1fad2.png?v8",om:"unicode/1f549.png?v8",oman:"unicode/1f1f4-1f1f2.png?v8",on:"unicode/1f51b.png?v8",oncoming_automobile:"unicode/1f698.png?v8",oncoming_bus:"unicode/1f68d.png?v8",oncoming_police_car:"unicode/1f694.png?v8",oncoming_taxi:"unicode/1f696.png?v8",one:"unicode/0031-20e3.png?v8",one_piece_swimsuit:"unicode/1fa71.png?v8",onion:"unicode/1f9c5.png?v8",open_book:"unicode/1f4d6.png?v8",open_file_folder:"unicode/1f4c2.png?v8",open_hands:"unicode/1f450.png?v8",open_mouth:"unicode/1f62e.png?v8",open_umbrella:"unicode/2602.png?v8",ophiuchus:"unicode/26ce.png?v8",orange:"unicode/1f34a.png?v8",orange_book:"unicode/1f4d9.png?v8",orange_circle:"unicode/1f7e0.png?v8",orange_heart:"unicode/1f9e1.png?v8",orange_square:"unicode/1f7e7.png?v8",orangutan:"unicode/1f9a7.png?v8",orthodox_cross:"unicode/2626.png?v8",otter:"unicode/1f9a6.png?v8",outbox_tray:"unicode/1f4e4.png?v8",owl:"unicode/1f989.png?v8",ox:"unicode/1f402.png?v8",oyster:"unicode/1f9aa.png?v8",package:"unicode/1f4e6.png?v8",page_facing_up:"unicode/1f4c4.png?v8",page_with_curl:"unicode/1f4c3.png?v8",pager:"unicode/1f4df.png?v8",paintbrush:"unicode/1f58c.png?v8",pakistan:"unicode/1f1f5-1f1f0.png?v8",palau:"unicode/1f1f5-1f1fc.png?v8",palestinian_territories:"unicode/1f1f5-1f1f8.png?v8",palm_tree:"unicode/1f334.png?v8",palms_up_together:"unicode/1f932.png?v8",panama:"unicode/1f1f5-1f1e6.png?v8",pancakes:"unicode/1f95e.png?v8",panda_face:"unicode/1f43c.png?v8",paperclip:"unicode/1f4ce.png?v8",paperclips:"unicode/1f587.png?v8",papua_new_guinea:"unicode/1f1f5-1f1ec.png?v8",parachute:"unicode/1fa82.png?v8",paraguay:"unicode/1f1f5-1f1fe.png?v8",parasol_on_ground:"unicode/26f1.png?v8",parking:"unicode/1f17f.png?v8",parrot:"unicode/1f99c.png?v8",part_alternation_mark:"unicode/303d.png?v8",partly_sunny:"unicode/26c5.png?v8",partying_face:"unicode/1f973.png?v8",passenger_ship:"unicode/1f6f3.png?v8",passport_control:"unicode/1f6c2.png?v8",pause_button:"unicode/23f8.png?v8",paw_prints:"unicode/1f43e.png?v8",peace_symbol:"unicode/262e.png?v8",peach:"unicode/1f351.png?v8",peacock:"unicode/1f99a.png?v8",peanuts:"unicode/1f95c.png?v8",pear:"unicode/1f350.png?v8",pen:"unicode/1f58a.png?v8",pencil:"unicode/1f4dd.png?v8",pencil2:"unicode/270f.png?v8",penguin:"unicode/1f427.png?v8",pensive:"unicode/1f614.png?v8",people_holding_hands:"unicode/1f9d1-1f91d-1f9d1.png?v8",people_hugging:"unicode/1fac2.png?v8",performing_arts:"unicode/1f3ad.png?v8",persevere:"unicode/1f623.png?v8",person_bald:"unicode/1f9d1-1f9b2.png?v8",person_curly_hair:"unicode/1f9d1-1f9b1.png?v8",person_feeding_baby:"unicode/1f9d1-1f37c.png?v8",person_fencing:"unicode/1f93a.png?v8",person_in_manual_wheelchair:"unicode/1f9d1-1f9bd.png?v8",person_in_motorized_wheelchair:"unicode/1f9d1-1f9bc.png?v8",person_in_tuxedo:"unicode/1f935.png?v8",person_red_hair:"unicode/1f9d1-1f9b0.png?v8",person_white_hair:"unicode/1f9d1-1f9b3.png?v8",person_with_probing_cane:"unicode/1f9d1-1f9af.png?v8",person_with_turban:"unicode/1f473.png?v8",person_with_veil:"unicode/1f470.png?v8",peru:"unicode/1f1f5-1f1ea.png?v8",petri_dish:"unicode/1f9eb.png?v8",philippines:"unicode/1f1f5-1f1ed.png?v8",phone:"unicode/260e.png?v8",pick:"unicode/26cf.png?v8",pickup_truck:"unicode/1f6fb.png?v8",pie:"unicode/1f967.png?v8",pig:"unicode/1f437.png?v8",pig2:"unicode/1f416.png?v8",pig_nose:"unicode/1f43d.png?v8",pill:"unicode/1f48a.png?v8",pilot:"unicode/1f9d1-2708.png?v8",pinata:"unicode/1fa85.png?v8",pinched_fingers:"unicode/1f90c.png?v8",pinching_hand:"unicode/1f90f.png?v8",pineapple:"unicode/1f34d.png?v8",ping_pong:"unicode/1f3d3.png?v8",pirate_flag:"unicode/1f3f4-2620.png?v8",pisces:"unicode/2653.png?v8",pitcairn_islands:"unicode/1f1f5-1f1f3.png?v8",pizza:"unicode/1f355.png?v8",placard:"unicode/1faa7.png?v8",place_of_worship:"unicode/1f6d0.png?v8",plate_with_cutlery:"unicode/1f37d.png?v8",play_or_pause_button:"unicode/23ef.png?v8",pleading_face:"unicode/1f97a.png?v8",plunger:"unicode/1faa0.png?v8",point_down:"unicode/1f447.png?v8",point_left:"unicode/1f448.png?v8",point_right:"unicode/1f449.png?v8",point_up:"unicode/261d.png?v8",point_up_2:"unicode/1f446.png?v8",poland:"unicode/1f1f5-1f1f1.png?v8",polar_bear:"unicode/1f43b-2744.png?v8",police_car:"unicode/1f693.png?v8",police_officer:"unicode/1f46e.png?v8",policeman:"unicode/1f46e-2642.png?v8",policewoman:"unicode/1f46e-2640.png?v8",poodle:"unicode/1f429.png?v8",poop:"unicode/1f4a9.png?v8",popcorn:"unicode/1f37f.png?v8",portugal:"unicode/1f1f5-1f1f9.png?v8",post_office:"unicode/1f3e3.png?v8",postal_horn:"unicode/1f4ef.png?v8",postbox:"unicode/1f4ee.png?v8",potable_water:"unicode/1f6b0.png?v8",potato:"unicode/1f954.png?v8",potted_plant:"unicode/1fab4.png?v8",pouch:"unicode/1f45d.png?v8",poultry_leg:"unicode/1f357.png?v8",pound:"unicode/1f4b7.png?v8",pout:"unicode/1f621.png?v8",pouting_cat:"unicode/1f63e.png?v8",pouting_face:"unicode/1f64e.png?v8",pouting_man:"unicode/1f64e-2642.png?v8",pouting_woman:"unicode/1f64e-2640.png?v8",pray:"unicode/1f64f.png?v8",prayer_beads:"unicode/1f4ff.png?v8",pregnant_woman:"unicode/1f930.png?v8",pretzel:"unicode/1f968.png?v8",previous_track_button:"unicode/23ee.png?v8",prince:"unicode/1f934.png?v8",princess:"unicode/1f478.png?v8",printer:"unicode/1f5a8.png?v8",probing_cane:"unicode/1f9af.png?v8",puerto_rico:"unicode/1f1f5-1f1f7.png?v8",punch:"unicode/1f44a.png?v8",purple_circle:"unicode/1f7e3.png?v8",purple_heart:"unicode/1f49c.png?v8",purple_square:"unicode/1f7ea.png?v8",purse:"unicode/1f45b.png?v8",pushpin:"unicode/1f4cc.png?v8",put_litter_in_its_place:"unicode/1f6ae.png?v8",qatar:"unicode/1f1f6-1f1e6.png?v8",question:"unicode/2753.png?v8",rabbit:"unicode/1f430.png?v8",rabbit2:"unicode/1f407.png?v8",raccoon:"unicode/1f99d.png?v8",racehorse:"unicode/1f40e.png?v8",racing_car:"unicode/1f3ce.png?v8",radio:"unicode/1f4fb.png?v8",radio_button:"unicode/1f518.png?v8",radioactive:"unicode/2622.png?v8",rage:"unicode/1f621.png?v8",rage1:"rage1.png?v8",rage2:"rage2.png?v8",rage3:"rage3.png?v8",rage4:"rage4.png?v8",railway_car:"unicode/1f683.png?v8",railway_track:"unicode/1f6e4.png?v8",rainbow:"unicode/1f308.png?v8",rainbow_flag:"unicode/1f3f3-1f308.png?v8",raised_back_of_hand:"unicode/1f91a.png?v8",raised_eyebrow:"unicode/1f928.png?v8",raised_hand:"unicode/270b.png?v8",raised_hand_with_fingers_splayed:"unicode/1f590.png?v8",raised_hands:"unicode/1f64c.png?v8",raising_hand:"unicode/1f64b.png?v8",raising_hand_man:"unicode/1f64b-2642.png?v8",raising_hand_woman:"unicode/1f64b-2640.png?v8",ram:"unicode/1f40f.png?v8",ramen:"unicode/1f35c.png?v8",rat:"unicode/1f400.png?v8",razor:"unicode/1fa92.png?v8",receipt:"unicode/1f9fe.png?v8",record_button:"unicode/23fa.png?v8",recycle:"unicode/267b.png?v8",red_car:"unicode/1f697.png?v8",red_circle:"unicode/1f534.png?v8",red_envelope:"unicode/1f9e7.png?v8",red_haired_man:"unicode/1f468-1f9b0.png?v8",red_haired_woman:"unicode/1f469-1f9b0.png?v8",red_square:"unicode/1f7e5.png?v8",registered:"unicode/00ae.png?v8",relaxed:"unicode/263a.png?v8",relieved:"unicode/1f60c.png?v8",reminder_ribbon:"unicode/1f397.png?v8",repeat:"unicode/1f501.png?v8",repeat_one:"unicode/1f502.png?v8",rescue_worker_helmet:"unicode/26d1.png?v8",restroom:"unicode/1f6bb.png?v8",reunion:"unicode/1f1f7-1f1ea.png?v8",revolving_hearts:"unicode/1f49e.png?v8",rewind:"unicode/23ea.png?v8",rhinoceros:"unicode/1f98f.png?v8",ribbon:"unicode/1f380.png?v8",rice:"unicode/1f35a.png?v8",rice_ball:"unicode/1f359.png?v8",rice_cracker:"unicode/1f358.png?v8",rice_scene:"unicode/1f391.png?v8",right_anger_bubble:"unicode/1f5ef.png?v8",ring:"unicode/1f48d.png?v8",ringed_planet:"unicode/1fa90.png?v8",robot:"unicode/1f916.png?v8",rock:"unicode/1faa8.png?v8",rocket:"unicode/1f680.png?v8",rofl:"unicode/1f923.png?v8",roll_eyes:"unicode/1f644.png?v8",roll_of_paper:"unicode/1f9fb.png?v8",roller_coaster:"unicode/1f3a2.png?v8",roller_skate:"unicode/1f6fc.png?v8",romania:"unicode/1f1f7-1f1f4.png?v8",rooster:"unicode/1f413.png?v8",rose:"unicode/1f339.png?v8",rosette:"unicode/1f3f5.png?v8",rotating_light:"unicode/1f6a8.png?v8",round_pushpin:"unicode/1f4cd.png?v8",rowboat:"unicode/1f6a3.png?v8",rowing_man:"unicode/1f6a3-2642.png?v8",rowing_woman:"unicode/1f6a3-2640.png?v8",ru:"unicode/1f1f7-1f1fa.png?v8",rugby_football:"unicode/1f3c9.png?v8",runner:"unicode/1f3c3.png?v8",running:"unicode/1f3c3.png?v8",running_man:"unicode/1f3c3-2642.png?v8",running_shirt_with_sash:"unicode/1f3bd.png?v8",running_woman:"unicode/1f3c3-2640.png?v8",rwanda:"unicode/1f1f7-1f1fc.png?v8",sa:"unicode/1f202.png?v8",safety_pin:"unicode/1f9f7.png?v8",safety_vest:"unicode/1f9ba.png?v8",sagittarius:"unicode/2650.png?v8",sailboat:"unicode/26f5.png?v8",sake:"unicode/1f376.png?v8",salt:"unicode/1f9c2.png?v8",samoa:"unicode/1f1fc-1f1f8.png?v8",san_marino:"unicode/1f1f8-1f1f2.png?v8",sandal:"unicode/1f461.png?v8",sandwich:"unicode/1f96a.png?v8",santa:"unicode/1f385.png?v8",sao_tome_principe:"unicode/1f1f8-1f1f9.png?v8",sari:"unicode/1f97b.png?v8",sassy_man:"unicode/1f481-2642.png?v8",sassy_woman:"unicode/1f481-2640.png?v8",satellite:"unicode/1f4e1.png?v8",satisfied:"unicode/1f606.png?v8",saudi_arabia:"unicode/1f1f8-1f1e6.png?v8",sauna_man:"unicode/1f9d6-2642.png?v8",sauna_person:"unicode/1f9d6.png?v8",sauna_woman:"unicode/1f9d6-2640.png?v8",sauropod:"unicode/1f995.png?v8",saxophone:"unicode/1f3b7.png?v8",scarf:"unicode/1f9e3.png?v8",school:"unicode/1f3eb.png?v8",school_satchel:"unicode/1f392.png?v8",scientist:"unicode/1f9d1-1f52c.png?v8",scissors:"unicode/2702.png?v8",scorpion:"unicode/1f982.png?v8",scorpius:"unicode/264f.png?v8",scotland:"unicode/1f3f4-e0067-e0062-e0073-e0063-e0074-e007f.png?v8",scream:"unicode/1f631.png?v8",scream_cat:"unicode/1f640.png?v8",screwdriver:"unicode/1fa9b.png?v8",scroll:"unicode/1f4dc.png?v8",seal:"unicode/1f9ad.png?v8",seat:"unicode/1f4ba.png?v8",secret:"unicode/3299.png?v8",see_no_evil:"unicode/1f648.png?v8",seedling:"unicode/1f331.png?v8",selfie:"unicode/1f933.png?v8",senegal:"unicode/1f1f8-1f1f3.png?v8",serbia:"unicode/1f1f7-1f1f8.png?v8",service_dog:"unicode/1f415-1f9ba.png?v8",seven:"unicode/0037-20e3.png?v8",sewing_needle:"unicode/1faa1.png?v8",seychelles:"unicode/1f1f8-1f1e8.png?v8",shallow_pan_of_food:"unicode/1f958.png?v8",shamrock:"unicode/2618.png?v8",shark:"unicode/1f988.png?v8",shaved_ice:"unicode/1f367.png?v8",sheep:"unicode/1f411.png?v8",shell:"unicode/1f41a.png?v8",shield:"unicode/1f6e1.png?v8",shinto_shrine:"unicode/26e9.png?v8",ship:"unicode/1f6a2.png?v8",shipit:"shipit.png?v8",shirt:"unicode/1f455.png?v8",shit:"unicode/1f4a9.png?v8",shoe:"unicode/1f45e.png?v8",shopping:"unicode/1f6cd.png?v8",shopping_cart:"unicode/1f6d2.png?v8",shorts:"unicode/1fa73.png?v8",shower:"unicode/1f6bf.png?v8",shrimp:"unicode/1f990.png?v8",shrug:"unicode/1f937.png?v8",shushing_face:"unicode/1f92b.png?v8",sierra_leone:"unicode/1f1f8-1f1f1.png?v8",signal_strength:"unicode/1f4f6.png?v8",singapore:"unicode/1f1f8-1f1ec.png?v8",singer:"unicode/1f9d1-1f3a4.png?v8",sint_maarten:"unicode/1f1f8-1f1fd.png?v8",six:"unicode/0036-20e3.png?v8",six_pointed_star:"unicode/1f52f.png?v8",skateboard:"unicode/1f6f9.png?v8",ski:"unicode/1f3bf.png?v8",skier:"unicode/26f7.png?v8",skull:"unicode/1f480.png?v8",skull_and_crossbones:"unicode/2620.png?v8",skunk:"unicode/1f9a8.png?v8",sled:"unicode/1f6f7.png?v8",sleeping:"unicode/1f634.png?v8",sleeping_bed:"unicode/1f6cc.png?v8",sleepy:"unicode/1f62a.png?v8",slightly_frowning_face:"unicode/1f641.png?v8",slightly_smiling_face:"unicode/1f642.png?v8",slot_machine:"unicode/1f3b0.png?v8",sloth:"unicode/1f9a5.png?v8",slovakia:"unicode/1f1f8-1f1f0.png?v8",slovenia:"unicode/1f1f8-1f1ee.png?v8",small_airplane:"unicode/1f6e9.png?v8",small_blue_diamond:"unicode/1f539.png?v8",small_orange_diamond:"unicode/1f538.png?v8",small_red_triangle:"unicode/1f53a.png?v8",small_red_triangle_down:"unicode/1f53b.png?v8",smile:"unicode/1f604.png?v8",smile_cat:"unicode/1f638.png?v8",smiley:"unicode/1f603.png?v8",smiley_cat:"unicode/1f63a.png?v8",smiling_face_with_tear:"unicode/1f972.png?v8",smiling_face_with_three_hearts:"unicode/1f970.png?v8",smiling_imp:"unicode/1f608.png?v8",smirk:"unicode/1f60f.png?v8",smirk_cat:"unicode/1f63c.png?v8",smoking:"unicode/1f6ac.png?v8",snail:"unicode/1f40c.png?v8",snake:"unicode/1f40d.png?v8",sneezing_face:"unicode/1f927.png?v8",snowboarder:"unicode/1f3c2.png?v8",snowflake:"unicode/2744.png?v8",snowman:"unicode/26c4.png?v8",snowman_with_snow:"unicode/2603.png?v8",soap:"unicode/1f9fc.png?v8",sob:"unicode/1f62d.png?v8",soccer:"unicode/26bd.png?v8",socks:"unicode/1f9e6.png?v8",softball:"unicode/1f94e.png?v8",solomon_islands:"unicode/1f1f8-1f1e7.png?v8",somalia:"unicode/1f1f8-1f1f4.png?v8",soon:"unicode/1f51c.png?v8",sos:"unicode/1f198.png?v8",sound:"unicode/1f509.png?v8",south_africa:"unicode/1f1ff-1f1e6.png?v8",south_georgia_south_sandwich_islands:"unicode/1f1ec-1f1f8.png?v8",south_sudan:"unicode/1f1f8-1f1f8.png?v8",space_invader:"unicode/1f47e.png?v8",spades:"unicode/2660.png?v8",spaghetti:"unicode/1f35d.png?v8",sparkle:"unicode/2747.png?v8",sparkler:"unicode/1f387.png?v8",sparkles:"unicode/2728.png?v8",sparkling_heart:"unicode/1f496.png?v8",speak_no_evil:"unicode/1f64a.png?v8",speaker:"unicode/1f508.png?v8",speaking_head:"unicode/1f5e3.png?v8",speech_balloon:"unicode/1f4ac.png?v8",speedboat:"unicode/1f6a4.png?v8",spider:"unicode/1f577.png?v8",spider_web:"unicode/1f578.png?v8",spiral_calendar:"unicode/1f5d3.png?v8",spiral_notepad:"unicode/1f5d2.png?v8",sponge:"unicode/1f9fd.png?v8",spoon:"unicode/1f944.png?v8",squid:"unicode/1f991.png?v8",sri_lanka:"unicode/1f1f1-1f1f0.png?v8",st_barthelemy:"unicode/1f1e7-1f1f1.png?v8",st_helena:"unicode/1f1f8-1f1ed.png?v8",st_kitts_nevis:"unicode/1f1f0-1f1f3.png?v8",st_lucia:"unicode/1f1f1-1f1e8.png?v8",st_martin:"unicode/1f1f2-1f1eb.png?v8",st_pierre_miquelon:"unicode/1f1f5-1f1f2.png?v8",st_vincent_grenadines:"unicode/1f1fb-1f1e8.png?v8",stadium:"unicode/1f3df.png?v8",standing_man:"unicode/1f9cd-2642.png?v8",standing_person:"unicode/1f9cd.png?v8",standing_woman:"unicode/1f9cd-2640.png?v8",star:"unicode/2b50.png?v8",star2:"unicode/1f31f.png?v8",star_and_crescent:"unicode/262a.png?v8",star_of_david:"unicode/2721.png?v8",star_struck:"unicode/1f929.png?v8",stars:"unicode/1f320.png?v8",station:"unicode/1f689.png?v8",statue_of_liberty:"unicode/1f5fd.png?v8",steam_locomotive:"unicode/1f682.png?v8",stethoscope:"unicode/1fa7a.png?v8",stew:"unicode/1f372.png?v8",stop_button:"unicode/23f9.png?v8",stop_sign:"unicode/1f6d1.png?v8",stopwatch:"unicode/23f1.png?v8",straight_ruler:"unicode/1f4cf.png?v8",strawberry:"unicode/1f353.png?v8",stuck_out_tongue:"unicode/1f61b.png?v8",stuck_out_tongue_closed_eyes:"unicode/1f61d.png?v8",stuck_out_tongue_winking_eye:"unicode/1f61c.png?v8",student:"unicode/1f9d1-1f393.png?v8",studio_microphone:"unicode/1f399.png?v8",stuffed_flatbread:"unicode/1f959.png?v8",sudan:"unicode/1f1f8-1f1e9.png?v8",sun_behind_large_cloud:"unicode/1f325.png?v8",sun_behind_rain_cloud:"unicode/1f326.png?v8",sun_behind_small_cloud:"unicode/1f324.png?v8",sun_with_face:"unicode/1f31e.png?v8",sunflower:"unicode/1f33b.png?v8",sunglasses:"unicode/1f60e.png?v8",sunny:"unicode/2600.png?v8",sunrise:"unicode/1f305.png?v8",sunrise_over_mountains:"unicode/1f304.png?v8",superhero:"unicode/1f9b8.png?v8",superhero_man:"unicode/1f9b8-2642.png?v8",superhero_woman:"unicode/1f9b8-2640.png?v8",supervillain:"unicode/1f9b9.png?v8",supervillain_man:"unicode/1f9b9-2642.png?v8",supervillain_woman:"unicode/1f9b9-2640.png?v8",surfer:"unicode/1f3c4.png?v8",surfing_man:"unicode/1f3c4-2642.png?v8",surfing_woman:"unicode/1f3c4-2640.png?v8",suriname:"unicode/1f1f8-1f1f7.png?v8",sushi:"unicode/1f363.png?v8",suspect:"suspect.png?v8",suspension_railway:"unicode/1f69f.png?v8",svalbard_jan_mayen:"unicode/1f1f8-1f1ef.png?v8",swan:"unicode/1f9a2.png?v8",swaziland:"unicode/1f1f8-1f1ff.png?v8",sweat:"unicode/1f613.png?v8",sweat_drops:"unicode/1f4a6.png?v8",sweat_smile:"unicode/1f605.png?v8",sweden:"unicode/1f1f8-1f1ea.png?v8",sweet_potato:"unicode/1f360.png?v8",swim_brief:"unicode/1fa72.png?v8",swimmer:"unicode/1f3ca.png?v8",swimming_man:"unicode/1f3ca-2642.png?v8",swimming_woman:"unicode/1f3ca-2640.png?v8",switzerland:"unicode/1f1e8-1f1ed.png?v8",symbols:"unicode/1f523.png?v8",synagogue:"unicode/1f54d.png?v8",syria:"unicode/1f1f8-1f1fe.png?v8",syringe:"unicode/1f489.png?v8","t-rex":"unicode/1f996.png?v8",taco:"unicode/1f32e.png?v8",tada:"unicode/1f389.png?v8",taiwan:"unicode/1f1f9-1f1fc.png?v8",tajikistan:"unicode/1f1f9-1f1ef.png?v8",takeout_box:"unicode/1f961.png?v8",tamale:"unicode/1fad4.png?v8",tanabata_tree:"unicode/1f38b.png?v8",tangerine:"unicode/1f34a.png?v8",tanzania:"unicode/1f1f9-1f1ff.png?v8",taurus:"unicode/2649.png?v8",taxi:"unicode/1f695.png?v8",tea:"unicode/1f375.png?v8",teacher:"unicode/1f9d1-1f3eb.png?v8",teapot:"unicode/1fad6.png?v8",technologist:"unicode/1f9d1-1f4bb.png?v8",teddy_bear:"unicode/1f9f8.png?v8",telephone:"unicode/260e.png?v8",telephone_receiver:"unicode/1f4de.png?v8",telescope:"unicode/1f52d.png?v8",tennis:"unicode/1f3be.png?v8",tent:"unicode/26fa.png?v8",test_tube:"unicode/1f9ea.png?v8",thailand:"unicode/1f1f9-1f1ed.png?v8",thermometer:"unicode/1f321.png?v8",thinking:"unicode/1f914.png?v8",thong_sandal:"unicode/1fa74.png?v8",thought_balloon:"unicode/1f4ad.png?v8",thread:"unicode/1f9f5.png?v8",three:"unicode/0033-20e3.png?v8",thumbsdown:"unicode/1f44e.png?v8",thumbsup:"unicode/1f44d.png?v8",ticket:"unicode/1f3ab.png?v8",tickets:"unicode/1f39f.png?v8",tiger:"unicode/1f42f.png?v8",tiger2:"unicode/1f405.png?v8",timer_clock:"unicode/23f2.png?v8",timor_leste:"unicode/1f1f9-1f1f1.png?v8",tipping_hand_man:"unicode/1f481-2642.png?v8",tipping_hand_person:"unicode/1f481.png?v8",tipping_hand_woman:"unicode/1f481-2640.png?v8",tired_face:"unicode/1f62b.png?v8",tm:"unicode/2122.png?v8",togo:"unicode/1f1f9-1f1ec.png?v8",toilet:"unicode/1f6bd.png?v8",tokelau:"unicode/1f1f9-1f1f0.png?v8",tokyo_tower:"unicode/1f5fc.png?v8",tomato:"unicode/1f345.png?v8",tonga:"unicode/1f1f9-1f1f4.png?v8",tongue:"unicode/1f445.png?v8",toolbox:"unicode/1f9f0.png?v8",tooth:"unicode/1f9b7.png?v8",toothbrush:"unicode/1faa5.png?v8",top:"unicode/1f51d.png?v8",tophat:"unicode/1f3a9.png?v8",tornado:"unicode/1f32a.png?v8",tr:"unicode/1f1f9-1f1f7.png?v8",trackball:"unicode/1f5b2.png?v8",tractor:"unicode/1f69c.png?v8",traffic_light:"unicode/1f6a5.png?v8",train:"unicode/1f68b.png?v8",train2:"unicode/1f686.png?v8",tram:"unicode/1f68a.png?v8",transgender_flag:"unicode/1f3f3-26a7.png?v8",transgender_symbol:"unicode/26a7.png?v8",triangular_flag_on_post:"unicode/1f6a9.png?v8",triangular_ruler:"unicode/1f4d0.png?v8",trident:"unicode/1f531.png?v8",trinidad_tobago:"unicode/1f1f9-1f1f9.png?v8",tristan_da_cunha:"unicode/1f1f9-1f1e6.png?v8",triumph:"unicode/1f624.png?v8",trolleybus:"unicode/1f68e.png?v8",trollface:"trollface.png?v8",trophy:"unicode/1f3c6.png?v8",tropical_drink:"unicode/1f379.png?v8",tropical_fish:"unicode/1f420.png?v8",truck:"unicode/1f69a.png?v8",trumpet:"unicode/1f3ba.png?v8",tshirt:"unicode/1f455.png?v8",tulip:"unicode/1f337.png?v8",tumbler_glass:"unicode/1f943.png?v8",tunisia:"unicode/1f1f9-1f1f3.png?v8",turkey:"unicode/1f983.png?v8",turkmenistan:"unicode/1f1f9-1f1f2.png?v8",turks_caicos_islands:"unicode/1f1f9-1f1e8.png?v8",turtle:"unicode/1f422.png?v8",tuvalu:"unicode/1f1f9-1f1fb.png?v8",tv:"unicode/1f4fa.png?v8",twisted_rightwards_arrows:"unicode/1f500.png?v8",two:"unicode/0032-20e3.png?v8",two_hearts:"unicode/1f495.png?v8",two_men_holding_hands:"unicode/1f46c.png?v8",two_women_holding_hands:"unicode/1f46d.png?v8",u5272:"unicode/1f239.png?v8",u5408:"unicode/1f234.png?v8",u55b6:"unicode/1f23a.png?v8",u6307:"unicode/1f22f.png?v8",u6708:"unicode/1f237.png?v8",u6709:"unicode/1f236.png?v8",u6e80:"unicode/1f235.png?v8",u7121:"unicode/1f21a.png?v8",u7533:"unicode/1f238.png?v8",u7981:"unicode/1f232.png?v8",u7a7a:"unicode/1f233.png?v8",uganda:"unicode/1f1fa-1f1ec.png?v8",uk:"unicode/1f1ec-1f1e7.png?v8",ukraine:"unicode/1f1fa-1f1e6.png?v8",umbrella:"unicode/2614.png?v8",unamused:"unicode/1f612.png?v8",underage:"unicode/1f51e.png?v8",unicorn:"unicode/1f984.png?v8",united_arab_emirates:"unicode/1f1e6-1f1ea.png?v8",united_nations:"unicode/1f1fa-1f1f3.png?v8",unlock:"unicode/1f513.png?v8",up:"unicode/1f199.png?v8",upside_down_face:"unicode/1f643.png?v8",uruguay:"unicode/1f1fa-1f1fe.png?v8",us:"unicode/1f1fa-1f1f8.png?v8",us_outlying_islands:"unicode/1f1fa-1f1f2.png?v8",us_virgin_islands:"unicode/1f1fb-1f1ee.png?v8",uzbekistan:"unicode/1f1fa-1f1ff.png?v8",v:"unicode/270c.png?v8",vampire:"unicode/1f9db.png?v8",vampire_man:"unicode/1f9db-2642.png?v8",vampire_woman:"unicode/1f9db-2640.png?v8",vanuatu:"unicode/1f1fb-1f1fa.png?v8",vatican_city:"unicode/1f1fb-1f1e6.png?v8",venezuela:"unicode/1f1fb-1f1ea.png?v8",vertical_traffic_light:"unicode/1f6a6.png?v8",vhs:"unicode/1f4fc.png?v8",vibration_mode:"unicode/1f4f3.png?v8",video_camera:"unicode/1f4f9.png?v8",video_game:"unicode/1f3ae.png?v8",vietnam:"unicode/1f1fb-1f1f3.png?v8",violin:"unicode/1f3bb.png?v8",virgo:"unicode/264d.png?v8",volcano:"unicode/1f30b.png?v8",volleyball:"unicode/1f3d0.png?v8",vomiting_face:"unicode/1f92e.png?v8",vs:"unicode/1f19a.png?v8",vulcan_salute:"unicode/1f596.png?v8",waffle:"unicode/1f9c7.png?v8",wales:"unicode/1f3f4-e0067-e0062-e0077-e006c-e0073-e007f.png?v8",walking:"unicode/1f6b6.png?v8",walking_man:"unicode/1f6b6-2642.png?v8",walking_woman:"unicode/1f6b6-2640.png?v8",wallis_futuna:"unicode/1f1fc-1f1eb.png?v8",waning_crescent_moon:"unicode/1f318.png?v8",waning_gibbous_moon:"unicode/1f316.png?v8",warning:"unicode/26a0.png?v8",wastebasket:"unicode/1f5d1.png?v8",watch:"unicode/231a.png?v8",water_buffalo:"unicode/1f403.png?v8",water_polo:"unicode/1f93d.png?v8",watermelon:"unicode/1f349.png?v8",wave:"unicode/1f44b.png?v8",wavy_dash:"unicode/3030.png?v8",waxing_crescent_moon:"unicode/1f312.png?v8",waxing_gibbous_moon:"unicode/1f314.png?v8",wc:"unicode/1f6be.png?v8",weary:"unicode/1f629.png?v8",wedding:"unicode/1f492.png?v8",weight_lifting:"unicode/1f3cb.png?v8",weight_lifting_man:"unicode/1f3cb-2642.png?v8",weight_lifting_woman:"unicode/1f3cb-2640.png?v8",western_sahara:"unicode/1f1ea-1f1ed.png?v8",whale:"unicode/1f433.png?v8",whale2:"unicode/1f40b.png?v8",wheel_of_dharma:"unicode/2638.png?v8",wheelchair:"unicode/267f.png?v8",white_check_mark:"unicode/2705.png?v8",white_circle:"unicode/26aa.png?v8",white_flag:"unicode/1f3f3.png?v8",white_flower:"unicode/1f4ae.png?v8",white_haired_man:"unicode/1f468-1f9b3.png?v8",white_haired_woman:"unicode/1f469-1f9b3.png?v8",white_heart:"unicode/1f90d.png?v8",white_large_square:"unicode/2b1c.png?v8",white_medium_small_square:"unicode/25fd.png?v8",white_medium_square:"unicode/25fb.png?v8",white_small_square:"unicode/25ab.png?v8",white_square_button:"unicode/1f533.png?v8",wilted_flower:"unicode/1f940.png?v8",wind_chime:"unicode/1f390.png?v8",wind_face:"unicode/1f32c.png?v8",window:"unicode/1fa9f.png?v8",wine_glass:"unicode/1f377.png?v8",wink:"unicode/1f609.png?v8",wolf:"unicode/1f43a.png?v8",woman:"unicode/1f469.png?v8",woman_artist:"unicode/1f469-1f3a8.png?v8",woman_astronaut:"unicode/1f469-1f680.png?v8",woman_beard:"unicode/1f9d4-2640.png?v8",woman_cartwheeling:"unicode/1f938-2640.png?v8",woman_cook:"unicode/1f469-1f373.png?v8",woman_dancing:"unicode/1f483.png?v8",woman_facepalming:"unicode/1f926-2640.png?v8",woman_factory_worker:"unicode/1f469-1f3ed.png?v8",woman_farmer:"unicode/1f469-1f33e.png?v8",woman_feeding_baby:"unicode/1f469-1f37c.png?v8",woman_firefighter:"unicode/1f469-1f692.png?v8",woman_health_worker:"unicode/1f469-2695.png?v8",woman_in_manual_wheelchair:"unicode/1f469-1f9bd.png?v8",woman_in_motorized_wheelchair:"unicode/1f469-1f9bc.png?v8",woman_in_tuxedo:"unicode/1f935-2640.png?v8",woman_judge:"unicode/1f469-2696.png?v8",woman_juggling:"unicode/1f939-2640.png?v8",woman_mechanic:"unicode/1f469-1f527.png?v8",woman_office_worker:"unicode/1f469-1f4bc.png?v8",woman_pilot:"unicode/1f469-2708.png?v8",woman_playing_handball:"unicode/1f93e-2640.png?v8",woman_playing_water_polo:"unicode/1f93d-2640.png?v8",woman_scientist:"unicode/1f469-1f52c.png?v8",woman_shrugging:"unicode/1f937-2640.png?v8",woman_singer:"unicode/1f469-1f3a4.png?v8",woman_student:"unicode/1f469-1f393.png?v8",woman_teacher:"unicode/1f469-1f3eb.png?v8",woman_technologist:"unicode/1f469-1f4bb.png?v8",woman_with_headscarf:"unicode/1f9d5.png?v8",woman_with_probing_cane:"unicode/1f469-1f9af.png?v8",woman_with_turban:"unicode/1f473-2640.png?v8",woman_with_veil:"unicode/1f470-2640.png?v8",womans_clothes:"unicode/1f45a.png?v8",womans_hat:"unicode/1f452.png?v8",women_wrestling:"unicode/1f93c-2640.png?v8",womens:"unicode/1f6ba.png?v8",wood:"unicode/1fab5.png?v8",woozy_face:"unicode/1f974.png?v8",world_map:"unicode/1f5fa.png?v8",worm:"unicode/1fab1.png?v8",worried:"unicode/1f61f.png?v8",wrench:"unicode/1f527.png?v8",wrestling:"unicode/1f93c.png?v8",writing_hand:"unicode/270d.png?v8",x:"unicode/274c.png?v8",yarn:"unicode/1f9f6.png?v8",yawning_face:"unicode/1f971.png?v8",yellow_circle:"unicode/1f7e1.png?v8",yellow_heart:"unicode/1f49b.png?v8",yellow_square:"unicode/1f7e8.png?v8",yemen:"unicode/1f1fe-1f1ea.png?v8",yen:"unicode/1f4b4.png?v8",yin_yang:"unicode/262f.png?v8",yo_yo:"unicode/1fa80.png?v8",yum:"unicode/1f60b.png?v8",zambia:"unicode/1f1ff-1f1f2.png?v8",zany_face:"unicode/1f92a.png?v8",zap:"unicode/26a1.png?v8",zebra:"unicode/1f993.png?v8",zero:"unicode/0030-20e3.png?v8",zimbabwe:"unicode/1f1ff-1f1fc.png?v8",zipper_mouth_face:"unicode/1f910.png?v8",zombie:"unicode/1f9df.png?v8",zombie_man:"unicode/1f9df-2642.png?v8",zombie_woman:"unicode/1f9df-2640.png?v8",zzz:"unicode/1f4a4.png?v8"};window&&window.console&&console.info("Docsify emoji plugin has been deprecated as of v4.13"),window.emojify=function(n,e){return!1===Object.prototype.hasOwnProperty.call(i,e)?n:''+e+''}}(); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js b/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js new file mode 100644 index 00000000..f1659f1e --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/prism-bash.min.js @@ -0,0 +1 @@ +!function(e){var t="\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\b",a={pattern:/(^(["']?)\w+\2)[ \t]+\S.*/,lookbehind:!0,alias:"punctuation",inside:null},n={bash:a,environment:{pattern:RegExp("\\$"+t),alias:"constant"},variable:[{pattern:/\$?\(\([\s\S]+?\)\)/,greedy:!0,inside:{variable:[{pattern:/(^\$\(\([\s\S]+)\)\)/,lookbehind:!0},/^\$\(\(/],number:/\b0x[\dA-Fa-f]+\b|(?:\b\d+(?:\.\d*)?|\B\.\d+)(?:[Ee]-?\d+)?/,operator:/--|\+\+|\*\*=?|<<=?|>>=?|&&|\|\||[=!+\-*/%<>^&|]=?|[?~:]/,punctuation:/\(\(?|\)\)?|,|;/}},{pattern:/\$\((?:\([^)]+\)|[^()])+\)|`[^`]+`/,greedy:!0,inside:{variable:/^\$\(|^`|\)$|`$/}},{pattern:/\$\{[^}]+\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\/]|##?|%%?|\^\^?|,,?/,punctuation:/[\[\]]/,environment:{pattern:RegExp("(\\{)"+t),lookbehind:!0,alias:"constant"}}},/\$(?:\w+|[#?*!@$])/],entity:/\\(?:[abceEfnrtv\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\s*\/.*/,alias:"important"},comment:{pattern:/(^|[^"{\\$])#.*/,lookbehind:!0},"function-name":[{pattern:/(\bfunction\s+)[\w-]+(?=(?:\s*\(?:\s*\))?\s*\{)/,lookbehind:!0,alias:"function"},{pattern:/\b[\w-]+(?=\s*\(\s*\)\s*\{)/,alias:"function"}],"for-or-select":{pattern:/(\b(?:for|select)\s+)\w+(?=\s+in\s)/,alias:"variable",lookbehind:!0},"assign-left":{pattern:/(^|[\s;|&]|[<>]\()\w+(?:\.\w+)*(?=\+?=)/,inside:{environment:{pattern:RegExp("(^|[\\s;|&]|[<>]\\()"+t),lookbehind:!0,alias:"constant"}},alias:"variable",lookbehind:!0},parameter:{pattern:/(^|\s)-{1,2}(?:\w+:[+-]?)?\w+(?:\.\w+)*(?=[=\s]|$)/,alias:"variable",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\s*)(\w+)\s[\s\S]*?(?:\r?\n|\r)\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\s*)(["'])(\w+)\2\s[\s\S]*?(?:\r?\n|\r)\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\](?:\\\\)*)"(?:\\[\s\S]|\$\([^)]+\)|\$(?!\()|`[^`]+`|[^"\\`$])*"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\$'(?:[^'\\]|\\[\s\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp("\\$?"+t),alias:"constant"},variable:n.variable,function:{pattern:/(^|[\s;|&]|[<>]\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\s;|&]|[<>]\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\s;|&]|[<>]\()(?:\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\s;|&])/,lookbehind:!0,alias:"class-name"},boolean:{pattern:/(^|[\s;|&]|[<>]\()(?:false|true)(?=$|[)\s;|&])/,lookbehind:!0},"file-descriptor":{pattern:/\B&\d\b/,alias:"important"},operator:{pattern:/\d?<>|>\||\+=|=[=~]?|!=?|<<[<-]?|[&\d]?>>|\d[<>]&?|[<>][&=]?|&[>&]?|\|[&|]?/,inside:{"file-descriptor":{pattern:/^\d/,alias:"important"}}},punctuation:/\$?\(\(?|\)\)?|\.\.|[{}[\];\\]/,number:{pattern:/(^|\s)(?:[1-9]\d*|0)(?:[.,]\d+)?\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=["comment","function-name","for-or-select","assign-left","parameter","string","environment","function","keyword","builtin","boolean","file-descriptor","operator","punctuation","number"],o=n.variable[1].inside,i=0;i]|<(?:[^<>]|<[^<>]*>)*>)*>)?/,lookbehind:!0,greedy:!0,inside:null},builtin:/\b(?:Array|Function|Promise|any|boolean|console|never|number|string|symbol|unknown)\b/}),e.languages.typescript.keyword.push(/\b(?:abstract|declare|is|keyof|readonly|require)\b/,/\b(?:asserts|infer|interface|module|namespace|type)\b(?=\s*(?:[{_$a-zA-Z\xA0-\uFFFF]|$))/,/\btype\b(?=\s*(?:[\{*]|$))/),delete e.languages.typescript.parameter,delete e.languages.typescript["literal-property"];var s=e.languages.extend("typescript",{});delete s["class-name"],e.languages.typescript["class-name"].inside=s,e.languages.insertBefore("typescript","function",{decorator:{pattern:/@[$\w\xA0-\uFFFF]+/,inside:{at:{pattern:/^@/,alias:"operator"},function:/^[\s\S]+/}},"generic-function":{pattern:/#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>(?=\s*\()/,greedy:!0,inside:{function:/^#?(?!\s)[_$a-zA-Z\xA0-\uFFFF](?:(?!\s)[$\w\xA0-\uFFFF])*/,generic:{pattern:/<[\s\S]+/,alias:"class-name",inside:s}}}}),e.languages.ts=e.languages.typescript}(Prism); \ No newline at end of file diff --git a/ruoyi-admin/src/main/resources/static/static/js/search.min.js b/ruoyi-admin/src/main/resources/static/static/js/search.min.js new file mode 100644 index 00000000..9719f653 --- /dev/null +++ b/ruoyi-admin/src/main/resources/static/static/js/search.min.js @@ -0,0 +1 @@ +!function(){function u(e){return e.replace(//,"").replace(/{docsify-ignore}/,"").replace(//,"").replace(/{docsify-ignore-all}/,"").trim()}var f={},m={EXPIRE_KEY:"docsify.search.expires",INDEX_KEY:"docsify.search.index"};function g(e){var n={"&":"&","<":"<",">":">",'"':""","'":"'"};return String(e).replace(/[&<>"']/g,function(e){return n[e]})}function y(e){return e.text||"table"!==e.type||(e.cells.unshift(e.header),e.text=e.cells.map(function(e){return e.join(" | ")}).join(" |\n ")),e.text}function v(e){return e.text||"list"!==e.type||(e.text=e.raw),e.text}function b(o,e,s,c){void 0===e&&(e="");var d,e=window.marked.lexer(e),l=window.Docsify.slugify,p={},h="";return e.forEach(function(e,n){var t,a,i,r;"heading"===e.type&&e.depth<=c?(t=(a=(i=e.text,r={},{str:i=(i=void 0===i?"":i)&&i.replace(/^('|")/,"").replace(/('|")$/,"").replace(/(?:^|\s):([\w-]+:?)=?([\w-%]+)?/g,function(e,n,t){return-1===n.indexOf(":")?(r[n]=t&&t.replace(/"/g,"")||!0,""):e}).trim(),config:r})).str,i=a.config,a=u(e.text),d=i.id?s.toURL(o,{id:l(i.id)}):s.toURL(o,{id:l(g(a))}),t&&(h=u(t)),p[d]={slug:d,title:h,body:""}):(0===n&&(d=s.toURL(o),p[d]={slug:d,title:"/"!==o?o.slice(1):"Home Page",body:e.text||""}),d&&(p[d]?p[d].body?(e.text=y(e),e.text=v(e),p[d].body+="\n"+(e.text||"")):(e.text=y(e),e.text=v(e),p[d].body=e.text||""):p[d]={slug:d,title:"",body:""}))}),l.clear(),p}function p(e){return e&&e.normalize?e.normalize("NFD").replace(/[\u0300-\u036f]/g,""):e}function o(e){var n=[],t=[];Object.keys(f).forEach(function(n){t=t.concat(Object.keys(f[n]).map(function(e){return f[n][e]}))});var a=(e=e.trim()).split(/[\s\-,\\/]+/);1!==a.length&&(a=[].concat(e,a));for(var i=0;il.length&&(t=l.length),a=c&&"..."+c.substring(n,t).replace(a,function(e){return''+e+""})+"...",o+=a)}),0\n\n

    '+e.title+"

    \n

    "+e.content+"

    \n
    \n"}),t.classList.add("show"),a.classList.add("show"),t.innerHTML=r||'

    '+c+"

    ",s.hideOtherSidebarContent&&(i&&i.classList.add("hide"),n&&n.classList.add("hide"))}function l(e){s=e}function h(e,n){var t,a,i=n.router.parse().query.s;l(e),Docsify.dom.style("\n.sidebar {\n padding-top: 0;\n}\n\n.search {\n margin-bottom: 20px;\n padding: 6px;\n border-bottom: 1px solid #eee;\n}\n\n.search .input-wrap {\n display: flex;\n align-items: center;\n}\n\n.search .results-panel {\n display: none;\n}\n\n.search .results-panel.show {\n display: block;\n}\n\n.search input {\n outline: none;\n border: none;\n width: 100%;\n padding: 0.6em 7px;\n font-size: inherit;\n border: 1px solid transparent;\n}\n\n.search input:focus {\n box-shadow: 0 0 5px var(--theme-color, #42b983);\n border: 1px solid var(--theme-color, #42b983);\n}\n\n.search input::-webkit-search-decoration,\n.search input::-webkit-search-cancel-button,\n.search input {\n -webkit-appearance: none;\n -moz-appearance: none;\n appearance: none;\n}\n\n.search input::-ms-clear {\n display: none;\n height: 0;\n width: 0;\n}\n\n.search .clear-button {\n cursor: pointer;\n width: 36px;\n text-align: right;\n display: none;\n}\n\n.search .clear-button.show {\n display: block;\n}\n\n.search .clear-button svg {\n transform: scale(.5);\n}\n\n.search h2 {\n font-size: 17px;\n margin: 10px 0;\n}\n\n.search a {\n text-decoration: none;\n color: inherit;\n}\n\n.search .matching-post {\n border-bottom: 1px solid #eee;\n}\n\n.search .matching-post:last-child {\n border-bottom: 0;\n}\n\n.search p {\n font-size: 14px;\n overflow: hidden;\n text-overflow: ellipsis;\n display: -webkit-box;\n -webkit-line-clamp: 2;\n -webkit-box-orient: vertical;\n}\n\n.search p.empty {\n text-align: center;\n}\n\n.app-name.hide, .sidebar-nav.hide {\n display: none;\n}"),function(e){void 0===e&&(e="");var n=Docsify.dom.create("div",'
    \n \n
    \n \n \n \n \n \n
    \n
    \n
    \n '),e=Docsify.dom.find("aside");Docsify.dom.toggleClass(n,"search"),Docsify.dom.before(e,n)}(i),n=Docsify.dom.find("div.search"),a=Docsify.dom.find(n,"input"),e=Docsify.dom.find(n,".input-wrap"),Docsify.dom.on(n,"click",function(e){return-1===["A","H2","P","EM"].indexOf(e.target.tagName)&&e.stopPropagation()}),Docsify.dom.on(a,"input",function(n){clearTimeout(t),t=setTimeout(function(e){return d(n.target.value.trim())},100)}),Docsify.dom.on(e,"click",function(e){"INPUT"!==e.target.tagName&&(a.value="",d())}),i&&setTimeout(function(e){return d(i)},500)}function x(e,n){var t,a,i,r,o;l(e),t=e.placeholder,a=n.route.path,(r=Docsify.dom.getNode('.search input[type="search"]'))&&("string"==typeof t?r.placeholder=t:(i=Object.keys(t).filter(function(e){return-1u.scrollOffset&&setTimeout(a,150))}),window.addEventListener("resize",a);var f={open:i,close:a,toggle:o,update:function(){var e=0org.springframework.ai spring-ai-ollama-spring-boot-starter + + + org.springframework.ai + spring-ai-core + + + + org.springframework.ai + spring-ai-ollama + diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAgentManageBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAgentManageBo.java index 6fd54c42..097d90a9 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAgentManageBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAgentManageBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatAgentManage; +import org.ruoyi.domain.ChatAgentManage; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAppStoreBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAppStoreBo.java index b77431b5..36a8aca3 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAppStoreBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatAppStoreBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatAppStore; +import org.ruoyi.domain.ChatAppStore; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatGptsBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatGptsBo.java index 2c77aa18..5c97704e 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatGptsBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatGptsBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatGpts; +import org.ruoyi.domain.ChatGpts; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPackagePlanBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPackagePlanBo.java index ac0fdc14..ab000479 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPackagePlanBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPackagePlanBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatPackagePlan; +import org.ruoyi.domain.ChatPackagePlan; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPayOrderBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPayOrderBo.java index 41191d55..e427c15f 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPayOrderBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPayOrderBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatPayOrder; +import org.ruoyi.domain.ChatPayOrder; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPluginBo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPluginBo.java index 4f6357ba..b96d6fcf 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPluginBo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/bo/ChatPluginBo.java @@ -2,7 +2,7 @@ package org.ruoyi.domain.bo; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; -import org.ruoyi.system.domain.ChatPlugin; +import org.ruoyi.domain.ChatPlugin; import org.ruoyi.common.mybatis.core.domain.BaseEntity; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAgentManageVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAgentManageVo.java index bb18e7f5..3ccc1760 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAgentManageVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAgentManageVo.java @@ -1,16 +1,16 @@ -package org.ruoyi.system.domain.vo; +package org.ruoyi.domain.vo; + -import org.ruoyi.system.domain.ChatAgentManage; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; -import annotation.excel.common.org.ruoyi.ExcelDictFormat; -import convert.excel.common.org.ruoyi.ExcelDictConvert; + import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatAgentManage; import java.io.Serial; import java.io.Serializable; -import java.util.Date; + diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAppStoreVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAppStoreVo.java index 24af7081..94840abb 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAppStoreVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatAppStoreVo.java @@ -1,11 +1,12 @@ -package org.ruoyi.system.domain.vo; +package org.ruoyi.domain.vo; + -import org.ruoyi.system.domain.ChatAppStore; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatAppStore; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatGptsVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatGptsVo.java index 1148b3dc..9d515d40 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatGptsVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatGptsVo.java @@ -1,11 +1,12 @@ package org.ruoyi.domain.vo; -import org.ruoyi.system.domain.ChatGpts; + import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatGpts; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatMessageVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatMessageVo.java index bbc6867f..501a1b6d 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatMessageVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatMessageVo.java @@ -1,12 +1,13 @@ package org.ruoyi.domain.vo; import java.math.BigDecimal; -import org.ruoyi.system.domain.ChatMessage; + import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatMessage; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java index 3e256946..56efb598 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatModelVo.java @@ -1,11 +1,12 @@ package org.ruoyi.domain.vo; -import org.ruoyi.system.domain.ChatModel; + import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatModel; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPackagePlanVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPackagePlanVo.java index 484c3d47..39236aee 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPackagePlanVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPackagePlanVo.java @@ -1,12 +1,13 @@ package org.ruoyi.domain.vo; import java.math.BigDecimal; -import org.ruoyi.system.domain.ChatPackagePlan; + import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatPackagePlan; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPayOrderVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPayOrderVo.java index 220d1afd..cfe47330 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPayOrderVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPayOrderVo.java @@ -1,12 +1,12 @@ package org.ruoyi.domain.vo; import java.math.BigDecimal; -import org.ruoyi.system.domain.ChatPayOrder; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; import io.github.linpeilie.annotations.AutoMapper; import lombok.Data; +import org.ruoyi.domain.ChatPayOrder; import java.io.Serial; import java.io.Serializable; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPluginVo.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPluginVo.java index 5246b585..3e900e6f 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPluginVo.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/domain/vo/ChatPluginVo.java @@ -1,6 +1,6 @@ package org.ruoyi.domain.vo; -import org.ruoyi.system.domain.ChatPlugin; +import org.ruoyi.domain.ChatPlugin; import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; import com.alibaba.excel.annotation.ExcelProperty; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAgentManageMapper.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAgentManageMapper.java index 978b213a..7e0769ec 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAgentManageMapper.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAgentManageMapper.java @@ -2,7 +2,7 @@ package org.ruoyi.mapper; import org.ruoyi.domain.ChatAgentManage; -import org.ruoyi.system.domain.vo.ChatAgentManageVo; +import org.ruoyi.domain.vo.ChatAgentManageVo; import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; /** diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAppStoreMapper.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAppStoreMapper.java index 22aef7b3..8d9e8e8e 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAppStoreMapper.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/mapper/ChatAppStoreMapper.java @@ -2,7 +2,7 @@ package org.ruoyi.mapper; import org.ruoyi.domain.ChatAppStore; -import org.ruoyi.system.domain.vo.ChatAppStoreVo; +import org.ruoyi.domain.vo.ChatAppStoreVo; import org.ruoyi.common.mybatis.core.mapper.BaseMapperPlus; /** diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAgentManageService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAgentManageService.java index bf511ddc..61310d08 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAgentManageService.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAgentManageService.java @@ -2,7 +2,7 @@ package org.ruoyi.service; import org.ruoyi.domain.bo.ChatAgentManageBo; -import org.ruoyi.system.domain.vo.ChatAgentManageVo; +import org.ruoyi.domain.vo.ChatAgentManageVo; import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.common.mybatis.core.page.PageQuery; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAppStoreService.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAppStoreService.java index 03a55b8c..495db04e 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAppStoreService.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/IChatAppStoreService.java @@ -2,7 +2,7 @@ package org.ruoyi.service; import org.ruoyi.domain.bo.ChatAppStoreBo; -import org.ruoyi.system.domain.vo.ChatAppStoreVo; +import org.ruoyi.domain.vo.ChatAppStoreVo; import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.common.mybatis.core.page.PageQuery; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAgentManageServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAgentManageServiceImpl.java index abcb4f72..29acb655 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAgentManageServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAgentManageServiceImpl.java @@ -1,10 +1,10 @@ package org.ruoyi.service.impl; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.common.mybatis.core.page.PageQuery; -import com.baomidou.mybatisplus.extension.plugins.pagination.Page; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.core.toolkit.Wrappers; import lombok.RequiredArgsConstructor; @@ -14,7 +14,7 @@ import org.ruoyi.mapper.ChatAgentManageMapper; import org.ruoyi.service.IChatAgentManageService; import org.springframework.stereotype.Service; -import org.ruoyi.system.domain.vo.ChatAgentManageVo; +import org.ruoyi.domain.vo.ChatAgentManageVo; import java.util.List; diff --git a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAppStoreServiceImpl.java b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAppStoreServiceImpl.java index 55a63408..b0e48896 100644 --- a/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAppStoreServiceImpl.java +++ b/ruoyi-modules-api/ruoyi-chat-api/src/main/java/org/ruoyi/service/impl/ChatAppStoreServiceImpl.java @@ -13,9 +13,7 @@ import org.ruoyi.domain.bo.ChatAppStoreBo; import org.ruoyi.mapper.ChatAppStoreMapper; import org.ruoyi.service.IChatAppStoreService; import org.springframework.stereotype.Service; - -import org.ruoyi.system.domain.vo.ChatAppStoreVo; - +import org.ruoyi.domain.vo.ChatAppStoreVo; import java.util.List; import java.util.Map; import java.util.Collection; diff --git a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java index 6aca9009..aa72d761 100644 --- a/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java +++ b/ruoyi-modules-api/ruoyi-knowledge-api/src/main/java/org/ruoyi/chain/loader/ResourceLoaderFactory.java @@ -1,13 +1,12 @@ package org.ruoyi.chain.loader; import lombok.AllArgsConstructor; -import org.ruoyi.chain.loader.ResourceLoader; -import org.ruoyi.chain.loader.TextFileLoader; import org.ruoyi.chain.split.CharacterTextSplitter; import org.ruoyi.chain.split.CodeTextSplitter; import org.ruoyi.chain.split.MarkdownTextSplitter; import org.ruoyi.chain.split.TokenTextSplitter; -import org.ruoyi.knowledge.constant.FileType; + +import org.ruoyi.constant.FileType; import org.springframework.stereotype.Component; @AllArgsConstructor diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml index 877d990a..34b27cd5 100644 --- a/ruoyi-modules/pom.xml +++ b/ruoyi-modules/pom.xml @@ -22,8 +22,14 @@ ruoyi-chat ruoyi-system ruoyi-generator + ruoyi-admin + + 4.5.14 + 2.15.2 + + org.ruoyi @@ -34,6 +40,34 @@ org.ruoyi ruoyi-common-idempotent + + + org.ruoyi + ruoyi-common-security + + + + org.ruoyi + ruoyi-common-sensitive + + + + org.ruoyi + ruoyi-common-tenant + + + + com.fasterxml.jackson.dataformat + jackson-dataformat-xml + ${jackson.version} + + + + org.apache.httpcomponents + httpmime + ${httpclient.version} + + diff --git a/ruoyi-modules/ruoyi-chat/pom.xml b/ruoyi-modules/ruoyi-chat/pom.xml index 5749f4e8..2a14fb14 100644 --- a/ruoyi-modules/ruoyi-chat/pom.xml +++ b/ruoyi-modules/ruoyi-chat/pom.xml @@ -114,20 +114,6 @@ ruoyi-system-api - - org.springframework.ai - spring-ai-core - 1.0.0-M6 - compile - - - - org.springframework.ai - spring-ai-ollama - 1.0.0-M6 - compile - - diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAgentManageController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAgentManageController.java index 935725d2..fbc94aa1 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAgentManageController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAgentManageController.java @@ -8,8 +8,10 @@ import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.idempotent.annotation.RepeatSubmit; +import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.common.web.core.BaseController; import org.ruoyi.domain.bo.ChatAgentManageBo; +import org.ruoyi.domain.vo.ChatAgentManageVo; import org.ruoyi.service.IChatAgentManageService; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; @@ -19,8 +21,6 @@ import org.ruoyi.common.core.domain.R; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; import org.ruoyi.common.log.enums.BusinessType; -import org.ruoyi.system.domain.vo.ChatAgentManageVo; -import org.ruoyi.common.mybatis.core.page.TableDataInfo; /** * 智能体管理 diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAppStoreController.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAppStoreController.java index 4d3ae9d2..fc5c9862 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAppStoreController.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/controller/chat/ChatAppStoreController.java @@ -8,7 +8,9 @@ import jakarta.validation.constraints.*; import cn.dev33.satoken.annotation.SaCheckPermission; import org.ruoyi.common.excel.utils.ExcelUtil; import org.ruoyi.common.idempotent.annotation.RepeatSubmit; +import org.ruoyi.common.mybatis.core.page.TableDataInfo; import org.ruoyi.domain.bo.ChatAppStoreBo; +import org.ruoyi.domain.vo.ChatAppStoreVo; import org.ruoyi.service.IChatAppStoreService; import org.springframework.web.bind.annotation.*; import org.springframework.validation.annotation.Validated; @@ -19,8 +21,6 @@ import org.ruoyi.common.core.domain.R; import org.ruoyi.common.core.validate.AddGroup; import org.ruoyi.common.core.validate.EditGroup; import org.ruoyi.common.log.enums.BusinessType; -import org.ruoyi.system.domain.vo.ChatAppStoreVo; -import org.ruoyi.common.mybatis.core.page.TableDataInfo; /** * 应用商店 diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java index aa70c9ae..83f27001 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/listener/SSEEventSourceListener.java @@ -12,8 +12,8 @@ import okhttp3.sse.EventSource; import okhttp3.sse.EventSourceListener; import org.jetbrains.annotations.NotNull; import org.ruoyi.chat.service.chat.IChatCostService; -import org.ruoyi.common.chat.domain.request.ChatRequest; import org.ruoyi.common.chat.entity.chat.ChatCompletionResponse; +import org.ruoyi.common.chat.request.ChatRequest; import org.ruoyi.common.core.utils.SpringUtils; import org.ruoyi.common.core.utils.StringUtils; import org.springframework.beans.factory.annotation.Autowired; diff --git a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/MjOkHttpUtil.java b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/MjOkHttpUtil.java index f7d056af..f7b43f7a 100644 --- a/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/MjOkHttpUtil.java +++ b/ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/util/MjOkHttpUtil.java @@ -5,12 +5,13 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import okhttp3.*; import org.ruoyi.common.core.service.ConfigService; -import org.ruoyi.system.domain.bo.SysModelBo; -import org.ruoyi.system.domain.vo.SysModelVo; -import org.ruoyi.system.service.ISysModelService; +import org.ruoyi.domain.bo.ChatModelBo; +import org.ruoyi.domain.vo.ChatModelVo; +import org.ruoyi.service.IChatModelService; import org.springframework.stereotype.Component; import java.io.IOException; + import java.util.List; import java.util.concurrent.TimeUnit; @@ -22,7 +23,7 @@ import java.util.concurrent.TimeUnit; @Slf4j public class MjOkHttpUtil { - private final ISysModelService sysModelService; + private final IChatModelService chatModelService; private final ConfigService configService; @@ -70,13 +71,12 @@ public class MjOkHttpUtil { @PostConstruct public void init() { - SysModelBo sysModelBo = new SysModelBo(); - sysModelBo.setModelName("midjourney"); - List sysModelList = sysModelService.queryList(sysModelBo); - if (!sysModelList.isEmpty()) { - SysModelVo model = sysModelList.get(0); - this.apiKey = model.getApiKey(); - this.apiHost = model.getApiHost(); + ChatModelBo sysModelBo = new ChatModelBo(); + sysModelBo.setModelName(""); + ChatModelVo midjourney = chatModelService.selectModelByName("midjourney"); + if (midjourney != null) { + this.apiKey = midjourney.getApiKey(); + this.apiHost = midjourney.getApiHost(); } } diff --git a/ruoyi-modules/ruoyi-system/pom.xml b/ruoyi-modules/ruoyi-system/pom.xml index 5290a5f8..3f7085d5 100644 --- a/ruoyi-modules/ruoyi-system/pom.xml +++ b/ruoyi-modules/ruoyi-system/pom.xml @@ -16,11 +16,6 @@ system系统模块 - - 4.5.14 - 2.15.2 - - @@ -51,37 +46,6 @@ ruoyi-common-sms - - org.ruoyi - ruoyi-common-tenant - - - - org.ruoyi - ruoyi-common-security - - - - org.ruoyi - ruoyi-common-web - - - - org.ruoyi - ruoyi-common-idempotent - - - - org.ruoyi - ruoyi-common-sensitive - - - - - org.ruoyi - ruoyi-common-chat - - org.ruoyi ruoyi-common-mail @@ -92,18 +56,6 @@ ruoyi-system-api - - com.fasterxml.jackson.dataformat - jackson-dataformat-xml - ${jackson.version} - - - - org.apache.httpcomponents - httpmime - ${httpclient.version} - -