121 Commits

Author SHA1 Message Date
wangle
bf7b5eac72 fix:修复上下文消息构建顺序,确保AI正确理解对话上下文
消息顺序调整为:历史消息 → 知识库内容 → 当前用户消息

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 22:13:32 +08:00
wangle
d602b805bd docs:更新技术栈版本号并清理文档
- 更新后端架构版本为 Spring Boot 3.5.8 + Langchain4j
- 删除 rag-failures.md 和文件上传接口文档
- 重命名 mcp-api-spec.md 为 MCP工具模块接口文档.md

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-07 21:04:31 +08:00
ageerle
9cf18904bb Merge pull request #284 from MuSan-Li/main
添加可观测性功能
2026-04-07 10:04:05 +08:00
evo
2f39fa0f53 feat:调整可观测性监听器逻辑 2026-04-05 21:36:53 +08:00
evo
d2005cfa48 feat:调整可观测性监听器逻辑 2026-04-05 21:34:41 +08:00
evo
4e38f853f3 feat:修复登录校验 & 调整主启动类的kill port 逻辑 2026-04-02 10:07:26 +08:00
evo
3cfb185dde feat:增加可观测性监听器 调整思考输出监听日志 2026-04-01 23:11:54 +08:00
evo
ef99c540bb feat:增加可观测性的相关监听器 & 修复前端问答报错outputkey问题 2026-04-01 22:32:01 +08:00
ageerle
3071bfd0f9 Merge pull request #282 from Anush008/main
docs: Docker Compose setup for Qdrant
2026-03-28 20:33:25 +08:00
Anush008
7bb938c145 docs: Docker Compose setup for Qdrant 2026-03-28 13:37:53 +05:30
ageerle
75b21d3633 Merge pull request #281 from Anush008/main
feat: Adds support for Qdrant vector search
2026-03-27 21:51:03 +08:00
Anush008
7ed9d8def4 chore: Rename METADATA_DOC_ID_KEY 2026-03-27 18:36:30 +05:30
Anush008
63ed7ddb02 feat: Adds support for Qdrant vector search 2026-03-27 18:31:05 +05:30
ageerle
11696a016d fix: 修复文件类型匹配和知识库切割配置问题
1. 修复 ResourceLoaderFactory 文件扩展名匹配问题
   - 去除扩展名前导点,确保 .pdf 能正确匹配 PDF 解析器
   - 修复 PDF/Word/Excel 等文件走错解析逻辑的问题

2. 优化文本切割器动态配置
   - CharacterTextSplitter 和 ExcelTextSplitter 支持从知识库读取配置
   - 根据 kid 查询 separator、textBlockSize、overlapChar
   - 查询失败时降级使用默认配置

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-25 18:51:01 +08:00
ageerle
1a10104751 docs: 更新README文档,同步中英文版本
- 移除优秀开源项目推荐章节
- 英文版添加Docker部署完整文档
- 英文版添加技术架构详细描述
- 英文版添加RAG排查手册链接
- 统一核心功能表格格式

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 13:02:46 +08:00
ageerle
f95cb17933 chore: 删除ruoyi-modules-api模块
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:31:09 +08:00
ageerle
0687b49542 Merge branch 'v3.0.0' into main
合并 v3.0.0 分支到 main,包含以下主要更新:
- 重构聊天模块架构,引入Handler模式
- 添加 Docker 部署支持
- 恢复 MCP 模块功能
- 工作流与大模型聊天对话整合
- 多项 bug 修复和文档更新

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-21 12:15:40 +08:00
ageerle
27ad00ac3a refactor: 抽离特殊聊天模式处理逻辑
- 将工作流、人机交互恢复、思考模式处理逻辑抽离为独立方法
- 新增 handleSpecialChatModes 方法统一处理特殊模式
- 新增 handleThinkingMode 方法专门处理思考模式
- 简化 sseChat 方法结构,提高代码可读性

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 10:38:54 +08:00
ageerle
c84d6247b0 refactor: 重构聊天模块架构
- 删除废弃的ChatMessageDTO、ChatContext、AbstractChatMessageService等类
- 迁移ChatServiceFactory和IChatMessageService到ruoyi-chat模块
- 重构ChatHandler体系,移除DefaultChatHandler和ChatContextBuilder
- 优化SSE消息处理,新增SseEventDto
- 简化各AI服务提供商实现类代码
- 优化工作流节点消息处理逻辑

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-20 01:20:41 +08:00
ageerle
f582f38570 docs: 整理Docker配置文件并更新文档
- 将Docker相关配置文件移动到docs/docker/ruoyi-ai/目录
- 更新README.md核心亮点表格格式
- 新增流程编排模块详细说明文档

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-19 15:22:47 +08:00
ageerle
13800dc389 Merge pull request #277 from XiaoEns/v3.0.0
fix: 修复知识库附件上传乱码问题
2026-03-17 22:07:32 +08:00
xiaoen
619d9b1e84 fix: 兼容旧代码,添加deepseek服务调用 2026-03-17 21:30:56 +08:00
xiaoen
556cc93f14 fix: 修复知识库附件上传乱码问题 2026-03-17 18:57:30 +08:00
ageerle
a50375616e Merge pull request #276 from LM20230311/v3.0.0
V3.0.0
2026-03-17 14:09:52 +08:00
LM20230311
e33447d023 Merge branch 'v3.0.0' of https://github.com/ageerle/ruoyi-ai into v3.0.0 2026-03-17 13:48:21 +08:00
LM20230311
7be277b3e6 Merge branch 'v3.0.0-deploy' into v3.0.0 2026-03-17 13:47:27 +08:00
LM20230311
5fa385e90b docs: add Docker deployment instructions and service port mappings to README; update sys_client table in MySQL script 2026-03-17 11:09:13 +08:00
LM20230311
0a78966737 chore: update UPSTREAM_HOST configuration in docker-compose-all.yaml to remove http:// prefix 2026-03-17 10:38:43 +08:00
LM20230311
0eb7f00867 chore: add environment variables for backend API configuration in docker-compose-all.yaml 2026-03-16 17:14:01 +08:00
LM20230311
00ce7f2d98 chore: update port mappings in docker-compose.yaml for MySQL, Weaviate, and backend services 2026-03-16 15:32:27 +08:00
ageerle
003c066361 chore(sql): 更新数据库脚本,移除chat_config表
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:57:55 +08:00
ageerle
a5e7c59fd4 refactor: 重构项目架构,优化向量服务
- 移除 Graph 知识图谱相关模块(Neo4j、GraphRAG等)
- 移除 demo、job、wechat 示例模块,简化项目结构
- 修复向量维度获取方式,改为从数据库配置读取
- 添加 gRPC BOM 依赖管理,解决 Milvus SDK 版本冲突
- 新增 PPIO 服务和 Embedding 提供者支持
- 清理冗余代码和未使用的依赖

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-15 23:39:30 +08:00
ageerle
accac603cf chore(sql): 更新数据库脚本v3版本
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 14:16:45 +08:00
ageerle
7c96c730e6 refactor(chat): 重构聊天服务架构,引入Handler模式
主要变更:
1. 移除ruoyi-ai-copilot模块
2. 重构docker配置目录结构,统一迁移至docs/docker/
3. 聊天服务引入Handler模式:
   - 新增ChatHandler接口及多种实现
   - DefaultChatHandler: 默认聊天处理
   - AgentChatHandler: Agent模式处理
   - WorkflowChatHandler: 工作流处理
   - ResumeChatHandler: 恢复会话处理
   - ChatContextBuilder: 上下文构建器
4. 简化AbstractStreamingChatService和ChatServiceFacade代码
5. 优化各Provider实现,统一代码风格

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-14 14:14:56 +08:00
LM20230311
a2dbdb30ff fix: remove unnecessary COPY command for ruoyi-modules-api in Dockerfile.backend 2026-03-11 09:57:47 +08:00
LM20230311
772e4af9bf Merge remote-tracking branch 'upstream/v3.0.0' into v3.0.0-deploy 2026-03-11 09:35:48 +08:00
ageerle
e601eb6db5 feat(wechat): 修复微信公众号无法登录 2026-03-09 10:27:53 +08:00
evo
84dbc2cfbf feat:恢复mcp模块 动态agent 2026-03-08 22:41:24 +08:00
evo
f160ec714b feat-恢复mcp模块 2026-03-07 15:53:06 +08:00
ageerle
a8bd4b47a0 chore: 移除项目文档和技术交流链接
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:44:07 +08:00
ageerle
6c4c661516 chore: 移除项目文档和技术交流链接
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:43:54 +08:00
ageerle
b85c17a126 refactor: 重构Issue模板为通用格式
- 删除企业合作登记模板
- 新增漏洞报告模板
- 新增想法建议模板
- 新增自定义模板

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:39:19 +08:00
ageerle
a59ddf6070 refactor: 重构Issue模板为通用格式
- 删除企业合作登记模板
- 新增漏洞报告模板
- 新增想法建议模板
- 新增自定义模板

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:39:06 +08:00
ageerle
797ecbb054 feat: 新增联系人/联系方式字段并添加填写示例
- 新增联系人/联系方式字段,支持登记后主动联系
- 在可复制模板中添加完整填写示例

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:30:15 +08:00
ageerle
b6b78afea9 refactor: 优化企业合作登记模板格式
- 改为评论登记模式,用户在Issue下评论填写
- 提供格式预览和可复制模板
- 新增公司Logo和项目Logo字段
- 移除联系方式模块,保护隐私

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:20:31 +08:00
ageerle
0690156362 refactor: 优化企业合作登记模板格式
- 改为评论登记模式,用户在Issue下评论填写
- 提供格式预览和可复制模板
- 新增公司Logo和项目Logo字段
- 移除联系方式模块,保护隐私

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:19:27 +08:00
ageerle
02240f3fd0 feat: 添加企业AI应用合作登记Issue模板
- 新增企业合作登记模板,用于收集企业AI应用需求
- 包含基本信息、AI应用需求、联系方式三个模块
- 预设筛选字段便于评估合作匹配度

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 11:07:25 +08:00
ageerle
dc1e84bc52 feat: 添加企业AI应用合作登记Issue模板
- 新增企业合作登记模板,用于收集企业AI应用需求
- 包含基本信息、AI应用需求、联系方式三个模块
- 预设筛选字段便于评估合作匹配度

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-06 10:57:53 +08:00
ageerle
4977df0ba8 feat: 更新项目文档 2026-03-06 10:27:45 +08:00
ageerle
27211b67f9 feat: 更新项目文档 2026-03-06 10:20:15 +08:00
LM20230311
1600ab384e feat: 支持手动挂载数据卷; 2026-03-05 09:35:27 +08:00
LM20230311
418805a1ef feat: 源码docker部署完成; 2026-03-05 09:27:34 +08:00
LM20230311
4c4b52bca7 feat: 忽略data目录; 2026-03-05 09:07:10 +08:00
LM20230311
7245259bc4 fix: 忽略所有错误以确保SQL脚本继续执行 2026-03-04 17:57:08 +08:00
LM20230311
6690c8204c fix: 修复表数量异常问题; 2026-03-04 17:56:20 +08:00
LM20230311
d8fc597f85 fix: 解决mysql容器长时间建表导致失败问题; 2026-03-04 17:34:38 +08:00
evo
7f1146ecae Merge pull request #272 from MuSan-Li/v3.0.0
fix: 还原 McpAgent 为通用工具调用版本
2026-03-04 16:37:28 +08:00
evo
0130028952 fix: 还原 McpAgent 为通用工具调用版本 2026-03-04 16:34:56 +08:00
LM20230311
5a716da5a6 feat: 添加docker部署文件; 2026-03-04 16:31:54 +08:00
evo
2470ec7573 Merge pull request #271 from MuSan-Li/feature-20260218-add-mcp-model
增加McpAgent空格
2026-03-04 14:36:32 +08:00
evo
e3fb25fba6 增加McpAgent空格 2026-03-04 14:32:41 +08:00
ageerle
a916f14efc Merge pull request #268 from onestardao/main
docs: add structured RAG 16-problem troubleshooting guide and README entry
2026-03-03 10:40:32 +08:00
PSBigBig × MiniPS
523628ade6 docs: add structured RAG 16-problem troubleshooting guide and README entry 2026-03-02 19:01:59 +08:00
PSBigBig × MiniPS
2259a2f717 docs: add structured RAG 16-problem troubleshooting guide and README entry
This commit introduces a structured RAG troubleshooting guide based on a fixed 16-problem failure map.

Changes include:

1. Added a dedicated RAG troubleshooting document:
   - docs/troubleshooting/rag-failures.md
   - Includes full 16-problem map (No.1–No.16) with layer tags [IN]/[RE]/[ST]/[OP]
   - Adds symptom-based entry points
   - Adds layer-based diagnostics section
   - Adds issue reporting template referencing No.X labels

2. Updated README.md:
   - Added entry link under the "使用文档" section
   - Direct link to the new RAG troubleshooting guide
   - Keeps README structure and tone consistent

No functional changes.
Documentation only.
2026-03-02 18:51:36 +08:00
PSBigBig × MiniPS
8df37274da docs: add RAG answer troubleshooting guide 2026-03-02 17:44:59 +08:00
PSBigBig × MiniPS
393057ab24 docs: add RAG answer troubleshooting guide 2026-03-02 17:41:47 +08:00
ageerle
2aa7e0f4f1 Merge pull request #267 from StevenJack666/v3.0.0
V3.0.0
2026-03-02 09:10:12 +08:00
steve
b2d2fb34b8 Merge branch 'ageerle:v3.0.0' into v3.0.0 2026-03-01 11:37:10 +08:00
zhang
c1e2a03178 解决冲突 2026-03-01 11:29:58 +08:00
zhang
fd38d2030e 修改异常节点 2026-02-28 11:53:36 +08:00
zhang
a42f881b67 Merge branch 'vFuture3.0.0' into v3.0.0 2026-02-27 17:35:42 +08:00
zengxb
20d531c0db context:新增工作流节点提供模板消息输出以及智谱大模型Chat对话接入 2026-02-27 14:53:07 +08:00
ageerle
1e6046cf52 feat: 移除数字人模块 2026-02-27 14:00:57 +08:00
zhang
495f2de6ef Merge remote-tracking branch 'origin/v3.0.0' into v3.0.0 2026-02-27 10:30:33 +08:00
zhang
e97bd4e201 去掉分号 2026-02-27 10:14:53 +08:00
zhang
70e5e393ef Merge branch 'work_flow_v3.0' into v3.0.0
# Conflicts:
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/chat/impl/ChatServiceFacade.java
2026-02-26 14:48:19 +08:00
zengxb
8954f59cd7 context:工作流和Ai Chat对话消息功能整合 2026-02-26 14:36:33 +08:00
ageerle
c78b1a14a9 feat: 增加ppio厂商支持 2026-02-25 21:20:22 +08:00
ageerle
e768c4b356 feat: 调整默认sql脚本 2026-02-24 22:46:47 +08:00
zhang
d059f50ba6 配置信息修改 2026-02-24 16:09:37 +08:00
zhang
26bcfbba8a 修改数据库读取工具 2026-02-24 16:07:18 +08:00
zengxb
d6e4a50d6e context:根据模型分类找到实现类修改为由模型供应商找到实现类(保持工作流和对话流程一致) 2026-02-24 10:58:11 +08:00
zengxb
0a115f289e context:通义万相文生图节点功能以及发送邮箱和HTTP请求节点调研 2026-02-24 10:34:26 +08:00
ageerle
31e8df8bc0 Merge pull request #262 from MuSan-Li/feature-20260218-add-mcp-model
add mcp model
2026-02-23 22:57:44 +08:00
evo
ee477213e0 优化mcp模块功能 2026-02-23 18:21:31 +08:00
evo
1e6e236d3c 优化导出报错提示 2026-02-23 16:07:38 +08:00
evo
593a0d0049 增加mcp工具模块 2026-02-23 16:07:13 +08:00
ageerle
d4f8f91893 Merge pull request #259 from StevenJack666/v3.0.0
chat对话接口如参改为ChatContext,方便后续扩展
2026-02-15 15:54:21 +08:00
zhang
f25ebdf9ec 去掉多余字符 2026-02-14 22:07:09 +08:00
zhang
32b8144b56 Merge branch 'work_flow_v3.0' into v3.0.0
# Conflicts:
#	ruoyi-common/ruoyi-common-chat/src/main/java/org/ruoyi/common/chat/Service/IChatService.java
#	ruoyi-modules/ruoyi-aiflow/src/main/java/org/ruoyi/workflow/workflow/WorkflowUtil.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/chat/impl/AbstractStreamingChatService.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/chat/impl/ChatServiceFacade.java
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/service/chat/impl/provider/QianWenChatServiceImpl.java
2026-02-14 21:14:50 +08:00
zengxb
b40805cb57 context:公共聊天接口调整为对话上下文对象传输 2026-02-14 10:55:53 +08:00
steve
008f64617f Merge pull request #4 from StevenJack666/feature-v3.0.0
Feature v3.0.0
2026-02-14 10:49:52 +08:00
zhang
3539e222d2 init 2026-02-14 10:48:43 +08:00
zhang
c4d1ea974d init 2026-02-14 10:48:33 +08:00
ageerle
ace7e961a4 Merge pull request #258 from StevenJack666/v3.0.0
修改千问模型调用逻辑
2026-02-14 10:47:14 +08:00
steve
5dc21653c0 Merge pull request #3 from StevenJack666/feature-v3.0.0
Feature v3.0.0
2026-02-14 10:44:13 +08:00
zhang
d0d4b2229f 合并v3.0.0使用 2026-02-14 10:08:29 +08:00
zhang
07c9727345 去掉空格 2026-02-14 09:54:24 +08:00
zhang
689adf079d 修改千问模型调用逻辑 2026-02-13 22:41:08 +08:00
ageerle
1d1b72c6e2 Merge pull request #257 from StevenJack666/v3.0.0
V3.0.0
2026-02-13 19:02:16 +08:00
zhang
d9bdce1d8a init 参数调整 2026-02-13 18:37:33 +08:00
zhang
885d46a4aa AI工作流优化 2026-02-13 18:14:39 +08:00
zengxb
420e05ecf3 context:工作流与大模型聊天对话整合(新增Common-Chat公共对话接口) 2026-02-13 17:56:55 +08:00
ageerle
afa3c78180 Merge pull request #254 from StevenJack666/v3.0.0
修复异常场景,请求链接无法关闭问题
2026-02-11 17:03:44 +08:00
ageerle
ee8c882b6f Merge pull request #256 from StevenJack666/main
修改AI工作流后端逻辑
2026-02-11 17:03:31 +08:00
zhang
69ec2a33a4 init 2026-02-09 17:47:18 +08:00
zhang
1cd8ae1cd9 人机交互节点逻辑修改 2026-02-09 17:43:29 +08:00
zhang
91a44e1ba8 非推理模式下,大模型调用失败。连接未关闭,且没有返回错误信息 2026-02-09 15:33:11 +08:00
zhang
4a36aaa780 修复异常场景,请求链接无法关闭问题 2026-02-09 14:58:46 +08:00
ageerle
c78b456dbf feat: 提交证书 2026-02-06 03:14:13 +08:00
ageerle
e8c187125f feat: 更新功能建议&bug提交文档 2026-02-06 03:08:33 +08:00
ageerle
7b8cfe02a1 v3.0.0 init 2026-02-06 03:00:23 +08:00
ageerle
eb2e8f3ff8 Merge pull request #250 from RobustH/main
feat: 对接ragflow的聊天助手
2025-12-25 04:56:05 +08:00
RobustH
2f7bff0bf0 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/chat/impl/RagFlowServiceImpl.java
2025-12-22 21:06:51 +08:00
Robust_H
c89f9657f3 feat: 添加RAGFLOW聊天服务实现 2025-12-22 21:06:13 +08:00
Robust_H
588c1730a6 feat: 添加RAGFLOW聊天服务实现 2025-12-19 21:08:19 +08:00
ageerle
3f1506b34b Merge pull request #249 from OpenX123/feature/添加多个实用MCP工具
Feature/添加多个实用mcp工具
2025-12-12 22:51:00 +08:00
OpenX123
deea428bfa 动态加载文件操作、图片搜索、PlantUML生成、网页搜索、终端命令、文档解析等实用MCP工具 2025-12-12 13:09:34 +08:00
OpenX123
66f133f089 Revert "为MCP服务器添加文件操作、图片搜索、PlantUML生成、网页搜索、终端命令、文档解析等实用功能"
This reverts commit 77aeabb4be.
2025-12-12 12:00:46 +08:00
ageerle
e5ed5d0ef6 Merge pull request #241 from stageluo/main
新增知识库、http分支工作流节点
2025-12-12 11:46:29 +08:00
OpenX123
77aeabb4be 为MCP服务器添加文件操作、图片搜索、PlantUML生成、网页搜索、终端命令、文档解析等实用功能 2025-12-11 20:41:04 +08:00
1578 changed files with 53042 additions and 76358 deletions

32
.editorconfig Normal file
View File

@@ -0,0 +1,32 @@
# http://editorconfig.org
root = true
# 所有文件 ([*])
# 使用空格缩进,每级 4 个空格
# UTF-8 编码
# Unix 风格换行符 (LF)
# 自动删除行尾空格
# 文件末尾自动添加空行
# JSON/YAML 文件:
# 缩进改为 2 个空格
# Markdown 文件:
# 不在末尾添加空行
# 保留行尾空格Markdown 语法需要)
# 作用:
# 支持此标准的编辑器VS Code、IDEA、Sublime 等)会自动读取并应用这些规则,确保不同开发者使用不同编辑器时,代码格式保持一致。
[*]
indent_style = space
indent_size = 4
charset = utf-8
end_of_line = lf
trim_trailing_whitespace = true
insert_final_newline = true
[*.{json,yml,yaml}]
indent_size = 2
[*.md]
insert_final_newline = false
trim_trailing_whitespace = false

41
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,41 @@
---
name: 漏洞报告
about: 报告项目中的Bug或安全问题
title: '[Bug] '
labels: 'bug'
assignees: ''
---
## 问题描述
简要描述遇到的问题:
## 复现步骤
1.
2.
3.
## 期望行为
描述你期望发生的情况:
## 实际行为
描述实际发生的情况:
## 环境信息
| 项目 | 信息 |
|:---|:---|
| 操作系统 | |
| JDK版本 | |
| 项目版本 | |
## 截图/日志
如有相关信息,请在此粘贴:
## 补充说明
其他补充信息:

1
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1 @@
blank_issues_enabled: true

15
.github/ISSUE_TEMPLATE/custom.md vendored Normal file
View File

@@ -0,0 +1,15 @@
---
name: 自定义
about: 其他问题或讨论
title: ''
labels: ''
assignees: ''
---
## 描述
请详细描述你的问题或需求:
## 补充信息
如有其他补充,请在此填写:

View File

@@ -0,0 +1,57 @@
---
name: 企业AI应用合作登记
about: 登记企业信息与合作意向,获取免费技术支持
title: '[合作登记] 企业AI应用需求登记'
labels: '合作登记'
assignees: ''
---
## 登记说明
感谢您关注 RuoYi AI我们团队今年的重点是帮助企业落地AI应用如果贵公司符合要求我们可以提供**免费的技术支持**。
请在下方评论中填写登记信息,格式如下:
---
## 登记格式预览
| 字段 | 内容 |
|:---|:---|
| 公司名称 | (必填) |
| 公司Logo地址 | (可选) |
| 所属行业 | (必填) |
| 公司所在地 | (必填) |
| 项目名称 | (必填) |
| 项目Logo地址 | (可选) |
| 项目简介 | (必填) |
| 当前AI应用状态 | □ 尚未开始 □ 规划中 □ 已有初步应用 □ 已有成熟应用 |
| 计划落地时间 | □ 1个月内 □ 1-3个月 □ 3-6个月 □ 6个月以上 |
| 当前痛点或挑战 | (可选) |
| 公司简介 | (可选) |
---
## 可复制格式
复制下方内容并在评论中填写:
```
| 字段 | 内容 |
|:---|:---|
| 公司名称 | |
| 公司Logo地址 | |
| 所属行业 | |
| 公司所在地 | |
| 项目名称 | |
| 项目Logo地址 | |
| 项目简介 | |
| 当前AI应用状态 | |
| 计划落地时间 | |
| 当前痛点或挑战 | |
| 公司简介 | |
```
---
> **温馨提示**:提交的信息仅用于合作沟通,不会对外公开。

View File

@@ -0,0 +1,31 @@
---
name: 想法建议
about: 提出新功能建议或改进想法
title: '[Feature] '
labels: 'enhancement'
assignees: ''
---
## 建议类型
□ 新功能 □ 功能改进 □ 文档完善 □ 其他
## 建议描述
清晰描述你的建议内容:
## 使用场景
描述这个功能在什么场景下会用到:
## 期望效果
描述你期望的效果:
## 参考示例
如有类似的参考实现或产品,请提供链接:
## 补充说明
其他补充信息:

BIN
.gitignore vendored

Binary file not shown.

View File

@@ -1,6 +1,6 @@
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2023 ruoyi-ai Copyright (c) 2026 ruoyi-ai
Permission is hereby granted, free of charge, to any person obtaining a copy of Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in this software and associated documentation files (the "Software"), to deal in

197
README.md
View File

@@ -15,62 +15,36 @@
</a> </a>
</p> </p>
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
<img src="image/00.png" alt="RuoYi AI Logo" width="120" height="120">
### 企业级AI助手平台 ### 企业级AI助手平台
*开箱即用的智能AI平台深度集成 FastGPT、扣子(Coze)、DIFY 等主流AI平台提供先进的RAG技术、知识图谱、数字人和AI流程编排能力* *开箱即用的全栈AI平台支持多智能体协同、Supervisor模式编排、多种决策模式、RAG技术和流程编排能力*
**[🇺🇸 English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** | * **[English](README_EN.md)** | **[📖 使用文档](https://doc.pandarobot.chat)** |
*[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | * **[🚀 在线体验](https://web.pandarobot.chat)** | **[🐛 问题反馈](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
*[💡 功能建议](https://github.com/ageerle/ruoyi-ai/issues)**
</div> </div>
## ✨ 核心亮点 ## ✨ 核心亮点
### 智能AI引擎 | 模块 | 现有能力
|:----------:|---
- **多模型接入**:支持 OpenAI GPT-4、Azure、ChatGLM、通义千问、智谱AI 等主流模型 | **模型管理** | 多模型接入(OpenAI/DeepSeek/通义/智谱)、多模态理解、Coze/DIFY/FastGPT平台集成
- **AI平台集成**:深度集成 **FastGPT**、**扣子(Coze)**、**DIFY** 等主流AI应用平台 | **知识管理** | 本地RAG + 向量库(Milvus/Weaviate/Qdrant) + 文档解析
- **Spring AI MCP 集成**基于模型上下文协议打造可扩展的AI工具生态系统 | **工具管理** | Mcp协议集成、Skills能力 + 可扩展工具生态
- **实时流式对话**:采用 SSE/WebSocket 技术,提供丝滑的对话体验 | **流程编排** | 可视化工作流设计器、节点拖拽编排、SSE流式执行,目前已经支持模型调用,邮件发送,人工审核等节点
- **AI 编程助手**:内置智能代码分析和项目脚手架生成能力 | **多智能体** | 基于Langchain4j的Agent框架、Supervisor模式编排,支持多种决策模型
### AI平台生态集成
- **FastGPT 深度集成**:原生支持 FastGPT API包括知识库检索、工作流编排和上下文管理
- **扣子(Coze) 官方SDK**集成字节跳动扣子平台官方SDK支持Bot对话和流式响应
- **DIFY 完整兼容**:使用 DIFY Java Client支持应用编排、工作流和知识库管理
- **统一聊天接口**:提供统一的聊天服务接口,支持多平台无缝切换和负载均衡
### 本地化RAG方案
- **私有知识库**:基于 Langchain4j 框架 + BGE-large-zh-v1.5 中文向量模型
- **多种向量库**:支持 Milvus、Weaviate、Qdrant 等主流向量数据库
- **数据安全可控**:支持完全本地部署,保护企业数据隐私
- **灵活模型部署**:兼容 Ollama、vLLM 等本地推理框架
### AI创作工具
- **AI 绘画创作**:深度集成 DALL·E-3、MidJourney、Stable Diffusion
- **智能PPT生成**:一键将文本内容转换为精美演示文稿
- **多模态理解**:支持文本、图片、文档等多种格式的智能处理
### 知识图谱与智能编排
- **知识图谱构建**:自动从文档和对话中提取实体关系,构建可视化知识网络
- **AI 流程编排**可视化工作流设计器支持复杂AI任务的编排和自动化执行
- **数字人交互**:集成数字人形象,提供更自然的人机交互体验
- **智能推理引擎**:基于知识图谱的智能推理和问答能力
## 🚀 快速体验 ## 🚀 快速体验
### 在线演示 ### 在线演示
- **用户端体验**[web.pandarobot.chat](https://web.pandarobot.chat) (账号admin 密码admin123) | 平台 | 地址 | 账号 |
- **管理后台**[admin.pandarobot.chat](https://admin.pandarobot.chat) (账号admin 密码admin123) |:------:|---|---|
| 用户端 | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
| 管理后台 | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
### 项目源码 ### 项目源码
@@ -81,26 +55,134 @@
| 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) | | 🛠️ 管理后台 | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
### 合作项目 ### 合作项目
| 项目名称 | GitHub 仓库 | Gitee 仓库
| 项目介绍 | GitHub 仓库 | Gitee 仓库 | |----------------|-------------------------------------------------------|------------------------------------------------------|
|:-----:|:----------------------------------------------------------------------:|:----------------------------------------------------------------:| | element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
| 前端简化版 | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) |
## 🛠️ 技术架构 ## 🛠️ 技术架构
### 核心框架 ### 核心框架
- **后端架构**Spring Boot 3.5.8 + Langchain4j
- **后端架构**Spring Boot 3.4 + Spring AI + Langchain4j
- **数据存储**MySQL 8.0 + Redis + 向量数据库Milvus/Weaviate/Qdrant - **数据存储**MySQL 8.0 + Redis + 向量数据库Milvus/Weaviate/Qdrant
- **前端技术**Vue 3 + Vben Admin + Naive UI - **前端技术**Vue 3 + Vben Admin + element-plus-x
- **安全认证**Sa-Token + JWT 双重保障 - **安全认证**Sa-Token + JWT 双重保障
### 系统组件
- **文档处理**PDF、Word、Excel 解析,图像智能分析 - **文档处理**PDF、Word、Excel 解析,图像智能分析
- **实时通信**WebSocket 实时通信SSE 流式响应 - **实时通信**WebSocket 实时通信SSE 流式响应
- **系统监控**:完善的日志体系、性能监控、服务健康检查 - **系统监控**:完善的日志体系、性能监控、服务健康检查
## 🐳 Docker 部署
本项目提供两种 Docker 部署方式:
### 方式一:一键启动所有服务(推荐)
使用 `docker-compose-all.yaml` 可以一键启动所有服务(包括后端、管理端、用户端及依赖服务):
```bash
# 克隆仓库
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# 启动所有服务(从镜像仓库拉取预构建镜像)
docker-compose -f docker-compose-all.yaml up -d
# 查看服务状态
docker-compose -f docker-compose-all.yaml ps
# 访问服务
# 管理端: http://localhost:25666 (admin / admin123)
# 用户端: http://localhost:25137
# 后端API: http://localhost:26039
```
### 方式二:分步部署(源码编译)
如果您需要从源码构建后端服务,请按照以下步骤操作:
#### 第一步:部署后端服务
```bash
# 进入后端项目目录
cd ruoyi-ai
# 启动后端服务(源码编译构建)
docker-compose up -d --build
# 等待后端服务启动完成
docker-compose logs -f backend
```
#### 第二步:部署管理端
```bash
# 进入管理端项目目录
cd ruoyi-admin
# 构建并启动管理端
docker-compose up -d --build
# 访问管理端
# 地址: http://localhost:5666
```
#### 第三步:部署用户端(可选)
```bash
# 进入用户端项目目录
cd ruoyi-web
# 构建并启动用户端
docker-compose up -d --build
# 访问用户端
# 地址: http://localhost:5137
```
### 服务端口说明
| 服务 | 一键启动端口 | 分步部署端口 | 说明 |
|------|-------------|-------------|------|
| 管理端 | 25666 | 5666 | 管理后台访问地址 |
| 用户端 | 25137 | 5137 | 用户前端访问地址 |
| 后端服务 | 26039 | 6039 | 后端 API 服务 |
| MySQL | 23306 | 23306 | 数据库服务 |
| Redis | 26379 | 6379 | 缓存服务 |
| Weaviate | 28080 | 28080 | 向量数据库 |
| MinIO API | 29000 | 9000 | 对象存储 API |
| MinIO Console | 29090 | 9090 | 对象存储控制台 |
### 镜像仓库
所有镜像托管在阿里云容器镜像服务:
```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
```
可用镜像:
- `mysql:v3` - MySQL 数据库(包含初始化 SQL
- `redis:6.2` - Redis 缓存
- `weaviate:1.30.0` - 向量数据库
- `minio:latest` - 对象存储
- `ruoyi-ai-backend:latest` - 后端服务
- `ruoyi-ai-admin:latest` - 管理端前端
- `ruoyi-ai-web:latest` - 用户端前端
### 常用命令
```bash
# 停止所有服务
docker-compose -f docker-compose-all.yaml down
# 查看服务日志
docker-compose -f docker-compose-all.yaml logs -f [服务名]
# 重启某个服务
docker-compose -f docker-compose-all.yaml restart [服务名]
```
## 📚 使用文档 ## 📚 使用文档
想要深入了解安装部署、功能配置和二次开发? 想要深入了解安装部署、功能配置和二次开发?
@@ -128,21 +210,17 @@
## 🙏 特别鸣谢 ## 🙏 特别鸣谢
感谢以下优秀的开源项目为本项目提供支持: 感谢以下优秀的开源项目为本项目提供支持:
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - 基于spring-ai-alibaba
- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - 基于spring-ai-alibaba
的智能编码助手 的智能编码助手
- [Spring AI](https://spring.io/projects/spring-ai) - Spring 官方 AI 集成框架
- [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架 - [Langchain4j](https://github.com/langchain4j/langchain4j) - 强大的 Java LLM 开发框架
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架 - [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - 成熟的企业级快速开发框架
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板 - [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - 现代化的 Vue 后台管理模板
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java) - 优秀的 ChatGPT Java SDK
## 🌐 生态伙伴 ## 🌐 生态伙伴
- [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU - [PPIO 派欧云](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - 提供高性价比的 GPU
算力和模型 API 服务 算力和模型 API 服务
- [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务秒级响应按量计费新客免费用。 - [优云智算](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - 万卡RTX40系GPU+海内外主流模型API服务秒级响应按量计费新客免费用。
- [胜算云](https://www.shengsuanyun.com/?from=CH_3WG71ZOS) - AI模型算力聚合超市云服务。
## 💬 社区交流 ## 💬 社区交流
@@ -151,12 +229,12 @@
<table> <table>
<tr> <tr>
<td align="center"> <td align="center">
<img src="image/wx.png" alt="微信二维码" width="200" height="200"><br> <img src="docs/image/wx.png" alt="微信二维码" width="200" height="200"><br>
<strong>扫码添加作者微信</strong><br> <strong>扫码添加作者微信</strong><br>
<em>邀请进群学习</em> <em>邀请进群学习</em>
</td> </td>
<td align="center"> <td align="center">
<img src="image/qq.png" alt="QQ群二维码" width="200" height="200"><br> <img src="docs/image/qq.png" alt="QQ群二维码" width="200" height="200"><br>
<strong>QQ技术交流群</strong><br> <strong>QQ技术交流群</strong><br>
<em>技术讨论</em> <em>技术讨论</em>
</td> </td>
@@ -167,12 +245,9 @@
</div> </div>
--- ---
<div align="center"> <div align="center">
**[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • * **[⭐ 点个Star支持一下](https://github.com/ageerle/ruoyi-ai)** • **[ Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • **[📖 查看完整文档](https://doc.pandarobot.chat)**
*[🍴 Fork 开始贡献](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 English](README_EN.md)** • *
*[📖 查看完整文档](https://doc.pandarobot.chat)**
*用 ❤️ 打造,由 RuoYi AI 开源社区维护* *用 ❤️ 打造,由 RuoYi AI 开源社区维护*

View File

@@ -1,3 +1,4 @@
# RuoYi AI # RuoYi AI
<div align="center"> <div align="center">
@@ -8,157 +9,227 @@
[![Issues][issues-shield]][issues-url] [![Issues][issues-shield]][issues-url]
[![MIT License][license-shield]][license-url] [![MIT License][license-shield]][license-url]
<img src="image/00.png" alt="RuoYi AI Logo" width="120" height="120">
<p align="center">
<a href="https://trendshift.io/repositories/13209">
<img src="https://trendshift.io/api/badge/repositories/13209" alt="GitHub Trending">
</a>
</p>
<img src="docs/image/logo.png" alt="RuoYi AI Logo" width="120" height="120">
### Enterprise-Grade AI Assistant Platform ### Enterprise-Grade AI Assistant Platform
*Production-ready AI platform with deep integration of FastGPT, Coze, DIFY, featuring advanced RAG technology, knowledge *An out-of-the-box full-stack AI platform supporting multi-agent collaboration, Supervisor mode orchestration, and multiple decision models, with advanced RAG technology and visual workflow orchestration capabilities*
graphs, digital humans, and AI workflow orchestration*
**[📖 中文文档](README.md)** | **[📚 Documentation](https://doc.pandarobot.chat)** | * **[中文](README.md)** | **[📖 Documentation](https://doc.pandarobot.chat)** |
*[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Bug](https://github.com/ageerle/ruoyi-ai/issues)** | * **[🚀 Live Demo](https://web.pandarobot.chat)** | **[🐛 Report Issues](https://github.com/ageerle/ruoyi-ai/issues)** | **[💡 Feature Requests](https://github.com/ageerle/ruoyi-ai/issues)**
*[💡 Request Feature](https://github.com/ageerle/ruoyi-ai/issues)**
</div> </div>
## ✨ Key Features
### 🤖 Advanced AI Engine
- **Multi-Model Support**: OpenAI GPT-4, Azure, ChatGLM, Qwen, ZhipuAI
- **AI Platform Integration**: Deep integration with **FastGPT**, **Coze**, **DIFY** and other leading AI platforms
- **Spring AI MCP Integration**: Extensible tool ecosystem with Model Context Protocol
- **Streaming Chat**: Real-time SSE/WebSocket communication
- **AI Copilot**: Intelligent code analysis and project scaffolding
### 🌟 AI Platform Ecosystem ## ✨ Core Features
- **FastGPT Deep Integration**: Native FastGPT API support with knowledge base retrieval, workflow orchestration and | Module | Current Capabilities |
context management |:---:|---|
- **Coze Official SDK**: Integration with ByteDance Coze platform official SDK, supporting Bot conversations and | **Model Management** | Multi-model integration (OpenAI/DeepSeek/Tongyi/Zhipu), multi-modal understanding, Coze/DIFY/FastGPT platform integration |
streaming responses | **Knowledge Base** | Local RAG + Vector DB (Milvus/Weaviate/Qdrant) + Document parsing |
- **DIFY Full Compatibility**: Using DIFY Java Client for app orchestration, workflows and knowledge base management | **Tool Management** | MCP protocol integration, Skills capability + Extensible tool ecosystem |
- **Unified Chat Interface**: Standardized chat service interface supporting seamless platform switching and load | **Workflow Orchestration** | Visual workflow designer, drag-and-drop node orchestration, SSE streaming execution, currently supports model calls, email sending, manual review nodes |
balancing | **Multi-Agent** | Agent framework based on Langchain4j, Supervisor mode orchestration, supports multiple decision models |
### 🧠 Enterprise RAG Solution
- **Local Knowledge Base**: Langchain4j + BGE-large-zh-v1.5 embeddings
- **Vector Database Support**: Milvus, Weaviate, Qdrant
- **Privacy-First**: On-premise deployment with local LLM support
- **Ollama & vLLM Compatible**: Flexible model deployment options
### 🎨 Creative AI Tools
- **AI Art Generation**: DALL·E-3, MidJourney, Stable Diffusion integration
- **PPT Creation**: Automated slide generation from text input
- **Multi-Modal Processing**: Text, image, and document understanding
### 🧩 Knowledge Graph & Intelligent Orchestration
- **Knowledge Graph Construction**: Automatically extract entities and relationships from documents and conversations to
build visual knowledge networks
- **AI Workflow Orchestration**: Visual workflow designer supporting complex AI task orchestration and automated
execution
- **Digital Human Interaction**: Integrated digital human avatars for more natural human-computer interaction
- **Intelligent Reasoning Engine**: Knowledge graph-based intelligent reasoning and Q&A capabilities
## 🚀 Quick Start ## 🚀 Quick Start
### Live Demo ### Live Demo
- **User Portal**: [web.pandarobot.chat](https://web.pandarobot.chat) (demo/demo123) | Platform | URL | Account |
- **Admin Panel**: [admin.pandarobot.chat](https://admin.pandarobot.chat) (admin/admin123) |:------:|---|---|
| User Frontend | [web.pandarobot.chat](https://web.pandarobot.chat) | admin / admin123 |
| Admin Panel | [admin.pandarobot.chat](https://admin.pandarobot.chat) | admin / admin123 |
### Source Code ### Project Repositories
| Component | GitHub | Gitee | GitCode | | Module | GitHub Repository | Gitee Repository | GitCode Repository |
|----------------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------| |----------|-------------------------------------------------------|------------------------------------------------------|--------------------------------------------------------|
| Backend API | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) | | 🔧 Backend | [ruoyi-ai](https://github.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitee.com/ageerle/ruoyi-ai) | [ruoyi-ai](https://gitcode.com/ageerle/ruoyi-ai) |
| User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) | | 🎨 User Frontend | [ruoyi-web](https://github.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitee.com/ageerle/ruoyi-web) | [ruoyi-web](https://gitcode.com/ageerle/ruoyi-web) |
| Admin Frontend | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) | | 🛠️ Admin Panel | [ruoyi-admin](https://github.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitee.com/ageerle/ruoyi-admin) | [ruoyi-admin](https://gitcode.com/ageerle/ruoyi-admin) |
### Collaborative Projects ### Partner Projects
| Project Name | GitHub Repository | Gitee Repository |
|----------------|-------------------------------------------------------|------------------------------------------------------|
| element-plus-x | [element-plus-x](https://github.com/element-plus-x/Element-Plus-X) | [element-plus-x](https://gitee.com/he-jiayue/element-plus-x) |
| Project Description | GitHub Repository | Gitee Repository | ## 🛠️ Technical Architecture
|:-------------------:|:----------------------------------------------------------------------:|:----------------------------------------------------------------:|
| Simplified Frontend | [ruoyi-element-ai](https://github.com/element-plus-x/ruoyi-element-ai) | [ruoyi-element-ai](https://gitee.com/he-jiayue/ruoyi-element-ai) |
## 🛠️ Tech Stack
### Core Framework ### Core Framework
- **Backend**: Spring Boot 3.5.8 + Langchain4j
- **Data Storage**: MySQL 8.0 + Redis + Vector Databases (Milvus/Weaviate/Qdrant)
- **Frontend**: Vue 3 + Vben Admin + element-plus-x
- **Security**: Sa-Token + JWT dual-layer security
- **Backend**: Spring Boot 3.4, Spring AI, Langchain4j
- **Database**: MySQL 8.0, Redis, Vector Databases (Milvus/Weaviate/Qdrant)
- **Frontend**: Vue 3, Vben Admin, Naive UI
- **Authentication**: Sa-Token, JWT
### System Components - **Document Processing**: PDF, Word, Excel parsing, intelligent image analysis
- **Real-time Communication**: WebSocket real-time communication, SSE streaming response
- **System Monitoring**: Comprehensive logging system, performance monitoring, service health checks
- **File Processing**: PDF, Word, Excel parsing, intelligent image analysis ## 🐳 Docker Deployment
- **Real-time Communication**: WebSocket real-time communication, SSE streaming
- **System Monitoring**: Comprehensive logging, performance monitoring, health checks This project provides two Docker deployment methods:
### Method 1: One-click Start All Services (Recommended)
Use `docker-compose-all.yaml` to start all services at once (including backend, admin panel, user frontend, and dependencies):
```bash
# Clone the repository
git clone https://github.com/ageerle/ruoyi-ai.git
cd ruoyi-ai
# Start all services (pull pre-built images from registry)
docker-compose -f docker-compose-all.yaml up -d
# Check service status
docker-compose -f docker-compose-all.yaml ps
# Access services
# Admin Panel: http://localhost:25666 (admin / admin123)
# User Frontend: http://localhost:25137
# Backend API: http://localhost:26039
```
### Method 2: Step-by-step Deployment (Source Build)
If you need to build backend services from source, follow these steps:
#### Step 1: Deploy Backend Service
```bash
# Enter backend project directory
cd ruoyi-ai
# Start backend service (build from source)
docker-compose up -d --build
# Wait for backend service to start
docker-compose logs -f backend
```
#### Step 2: Deploy Admin Panel
```bash
# Enter admin panel project directory
cd ruoyi-admin
# Build and start admin panel
docker-compose up -d --build
# Access admin panel
# URL: http://localhost:5666
```
#### Step 3: Deploy User Frontend (Optional)
```bash
# Enter user frontend project directory
cd ruoyi-web
# Build and start user frontend
docker-compose up -d --build
# Access user frontend
# URL: http://localhost:5137
```
### Service Ports
| Service | One-click Port | Step-by-step Port | Description |
|------|-------------|-------------|------|
| Admin Panel | 25666 | 5666 | Admin backend access |
| User Frontend | 25137 | 5137 | User frontend access |
| Backend Service | 26039 | 6039 | Backend API service |
| MySQL | 23306 | 23306 | Database service |
| Redis | 26379 | 6379 | Cache service |
| Weaviate | 28080 | 28080 | Vector database |
| MinIO API | 29000 | 9000 | Object storage API |
| MinIO Console | 29090 | 9090 | Object storage console |
### Image Registry
All images are hosted on Alibaba Cloud Container Registry:
```
crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
```
Available images:
- `mysql:v3` - MySQL database (includes initialization SQL)
- `redis:6.2` - Redis cache
- `weaviate:1.30.0` - Vector database
- `minio:latest` - Object storage
- `ruoyi-ai-backend:latest` - Backend service
- `ruoyi-ai-admin:latest` - Admin frontend
- `ruoyi-ai-web:latest` - User frontend
### Common Commands
```bash
# Stop all services
docker-compose -f docker-compose-all.yaml down
# View service logs
docker-compose -f docker-compose-all.yaml logs -f [service-name]
# Restart a service
docker-compose -f docker-compose-all.yaml restart [service-name]
```
## 📚 Documentation ## 📚 Documentation
For detailed setup, configuration, and development guides, visit our comprehensive documentation: Want to learn more about installation, deployment, configuration, and secondary development?
**[📖 Official Documentation](https://doc.pandarobot.chat)** **👉 [Complete Documentation](https://doc.pandarobot.chat)**
## 🤝 Contributing ## 🤝 Contributing
We welcome contributions from developers of all skill levels! Whether you're fixing bugs, adding features, or improving We warmly welcome community contributions! Whether you are a seasoned developer or just getting started, you can contribute to the project 💪
documentation, your help is appreciated.
### How to Contribute ### How to Contribute
1. Fork the repository 1. **Fork** the project to your account
2. Create your feature branch (`git checkout -b feature/amazing-feature`) 2. **Create a branch** (`git checkout -b feature/new-feature-name`)
3. Commit your changes (`git commit -m 'Add amazing feature'`) 3. **Commit your changes** (`git commit -m 'Add new feature'`)
4. Push to the branch (`git push origin feature/amazing-feature`) 4. **Push to the branch** (`git push origin feature/new-feature-name`)
5. Open a Pull Request 5. **Create a Pull Request**
*Please submit PRs to GitHub - they will be synchronized to other platforms automatically.* > 💡 **Tip**: We recommend submitting PRs to GitHub, we will automatically sync to other code hosting platforms
## 📄 License ## 📄 License
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. This project is licensed under the **MIT License**. See the [LICENSE](LICENSE) file for details.
## 🙏 Acknowledgments ## 🙏 Acknowledgments
Special thanks to these amazing open source projects: Thanks to the following excellent open-source projects for their support:
- [Spring AI Alibaba Copilot](https://github.com/spring-ai-alibaba/copilot) - Intelligent coding assistant based on spring-ai-alibaba
- [Spring AI Alibaba Copilot](https://github.com/springaialibaba/spring-ai-alibaba-copilot) - Intelligent coding - [Langchain4j](https://github.com/langchain4j/langchain4j) - Powerful Java LLM development framework
assistant based on spring-ai-alibaba with MCP protocol integration for project analysis and code generation - [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Mature enterprise-level rapid development framework
- [Spring AI](https://spring.io/projects/spring-ai) - Spring's AI integration framework - [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Modern Vue admin template
- [Langchain4j](https://github.com/langchain4j/langchain4j) - Java LLM framework
- [RuoYi-Vue-Plus](https://gitee.com/dromara/RuoYi-Vue-Plus) - Enterprise development framework
- [Vben Admin](https://github.com/vbenjs/vue-vben-admin) - Vue admin template
- [chatgpt-java](https://github.com/Grt1228/chatgpt-java) - ChatGPT Java SDK
## 🌐 Ecosystem Partners ## 🌐 Ecosystem Partners
- [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Cost-effective GPU - [PPIO Cloud](https://ppinfra.com/user/register?invited_by=P8QTUY&utm_source=github_ruoyi-ai) - Provides cost-effective GPU computing and model API services
containers and model APIs - [Youyun Intelligent Computing](https://www.compshare.cn/?ytag=GPU_YY-gh_ruoyi) - Thousands of RTX40 series GPUs + mainstream models API services, second-level response, pay-per-use, free for new customers.
## 💬 Community
## 💬 Community Chat
<div align="center"> <div align="center">
<table> **[📱 Join Telegram Group](
<tr> https://t.me/+LqooQAc5HxRmYmE1)**
<td align="center">
<img src="image/wx.png" alt="WeChat" width="200" height="200"><br>
<strong>Add Author WeChat</strong><br>
<em>Scan to join learning group</em>
</td>
<td align="center">
<img src="image/qq.png" alt="QQ Group" width="200" height="200"><br>
<strong>QQ Group</strong><br>
<em>Technical discussion</em>
</td>
</tr>
</table>
</div> </div>
@@ -166,10 +237,9 @@ Special thanks to these amazing open source projects:
<div align="center"> <div align="center">
**[⭐ Star this repo](https://github.com/ageerle/ruoyi-ai)** • **[🍴 Fork it](https://github.com/ageerle/ruoyi-ai/fork) **[⭐ Star to Support](https://github.com/ageerle/ruoyi-ai)** • **[Fork to Contribute](https://github.com/ageerle/ruoyi-ai/fork)** • **[📚 中文](README.md)** • **[📖 Complete Documentation](https://doc.pandarobot.chat)**
****[📖 中文文档](README.md)** • **[📚 Documentation](https://doc.pandarobot.chat)**
*Built with ❤️ by the RuoYi AI community* *Built with ❤️, maintained by the RuoYi AI open-source community*
</div> </div>
@@ -194,7 +264,3 @@ Special thanks to these amazing open source projects:
[license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square [license-shield]: https://img.shields.io/github/license/ageerle/ruoyi-ai.svg?style=flat-square
[license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE [license-url]: https://github.com/ageerle/ruoyi-ai/blob/main/LICENSE

View File

@@ -1,222 +0,0 @@
## RuoYi-AI 后端部署教程Docker 部署版)
### 一、前置条件
在部署前,请确保系统已满足以下条件:
#### ✅ 系统环境要求
- 操作系统Linux / MacOS推荐 Linux 服务器)
- CPU4 核以上
- 内存:≥ 4GB
- 磁盘空间:≥ 10GB建议 20GB+
#### ✅ 已安装软件
- **Docker**
- **Docker Compose**
验证命令是否可用:
```
docker -v
docker compose version
```
若无输出或提示“command not found”请先安装 Docker 及 Compose。
------
### 二、目录结构配置
#### 1⃣ 创建部署目录
在目标服务器执行以下命令:
```
# 第一级目录
mkdir /ruoyi-ai
cd /ruoyi-ai
# 第二级目录
mkdir deploy
cd deploy
# 第三级目录
mkdir data mysql-init
# 第四级目录
mkdir logs minio minio-config mysql redis weaviate
```
> 💡 `data` 目录用于挂载容器运行期间生成的数据文件。
最终目录结构示例:
```
/ruoyi-ai
└── deploy
├── data/
├── mysql-init/
├── logs/
├── minio/
├── minio-config/
├── mysql/
├── redis/
├── weaviate/
```
------
### 三、上传配置文件
将以下配置文件上传到 `/ruoyi-ai/deploy` 目录:
- `docker-compose.yaml`
- `.env`
- `ruoyi-ai.sql`
- `Dockerfile`
> 📂 这些文件在项目目录 `/script/deploy/deploy` 下。
> 上传后请检查文件路径是否与上方目录结构一致。
------
### 四、构建 Jar 包
1. 打开 IDEA 或其他构建工具
2. 选择 **Maven 构建配置**,勾选 `prod` 环境,取消 `dev` 环境
3. 点击 `package` 进行打包
4. **注意:** 在构建前请将 `application-prod.yml` 拖入
`ruoyi-admin/src/main/resources` 目录中
构建完成后会在:
```
ruoyi-admin/target/ruoyi-admin.jar
```
生成打包文件。
------
### 五、上传 Jar 包至服务器
将生成的 `ruoyi-admin.jar` 上传到服务器 `/ruoyi-ai/deploy` 目录下。
确保与 `Dockerfile` 同目录。
------
### 六、构建 Docker 镜像
`Dockerfile` 内容如下:
```
FROM openjdk:17-jdk
RUN mkdir -p /ruoyi/server/logs \
/ruoyi/server/temp
WORKDIR /ruoyi/server
COPY ruoyi-admin.jar ruoyi-admin.jar
ENTRYPOINT ["java","-jar","ruoyi-admin.jar"]
```
`/ruoyi-ai/deploy` 目录执行以下命令:
```
# 构建镜像
docker build -t ruoyi-ai-backend:v20251013 .
# 查看镜像是否构建成功
docker image ls
```
然后在 `docker-compose.yaml` 文件中,将对应服务的镜像名修改为:
```
image: ruoyi-ai-backend:v20251013
```
------
### 七、启动容器服务
在启动前请确认:
- `.env` 中端口号、数据库密码、环境变量已正确配置
- `docker-compose.yaml` 中 MySQL 的端口已开放(用于导入数据)
如示例:
```
ports:
- "3306:3306"
```
#### 启动命令:
```
cd /ruoyi-ai/deploy
docker compose up -d
```
#### 查看运行状态:
```
docker compose ps
```
#### 查看日志:
```
docker logs -f <容器名称>
```
> ⚠️ 初次启动时可仅运行 `ruoyi-admin`(后端)模块,将前端 `ruoyi-web` 服务暂时注释,确认后端服务正常后再启用前端容器。
------
### 八、数据库初始化
启动 MySQL 容器后,执行以下操作:
```
docker exec -it <mysql_container_name> bash
mysql -uroot -p
source /docker-entrypoint-initdb.d/ruoyi-ai.sql;
```
或手动在客户端中导入 `/ruoyi-ai/deploy/ruoyi-ai.sql` 文件。
------
### 九、常用 Docker 命令
| 功能 | 命令 |
|-----------|-----------------------------------|
| 查看容器状态 | `docker ps -a` |
| 查看日志 | `docker logs -f <容器名>` |
| 停止服务 | `docker compose down` |
| 重启服务 | `docker compose restart` |
| 重新构建镜像 | `docker compose build --no-cache` |
| 清理无用镜像/容器 | `docker system prune -a` |
------
### 🔍 十、部署验证
1. 检查容器是否全部启动成功:
```
docker compose ps
```
2. 访问后端接口:
```
http://<服务器IP>:<后端端口>
```
3. 检查日志输出无异常。

View File

@@ -0,0 +1,75 @@
version: '3.5'
services:
etcd:
container_name: milvus-etcd
image: quay.io/coreos/etcd:v3.5.18
environment:
- ETCD_AUTO_COMPACTION_MODE=revision
- ETCD_AUTO_COMPACTION_RETENTION=1000
- ETCD_QUOTA_BACKEND_BYTES=4294967296
- ETCD_SNAPSHOT_COUNT=50000
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/etcd:/etcd
command: etcd -advertise-client-urls=http://etcd:2379 -listen-client-urls http://0.0.0.0:2379 --data-dir /etcd
healthcheck:
test: ["CMD", "etcdctl", "endpoint", "health"]
interval: 30s
timeout: 20s
retries: 3
minio:
container_name: milvus-minio
image: minio/minio:RELEASE.2023-03-20T20-16-18Z
environment:
MINIO_ACCESS_KEY: minioadmin
MINIO_SECRET_KEY: minioadmin
ports:
- "9001:9001"
- "9000:9000"
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/minio:/minio_data
command: minio server /minio_data --console-address ":9001"
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
interval: 30s
timeout: 20s
retries: 3
standalone:
container_name: milvus-standalone
image: milvusdb/milvus:v2.5.7
command: ["milvus", "run", "standalone"]
security_opt:
- seccomp:unconfined
environment:
ETCD_ENDPOINTS: etcd:2379
MINIO_ADDRESS: minio:9000
volumes:
- ${DOCKER_VOLUME_DIRECTORY:-.}/volumes/milvus:/var/lib/milvus
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:9091/healthz"]
interval: 30s
start_period: 90s
timeout: 20s
retries: 3
ports:
- "19530:19530"
- "9091:9091"
depends_on:
- "etcd"
- "minio"
attu:
container_name: attu
image: zilliz/attu:v2.5.7
environment:
MILVUS_URL: milvus-standalone:19530
ports:
- "19500:3000" # 外部端口19500可以自定义
depends_on:
- "standalone"
networks:
default:
name: milvus

View File

@@ -0,0 +1,12 @@
---
services:
qdrant:
image: qdrant/qdrant:latest
ports:
- 6333:6333
- 6334:6334
volumes:
- qdrant_data:/qdrant/storage
volumes:
qdrant_data:
...

View File

@@ -0,0 +1,36 @@
# RuoYi-AI 后端 Dockerfile
# 基于 Maven + OpenJDK 17
FROM maven:3.9-eclipse-temurin-17 AS builder
# 设置工作目录
WORKDIR /build
# 复制 pom.xml 和源码
COPY pom.xml .
COPY ruoyi-admin ./ruoyi-admin
COPY ruoyi-common ./ruoyi-common
COPY ruoyi-modules ./ruoyi-modules
COPY ruoyi-extend ./ruoyi-extend
# 构建项目 (使用 prod profile)
RUN mvn clean package -Pprod -DskipTests
# 最终运行镜像
FROM eclipse-temurin:17-jre-alpine
# 设置工作目录
WORKDIR /app
# 从构建阶段复制 jar 包
COPY --from=builder /build/ruoyi-admin/target/ruoyi-admin.jar ./ruoyi-admin.jar
# 创建日志目录
RUN mkdir -p /ruoyi/server/logs
# 暴露端口
EXPOSE 6039
# 启动命令
ENTRYPOINT ["java", "-jar", "ruoyi-admin.jar", "--spring.profiles.active=prod"]

View File

@@ -0,0 +1,21 @@
# 基于官方MySQL 8.0镜像构建自定义镜像
# 构建命令: docker build -t registry.cn-hangzhou.aliyuncs.com/ruoyi-ai/mysql:v3 -f Dockerfile.mysql .
FROM mysql:8.0.33
# 设置时区
ENV TZ=Asia/Shanghai
# 复制初始化脚本和SQL文件到镜像中
COPY docs/script/docker/mysql/init/init-db.sh /docker-entrypoint-initdb.d/init-db.sh
COPY docs/script/sql/ruoyi-ai-v3_mysql8.sql /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
# 设置脚本可执行权限
RUN chmod +x /docker-entrypoint-initdb.d/init-db.sh
# MySQL启动参数
CMD ["--default-authentication-plugin=mysql_native_password", \
"--character-set-server=utf8mb4", \
"--collation-server=utf8mb4_general_ci", \
"--explicit_defaults_for_timestamp=true", \
"--lower_case_table_names=1", \
"--skip-ssl"]

View File

@@ -0,0 +1,180 @@
# RuoYi-AI 一键启动全部服务
# 使用方式: docker-compose up -d
#
# 包含服务:
# - MySQL 8.0 (数据库包含初始化SQL)
# - Redis 6.2 (缓存)
# - Weaviate (向量数据库)
# - MinIO (对象存储)
# - RuoYi-Backend (后端服务)
# - RuoYi-Admin (管理端前端)
# - RuoYi-Web (用户端前端)
#
# 镜像仓库地址: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai
version: '3.8'
services:
# ==================== MySQL 数据库 ====================
mysql:
# 阿里云镜像地址包含初始化SQL
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/mysql:v3
container_name: ruoyi-ai-mysql
restart: always
ports:
- "23306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ruoyi-ai-agent
TZ: Asia/Shanghai
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
interval: 15s
timeout: 10s
retries: 10
start_period: 60s
networks:
- ruoyi-net
# ==================== Redis 缓存 ====================
redis:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/redis:6.2
container_name: ruoyi-ai-redis
restart: always
ports:
- "26379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ruoyi-net
# ==================== Weaviate 向量数据库 ====================
weaviate:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/weaviate:1.30.0
container_name: ruoyi-ai-weaviate
restart: always
ports:
- "28080:8080"
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: true
PERSISTENCE_DATA_PATH: /var/lib/weaviate
DEFAULT_VECTORIZER_MODULE: none
ENABLE_MODULES: text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai
CLUSTER_HOSTNAME: node1
volumes:
- weaviate-data:/var/lib/weaviate
networks:
- ruoyi-net
# ==================== MinIO 对象存储 ====================
minio:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/minio:latest
container_name: ruoyi-ai-minio
restart: always
ports:
- "29000:9000"
- "29090:9090"
environment:
MINIO_ROOT_USER: ruoyi
MINIO_ROOT_PASSWORD: ruoyi123
volumes:
- minio-data:/data
command: server /data --console-address ":9090"
networks:
- ruoyi-net
# ==================== RuoYi-AI 后端服务 ====================
backend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-backend:latest
container_name: ruoyi-ai-backend
restart: always
ports:
- "26039:6039"
environment:
TZ: Asia/Shanghai
# MySQL 配置
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
# Redis 配置
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
SPRING_DATA_REDIS_DATABASE: 0
# 日志配置
LOGGING_LEVEL_ORG_RUOYI: info
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: warn
SYS_UPLOAD_PATH: /ruoyi/upload
volumes:
- logs-data:/ruoyi/server/logs
- upload-data:/ruoyi/upload
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- ruoyi-net
# ==================== RuoYi-AI 管理端前端 ====================
admin-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-admin:latest
container_name: ruoyi-ai-admin
restart: always
ports:
- "25666:5666"
environment:
# 后端 API 地址 - 运行时动态配置(无需重新构建镜像)
# nginx upstream 配置不需要 http:// 前缀,直接使用 host:port
UPSTREAM_HOST: backend:6039
# 资源限制 - 防止 CPU 和内存耗尽
deploy:
resources:
limits:
cpus: '2'
memory: 3G
reservations:
cpus: '1'
memory: 1G
depends_on:
- backend
networks:
- ruoyi-net
# ==================== RuoYi-AI 用户端前端 ====================
web-frontend:
image: crpi-31mraxd99y2gqdgr.cn-beijing.personal.cr.aliyuncs.com/ruoyi_ai/ruoyi-ai-web:latest
container_name: ruoyi-ai-web
restart: always
ports:
- "25137:5137"
environment:
UPSTREAM_URL: http://backend:6039
depends_on:
- backend
networks:
- ruoyi-net
# ==================== 网络配置 ====================
networks:
ruoyi-net:
driver: bridge
# ==================== 数据卷配置 ====================
volumes:
mysql-data:
redis-data:
weaviate-data:
minio-data:
logs-data:
upload-data:

View File

@@ -0,0 +1,144 @@
# RuoYi-AI 一键启动后端服务
# 使用方式: docker-compose up -d --build
#
# 包含服务:
# - MySQL 8.0 (数据库)
# - Redis 6.2 (缓存)
# - Weaviate (向量数据库)
# - MinIO (对象存储)
# - RuoYi-Backend (后端服务,源码编译)
services:
# MySQL 数据库
mysql:
image: mysql:8.0.33
container_name: ruoyi-ai-mysql
restart: always
ports:
- "23306:3306"
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: ruoyi-ai-agent
TZ: Asia/Shanghai
volumes:
- ./docs/script/docker/mysql/init/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro
- ./docs/script/sql/ruoyi-ai-v3_mysql8.sql:/docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql:ro
- mysql-data:/var/lib/mysql
command:
--default-authentication-plugin=mysql_native_password
--character-set-server=utf8mb4
--collation-server=utf8mb4_general_ci
--explicit_defaults_for_timestamp=true
--lower_case_table_names=1
--skip-ssl
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u", "root", "-proot"]
interval: 15s
timeout: 10s
retries: 10
start_period: 60s
networks:
- ruoyi-net
# Redis 缓存
redis:
image: redis:6.2
container_name: ruoyi-ai-redis
restart: always
ports:
- "6379:6379"
volumes:
- redis-data:/data
command: redis-server --appendonly yes
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
networks:
- ruoyi-net
# Weaviate 向量数据库
weaviate:
image: semitechnologies/weaviate:1.30.0
container_name: ruoyi-ai-weaviate
restart: always
ports:
- "28080:8080"
environment:
QUERY_DEFAULTS_LIMIT: 25
AUTHENTICATION_ANONYMOUS_ACCESS_ENABLED: true
PERSISTENCE_DATA_PATH: /var/lib/weaviate
DEFAULT_VECTORIZER_MODULE: none
ENABLE_MODULES: text2vec-cohere,text2vec-huggingface,text2vec-palm,text2vec-openai,generative-openai,generative-cohere,generative-palm,ref2vec-centroid,reranker-cohere,qna-openai
CLUSTER_HOSTNAME: node1
volumes:
- weaviate-data:/var/lib/weaviate
networks:
- ruoyi-net
# MinIO 对象存储
minio:
image: minio/minio
container_name: ruoyi-ai-minio
restart: always
ports:
- "9000:9000"
- "9090:9090"
environment:
MINIO_ROOT_USER: ruoyi
MINIO_ROOT_PASSWORD: ruoyi123
volumes:
- minio-data:/data
command: server /data --console-address ":9090"
networks:
- ruoyi-net
# RuoYi-AI 后端服务 (源码编译)
backend:
build:
context: .
dockerfile: Dockerfile.backend
container_name: ruoyi-ai-backend
restart: always
ports:
- "26039:6039"
environment:
TZ: Asia/Shanghai
# MySQL 配置
SPRING_DATASOURCE_DYNAMIC_PRIMARY: master
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_DRIVERCLASSNAME: com.mysql.cj.jdbc.Driver
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_URL: jdbc:mysql://mysql:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=false&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_USERNAME: root
SPRING_DATASOURCE_DYNAMIC_DATASOURCE_MASTER_PASSWORD: root
# Redis 配置
SPRING_DATA_REDIS_HOST: redis
SPRING_DATA_REDIS_PORT: 6379
SPRING_DATA_REDIS_DATABASE: 0
# 日志配置
LOGGING_LEVEL_ORG_RUOYI: info
LOGGING_LEVEL_ORG_SPRINGFRAMEWORK: warn
SYS_UPLOAD_PATH: /ruoyi/upload # 新增:对应 sys.upload.path
volumes:
- logs-data:/ruoyi/server/logs
- upload-data:/ruoyi/upload
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_started
networks:
- ruoyi-net
networks:
ruoyi-net:
driver: bridge
# 数据卷 支持手动指定 空为默认值
volumes:
mysql-data:
redis-data:
weaviate-data:
minio-data:
logs-data:
upload-data:

BIN
docs/image/bibi.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

BIN
docs/image/dy.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

BIN
docs/image/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

BIN
docs/image/qq.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 193 KiB

BIN
docs/image/wx.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

View File

@@ -0,0 +1,10 @@
#!/bin/bash
# 数据库初始化脚本
# 使用 --force 参数确保即使出错也继续执行
echo "开始初始化数据库..."
# 使用 --force 参数忽略错误继续执行
mysql -uroot -proot ruoyi-ai-agent --force < /docker-entrypoint-initdb.d/ruoyi-ai-v3_mysql8.sql
echo "数据库初始化完成"

View File

@@ -0,0 +1,129 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "200,200|200,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "d5ee3ddf-3968-4379-a86f-9ceabde5faac",
"nextNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
"coordinate": "220,200;310,200"
}
]
},
{
"nodeType": "1",
"nodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,copy\"}]",
"coordinate": "360,200|360,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "dd515cdd-59f6-446f-94ca-25ca062afb42",
"nextNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
"coordinate": "410,200;490,200"
}
]
},
{
"nodeType": "1",
"nodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
"nodeName": "组长",
"permissionFlag": "role:1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
"coordinate": "540,200|540,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "78fa8e5b-e809-44ed-978a-41092409ebcf",
"nextNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
"coordinate": "590,200;670,200"
}
]
},
{
"nodeType": "1",
"nodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
"nodeName": "部门主管",
"permissionFlag": "role:3@@role:4",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,copy,transfer,trust,file\"}]",
"coordinate": "720,200|720,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "a8abf15f-b83e-428a-86cc-033555ea9bbe",
"nextNodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
"coordinate": "770,200;880,200"
}
]
},
{
"nodeType": "2",
"nodeCode": "8b82b7d7-8660-455e-b880-d6d22ea3eb6d",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "900,200|900,200",
"version": "1",
"skipList": []
}
],
"flowCode": "leave1",
"flowName": "请假申请-普通",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

View File

@@ -0,0 +1,187 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "300,240|300,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "cef3895c-f7d8-4598-8bf3-8ec2ef6ce84a",
"nextNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
"coordinate": "320,240;390,240"
}
]
},
{
"nodeType": "1",
"nodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
"coordinate": "440,240|440,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "fdcae93b-b69c-498a-b231-09255e74bcbd",
"nextNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
"coordinate": "490,240;535,240"
}
]
},
{
"nodeType": "3",
"nodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "560,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": "le@@leaveDays|2",
"skipName": null,
"nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
"nextNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
"coordinate": "560,265;560,320;670,320"
},
{
"skipType": "PASS",
"skipCondition": "gt@@leaveDays|2",
"skipName": "大于两天",
"nowNodeCode": "7b8c7ead-7dc8-4951-a7f3-f0c41995909e",
"nextNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
"coordinate": "560,215;560,160;670,160|560,187"
}
]
},
{
"nodeType": "1",
"nodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
"nodeName": "组长",
"permissionFlag": "3@@4",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "720,320|720,320",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "b3528155-dcb7-4445-bbdf-3d00e3499e86",
"nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
"coordinate": "770,320;860,320;860,280"
}
]
},
{
"nodeType": "1",
"nodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
"nodeName": "总经理",
"permissionFlag": "role:1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "860,240|860,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
"nextNodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
"coordinate": "910,240;980,240"
}
]
},
{
"nodeType": "2",
"nodeCode": "40aa65fd-0712-4d23-b6f7-d0432b920fd1",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1000,240|1000,240",
"version": "1",
"skipList": []
},
{
"nodeType": "1",
"nodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
"nodeName": "部门领导",
"permissionFlag": "role:1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "720,160|720,160",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "5ed2362b-fc0c-4d52-831f-95208b830605",
"nextNodeCode": "c9fa6d7d-2a74-4e78-b947-0cad8a6af869",
"nextNodeType": "1",
"coordinate": "770,160;860,160;860,200"
}
]
}
],
"flowCode": "leave2",
"flowName": "请假申请-排他网关",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

View File

@@ -0,0 +1,211 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "380,220|380,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "a80ecf9f-f465-4ae5-a429-e30ec5d0f957",
"nextNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
"coordinate": "400,220;470,220"
}
]
},
{
"nodeType": "1",
"nodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
"coordinate": "520,220|520,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "b7bbb571-06de-455c-8083-f83c07bf0b99",
"nextNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
"coordinate": "570,220;655,220"
}
]
},
{
"nodeType": "4",
"nodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "680,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
"nextNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
"coordinate": "680,195;680,140;750,140"
},
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "84d7ed24-bb44-4ba1-bf1f-e6f5092d3f0a",
"nextNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
"coordinate": "680,245;680,300;750,300"
}
]
},
{
"nodeType": "1",
"nodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
"nodeName": "市场部",
"permissionFlag": "role:1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "800,140|800,140",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "4b7743cd-940c-431b-926f-e7b614fbf1fe",
"nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
"coordinate": "850,140;920,140;920,195"
}
]
},
{
"nodeType": "4",
"nodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "920,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
"nextNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
"coordinate": "945,220;975,220;975,220;960,220;960,220;990,220"
}
]
},
{
"nodeType": "1",
"nodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
"nodeName": "CEO",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "1040,220|1040,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "23e7429e-2b47-4431-b93e-40db7c431ce6",
"nextNodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
"coordinate": "1090,220;1140,220"
}
]
},
{
"nodeType": "2",
"nodeCode": "f5ace37f-5a5e-4e64-a6f6-913ab9a71cd1",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1160,220|1160,220",
"version": "1",
"skipList": []
},
{
"nodeType": "1",
"nodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
"nodeName": "综合部",
"permissionFlag": "role:3@@role:4",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "800,300|800,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "762cb975-37d8-4276-b6db-79a4c3606394",
"nextNodeCode": "b66b6563-f9fe-41cc-a782-f7837bb6f3d2",
"nextNodeType": "4",
"coordinate": "850,300;920,300;920,245"
}
]
}
],
"flowCode": "leave3",
"flowName": "请假申请-并行网关",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

View File

@@ -0,0 +1,154 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "320,240|320,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "9ce8bf00-f25b-4fc6-91b8-827082fc4876",
"nextNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
"coordinate": "340,240;410,240"
}
]
},
{
"nodeType": "1",
"nodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
"coordinate": "460,240|460,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "e90b98ef-35b4-410c-a663-bae8b7624b9f",
"nextNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
"coordinate": "510,240;590,240"
}
]
},
{
"nodeType": "1",
"nodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
"nodeName": "百分之60通过",
"permissionFlag": "${userList}",
"nodeRatio": "60.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
"coordinate": "640,240|640,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "768b5b1a-6726-4d67-8853-4cc70d5b1045",
"nextNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
"coordinate": "690,240;770,240"
}
]
},
{
"nodeType": "1",
"nodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
"nodeName": "全部审批通过",
"permissionFlag": "role:1@@role:3",
"nodeRatio": "100.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
"coordinate": "820,240|820,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "2f9f2e21-9bcf-42a3-a07c-13037aad22d1",
"nextNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
"coordinate": "870,240;950,240"
}
]
},
{
"nodeType": "1",
"nodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
"nodeName": "CEO",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "1000,240|1000,240",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "27461e01-3d9f-4530-8fe3-bd5ec7f9571f",
"nextNodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
"coordinate": "1050,240;1080,240;1080,240;1070,240;1070,240;1100,240"
}
]
},
{
"nodeType": "2",
"nodeCode": "b62b88c3-8d8d-4969-911e-2aaea219e7fc",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1120,240|1120,240",
"version": "1",
"skipList": []
}
],
"flowCode": "leave4",
"flowName": "请假申请-会签",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

View File

@@ -0,0 +1,211 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "300,220|300,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "ebebaf26-9cb6-497e-8119-4c9fed4c597c",
"nextNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
"coordinate": "320,220;350,220;350,220;340,220;340,220;370,220"
}
]
},
{
"nodeType": "1",
"nodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
"coordinate": "420,220|420,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "e1b04e96-dc81-4858-a309-2fe945d2f374",
"nextNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
"coordinate": "470,220;535,220"
}
]
},
{
"nodeType": "4",
"nodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "560,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
"nextNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
"coordinate": "560,245;560,320;650,320"
},
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "3e743f4f-51ca-41d4-8e94-21f5dd9b59c9",
"nextNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
"coordinate": "560,195;560,120;650,120"
}
]
},
{
"nodeType": "1",
"nodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
"nodeName": "会签",
"permissionFlag": "role:1@@role:3",
"nodeRatio": "100.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
"coordinate": "700,320|700,320",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "c80f273e-1f17-4bd8-9ad1-04a4a94ea862",
"nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
"coordinate": "750,320;860,320;860,245"
}
]
},
{
"nodeType": "4",
"nodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "860,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
"nextNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
"coordinate": "885,220;950,220"
}
]
},
{
"nodeType": "1",
"nodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
"nodeName": "CEO",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,transfer,trust,copy\"}]",
"coordinate": "1000,220|1000,220",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "7a8f0473-e409-442e-a843-5c2b813d00e9",
"nextNodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
"coordinate": "1050,220;1120,220"
}
]
},
{
"nodeType": "2",
"nodeCode": "03c4d2bc-58b5-4408-a2e4-65afb046f169",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1140,220|1140,220",
"version": "1",
"skipList": []
},
{
"nodeType": "1",
"nodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
"nodeName": "百分之60票签",
"permissionFlag": "${userList}",
"nodeRatio": "60.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file,addSign,subSign\"}]",
"coordinate": "700,120|700,120",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "1e3e8d3b-18ae-4d6c-a814-ce0d724adfa4",
"nextNodeCode": "1a20169e-3d82-4926-a151-e2daad28de1b",
"nextNodeType": "4",
"coordinate": "750,120;860,120;860,195"
}
]
}
],
"flowCode": "leave5",
"flowName": "请假申请-并行会签网关",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

View File

@@ -0,0 +1,368 @@
{
"nodeList": [
{
"nodeType": "0",
"nodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
"nodeName": "开始",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "240,300|240,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "122b89a5-7c6f-40a3-aa09-7a263f902054",
"nextNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
"coordinate": "260,300;350,300"
}
]
},
{
"nodeType": "1",
"nodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
"nodeName": "申请人",
"permissionFlag": "",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,file\"}]",
"coordinate": "400,300|400,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "c25a0e86-fdd1-4f03-8e22-14db70389dbd",
"nextNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
"coordinate": "450,300;510,300"
}
]
},
{
"nodeType": "1",
"nodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
"nodeName": "副经理",
"permissionFlag": "role:1@@role:3@@role:4",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
"coordinate": "860,200|860,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
"nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
"coordinate": "910,200;1000,200;1000,275"
}
]
},
{
"nodeType": "1",
"nodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
"nodeName": "组长",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
"coordinate": "860,400|860,400",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
"nextNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
"coordinate": "910,400;1000,400;1000,325"
}
]
},
{
"nodeType": "1",
"nodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
"nodeName": "副组长",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,transfer,copy,pop\"}]",
"coordinate": "560,300|560,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "07ecda1d-7a0a-47b5-8a91-6186c9473742",
"nextNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
"coordinate": "610,300;675,300"
}
]
},
{
"nodeType": "3",
"nodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "700,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": "default@@${leaveDays > 2}",
"skipName": "大于两天",
"nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
"nextNodeCode": "2bfa3919-78cf-4bc1-b59b-df463a4546f9",
"nextNodeType": "1",
"coordinate": "700,275;700,200;810,200|700,237"
},
{
"skipType": "PASS",
"skipCondition": "spel@@#{@testLeaveServiceImpl.eval(#leaveDays)}",
"skipName": null,
"nowNodeCode": "48117e2c-6328-406b-b102-c4a9d115bb13",
"nextNodeCode": "ec17f60e-94e0-4d96-a3ce-3417e9d32d60",
"nextNodeType": "1",
"coordinate": "700,325;700,400;810,400"
}
]
},
{
"nodeType": "3",
"nodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1000,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "394e1cc8-b8b2-4189-9f81-44448e88ac32",
"nextNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
"coordinate": "1025,300;1130,300"
}
]
},
{
"nodeType": "1",
"nodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
"nodeName": "经理会签",
"permissionFlag": "1@@3",
"nodeRatio": "100.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination,pop,addSign,subSign\"}]",
"coordinate": "1180,300|1180,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "9c93a195-cff2-4e17-ab0a-a4f264191496",
"nextNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
"coordinate": "1230,300;1315,300"
}
]
},
{
"nodeType": "4",
"nodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1340,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
"nextNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
"coordinate": "1340,325;1340,400;1430,400"
},
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "a1a42056-afd1-4e90-88bc-36cbf5a66992",
"nextNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
"coordinate": "1340,275;1340,200;1430,200"
}
]
},
{
"nodeType": "1",
"nodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
"nodeName": "总经理",
"permissionFlag": "3@@1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
"coordinate": "1480,200|1480,200",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "350dfa0c-a77c-4efa-8527-10efa02d8be4",
"nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
"coordinate": "1530,200;1640,200;1640,275"
}
]
},
{
"nodeType": "1",
"nodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
"nodeName": "副总经理",
"permissionFlag": "1@@3",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
"coordinate": "1480,400|1480,400",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "fcfdd9f6-f526-4c1a-b71d-88afa31aebc5",
"nextNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
"coordinate": "1530,400;1640,400;1640,325"
}
]
},
{
"nodeType": "4",
"nodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1640,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "c36a46ef-04f9-463f-bad7-4b395c818519",
"nextNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
"coordinate": "1665,300;1770,300"
}
]
},
{
"nodeType": "1",
"nodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
"nodeName": "董事",
"permissionFlag": "1",
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": "",
"listenerPath": "",
"formCustom": "N",
"formPath": null,
"ext": "[{\"code\":\"ButtonPermissionEnum\",\"value\":\"back,termination\"}]",
"coordinate": "1820,300|1820,300",
"version": "1",
"skipList": [
{
"skipType": "PASS",
"skipCondition": null,
"skipName": null,
"nowNodeCode": "3fcea762-b53a-4ae1-8365-7bec90444828",
"nextNodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
"coordinate": "1870,300;1960,300"
}
]
},
{
"nodeType": "2",
"nodeCode": "9cfbfd3e-6c04-41d6-9fc2-6787a7d2cd31",
"nodeName": "结束",
"permissionFlag": null,
"nodeRatio": "0.000",
"anyNodeSkip": null,
"listenerType": null,
"listenerPath": null,
"formCustom": "N",
"formPath": null,
"ext": "[]",
"coordinate": "1980,300|1980,300",
"version": "1",
"skipList": []
}
],
"flowCode": "leave6",
"flowName": "请假申请-排他并行会签",
"modelValue": "CLASSICS",
"category": "103",
"version": "1",
"formCustom": "N",
"formPath": "/workflow/leaveEdit/index",
"listenerType": null,
"listenerPath": null
}

File diff suppressed because one or more lines are too long

Binary file not shown.

Before

Width:  |  Height:  |  Size: 78 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 144 KiB

322
pom.xml
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
@@ -9,58 +9,77 @@
<version>${revision}</version> <version>${revision}</version>
<name>ruoyi-ai</name> <name>ruoyi-ai</name>
<url>https://gitee.com/ageerle/ruoyi-ai</url> <url>>https://gitee.com/ageerle/ruoyi-ai</url>
<description>AI助手</description> <description>全栈式AI开发平台</description>
<properties> <properties>
<revision>1.0.0</revision> <revision>3.0.0</revision>
<spring-boot.version>3.4.4</spring-boot.version> <spring-boot.version>3.5.8</spring-boot.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding> <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>17</java.version> <java.version>17</java.version>
<mysql.version>8.0.33</mysql.version>
<mybatis.version>3.5.16</mybatis.version> <mybatis.version>3.5.16</mybatis.version>
<springdoc.version>2.8.13</springdoc.version> <springdoc.version>2.8.13</springdoc.version>
<therapi-javadoc.version>0.15.0</therapi-javadoc.version> <therapi-javadoc.version>0.15.0</therapi-javadoc.version>
<poi.version>5.2.3</poi.version> <fastexcel.version>1.3.0</fastexcel.version>
<easyexcel.version>3.2.1</easyexcel.version>
<velocity.version>2.3</velocity.version> <velocity.version>2.3</velocity.version>
<satoken.version>1.34.0</satoken.version> <satoken.version>1.44.0</satoken.version>
<mybatis-plus.version>3.5.11</mybatis-plus.version> <mybatis-plus.version>3.5.14</mybatis-plus.version>
<p6spy.version>3.9.1</p6spy.version> <p6spy.version>3.9.1</p6spy.version>
<hutool.version>5.8.35</hutool.version> <hutool.version>5.8.40</hutool.version>
<okhttp.version>4.10.0</okhttp.version> <spring-boot-admin.version>3.5.5</spring-boot-admin.version>
<redisson.version>3.51.0</redisson.version>
<lock4j.version>2.2.7</lock4j.version>
<dynamic-ds.version>4.3.1</dynamic-ds.version> <dynamic-ds.version>4.3.1</dynamic-ds.version>
<spring-boot-admin.version>3.0.3</spring-boot-admin.version> <snailjob.version>1.8.0</snailjob.version>
<redisson.version>3.20.1</redisson.version> <mapstruct-plus.version>1.5.0</mapstruct-plus.version>
<lock4j.version>2.2.4</lock4j.version>
<alibaba-ttl.version>2.14.2</alibaba-ttl.version>
<xxl-job.version>2.4.0</xxl-job.version>
<mapstruct-plus.version>1.2.1</mapstruct-plus.version>
<mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version> <mapstruct-plus.lombok.version>0.2.0</mapstruct-plus.lombok.version>
<lombok.version>1.18.26</lombok.version> <lombok.version>1.18.40</lombok.version>
<bouncycastle.version>1.72</bouncycastle.version> <bouncycastle.version>1.80</bouncycastle.version>
<!-- Apache Commons Compress 版本 --> <justauth.version>1.16.7</justauth.version>
<commons-compress.version>1.26.2</commons-compress.version>
<!-- 离线IP地址定位库 --> <!-- 离线IP地址定位库 -->
<ip2region.version>2.7.0</ip2region.version> <ip2region.version>2.7.0</ip2region.version>
<!-- OSS 配置 --> <!-- OSS 配置 -->
<aws-java-sdk-s3.version>1.12.400</aws-java-sdk-s3.version> <aws.sdk.version>2.28.22</aws.sdk.version>
<!-- SMS 配置 --> <!-- SMS 配置 -->
<aliyun.sms.version>2.0.23</aliyun.sms.version> <sms4j.version>3.3.5</sms4j.version>
<tencent.sms.version>3.1.687</tencent.sms.version> <!-- 限制框架中的fastjson版本 -->
<fastjson.version>1.2.83</fastjson.version>
<!-- 面向运行时的D-ORM依赖 -->
<anyline.version>8.7.2-20250603</anyline.version>
<!-- 工作流配置 -->
<warm-flow.version>1.8.2</warm-flow.version>
<!-- 企业微信SDK -->
<weixin-java-cp.version>4.6.0</weixin-java-cp.version>
<!-- Jackson XML -->
<jackson-dataformat-xml.version>2.18.2</jackson-dataformat-xml.version>
<!-- AI 相关依赖 -->
<langchain4j.version>1.11.0</langchain4j.version>
<langchain4j.community.version>1.11.0-beta19</langchain4j.community.version>
<langgraph4j.version>1.5.3</langgraph4j.version>
<weaviate.version>1.19.6</weaviate.version>
<dify.version>1.0.7</dify.version>
<!-- gRPC 版本 - 解决 Milvus SDK 依赖冲突 -->
<grpc.version>1.62.2</grpc.version>
<!-- Apache Commons Compress - 用于POI处理ZIP格式 -->
<commons-compress.version>1.27.1</commons-compress.version>
<!-- Neo4j 相关版本 -->
<neo4j-driver.version>5.26.0</neo4j-driver.version> <avatar-generator.version>1.1.0</avatar-generator.version>
<neo4j-cypher-dsl.version>2024.1.0</neo4j-cypher-dsl.version> <jsoup.version>1.21.2</jsoup.version>
<langchain4j-neo4j.version>1.2.0-beta8</langchain4j-neo4j.version> <knife4j.version>4.4.0</knife4j.version>
<swagger-annotations.version>2.2.8</swagger-annotations.version>
<google-api-client.version>2.6.0</google-api-client.version>
<commons-collections4.version>4.5.0</commons-collections4.version>
<!-- 插件版本 --> <!-- 插件版本 -->
<maven-jar-plugin.version>3.2.2</maven-jar-plugin.version> <maven-jar-plugin.version>3.4.2</maven-jar-plugin.version>
<maven-war-plugin.version>3.2.2</maven-war-plugin.version> <maven-war-plugin.version>3.4.0</maven-war-plugin.version>
<maven-compiler-plugin.verison>3.11.0</maven-compiler-plugin.verison> <maven-compiler-plugin.version>3.14.0</maven-compiler-plugin.version>
<maven-surefire-plugin.version>3.0.0</maven-surefire-plugin.version> <maven-surefire-plugin.version>3.5.3</maven-surefire-plugin.version>
<flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version> <flatten-maven-plugin.version>1.3.0</flatten-maven-plugin.version>
<!-- 打包默认跳过测试 -->
<skipTests>true</skipTests>
</properties> </properties>
<profiles> <profiles>
@@ -69,7 +88,9 @@
<properties> <properties>
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>local</profiles.active> <profiles.active>local</profiles.active>
<logging.level>debug</logging.level> <logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
</profile> </profile>
<profile> <profile>
@@ -77,7 +98,9 @@
<properties> <properties>
<!-- 环境标识,需要与配置文件的名称相对应 --> <!-- 环境标识,需要与配置文件的名称相对应 -->
<profiles.active>dev</profiles.active> <profiles.active>dev</profiles.active>
<logging.level>debug</logging.level> <logging.level>info</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
<activation> <activation>
<!-- 默认环境 --> <!-- 默认环境 -->
@@ -89,6 +112,8 @@
<properties> <properties>
<profiles.active>prod</profiles.active> <profiles.active>prod</profiles.active>
<logging.level>warn</logging.level> <logging.level>warn</logging.level>
<monitor.username>ruoyi</monitor.username>
<monitor.password>123456</monitor.password>
</properties> </properties>
</profile> </profile>
</profiles> </profiles>
@@ -97,12 +122,6 @@
<dependencyManagement> <dependencyManagement>
<dependencies> <dependencies>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<!-- SpringBoot的依赖配置--> <!-- SpringBoot的依赖配置-->
<dependency> <dependency>
<groupId>org.springframework.boot</groupId> <groupId>org.springframework.boot</groupId>
@@ -112,6 +131,15 @@
<scope>import</scope> <scope>import</scope>
</dependency> </dependency>
<!-- gRPC BOM - 解决 Milvus SDK 依赖冲突,强制统一版本 -->
<dependency>
<groupId>io.grpc</groupId>
<artifactId>grpc-bom</artifactId>
<version>${grpc.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- hutool 的依赖配置--> <!-- hutool 的依赖配置-->
<dependency> <dependency>
<groupId>cn.hutool</groupId> <groupId>cn.hutool</groupId>
@@ -149,25 +177,9 @@
</dependency> </dependency>
<dependency> <dependency>
<groupId>org.apache.poi</groupId> <groupId>cn.idev.excel</groupId>
<artifactId>poi</artifactId> <artifactId>fastexcel</artifactId>
<version>${poi.version}</version> <version>${fastexcel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>${poi.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>${easyexcel.version}</version>
<exclusions>
<exclusion>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
</exclusion>
</exclusions>
</dependency> </dependency>
<!-- velocity代码生成使用模板 --> <!-- velocity代码生成使用模板 -->
@@ -201,6 +213,12 @@
<version>${satoken.version}</version> <version>${satoken.version}</version>
</dependency> </dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.mybatis</groupId> <groupId>org.mybatis</groupId>
@@ -226,13 +244,6 @@
<version>${mybatis-plus.version}</version> <version>${mybatis-plus.version}</version>
</dependency> </dependency>
<!-- dynamic-datasource 多数据源-->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>dynamic-datasource-spring-boot3-starter</artifactId>
<version>${dynamic-ds.version}</version>
</dependency>
<!-- sql性能分析插件 --> <!-- sql性能分析插件 -->
<dependency> <dependency>
<groupId>p6spy</groupId> <groupId>p6spy</groupId>
@@ -240,24 +251,43 @@
<version>${p6spy.version}</version> <version>${p6spy.version}</version>
</dependency> </dependency>
<!-- AWS SDK for Java 2.x -->
<dependency> <dependency>
<groupId>com.amazonaws</groupId> <groupId>software.amazon.awssdk</groupId>
<artifactId>aws-java-sdk-s3</artifactId> <artifactId>s3</artifactId>
<version>${aws-java-sdk-s3.version}</version> <version>${aws.sdk.version}</version>
</dependency>
<!-- 基于 AWS CRT 的 S3 客户端的性能增强的 S3 传输管理器 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>s3-transfer-manager</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!-- 将基于 Netty 的 HTTP 客户端从类路径中移除 -->
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>netty-nio-client</artifactId>
<version>${aws.sdk.version}</version>
</dependency>
<!--短信sms4j-->
<dependency>
<groupId>org.dromara.sms4j</groupId>
<artifactId>sms4j-spring-boot-starter</artifactId>
<version>${sms4j.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.aliyun</groupId> <groupId>de.codecentric</groupId>
<artifactId>dysmsapi20170525</artifactId> <artifactId>spring-boot-admin-starter-server</artifactId>
<version>${aliyun.sms.version}</version> <version>${spring-boot-admin.version}</version>
</dependency> </dependency>
<dependency> <dependency>
<groupId>com.tencentcloudapi</groupId> <groupId>de.codecentric</groupId>
<artifactId>tencentcloud-sdk-java-sms</artifactId> <artifactId>spring-boot-admin-starter-client</artifactId>
<version>${tencent.sms.version}</version> <version>${spring-boot-admin.version}</version>
</dependency> </dependency>
<!--redisson-->
<dependency> <dependency>
<groupId>org.redisson</groupId> <groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId> <artifactId>redisson-spring-boot-starter</artifactId>
@@ -270,10 +300,16 @@
<version>${lock4j.version}</version> <version>${lock4j.version}</version>
</dependency> </dependency>
<!-- SnailJob Client -->
<dependency> <dependency>
<groupId>com.alibaba</groupId> <groupId>com.aizuda</groupId>
<artifactId>transmittable-thread-local</artifactId> <artifactId>snail-job-client-starter</artifactId>
<version>${alibaba-ttl.version}</version> <version>${snailjob.version}</version>
</dependency>
<dependency>
<groupId>com.aizuda</groupId>
<artifactId>snail-job-client-job-core</artifactId>
<version>${snailjob.version}</version>
</dependency> </dependency>
<!-- 加密包引入 --> <!-- 加密包引入 -->
@@ -283,19 +319,31 @@
<version>${bouncycastle.version}</version> <version>${bouncycastle.version}</version>
</dependency> </dependency>
<!-- Apache Commons Compress -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
<dependency> <dependency>
<groupId>io.github.linpeilie</groupId> <groupId>io.github.linpeilie</groupId>
<artifactId>mapstruct-plus-spring-boot-starter</artifactId> <artifactId>mapstruct-plus-spring-boot-starter</artifactId>
<version>${mapstruct-plus.version}</version> <version>${mapstruct-plus.version}</version>
</dependency> </dependency>
<!-- Warm-Flow国产工作流引擎, 在线文档http://warm-flow.cn/ -->
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-mybatis-plus-sb3-starter</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<dependency>
<groupId>org.dromara.warm</groupId>
<artifactId>warm-flow-plugin-ui-sb-web</artifactId>
<version>${warm-flow.version}</version>
</dependency>
<!-- JustAuth 的依赖配置-->
<dependency>
<groupId>me.zhyd.oauth</groupId>
<artifactId>JustAuth</artifactId>
<version>${justauth.version}</version>
</dependency>
<!-- 离线IP地址定位库 ip2region --> <!-- 离线IP地址定位库 ip2region -->
<dependency> <dependency>
<groupId>org.lionsoul</groupId> <groupId>org.lionsoul</groupId>
@@ -303,37 +351,18 @@
<version>${ip2region.version}</version> <version>${ip2region.version}</version>
</dependency> </dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>${fastjson.version}</version>
</dependency>
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system</artifactId> <artifactId>ruoyi-system</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-knowledge-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system-api</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>
@@ -342,61 +371,47 @@
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-graph</artifactId> <artifactId>ruoyi-chat</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- Neo4j Driver --> <!-- 工作流模块 -->
<dependency>
<groupId>org.neo4j.driver</groupId>
<artifactId>neo4j-java-driver</artifactId>
<version>${neo4j-driver.version}</version>
</dependency>
<!-- Neo4j Cypher DSL -->
<dependency>
<groupId>org.neo4j</groupId>
<artifactId>neo4j-cypher-dsl</artifactId>
<version>${neo4j-cypher-dsl.version}</version>
</dependency>
<!-- Langchain4j Neo4j 扩展 -->
<dependency>
<groupId>dev.langchain4j</groupId>
<artifactId>langchain4j-community-neo4j</artifactId>
<version>${langchain4j-neo4j.version}</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-aihuman</artifactId>
<version>${revision}</version>
</dependency>
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-workflow</artifactId> <artifactId>ruoyi-workflow</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- AI流程编排模块 -->
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-workflow-api</artifactId> <artifactId>ruoyi-aiflow</artifactId>
<version>${revision}</version> <version>${revision}</version>
</dependency> </dependency>
<!-- Jackson XML -->
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>${jackson-dataformat-xml.version}</version>
</dependency>
<!-- Apache Commons Compress - 用于POI处理ZIP格式解决导出Excel时的NoSuchMethodError -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-compress</artifactId>
<version>${commons-compress.version}</version>
</dependency>
</dependencies> </dependencies>
</dependencyManagement> </dependencyManagement>
<modules> <modules>
<module>ruoyi-common</module>
<module>ruoyi-modules</module>
<module>ruoyi-modules-api</module>
<module>ruoyi-admin</module> <module>ruoyi-admin</module>
<module>ruoyi-common</module>
<module>ruoyi-extend</module> <module>ruoyi-extend</module>
<module>ruoyi-modules</module>
</modules> </modules>
<packaging>pom</packaging> <packaging>pom</packaging>
<build> <build>
@@ -404,7 +419,7 @@
<plugin> <plugin>
<groupId>org.apache.maven.plugins</groupId> <groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId> <artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.verison}</version> <version>${maven-compiler-plugin.version}</version>
<configuration> <configuration>
<source>${java.version}</source> <source>${java.version}</source>
<target>${java.version}</target> <target>${java.version}</target>
@@ -447,6 +462,7 @@
<artifactId>maven-surefire-plugin</artifactId> <artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version> <version>${maven-surefire-plugin.version}</version>
<configuration> <configuration>
<argLine>-Dfile.encoding=UTF-8</argLine>
<!-- 根据打包环境执行对应的@Tag测试方法 --> <!-- 根据打包环境执行对应的@Tag测试方法 -->
<groups>${profiles.active}</groups> <groups>${profiles.active}</groups>
<!-- 排除标签 --> <!-- 排除标签 -->
@@ -503,8 +519,8 @@
<repositories> <repositories>
<repository> <repository>
<id>public</id> <id>public</id>
<name>aliyun nexus</name> <name>huawei nexus</name>
<url>https://maven.aliyun.com/repository/public/</url> <url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases> <releases>
<enabled>true</enabled> <enabled>true</enabled>
</releases> </releases>
@@ -514,8 +530,8 @@
<pluginRepositories> <pluginRepositories>
<pluginRepository> <pluginRepository>
<id>public</id> <id>public</id>
<name>aliyun nexus</name> <name>huawei nexus</name>
<url>https://maven.aliyun.com/repository/public/</url> <url>https://mirrors.huaweicloud.com/repository/maven/</url>
<releases> <releases>
<enabled>true</enabled> <enabled>true</enabled>
</releases> </releases>
@@ -526,3 +542,5 @@
</pluginRepositories> </pluginRepositories>
</project> </project>

31
ruoyi-admin/Dockerfile Normal file
View File

@@ -0,0 +1,31 @@
# 贝尔实验室 Spring 官方推荐镜像 JDK下载地址 https://bell-sw.com/pages/downloads/
FROM bellsoft/liberica-openjdk-rocky:17.0.16-cds
#FROM bellsoft/liberica-openjdk-rocky:21.0.8-cds
#FROM findepi/graalvm:java17-native
LABEL maintainer="Lion Li"
RUN mkdir -p /ruoyi/server/logs \
/ruoyi/server/temp \
/ruoyi/skywalking/agent
WORKDIR /ruoyi/server
ENV SERVER_PORT=8080 SNAIL_PORT=28080 LANG=C.UTF-8 LC_ALL=C.UTF-8 JAVA_OPTS=""
EXPOSE ${SERVER_PORT}
# 暴露 snail job 客户端端口 用于定时任务调度中心通信
EXPOSE ${SNAIL_PORT}
ADD ./target/ruoyi-admin.jar ./app.jar
SHELL ["/bin/bash", "-c"]
ENTRYPOINT java -Djava.security.egd=file:/dev/./urandom -Dserver.port=${SERVER_PORT} \
-Dsnail-job.port=${SNAIL_PORT} \
# 应用名称 如果想区分集群节点监控 改成不同的名称即可
#-Dskywalking.agent.service_name=ruoyi-server \
#-javaagent:/ruoyi/skywalking/agent/skywalking-agent.jar \
-XX:+HeapDumpOnOutOfMemoryError -XX:+UseZGC ${JAVA_OPTS} \
-jar app.jar

View File

@@ -1,12 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" <project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent> <parent>
<artifactId>ruoyi-ai</artifactId> <artifactId>ruoyi-ai</artifactId>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<version>${revision}</version> <version>${revision}</version>
<relativePath>../pom.xml</relativePath>
</parent> </parent>
<modelVersion>4.0.0</modelVersion> <modelVersion>4.0.0</modelVersion>
<packaging>jar</packaging> <packaging>jar</packaging>
@@ -24,22 +23,46 @@
<artifactId>mysql-connector-j</artifactId> <artifactId>mysql-connector-j</artifactId>
</dependency> </dependency>
<!-- Oracle --> <!-- &lt;!&ndash; mp支持的数据库均支持 只需要增加对应的jdbc依赖即可 &ndash;&gt;-->
<!-- &lt;!&ndash; Oracle &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.jdbc</groupId>-->
<!-- <artifactId>ojdbc8</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; 兼容oracle低版本 &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.oracle.database.nls</groupId>-->
<!-- <artifactId>orai18n</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; PostgreSql &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.postgresql</groupId>-->
<!-- <artifactId>postgresql</artifactId>-->
<!-- </dependency>-->
<!-- &lt;!&ndash; SqlServer &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>com.microsoft.sqlserver</groupId>-->
<!-- <artifactId>mssql-jdbc</artifactId>-->
<!-- </dependency>-->
<dependency> <dependency>
<groupId>com.oracle.database.jdbc</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ojdbc8</artifactId> <artifactId>ruoyi-common-doc</artifactId>
</dependency> </dependency>
<!-- PostgreSql -->
<dependency> <dependency>
<groupId>org.postgresql</groupId> <groupId>org.ruoyi</groupId>
<artifactId>postgresql</artifactId> <artifactId>ruoyi-common-social</artifactId>
</dependency> </dependency>
<!-- SqlServer -->
<dependency> <dependency>
<groupId>com.microsoft.sqlserver</groupId> <groupId>org.ruoyi</groupId>
<artifactId>mssql-jdbc</artifactId> <artifactId>ruoyi-common-ratelimiter</artifactId>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-common-mail</artifactId>
</dependency> </dependency>
<dependency> <dependency>
@@ -47,31 +70,53 @@
<artifactId>ruoyi-system</artifactId> <artifactId>ruoyi-system</artifactId>
</dependency> </dependency>
<dependency> <!-- 代码生成-->
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-chat</artifactId>
</dependency>
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-generator</artifactId> <artifactId>ruoyi-generator</artifactId>
</dependency> </dependency>
<!-- 知识图谱模块 -->
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-graph</artifactId> <artifactId>ruoyi-chat</artifactId>
</dependency> </dependency>
<!-- 工作流模块 -->
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-workflow</artifactId> <artifactId>ruoyi-workflow</artifactId>
</dependency> </dependency>
<!-- AI流程编排模块 -->
<dependency> <dependency>
<groupId>org.ruoyi</groupId> <groupId>org.ruoyi</groupId>
<artifactId>ruoyi-aihuman</artifactId> <artifactId>ruoyi-aiflow</artifactId>
</dependency> </dependency>
<dependency>
<groupId>de.codecentric</groupId>
<artifactId>spring-boot-admin-starter-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- skywalking 整合 logback -->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-logback-1.x</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
<!-- <dependency>-->
<!-- <groupId>org.apache.skywalking</groupId>-->
<!-- <artifactId>apm-toolkit-trace</artifactId>-->
<!-- <version>${与你的agent探针版本保持一致}</version>-->
<!-- </dependency>-->
</dependencies> </dependencies>
<build> <build>

View File

@@ -3,23 +3,79 @@ package org.ruoyi;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup; import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import java.net.InetSocketAddress;
import java.net.ServerSocket;
/** /**
* 启动程序 * 启动程序
* *
* @author Lion Li * @author Lion Li
*/ */
@SpringBootApplication(scanBasePackages = {"org.ruoyi", "org.ruoyi.aihuman"}) @SpringBootApplication
@EnableScheduling
@EnableAsync
public class RuoYiAIApplication { public class RuoYiAIApplication {
public static void main(String[] args) { public static void main(String[] args) {
// killPortProcess(6039);
SpringApplication application = new SpringApplication(RuoYiAIApplication.class); SpringApplication application = new SpringApplication(RuoYiAIApplication.class);
application.setApplicationStartup(new BufferingApplicationStartup(2048)); application.setApplicationStartup(new BufferingApplicationStartup(2048));
application.run(args); application.run(args);
System.out.println("(♥◠‿◠)ノ゙ RuoYiAI启动成功 ლ(´ڡ`ლ)"); System.out.println("(♥◠‿◠)ノ゙ RuoYi-AI启动成功 ლ(´ڡ`ლ)");
} }
/**
* 检查并终止占用指定端口的进程
*
* @param port 端口号
*/
private static void killPortProcess(int port) {
try {
if (!isPortInUse(port)) {
return;
}
System.out.println("端口 " + port + " 已被占用,正在查找并终止进程...");
ProcessBuilder pb = new ProcessBuilder("netstat", "-ano");
Process process = pb.start();
java.io.BufferedReader reader = new java.io.BufferedReader(
new java.io.InputStreamReader(process.getInputStream()));
String line;
while ((line = reader.readLine()) != null) {
if (line.contains(":" + port + " ") && line.contains("LISTENING")) {
String[] parts = line.trim().split("\\s+");
String pid = parts[parts.length - 1];
System.out.println("找到占用端口 " + port + " 的进程 PID: " + pid + ",正在终止...");
ProcessBuilder killPb = new ProcessBuilder("taskkill", "/F", "/PID", pid);
Process killProcess = killPb.start();
int exitCode = killProcess.waitFor();
if (exitCode == 0) {
System.out.println("进程 " + pid + " 已成功终止");
} else {
System.out.println("终止进程 " + pid + " 失败exitCode: " + exitCode);
}
break;
}
}
// 等待一小段时间确保端口释放
Thread.sleep(500);
} catch (Exception e) {
System.out.println("检查/终止端口进程时发生异常: " + e.getMessage());
}
}
/**
* 检查端口是否被占用
*/
private static boolean isPortInUse(int port) {
try (ServerSocket socket = new ServerSocket()) {
socket.bind(new InetSocketAddress(port));
return false;
} catch (Exception e) {
return true;
}
}
} }

View File

@@ -0,0 +1,48 @@
package org.ruoyi.config;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.Configuration;
/**
* BeanDefinitionRegistry后置处理器
* 解决 MapStruct Plus 生成的 mapper 冲突问题
*
* @author ruoyi team
*/
@Configuration
public class MapperConflictResolver implements BeanDefinitionRegistryPostProcessor {
private static final Logger log = LoggerFactory.getLogger(MapperConflictResolver.class);
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
String[] beanNames = registry.getBeanDefinitionNames();
// 查找冲突的 mapper bean
for (String beanName : beanNames) {
if (beanName.equals("chatMessageBoToChatMessageMapperImpl")) {
BeanDefinition beanDefinition = registry.getBeanDefinition(beanName);
String beanClassName = beanDefinition.getBeanClassName();
log.info("Found mapper bean: {} -> {}", beanName, beanClassName);
// 如果是 org.ruoyi.domain.bo.chat 包下的(冲突的),移除它
if (beanClassName != null && beanClassName.startsWith("org.ruoyi.domain.bo.chat")) {
log.warn("Removing conflicting bean definition: {} ({})", beanName, beanClassName);
registry.removeBeanDefinition(beanName);
}
}
}
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
// 不需要实现
}
}

View File

@@ -1,46 +1,70 @@
package org.ruoyi.controller; package org.ruoyi.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.codec.Base64;
import cn.hutool.core.collection.CollUtil; import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.constant.Constants; import lombok.extern.slf4j.Slf4j;
import me.zhyd.oauth.model.AuthResponse;
import me.zhyd.oauth.model.AuthUser;
import me.zhyd.oauth.request.AuthRequest;
import me.zhyd.oauth.utils.AuthStateUtils;
import org.ruoyi.common.core.constant.SystemConstants;
import org.ruoyi.common.core.domain.R; import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.domain.model.*; import org.ruoyi.common.core.domain.model.LoginBody;
import org.ruoyi.common.core.utils.MapstructUtils; import org.ruoyi.common.core.domain.model.RegisterBody;
import org.ruoyi.common.core.utils.StreamUtils; import org.ruoyi.common.core.domain.model.SocialLoginBody;
import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.core.utils.*;
import org.ruoyi.common.encrypt.annotation.ApiEncrypt;
import org.ruoyi.common.json.utils.JsonUtils;
import org.ruoyi.common.ratelimiter.annotation.RateLimiter;
import org.ruoyi.common.ratelimiter.enums.LimitType;
import org.ruoyi.common.satoken.utils.LoginHelper; import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.common.social.config.properties.SocialLoginConfigProperties;
import org.ruoyi.common.social.config.properties.SocialProperties;
import org.ruoyi.common.social.utils.SocialUtils;
import org.ruoyi.common.sse.dto.SseMessageDto;
import org.ruoyi.common.sse.utils.SseMessageUtils;
import org.ruoyi.common.tenant.helper.TenantHelper; import org.ruoyi.common.tenant.helper.TenantHelper;
import org.ruoyi.system.domain.bo.SysTenantBo; import org.ruoyi.system.domain.bo.SysTenantBo;
import org.ruoyi.system.domain.vo.LoginTenantVo; import org.ruoyi.system.domain.vo.*;
import org.ruoyi.system.domain.vo.LoginVo; import org.ruoyi.system.service.*;
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.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/** /**
* 认证 * 认证
* *
* @author Lion Li * @author Lion Li
*/ */
@Slf4j
@SaIgnore @SaIgnore
@Validated
@RequiredArgsConstructor @RequiredArgsConstructor
@RestController @RestController
@RequestMapping("/auth") @RequestMapping("/auth")
public class AuthController { public class AuthController {
private final SocialProperties socialProperties;
private final SysLoginService loginService; private final SysLoginService loginService;
private final SysRegisterService registerService; private final SysRegisterService registerService;
private final ISysConfigService configService;
private final ISysTenantService tenantService; private final ISysTenantService tenantService;
private final ISysSocialService socialUserService;
private final ISysClientService clientService;
private final ScheduledExecutorService scheduledExecutorService;
/** /**
* 登录方法 * 登录方法
@@ -48,64 +72,103 @@ public class AuthController {
* @param body 登录信息 * @param body 登录信息
* @return 结果 * @return 结果
*/ */
@ApiEncrypt
@PostMapping("/login") @PostMapping("/login")
public R<LoginVo> login(@Validated @RequestBody LoginBody body) { public R<LoginVo> login(@RequestBody String body) {
body.setTenantId(Constants.TENANT_ID); LoginBody loginBody = JsonUtils.parseObject(body, LoginBody.class);
LoginVo loginVo = new LoginVo(); ValidatorUtils.validate(loginBody);
// 生成令牌 // 授权类型和客户端id
String token = loginService.login( String clientId = loginBody.getClientId();
body.getTenantId(), String grantType = loginBody.getGrantType();
body.getUsername(), body.getPassword(), log.info("登录请求 - clientId: {}, grantType: {}", clientId, grantType);
body.getCode(), body.getUuid()); SysClientVo client = clientService.queryByClientId(clientId);
loginVo.setToken(token); log.info("查询客户端结果 - client: {}, grantType: {}", client, client != null ? client.getGrantType() : "null");
// 兼容后台管理登录 // 查询不到 client 或 client 内不包含 grantType
loginVo.setAccess_token(token); if (ObjectUtil.isNull(client)) {
loginVo.setUserInfo(LoginHelper.getLoginUser()); log.info("客户端id: {} 不存在!", clientId);
return R.fail(MessageUtils.message("auth.grant.type.error"));
}
if (!StringUtils.contains(client.getGrantType(), grantType)) {
log.info("客户端id: {} 认证类型:{} 不匹配! 数据库grantType: {}", clientId, grantType, client.getGrantType());
return R.fail(MessageUtils.message("auth.grant.type.error"));
} else if (!SystemConstants.NORMAL.equals(client.getStatus())) {
return R.fail(MessageUtils.message("auth.grant.type.blocked"));
}
// 校验租户
loginService.checkTenant(loginBody.getTenantId());
// 登录
LoginVo loginVo = IAuthStrategy.login(body, client, grantType);
Long userId = LoginHelper.getUserId();
scheduledExecutorService.schedule(() -> {
SseMessageDto dto = new SseMessageDto();
dto.setMessage("欢迎登录ruoyi-ai后台管理系统");
dto.setUserIds(List.of(userId));
SseMessageUtils.publishMessage(dto);
}, 5, TimeUnit.SECONDS);
return R.ok(loginVo); return R.ok(loginVo);
} }
/** /**
* 短信登录 * 获取跳转URL
* *
* @param body 登录信息 * @param source 登录来源
* @return 结果 * @return 结果
*/ */
@PostMapping("/smsLogin") @GetMapping("/binding/{source}")
public R<LoginVo> smsLogin(@Validated @RequestBody SmsLoginBody body) { public R<String> authBinding(@PathVariable("source") String source,
LoginVo loginVo = new LoginVo(); @RequestParam String tenantId, @RequestParam String domain) {
// 生成令牌 SocialLoginConfigProperties obj = socialProperties.getType().get(source);
String token = loginService.smsLogin(body.getTenantId(), body.getPhonenumber(), body.getSmsCode()); if (ObjectUtil.isNull(obj)) {
loginVo.setToken(token); return R.fail(source + "平台账号暂不支持");
return R.ok(loginVo); }
AuthRequest authRequest = SocialUtils.getAuthRequest(source, socialProperties);
Map<String, String> map = new HashMap<>();
map.put("tenantId", tenantId);
map.put("domain", domain);
map.put("state", AuthStateUtils.createState());
String authorizeUrl = authRequest.authorize(Base64.encode(JsonUtils.toJsonString(map), StandardCharsets.UTF_8));
return R.ok("操作成功", authorizeUrl);
} }
/** /**
* 访客登录 * 前端回调绑定授权(需要token)
* *
* @param loginBody 登录信息 * @param loginBody 请求体
* @return token信息
*/
@PostMapping("/visitorLogin")
public R<LoginVo> visitorLogin(@RequestBody VisitorLoginBody loginBody) {
LoginVo loginVo = new LoginVo();
return R.ok(loginVo);
}
/**
* 邮件登录
*
* @param body 登录信息
* @return 结果 * @return 结果
*/ */
@PostMapping("/emailLogin") @PostMapping("/social/callback")
public R<LoginVo> emailLogin(@Validated @RequestBody EmailLoginBody body) { public R<Void> socialCallback(@RequestBody SocialLoginBody loginBody) {
LoginVo loginVo = new LoginVo(); // 校验token
// 生成令牌 StpUtil.checkLogin();
String token = loginService.emailLogin(body.getTenantId(), body.getEmail(), body.getEmailCode()); // 获取第三方登录信息
loginVo.setToken(token); AuthResponse<AuthUser> response = SocialUtils.loginAuth(
return R.ok(loginVo); loginBody.getSource(), loginBody.getSocialCode(),
loginBody.getSocialState(), socialProperties);
AuthUser authUserData = response.getData();
// 判断授权响应是否成功
if (!response.ok()) {
return R.fail(response.getMsg());
}
loginService.socialRegister(authUserData);
return R.ok();
} }
/**
* 取消授权(需要token)
*
* @param socialId socialId
*/
@DeleteMapping(value = "/unlock/{socialId}")
public R<Void> unlockSocial(@PathVariable Long socialId) {
// 校验token
StpUtil.checkLogin();
Boolean rows = socialUserService.deleteWithValidById(socialId);
return rows ? R.ok() : R.fail("取消授权失败");
}
/** /**
* 退出登录 * 退出登录
*/ */
@@ -118,42 +181,58 @@ public class AuthController {
/** /**
* 用户注册 * 用户注册
*/ */
@ApiEncrypt
@PostMapping("/register") @PostMapping("/register")
public R<Void> register(@Validated @RequestBody RegisterBody user, HttpServletRequest request) { public R<Void> register(@Validated @RequestBody RegisterBody user) {
String domainName = request.getServerName(); if (!configService.selectRegisterEnabled(user.getTenantId())) {
user.setDomainName(domainName); return R.fail("当前系统没有开启注册功能!");
}
registerService.register(user); registerService.register(user);
return R.ok(); return R.ok();
} }
/**
* 重置密码
*/
@PostMapping("/reset/password")
@SaIgnore
public R<Void> resetPassWord(@Validated @RequestBody RegisterBody user) {
registerService.resetPassWord(user);
return R.ok();
}
/** /**
* 登录页面租户下拉框 * 登录页面租户下拉框
* *
* @return 租户列表 * @return 租户列表
*/ */
@RateLimiter(time = 60, count = 20, limitType = LimitType.IP)
@GetMapping("/tenant/list") @GetMapping("/tenant/list")
public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception { public R<LoginTenantVo> tenantList(HttpServletRequest request) throws Exception {
// 返回对象
LoginTenantVo result = new LoginTenantVo();
boolean enable = TenantHelper.isEnable();
result.setTenantEnabled(enable);
// 如果未开启租户这直接返回
if (!enable) {
return R.ok(result);
}
List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo()); List<SysTenantVo> tenantList = tenantService.queryList(new SysTenantBo());
List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class); List<TenantListVo> voList = MapstructUtils.convert(tenantList, TenantListVo.class);
try {
// 如果只超管返回所有租户
if (LoginHelper.isSuperAdmin()) {
result.setVoList(voList);
return R.ok(result);
}
} catch (NotLoginException ignored) {
}
// 获取域名 // 获取域名
String host = new URL(request.getRequestURL().toString()).getHost(); String host;
String referer = request.getHeader("referer");
if (StringUtils.isNotBlank(referer)) {
// 这里从referer中取值是为了本地使用hosts添加虚拟域名方便本地环境调试
host = referer.split("//")[1].split("/")[0];
} else {
host = new URL(request.getRequestURL().toString()).getHost();
}
// 根据域名进行筛选 // 根据域名进行筛选
List<TenantListVo> list = StreamUtils.filter(voList, vo -> StringUtils.equals(vo.getDomain(), host)); List<TenantListVo> list = StreamUtils.filter(voList, vo ->
// 返回对象 StringUtils.equalsIgnoreCase(vo.getDomain(), host));
LoginTenantVo vo = new LoginTenantVo(); result.setVoList(CollUtil.isNotEmpty(list) ? list : voList);
vo.setVoList(CollUtil.isNotEmpty(list) ? list : voList); return R.ok(result);
vo.setTenantEnabled(TenantHelper.isEnable());
return R.ok(vo);
} }
} }

View File

@@ -5,38 +5,36 @@ import cn.hutool.captcha.AbstractCaptcha;
import cn.hutool.captcha.generator.CodeGenerator; import cn.hutool.captcha.generator.CodeGenerator;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotBlank;
import lombok.RequiredArgsConstructor; import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.ruoyi.common.core.constant.Constants; import org.ruoyi.common.core.constant.Constants;
import org.ruoyi.common.core.constant.GlobalConstants; import org.ruoyi.common.core.constant.GlobalConstants;
import org.ruoyi.common.core.domain.R; import org.ruoyi.common.core.domain.R;
import org.ruoyi.common.core.service.ConfigService; import org.ruoyi.common.core.exception.ServiceException;
import org.ruoyi.common.core.utils.SpringUtils; import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.common.core.utils.StringUtils; import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.core.utils.reflect.ReflectUtils; import org.ruoyi.common.core.utils.reflect.ReflectUtils;
import org.ruoyi.common.mail.config.properties.MailProperties;
import org.ruoyi.common.mail.utils.MailUtils; import org.ruoyi.common.mail.utils.MailUtils;
import org.ruoyi.common.ratelimiter.annotation.RateLimiter;
import org.ruoyi.common.ratelimiter.enums.LimitType;
import org.ruoyi.common.redis.utils.RedisUtils; import org.ruoyi.common.redis.utils.RedisUtils;
import org.ruoyi.common.sms.config.properties.SmsProperties;
import org.ruoyi.common.sms.core.SmsTemplate;
import org.ruoyi.common.sms.entity.SmsResult;
import org.ruoyi.common.web.config.properties.CaptchaProperties; import org.ruoyi.common.web.config.properties.CaptchaProperties;
import org.ruoyi.common.web.enums.CaptchaType; import org.ruoyi.common.web.enums.CaptchaType;
import org.ruoyi.system.domain.request.EmailRequest; import org.dromara.sms4j.api.SmsBlend;
import org.dromara.sms4j.api.entity.SmsResponse;
import org.dromara.sms4j.core.factory.SmsFactory;
import org.ruoyi.system.domain.vo.CaptchaVo; import org.ruoyi.system.domain.vo.CaptchaVo;
import org.springframework.expression.Expression; import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser; import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser; import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.validation.annotation.Validated; import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
import java.time.Duration; import java.time.Duration;
import java.util.HashMap; import java.util.LinkedHashMap;
import java.util.Map;
/** /**
* 验证码操作处理 * 验证码操作处理
@@ -51,31 +49,28 @@ import java.util.Map;
public class CaptchaController { public class CaptchaController {
private final CaptchaProperties captchaProperties; private final CaptchaProperties captchaProperties;
private final SmsProperties smsProperties; private final MailProperties mailProperties;
private final ConfigService configService;
/** /**
* 短信验证码 * 短信验证码
* *
* @param phonenumber 用户手机号 * @param phonenumber 用户手机号
*/ */
@RateLimiter(key = "#phonenumber", time = 60, count = 1)
@GetMapping("/resource/sms/code") @GetMapping("/resource/sms/code")
public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) { public R<Void> smsCode(@NotBlank(message = "{user.phonenumber.not.blank}") String phonenumber) {
if (!smsProperties.getEnabled()) {
return R.fail("当前系统没有开启短信功能!");
}
String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber; String key = GlobalConstants.CAPTCHA_CODE_KEY + phonenumber;
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 验证码模板id // 验证码模板id 自行处理 (查数据库或写死均可)
String templateId = ""; String templateId = "";
Map<String, String> map = new HashMap<>(1); LinkedHashMap<String, String> map = new LinkedHashMap<>(1);
map.put("code", code); map.put("code", code);
SmsTemplate smsTemplate = SpringUtils.getBean(SmsTemplate.class); SmsBlend smsBlend = SmsFactory.getSmsBlend("config1");
SmsResult result = smsTemplate.send(phonenumber, templateId, map); SmsResponse smsResponse = smsBlend.sendMessage(phonenumber, templateId, map);
if (!result.isSuccess()) { if (!smsResponse.isSuccess()) {
log.error("验证码短信发送异常 => {}", result); log.error("验证码短信发送异常 => {}", smsResponse);
return R.fail(result.getMessage()); return R.fail(smsResponse.getData().toString());
} }
return R.ok(); return R.ok();
} }
@@ -83,24 +78,32 @@ public class CaptchaController {
/** /**
* 邮箱验证码 * 邮箱验证码
* *
* @param emailRequest 用户邮箱 * @param email 邮箱
*/ */
@PostMapping("/resource/email/code") @GetMapping("/resource/email/code")
public R<Void> emailCode(@RequestBody @Valid EmailRequest emailRequest) { public R<Void> emailCode(@NotBlank(message = "{user.email.not.blank}") String email) {
String key = GlobalConstants.CAPTCHA_CODE_KEY + emailRequest.getUsername(); if (!mailProperties.getEnabled()) {
return R.fail("当前系统没有开启邮箱功能!");
}
SpringUtils.getAopProxy(this).emailCodeImpl(email);
return R.ok();
}
/**
* 邮箱验证码
* 独立方法避免验证码关闭之后仍然走限流
*/
@RateLimiter(key = "#email", time = 60, count = 1)
public void emailCodeImpl(String email) {
String key = GlobalConstants.CAPTCHA_CODE_KEY + email;
String code = RandomUtil.randomNumbers(4); String code = RandomUtil.randomNumbers(4);
RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(key, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
// 自定义邮箱模板
String model = configService.getConfigValue("mail", "mailModel");
String mailTitle = configService.getConfigValue("mail", "mailTitle");
String replacedModel = model.replace("{code}", code);
try { try {
MailUtils.sendHtml(emailRequest.getUsername(), mailTitle, replacedModel); MailUtils.sendText(email, "登录验证码", "您本次验证码为:" + code + ",有效性为" + Constants.CAPTCHA_EXPIRATION + "分钟,请尽快填写。");
} catch (Exception e) { } catch (Exception e) {
log.error("邮箱验证码发送异常 => {}", e.getMessage()); log.error("验证码短信发送异常 => {}", e.getMessage());
return R.fail(e.getMessage()); throw new ServiceException(e.getMessage());
} }
return R.ok();
} }
/** /**
@@ -108,33 +111,47 @@ public class CaptchaController {
*/ */
@GetMapping("/auth/code") @GetMapping("/auth/code")
public R<CaptchaVo> getCode() { public R<CaptchaVo> getCode() {
CaptchaVo captchaVo = new CaptchaVo();
boolean captchaEnabled = captchaProperties.getEnable(); boolean captchaEnabled = captchaProperties.getEnable();
if (!captchaEnabled) { if (!captchaEnabled) {
CaptchaVo captchaVo = new CaptchaVo();
captchaVo.setCaptchaEnabled(false); captchaVo.setCaptchaEnabled(false);
return R.ok(captchaVo); return R.ok(captchaVo);
} }
return R.ok(SpringUtils.getAopProxy(this).getCodeImpl());
}
/**
* 生成验证码
* 独立方法避免验证码关闭之后仍然走限流
*/
@RateLimiter(time = 60, count = 10, limitType = LimitType.IP)
public CaptchaVo getCodeImpl() {
// 保存验证码信息 // 保存验证码信息
String uuid = IdUtil.simpleUUID(); String uuid = IdUtil.simpleUUID();
String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid; String verifyKey = GlobalConstants.CAPTCHA_CODE_KEY + uuid;
// 生成验证码 // 生成验证码
CaptchaType captchaType = captchaProperties.getType(); CaptchaType captchaType = captchaProperties.getType();
boolean isMath = CaptchaType.MATH == captchaType; CodeGenerator codeGenerator;
Integer length = isMath ? captchaProperties.getNumberLength() : captchaProperties.getCharLength(); if (CaptchaType.MATH == captchaType) {
CodeGenerator codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), length); codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), captchaProperties.getNumberLength(), false);
} else {
codeGenerator = ReflectUtils.newInstance(captchaType.getClazz(), captchaProperties.getCharLength());
}
AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz()); AbstractCaptcha captcha = SpringUtils.getBean(captchaProperties.getCategory().getClazz());
captcha.setGenerator(codeGenerator); captcha.setGenerator(codeGenerator);
captcha.createCode(); captcha.createCode();
// 如果是数学验证码使用SpEL表达式处理验证码结果
String code = captcha.getCode(); String code = captcha.getCode();
if (isMath) { if (CaptchaType.MATH == captchaType) {
ExpressionParser parser = new SpelExpressionParser(); ExpressionParser parser = new SpelExpressionParser();
Expression exp = parser.parseExpression(StringUtils.remove(code, "=")); Expression exp = parser.parseExpression(StringUtils.remove(code, "="));
code = exp.getValue(String.class); code = exp.getValue(String.class);
} }
RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION)); RedisUtils.setCacheObject(verifyKey, code, Duration.ofMinutes(Constants.CAPTCHA_EXPIRATION));
CaptchaVo captchaVo = new CaptchaVo();
captchaVo.setUuid(uuid); captchaVo.setUuid(uuid);
captchaVo.setImg(captcha.getImageBase64()); captchaVo.setImg(captcha.getImageBase64());
return R.ok(captchaVo); return captchaVo;
} }
} }

View File

@@ -1,6 +1,9 @@
package org.ruoyi.controller; package org.ruoyi.controller;
import cn.dev33.satoken.annotation.SaIgnore; import cn.dev33.satoken.annotation.SaIgnore;
import lombok.RequiredArgsConstructor;
import org.ruoyi.common.core.utils.SpringUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController; import org.springframework.web.bind.annotation.RestController;
@@ -10,6 +13,7 @@ import org.springframework.web.bind.annotation.RestController;
* @author Lion Li * @author Lion Li
*/ */
@SaIgnore @SaIgnore
@RequiredArgsConstructor
@RestController @RestController
public class IndexController { public class IndexController {
@@ -18,8 +22,7 @@ public class IndexController {
*/ */
@GetMapping("/") @GetMapping("/")
public String index() { public String index() {
return "RuoYi AI启动成功"; return StringUtils.format("欢迎使用{}后台管理框架,请通过前端地址访问。", SpringUtils.getApplicationName());
} }
} }

View File

@@ -1,3 +1,44 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # mcp配置信息
mcp:
sse:
enabled: false
url: http://localhost:8085/sse
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置 --- # 数据源配置
spring: spring:
datasource: datasource:
@@ -15,9 +56,17 @@ spring:
master: master:
type: ${spring.datasource.type} type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true # jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root username: root
password: root password: root
# agent:
# url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# # url: jdbc:mysql://localhost:3306/agent_db
# username: root
# password: root
# driverClassName: com.mysql.cj.jdbc.Driver
hikari: hikari:
# 最大连接池数量 # 最大连接池数量
@@ -32,26 +81,33 @@ spring:
idleTimeout: 600000 idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟 # 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000 maxLifetime: 1800000
# 连接测试query配置检测连接是否有效
connectionTestQuery: SELECT 1
# 多久检查一次连接的活性 # 多久检查一次连接的活性
keepaliveTime: 30000 keepaliveTime: 30000
mail:
username: xx
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉) --- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data: spring.data:
redis: redis:
# 地址 # 地址
host: 127.0.0.1 host: localhost
# 端口默认为6379 # 端口默认为6379
port: 6379 port: 6379
# 数据库索引 # 数据库索引
database: 0 database: 0
# 密码(如没有密码请注释掉) # redis 密码必须配置
# password: 123456 # password: 123456
# 连接超时时间 # 连接超时时间
timeout: 10S timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson: redisson:
# redis key前缀 # redis key前缀
keyPrefix: keyPrefix:
@@ -61,8 +117,8 @@ redisson:
nettyThreads: 8 nettyThreads: 8
# 单节点配置 # 单节点配置
singleServerConfig: singleServerConfig:
# 客户端名称 # 客户端名称 不能用中文
clientName: ${ruoyi.name} clientName: ruoyi-ai
# 最小空闲连接数 # 最小空闲连接数
connectionMinimumIdleSize: 8 connectionMinimumIdleSize: 8
# 连接池大小 # 连接池大小
@@ -74,35 +130,142 @@ redisson:
# 发布和订阅连接池大小 # 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50 subscriptionConnectionPoolSize: 50
--- # sms 短信 --- # mail 邮件发送
sms: mail:
enabled: false enabled: false
# 阿里云 dysmsapi.aliyuncs.com host: smtp.163.com
# 腾讯云 sms.tencentcloudapi.com port: 465
endpoint: "dysmsapi.aliyuncs.com" # 是否需要用户名密码验证
accessKeyId: xxxxxxx auth: true
accessKeySecret: xxxxxx # 发送方遵循RFC-822标准
signName: 测试 from: xxx@163.com
# 腾讯专 # 用户名注意如果使用foxmail邮箱此处user为qq号
sdkAppId: user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pdf: pass: xxxxxxxxxx
extract: # 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
service: starttlsEnable: true
url: http://localhost:8080 # 使用SSL安全连接
ai-api: sslEnable: true
url: https://api.pandarobot.chat/v1/chat/completions # SMTP超时时长单位毫秒缺省值不超时
key: sk-xxxx timeout: 0
transition: # Socket连接超时值单位毫秒缺省值不超时
# 是否开启mineru connectionTimeout: 0
enable-minerU: true
# mineru conda环境路径
conda-env-path: "F:\\ProgramData\\Computer\\Anaconda\\envs\\mineru"
# 是否开启图片OCR
enable-ocr: true
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/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, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
AGENT_ALLOWED_TABLES: ""

View File

@@ -0,0 +1,271 @@
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
metadata:
username: ${spring.boot.admin.client.username}
userpassword: ${spring.boot.admin.client.password}
username: @monitor.username@
password: @monitor.password@
--- # mcp配置信息
mcp:
sse:
enabled: false
url: http://localhost:8085/sse
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # snail-job 配置
snail-job:
enabled: false
# 需要在 SnailJob 后台组管理创建对应名称的组,然后创建任务的时候选择对应的组,才能正确分派任务
group: "ruoyi_group"
# SnailJob 接入验证令牌 详见 script/sql/ry_job.sql `sj_group_config` 表
token: "SJ_cKqBTPzCsWA3VyuCfFoccmuIEGXjr5KT"
server:
host: 127.0.0.1
port: 17888
# 命名空间UUID 详见 script/sql/ry_job.sql `sj_namespace`表`unique_id`字段
namespace: ${spring.profiles.active}
# 随主应用端口漂移
port: 2${server.port}
# 客户端ip指定
host:
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: true
# 设置默认的数据源或者数据源组,默认值即为 master
primary: master
# 严格模式 匹配不到数据源则报错
strict: true
datasource:
# 主库数据源
master:
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
# jdbc 所有参数配置参考 https://lionli.blog.csdn.net/article/details/122018562
# rewriteBatchedStatements=true 批处理优化 大幅提升批量插入更新删除性能(对数据库有性能损耗 使用批量操作应考虑性能问题)
url: jdbc:mysql://127.0.0.1:3306/ruoyi-ai-agent?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
username: root
password: root
# agent:
# url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true&allowPublicKeyRetrieval=true&nullCatalogMeansCurrent=true
# # url: jdbc:mysql://localhost:3306/agent_db
# username: root
# password: root
# driverClassName: com.mysql.cj.jdbc.Driver
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # 上传文件地址
sys:
upload:
path: D:\\DownLoad
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: localhost
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# redis 密码必须配置
# password: 123456
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl.enabled: false
# redisson 配置
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 4
# Netty线程池数量
nettyThreads: 8
# 单节点配置
singleServerConfig:
# 客户端名称 不能用中文
clientName: ruoyi-ai
# 最小空闲连接数
connectionMinimumIdleSize: 8
# 连接池大小
connectionPoolSize: 32
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: xxx@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: xxx@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: xxxxxxxxxx
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信 支持 阿里云 腾讯云 云片 等等各式各样的短信服务商
# https://sms4j.com/doc3/ 差异配置文档地址 支持单厂商多配置,可以配置多个同时使用
sms:
# 配置源类型用于标定配置来源(interface,yaml)
config-type: yaml
# 用于标定yml中的配置是否开启短信拦截接口配置不受此限制
restricted: true
# 短信拦截限制单手机号每分钟最大发送,只对开启了拦截的配置有效
minute-max: 1
# 短信拦截限制单手机号每日最大发送量,只对开启了拦截的配置有效
account-max: 30
# 以下配置来自于 org.dromara.sms4j.provider.config.BaseConfig类中
blends:
# 唯一ID 用于发送短信寻找具体配置 随便定义别用中文即可
# 可以同时存在两个相同厂商 例如: ali1 ali2 两个不同的阿里短信账号 也可用于区分租户
config1:
# 框架定义的厂商名称标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: alibaba
# 有些称为accessKey有些称之为apiKey也有称为sdkKey或者appId。
access-key-id: 您的accessKey
# 称为accessSecret有些称之为apiSecret
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
config2:
# 厂商标识,标定此配置是哪个厂商,详细请看厂商标识介绍部分
supplier: tencent
access-key-id: 您的accessKey
access-key-secret: 您的accessKeySecret
signature: 您的短信签名
sdk-app-id: 您的sdkAppId
--- # 三方授权
justauth:
# 前端外网访问地址
address: http://localhost:80
type:
maxkey:
# maxkey 服务器地址
# 注意 如下均配置均不需要修改 maxkey 已经内置好了数据
server-url: http://sso.maxkey.top
client-id: 876892492581044224
client-secret: x1Y5MTMwNzIwMjMxNTM4NDc3Mzche8
redirect-uri: ${justauth.address}/social-callback?source=maxkey
topiam:
# topiam 服务器地址
server-url: http://127.0.0.1:1898/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, email, phone, profile]
qq:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=qq
union-id: false
weibo:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=weibo
gitee:
client-id: 91436b7940090d09c72c7daf85b959cfd5f215d67eea73acbf61b6b590751a98
client-secret: 02c6fcfd70342980cd8dd2f2c06c1a350645d76c754d7a264c4e125f9ba915ac
redirect-uri: ${justauth.address}/social-callback?source=gitee
dingtalk:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=dingtalk
baidu:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=baidu
csdn:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=csdn
coding:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=coding
coding-group-name: xx
oschina:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=oschina
alipay_wallet:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=alipay_wallet
alipay-public-key: MIIB**************DAQAB
wechat_open:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_open
wechat_mp:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_mp
wechat_enterprise:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=wechat_enterprise
agent-id: 1000002
gitlab:
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitlab
gitea:
# 前端改动 https://gitee.com/JavaLionLi/plus-ui/pulls/204
# gitea 服务器地址
server-url: https://demo.gitea.com
client-id: 10**********6
client-secret: 1f7d08**********5b7**********29e
redirect-uri: ${justauth.address}/social-callback?source=gitea
AGENT_ALLOWED_TABLES: "abtest_rule,abtest_project,agent_ban_log,agent_ban_logs,agent_install_sub_task,agent_install_sum_task,agent_install_task"

View File

@@ -1,29 +1,6 @@
# 项目相关配置
ruoyi:
# 名称
name: "ruoyi-ai"
# 版本
version: ${revision}
# 版权年份
copyrightYear: 2025
# 实例演示开关
demoEnabled: false
captcha:
enable: false
# 页面 <参数设置> 可开启关闭 验证码校验
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
# 开发环境配置 # 开发环境配置
server: server:
# 服务器的HTTP端口默认为8080 # 服务器的HTTP端口默认为6039
port: 6039 port: 6039
servlet: servlet:
# 应用的访问路径 # 应用的访问路径
@@ -43,6 +20,18 @@ server:
# 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载 # 阻塞任务线程池, 当执行类似servlet请求阻塞操作, undertow会从这个线程池中取得线程,它的值设置取决于系统的负载
worker: 256 worker: 256
captcha:
# 是否启用验证码校验
enable: false
# 验证码类型 math 数组计算 char 字符验证
type: MATH
# line 线段干扰 circle 圆圈干扰 shear 扭曲干扰
category: CIRCLE
# 数字验证码位数
numberLength: 1
# 字符验证码长度
charLength: 4
# 日志配置 # 日志配置
logging: logging:
level: level:
@@ -63,7 +52,24 @@ user:
# Spring配置 # Spring配置
spring: spring:
application: application:
name: ${ruoyi.name} name: ruoyi-ai
# ⚠️ 禁用 Spring Boot 的 Neo4j 自动配置
# 默认情况下,如果类路径上存在 neo4j-java-driverSpring Boot 会尝试自动配置
# 这会导致应用在启动时尝试连接到 Neo4j即使我们没有需要它
autoconfigure:
exclude:
- org.springframework.boot.autoconfigure.neo4j.Neo4jAutoConfiguration
threads:
# 开启虚拟线程 仅jdk21可用
virtual:
enabled: false
task:
execution:
# 从 springboot 3.5 开始 spring自带线程池
# 不再需要 AsyncConfig与ThreadPoolConfig 可直接注入线程池使用
thread-name-prefix: async-
# 由spring自己初始化线程池
mode: force
# 资源信息 # 资源信息
messages: messages:
# 国际化资源文件路径 # 国际化资源文件路径
@@ -74,10 +80,12 @@ spring:
servlet: servlet:
multipart: multipart:
# 单个文件大小 # 单个文件大小
max-file-size: 50MB max-file-size: 10MB
# 设置总上传的文件大小 # 设置总上传的文件大小
max-request-size: 200MB max-request-size: 20MB
mvc: mvc:
# 设置静态资源路径 防止所有请求都去查静态资源
static-path-pattern: /static/**
format: format:
date-time: yyyy-MM-dd HH:mm:ss date-time: yyyy-MM-dd HH:mm:ss
jackson: jackson:
@@ -96,20 +104,10 @@ spring:
sa-token: sa-token:
# token名称 (同时也是cookie名称) # token名称 (同时也是cookie名称)
token-name: Authorization token-name: Authorization
# token有效期 设为7天 (必定过期) 单位: 秒
timeout: 604800
# token临时有效期 (指定时间无操作就过期) 单位: 秒
activity-timeout: 604800
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录) # 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: true is-concurrent: true
# 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token) # 在多人登录同一账号时是否共用一个token (为true时所有登录共用一个token, 为false时每次登录新建一个token)
is-share: false is-share: false
# 是否尝试从header里读取token
is-read-header: true
# 是否尝试从cookie里读取token
is-read-cookie: false
# token前缀
token-prefix: "Bearer"
# jwt秘钥 # jwt秘钥
jwt-secret-key: abcdefghijklmnopqrstuvwxyz jwt-secret-key: abcdefghijklmnopqrstuvwxyz
@@ -117,51 +115,20 @@ sa-token:
security: security:
# 排除路径 # 排除路径
excludes: excludes:
# 获取模型信息
- /system/model/modelList
# 支付回调
- /pay/returnUrl
- /pay/notifyUrl
# 上传文件
- /resource/oss/upload
# 重置密码
- /auth/reset/password
# 聊天接口
- /chat/send
# 文件上传
- /chat/upload
# 代码生成调用
- /tool/gen/getByTableName
- /tool/gen/batchGenCode
# 静态资源
- /*.html - /*.html
- /**/*.html - /**/*.html
- /**/*.css - /**/*.css
- /**/*.js - /**/*.js
# 公共路径
- /favicon.ico - /favicon.ico
- /error - /error
# swagger 文档配置
- /*/api-docs - /*/api-docs
- /*/api-docs/** - /*/api-docs/**
- /v3/api-docs - /warm-flow-ui/config
- /v3/api-docs/** - /workflow/run
- /v3/api-docs/swagger-config
- /swagger-ui.html
- /swagger-ui/**
- /doc.html
- /webjars/**
- /swagger-resources
- /swagger-resources/**
# actuator 监控配置
- /actuator
- /actuator/**
- /workflow/**
- /admin/workflow/**
# 多租户配置 # 多租户配置
tenant: tenant:
# 是否开启 # 是否开启
enable: false enable: true
# 排除表 # 排除表
excludes: excludes:
- sys_menu - sys_menu
@@ -171,53 +138,27 @@ tenant:
- sys_role_menu - sys_role_menu
- sys_user_post - sys_user_post
- sys_user_role - sys_user_role
- sys_client
knowledge-role: - sys_oss_config
enable: false - flow_spel
# MyBatisPlus配置 # MyBatisPlus配置
# https://baomidou.com/config/ # https://baomidou.com/config/
mybatis-plus: mybatis-plus:
# 不支持多包, 如有需要可在注解配置 或 提升扫包等级 # 自定义配置 是否全局开启逻辑删除 关闭后 所有逻辑删除功能将失效
# 例如 com.**.**.mapper enableLogicDelete: true
# 多包名使用 例如 org.ruoyi.**.mapper,org.xxx.**.mapper
mapperPackage: org.ruoyi.**.mapper mapperPackage: org.ruoyi.**.mapper
# 对应的 XML 文件位置 # 对应的 XML 文件位置
mapperLocations: classpath*:mapper/**/*Mapper.xml mapperLocations: classpath*:mapper/**/*Mapper.xml
# 实体扫描多个package用逗号或者分号分隔 # 实体扫描多个package用逗号或者分号分隔
typeAliasesPackage: org.ruoyi.**.domain typeAliasesPackage: org.ruoyi.**.domain
# 启动时是否检查 MyBatis XML 文件的存在,默认不检查
checkConfigLocation: false
configuration:
# 自动驼峰命名规则camel case映射
mapUnderscoreToCamelCase: true
# MyBatis 自动映射策略
# NONE不启用 PARTIAL只对非嵌套 resultMap 自动映射 FULL对所有 resultMap 自动映射
autoMappingBehavior: FULL
# MyBatis 自动映射时未知列或未知属性处理策
# NONE不做处理 WARNING打印相关警告 FAILING抛出异常和详细信息
autoMappingUnknownColumnBehavior: NONE
# 更详细的日志输出 会有性能损耗 org.apache.ibatis.logging.stdout.StdOutImpl
# 关闭日志记录 (可单纯使用 p6spy 分析) org.apache.ibatis.logging.nologging.NoLoggingImpl
# 默认日志输出 org.apache.ibatis.logging.slf4j.Slf4jImpl
logImpl: org.apache.ibatis.logging.slf4j.Slf4jImpl
global-config: global-config:
# 是否打印 Logo banner
banner: true
dbConfig: dbConfig:
# 主键类型 # 主键类型
# AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID # AUTO 自增 NONE 空 INPUT 用户输入 ASSIGN_ID 雪花 ASSIGN_UUID 唯一 UUID
# 如需改为自增 需要将数据库表全部设置为自增
idType: ASSIGN_ID idType: ASSIGN_ID
# 逻辑已删除值
logicDeleteValue: 2
# 逻辑未删除值
logicNotDeleteValue: 0
# 字段验证策略之 insert,在 insert 的时候的字段验证策略
# IGNORED 忽略 NOT_NULL 非NULL NOT_EMPTY 非空 DEFAULT 默认 NEVER 不加入 SQL
insertStrategy: NOT_NULL
# 字段验证策略之 update,在 update 的时候的字段验证策略
updateStrategy: NOT_NULL
# 字段验证策略之 select,在 select 的时候的字段验证策略既 wrapper 根据内部 entity 生成的 where 条件
where-strategy: NOT_NULL
# 数据加密 # 数据加密
mybatis-encryptor: mybatis-encryptor:
@@ -233,57 +174,58 @@ mybatis-encryptor:
publicKey: publicKey:
privateKey: privateKey:
# api接口加密
api-decrypt:
# 是否开启全局接口加密
enabled: false
# AES 加密头标识
headerFlag: encrypt-key
# 响应加密公钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端解密私钥 MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
publicKey: MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJnNwrj4hi/y3CCJu868ghCG5dUj8wZK++RNlTLcXoMmdZWEQ/u02RgD5LyLAXGjLOjbMtC+/J9qofpSGTKSx/MCAwEAAQ==
# 请求解密私钥 非对称算法的公私钥 如SM2RSA 使用者请自行更换
# 对应前端加密公钥 MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
privateKey: MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAqhHyZfSsYourNxaY7Nt+PrgrxkiA50efORdI5U5lsW79MmFnusUA355oaSXcLhu5xxB38SMSyP2KvuKNPuH3owIDAQABAkAfoiLyL+Z4lf4Myxk6xUDgLaWGximj20CUf+5BKKnlrK+Ed8gAkM0HqoTt2UZwA5E2MzS4EI2gjfQhz5X28uqxAiEA3wNFxfrCZlSZHb0gn2zDpWowcSxQAgiCstxGUoOqlW8CIQDDOerGKH5OmCJ4Z21v+F25WaHYPxCFMvwxpcw99EcvDQIgIdhDTIqD2jfYjPTY8Jj3EDGPbH2HHuffvflECt3Ek60CIQCFRlCkHpi7hthhYhovyloRYsM+IS9h/0BzlEAuO0ktMQIgSPT3aFAgJYwKpqRYKlLDVcflZFCKY7u3UP8iWi1Qw0Y=
springdoc: springdoc:
api-docs: api-docs:
# 是否开启接口文档 # 是否开启接口文档
enabled: true enabled: true
# swagger-ui:
# # 持久化认证数据
# persistAuthorization: true
info: info:
# 标题 # 标题
title: '标题ruoyi-ai 接口文档' title: '标题ruoyi-ai管理系统_接口文档'
# 描述 # 描述
description: '' description: '描述:用于管理集团旗下公司的人员信息,具体包括XXX,XXX模块...'
# 版本 # 版本
version: '版本号: ${ruoyi.version}' version: '版本号: ${project.version}'
# 作者信息 # 作者信息
contact: contact:
name: ageerle name: ageerle
email: ageerle@163.com email: ageerle@163.com
url: https://gitee.com/ageerle/ruoyi-ai url: https://gitee.com/ageerle/ruoyi-ai
components:
# 鉴权方式配置
security-schemes:
apiKey:
type: APIKEY
in: HEADER
name: ${sa-token.token-name}
#这里定义了两个分组,可定义多个,也可以不定义
packages-to-scan: org.ruoyi
knife4j: #这里定义了两个分组,可定义多个,也可以不定义
enable: true group-configs:
setting: - group: 1.演示模块
language: zh_cn packages-to-scan: org.ruoyi.demo
- group: 2.通用模块
packages-to-scan: org.ruoyi.web
- group: 3.系统模块
packages-to-scan: org.ruoyi.system
- group: 4.代码生成模块
packages-to-scan: org.ruoyi.generator
- group: 5.工作流模块
packages-to-scan: org.ruoyi.workflow
- group: 6.MCP模块
packages-to-scan: org.ruoyi.mcp
# 防止XSS攻击 # 防止XSS攻击
xss: xss:
# 过滤开关 # 过滤开关
enabled: true enabled: true
# 排除链接(多个用逗号分隔) # 排除链接
excludes: /system/notice,/v3/api-docs/**,/doc.html,/swagger-ui/**,/swagger-ui.html,/swagger-resources/**,/webjars/**,/druid/**,/actuator/**,/favicon.ico excludeUrls:
# 匹配链接 - /system/notice
urlPatterns: /system/*,/monitor/*,/tool/*
# 全局线程池相关配置
thread-pool:
# 是否开启线程池
enabled: false
# 队列最大长度
queueCapacity: 128
# 线程池维护线程所允许的空闲时间
keepAliveSeconds: 300
--- # 分布式锁 lock4j 全局配置 --- # 分布式锁 lock4j 全局配置
lock4j: lock4j:
@@ -303,43 +245,39 @@ management:
show-details: ALWAYS show-details: ALWAYS
logfile: logfile:
external-file: ./logs/sys-console.log external-file: ./logs/sys-console.log
health:
# 禁用 Neo4j 健康检查(当知识图谱功能未启用时)
neo4j:
enabled: false
# websocket --- # 默认/推荐使用sse推送
# websocket sse:
websocket:
enabled: true enabled: true
path: /resource/sse
--- # websocket
websocket:
# 如果关闭 需要和前端开关一起关闭
enabled: false
# 路径 # 路径
path: '/resource/websocket' path: /resource/websocket
# 设置访问源地址 # 设置访问源地址
allowedOrigins: '*' allowedOrigins: '*'
spring: --- # warm-flow工作流配置
ai: warm-flow:
openai: # 是否开启工作流默认true
api-key: sk-xx enabled: true
base-url: https://api.pandarobot.chat/ # 是否开启设计器ui
mcp: ui: true
client: # 是否显示流程图顶部文字
enabled: false top-text-show: true
name: ruoyi-ai-mcp # 是否渲染节点悬浮提示默认true
sse: node-tooltip: true
connections: # 默认Authorization如果有多个token用逗号分隔
server: token-name: ${sa-token.token-name},clientid
url: http://127.0.0.1:8081
stdio:
servers-configuration: classpath:mcp-server.json
request-timeout: 300s
# 向量库配置 # 向量库配置
vector-store: vector-store:
# 向量存储类型 可选(weaviate/milvus) # 向量存储类型 可选(weaviate/milvus/qdrant)
# 如需修改向量库类型,请修改此配置值! # 如需修改向量库类型,请修改此配置值!
type: weaviate type: milvus
# Weaviate配置 # Weaviate配置
weaviate: weaviate:
protocol: http protocol: http
@@ -349,56 +287,10 @@ vector-store:
milvus: milvus:
url: http://localhost:19530 url: http://localhost:19530
collectionname: LocalKnowledge collectionname: LocalKnowledge
# Qdrant配置
qdrant:
--- # Neo4j 知识图谱配置 host: localhost
#neo4j: port: 6334
# uri: bolt://117.72.192.162:7687 collectionname: LocalKnowledge
# username: neo4j api-key:
# password: MySecurePass123! use-tls: false
# database: neo4j
# max-connection-pool-size: 50
# connection-timeout-seconds: 30
# 知识图谱配置
knowledge:
graph:
# 是否启用知识图谱功能
enabled: false
# 图数据库类型: neo4j 或 apache-age
database-type: neo4j
# 是否自动创建索引
auto-create-index: true
# 批量处理大小
batch-size: 1000
# 最大重试次数
max-retry-count: 3
# 实体抽取配置
extraction:
# 置信度阈值(低于此值的实体将被过滤)
confidence-threshold: 0.7
# 最大实体数量(每个文档)
max-entities-per-doc: 100
# 最大关系数量(每个文档)
max-relations-per-doc: 200
# 文本分片大小(用于长文档)
chunk-size: 2000
# 分片重叠大小
chunk-overlap: 200
# 查询配置
query:
# 默认查询限制数量
default-limit: 100
# 最大查询限制数量
max-limit: 1000
# 路径查询最大深度
max-path-depth: 5
# 查询超时时间(秒)
timeout-seconds: 30
# 是否启用查询缓存
cache-enabled: true
# 缓存过期时间(分钟)
cache-expire-minutes: 60

View File

@@ -1,2 +1,8 @@
Application Version: ${revision} Application Version: ${revision}
Spring Boot Version: ${spring-boot.version} Spring Boot Version: ${spring-boot.version}
__________ _____.___.__ _____ .___
\______ \__ __ ____\__ | |__| / _ \ | |
| _/ | \/ _ \/ | | | ______ / /_\ \| |
| | \ | ( <_> )____ | | /_____/ / | \ |
|____|_ /____/ \____// ______|__| \____|__ /___|
\/ \/ \/

View File

@@ -17,6 +17,7 @@ user.username.length.valid=账户长度必须在{min}到{max}个字符之间
user.password.not.blank=用户密码不能为空 user.password.not.blank=用户密码不能为空
user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间 user.password.length.valid=用户密码长度必须在{min}到{max}个字符之间
user.password.not.valid=* 5-50个字符 user.password.not.valid=* 5-50个字符
user.password.format.valid=密码必须包含大写字母、小写字母、数字和特殊字符
user.email.not.valid=邮箱格式错误 user.email.not.valid=邮箱格式错误
user.email.not.blank=邮箱不能为空 user.email.not.blank=邮箱不能为空
user.phonenumber.not.blank=用户手机号不能为空 user.phonenumber.not.blank=用户手机号不能为空
@@ -28,6 +29,10 @@ user.register.error=注册失败,请联系系统管理人员
user.notfound=请重新登录 user.notfound=请重新登录
user.forcelogout=管理员强制退出,请重新登录 user.forcelogout=管理员强制退出,请重新登录
user.unknown.error=未知错误,请重新登录 user.unknown.error=未知错误,请重新登录
auth.grant.type.error=认证权限类型错误
auth.grant.type.blocked=认证权限类型已禁用
auth.grant.type.not.blank=认证权限类型不能为空
auth.clientid.not.blank=认证客户端id不能为空
##文件上传消息 ##文件上传消息
upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB upload.exceed.maxSize=上传的文件大小超出限制的文件大小!<br/>允许的文件最大大小是:{0}MB
upload.filename.exceed.length=上传的文件名最长{0}个字符 upload.filename.exceed.length=上传的文件名最长{0}个字符
@@ -46,7 +51,10 @@ sms.code.retry.limit.exceed=短信验证码输入错误{0}次,帐户锁定{1}
email.code.not.blank=邮箱验证码不能为空 email.code.not.blank=邮箱验证码不能为空
email.code.retry.limit.count=邮箱验证码输入错误{0}次 email.code.retry.limit.count=邮箱验证码输入错误{0}次
email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟 email.code.retry.limit.exceed=邮箱验证码输入错误{0}次,帐户锁定{1}分钟
xcx.code.not.blank=小程序code不能为空 xcx.code.not.blank=小程序[code]不能为空
social.source.not.blank=第三方登录平台[source]不能为空
social.code.not.blank=第三方登录平台[code]不能为空
social.state.not.blank=第三方登录平台[state]不能为空
##租户 ##租户
tenant.number.not.blank=租户编号不能为空 tenant.number.not.blank=租户编号不能为空
tenant.not.exists=对不起, 您的租户不存在,请联系管理员 tenant.not.exists=对不起, 您的租户不存在,请联系管理员

Some files were not shown because too many files have changed in this diff Show More