13 Commits

Author SHA1 Message Date
ageer
158a0190b5 feat: 优化会话管理查询逻辑 2025-05-16 23:52:43 +08:00
ageerle
096fc11313 Merge pull request #86 from alanpeng/main
Containerized service package/imagese build and deploy
2025-05-16 22:36:21 +08:00
root
e9ac795d23 Add manual 2025-05-16 22:31:14 +08:00
root
32f1a6bab1 Containerized service package/imagese build and deploy 2025-05-16 22:29:36 +08:00
ageerle
052069a2df Merge pull request #85 from MuSan-Li/feature_20250516_fix_auth
修复未登录也可以访问接口
2025-05-16 22:11:41 +08:00
MuSan-Li
e1c997883f 修复未登录也可以访问接口 2025-05-16 21:01:37 +08:00
ageerle
031b7da198 Merge pull request #84 from janzhou123/main
feat:pdf文件解析图片和分析图片,上传向量数据库都修改成 成异步处理
2025-05-16 16:29:21 +08:00
zhouweiyi
931af963b1 feat:pdf文件解析图片和分析图片,上传向量数据库都修改成 成异步处理 2025-05-16 13:50:12 +08:00
Albert
f5fa7d5da8 Merge branch 'ageerle:main' into main 2025-05-15 17:49:09 +08:00
zhouweiyi
c6ffbcb3cf feat:pdf文件解析图片和分析图片,上传向量数据库都修改成 成异步处理 2025-05-15 17:46:38 +08:00
zhouweiyi
584212c569 Merge remote-tracking branch 'origin/main'
# Conflicts:
#	ruoyi-modules/ruoyi-chat/src/main/java/org/ruoyi/chat/service/knowledge/KnowledgeInfoServiceImpl.java
2025-05-14 16:13:07 +08:00
zhouweiyi
dc9bf3e25d pdf文件解析成异步处理 2025-05-14 15:41:57 +08:00
zhouweiyi
52e0feda01 修改方法描述 2025-05-13 13:44:31 +08:00
61 changed files with 5482 additions and 958 deletions

View File

@@ -0,0 +1,5 @@
FROM nginx:1.25-alpine
COPY dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,22 @@
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /prod-api/ {
proxy_pass http://ruoyi-backend:6039/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1,5 @@
FROM openjdk:17-jdk
WORKDIR /app
COPY ruoyi-admin.jar /app/ruoyi-admin.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","ruoyi-admin.jar"]

View File

@@ -0,0 +1,5 @@
FROM nginx:1.25-alpine
COPY dist/ /usr/share/nginx/html/
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

View File

@@ -0,0 +1,22 @@
server {
listen 80;
server_name localhost;
location / {
root /usr/share/nginx/html;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /api/ {
proxy_pass http://ruoyi-backend:6039/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}

View File

@@ -0,0 +1,5 @@
# 应用标题
VITE_APP_TITLE=RuoYi AI
# 应用命名空间用于缓存、store等功能的前缀确保隔离
VITE_APP_NAMESPACE=vben-web-antd

View File

@@ -0,0 +1,7 @@
# public path
VITE_BASE=/
# Basic interface address SPA
VITE_GLOB_API_URL=/api
VITE_VISUALIZER=true

View File

@@ -0,0 +1,25 @@
# 端口号
VITE_PORT=5666
VITE_BASE=/
# 是否开启 Nitro Mock服务true 为开启false 为关闭
VITE_NITRO_MOCK=false
# 是否打开 devtoolstrue 为打开false 为关闭
VITE_DEVTOOLS=false
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 后台请求路径 具体在vite.config.mts配置代理
VITE_GLOB_API_URL=/api
# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
VITE_GLOB_ENABLE_ENCRYPT=false
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# 开启SSE
VITE_GLOB_SSE_ENABLE=false

View File

@@ -0,0 +1,32 @@
VITE_BASE=/
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=gzip
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=history
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true
# 后端接口地址
VITE_GLOB_API_URL=/prod-api
# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
VITE_GLOB_ENABLE_ENCRYPT=false
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# 开启SSE
VITE_GLOB_SSE_ENABLE=false

View File

@@ -0,0 +1,35 @@
# 该文件是为了给一个增加环境变量打包的例子
# 对应在根目录package.json -> build:antd:test 命令
VITE_BASE=/
# 是否开启压缩,可以设置为 none, brotli, gzip
VITE_COMPRESS=gzip
# 是否开启 PWA
VITE_PWA=false
# vue-router 的模式
VITE_ROUTER_HISTORY=history
# 是否注入全局loading
VITE_INJECT_APP_LOADING=true
# 打包后是否生成dist.zip
VITE_ARCHIVER=true
# 后端接口地址
VITE_GLOB_API_URL=/test-api
# 全局加密开关(即开启了加解密功能才会生效 不是全部接口加密 需要和后端对应)
VITE_GLOB_ENABLE_ENCRYPT=true
# RSA公钥 请求加密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PUBLIC_KEY=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAKoR8mX0rGKLqzcWmOzbfj64K8ZIgOdHnzkXSOVOZbFu/TJhZ7rFAN+eaGkl3C4buccQd/EjEsj9ir7ijT7h96MCAwEAAQ==
# RSA私钥 响应解密使用 注意这两个是两对RSA公私钥 请求加密-后端解密是一对 响应解密-后端加密是一对
VITE_GLOB_RSA_PRIVATE_KEY=MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAmc3CuPiGL/LcIIm7zryCEIbl1SPzBkr75E2VMtxegyZ1lYRD+7TZGAPkvIsBcaMs6Nsy0L78n2qh+lIZMpLH8wIDAQABAkEAk82Mhz0tlv6IVCyIcw/s3f0E+WLmtPFyR9/WtV3Y5aaejUkU60JpX4m5xNR2VaqOLTZAYjW8Wy0aXr3zYIhhQQIhAMfqR9oFdYw1J9SsNc+CrhugAvKTi0+BF6VoL6psWhvbAiEAxPPNTmrkmrXwdm/pQQu3UOQmc2vCZ5tiKpW10CgJi8kCIFGkL6utxw93Ncj4exE/gPLvKcT+1Emnoox+O9kRXss5AiAMtYLJDaLEzPrAWcZeeSgSIzbL+ecokmFKSDDcRske6QIgSMkHedwND1olF8vlKsJUGK3BcdtM8w4Xq7BpSBwsloE=
# 客户端id
VITE_GLOB_APP_CLIENT_ID=e5cd7e4891bf95d1d19206ce24a7b32e
# 开启SSE
VITE_GLOB_SSE_ENABLE=true

View File

@@ -0,0 +1,37 @@
import { defineConfig } from '@vben/vite-config';
// 自行取消注释来启用按需导入功能
// import { AntDesignVueResolver } from 'unplugin-vue-components/resolvers';
// import Components from 'unplugin-vue-components/vite';
export default defineConfig(async () => {
return {
application: {},
vite: {
plugins: [
// Components({
// dirs: [], // 默认会导入src/components目录下所有组件 不需要
// dts: './types/components.d.ts', // 输出类型文件
// resolvers: [
// AntDesignVueResolver({
// // 需要排除Button组件 全局已经默认导入了
// exclude: ['Button'],
// importStyle: false, // css in js
// }),
// ],
// }),
],
server: {
proxy: {
'/api': {
changeOrigin: true,
rewrite: (path) => path.replace(/^\/api/, ''),
// mock代理目标地址
target: 'http://ruoyi-backend:6039',
ws: true,
},
},
},
},
};
});

View File

@@ -0,0 +1,174 @@
--- # 临时文件存储位置 避免临时文件被系统清理报错
spring.servlet.multipart.location: /ruoyi/server/temp
--- # 监控中心配置
spring.boot.admin.client:
# 增加客户端开关
enabled: false
url: http://localhost:9090/admin
instance:
service-host-type: IP
username: ruoyi
password: 123456
--- # xxl-job 配置
xxl.job:
# 执行器开关
enabled: false
# 调度中心地址:如调度中心集群部署存在多个地址则用逗号分隔。
admin-addresses: http://localhost:9100/xxl-job-admin
# 执行器通讯TOKEN非空时启用
access-token: xxl-job
executor:
# 执行器AppName执行器心跳注册分组依据为空则关闭自动注册
appname: xxl-job-executor
# 执行器端口号 执行器从9101开始往后写
port: 9101
# 执行器注册默认IP:PORT
address:
# 执行器IP默认自动获取IP
ip:
# 执行器运行日志文件存储磁盘路径
logpath: ./logs/xxl-job
# 执行器日志文件保存天数大于3生效
logretentiondays: 30
--- # 数据源配置
spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# 动态数据源文档 https://www.kancloud.cn/tracy5546/dynamic-datasource/content
dynamic:
# 性能分析插件(有性能损耗 不建议生产环境使用)
p6spy: false
# 设置默认的数据源或者数据源组,默认值即为 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://mysql:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username: root
password: root
# 从库数据源
slave:
lazy: true
type: ${spring.datasource.type}
driverClassName: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://mysql:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
username:
password:
# oracle:
# type: ${spring.datasource.type}
# driverClassName: oracle.jdbc.OracleDriver
# url: jdbc:oracle:thin:@//localhost:1521/XE
# username: ROOT
# password: root
# hikari:
# connectionTestQuery: SELECT 1 FROM DUAL
# postgres:
# type: ${spring.datasource.type}
# driverClassName: org.postgresql.Driver
# url: jdbc:postgresql://localhost:5432/postgres?useUnicode=true&characterEncoding=utf8&useSSL=true&autoReconnect=true&reWriteBatchedInserts=true
# username: root
# password: root
# sqlserver:
# type: ${spring.datasource.type}
# driverClassName: com.microsoft.sqlserver.jdbc.SQLServerDriver
# url: jdbc:sqlserver://localhost:1433;DatabaseName=tempdb;SelectMethod=cursor;encrypt=false;rewriteBatchedStatements=true
# username: SA
# password: root
hikari:
# 最大连接池数量
maxPoolSize: 20
# 最小空闲线程数量
minIdle: 10
# 配置获取连接等待超时的时间
connectionTimeout: 30000
# 校验超时时间
validationTimeout: 5000
# 空闲连接存活最大时间默认10分钟
idleTimeout: 600000
# 此属性控制池中连接的最长生命周期值0表示无限生命周期默认30分钟
maxLifetime: 1800000
# 连接测试query配置检测连接是否有效
connectionTestQuery: SELECT 1
# 多久检查一次连接的活性
keepaliveTime: 30000
--- # redis 单机配置(单机与集群只能开启一个另一个需要注释掉)
spring.data:
redis:
# 地址
host: redis
# 端口默认为6379
port: 6379
# 数据库索引
database: 0
# 密码(如没有密码请注释掉)
# password:
# 连接超时时间
timeout: 10s
# 是否开启ssl
ssl: false
redisson:
# redis key前缀
keyPrefix:
# 线程池数量
threads: 16
# Netty线程池数量
nettyThreads: 32
# 单节点配置
singleServerConfig:
# 客户端名称
clientName: ${ruoyi.name}
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
--- # mail 邮件发送
mail:
enabled: false
host: smtp.163.com
port: 465
# 是否需要用户名密码验证
auth: true
# 发送方遵循RFC-822标准
from: pengpan@163.com
# 用户名注意如果使用foxmail邮箱此处user为qq号
user: pengpan@163.com
# 密码注意某些邮箱需要为SMTP服务单独设置密码详情查看相关帮助
pass: JXLAASWFNLNNAYJU
# 使用 STARTTLS安全连接STARTTLS是对纯文本通信协议的扩展。
starttlsEnable: true
# 使用SSL安全连接
sslEnable: true
# SMTP超时时长单位毫秒缺省值不超时
timeout: 0
# Socket连接超时值单位毫秒缺省值不超时
connectionTimeout: 0
--- # sms 短信
sms:
enabled: false
# 阿里云 dysmsapi.aliyuncs.com
# 腾讯云 sms.tencentcloudapi.com
endpoint: "dysmsapi.aliyuncs.com"
accessKeyId: xxxxxxx
accessKeySecret: xxxxxx
signName: 测试
# 腾讯专用
sdkAppId:

View File

@@ -0,0 +1,22 @@
#!/bin/bash
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/.env.analyze
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/.env.development
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/.env.production
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/.env.test
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/vite.config.mts
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-admin/.env.analyze /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-admin/.env.development /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-admin/.env.production /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-admin/.env.test /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-admin/vite.config.mts /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/
docker run --rm --name build-ruoyi-ai-admin -v /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin:/app -w /app node:20 bash -c "npm install -g pnpm && pnpm install && pnpm build"
rm -f /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-admin/dist.zip
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-admin/apps/web-antd/dist.zip /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-admin/
cd /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-admin/
rm -rf dist
unzip dist.zip -d dist
rm -f dist.zip
docker build -t ruoyi-ai-admin:v2.0.5 .

View File

@@ -0,0 +1,8 @@
#!/bin/bash
rm -f /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/ruoyi-admin/src/main/resources/application-prod.yml
cp /root/ruoyi-ai-docker/build-docker-images/modify-source-code/ruoyi-ai-backend/application-prod.yml /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/ruoyi-admin/src/main/resources/application-prod.yml
docker run --rm --name build-ruoyi-ai-backend -v /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend:/app -w /app maven:3.9.9-eclipse-temurin-17-alpine bash -c "mvn clean package -Pprod"
rm -f /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-backend/ruoyi-admin.jar
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/ruoyi-admin/target/ruoyi-admin.jar /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-backend/
cd /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-backend/
docker build -t ruoyi-ai-backend:v2.0.5 .

View File

@@ -0,0 +1,6 @@
#!/bin/bash
docker run --rm --name build-ruoyi-ai-web -v /root/ruoyi-ai-docker/source-code/ruoyi-ai-web:/app -w /app node:20 bash -c "npm install -g pnpm && pnpm install && pnpm approve-builds && pnpm build"
rm -rf /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-web/dist
cp -pr /root/ruoyi-ai-docker/source-code/ruoyi-ai-web/dist /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-web/
cd /root/ruoyi-ai-docker/build-docker-images/Dockerfile-Resources/ruoyi-ai-web/
docker build -t ruoyi-ai-web:v2.0.5 .

View File

@@ -0,0 +1,2 @@
#!/bin/bash
sed -i 's/[ \t]*$//' filename

26
docker-deploy/deploy/.env Normal file
View File

@@ -0,0 +1,26 @@
# Timezone
TZ=Asia/Shanghai
# MySQL Configuration
MYSQL_ROOT_PASSWORD=root
MYSQL_DATABASE=ruoyi-ai
MYSQL_PORT=3306
# Redis Configuration
REDIS_PORT=6379
REDIS_PASSWORD=
REDIS_DATABASE=0
REDIS_TIMEOUT=10s
# Backend Configuration
BACKEND_SERVER_PORT=6039
DB_URL=jdbc:mysql://mysql:3306/ruoyi-ai?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8&autoReconnect=true&rewriteBatchedStatements=true
DB_USERNAME=root
DB_PASSWORD=root
REDIS_HOST=redis
# Admin Configuration
ADMIN_SERVER_PORT=8082
# Web Configuration
WEB_SERVER_PORT=8081

View File

@@ -0,0 +1,6 @@
#!/bin/bash
rm -f /root/ruoyi-ai-docker/deploy/mysql-init/*.sql
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/script/sql/ruoyi-ai.sql /root/ruoyi-ai-docker/deploy/mysql-init/01_ruoyi-ai.sql
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/script/sql/update/20250407.sql /root/ruoyi-ai-docker/deploy/mysql-init/02_update_20250407.sql
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/script/sql/update/20250505.sql /root/ruoyi-ai-docker/deploy/mysql-init/03_update_20250505.sql
cp /root/ruoyi-ai-docker/source-code/ruoyi-ai-backend/script/sql/update/20250509.sql /root/ruoyi-ai-docker/deploy/mysql-init/04_update_20250509.sql

View File

@@ -0,0 +1,83 @@
version: '3'
services:
mysql:
image: mysql:8.0.33
container_name: ruoyi-ai-mysql
env_file:
- ./.env
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
#ports:
# - "${MYSQL_PORT}:3306"
volumes:
- ./mysql-init:/docker-entrypoint-initdb.d
- ./data/mysql:/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
restart: always
networks:
- ruoyi-net
redis:
image: redis:6.2
container_name: ruoyi-ai-redis
env_file:
- ./.env
#ports:
# - "${REDIS_PORT}:6379"
volumes:
- ./data/redis:/data
command: redis-server --appendonly yes ${REDIS_PASSWORD:+--requirepass ${REDIS_PASSWORD}}
restart: always
networks:
- ruoyi-net
ruoyi-backend:
image: ruoyi-ai-backend:v2.0.5
container_name: ruoyi-ai-backend
env_file:
- ./.env
ports:
- "${BACKEND_SERVER_PORT}:${BACKEND_SERVER_PORT}"
volumes:
- ./data/logs:/ruoyi/server/logs
restart: always
depends_on:
- mysql
- redis
networks:
- ruoyi-net
ruoyi-admin:
image: ruoyi-ai-admin:v2.0.5
container_name: ruoyi-ai-admin
ports:
#- "8082:80"
- "${ADMIN_SERVER_PORT}:80"
restart: always
depends_on:
- ruoyi-backend
networks:
- ruoyi-net
ruoyi-web:
image: ruoyi-ai-web:v2.0.5
container_name: ruoyi-ai-web
ports:
#- "8081:80"
- "${WEB_SERVER_PORT}:80"
restart: always
depends_on:
- ruoyi-backend
networks:
- ruoyi-net
networks:
ruoyi-net:
driver: bridge

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,4 @@
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907575746601119746, '000000', 'vector', 'text-embedding-3-small', 'text-embedding-3-small', 0, '2', '0', NULL, 'https://api.pandarobot.chat/', 'sk-cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:27:54', 1, '2025-04-03 07:27:54', 'text-embedding-3-small');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576007017066497, '000000', 'vector', 'quentinz/bge-large-zh-v1.5', 'bge-large-zh-v1.5', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'cdBlIaZcufccm2RaDe547cBd054d49C7B0782eCa72A0052b', 103, 1, '2025-04-03 07:28:56', 1, '2025-04-03 07:28:56', 'bge-large-zh-v1.5');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907576806191362049, '000000', 'vector', 'nomic-embed-text', 'nomic-embed-text', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'nomic-embed-text', 103, 1, '2025-04-03 07:32:06', 1, '2025-04-03 07:32:06', 'nomic-embed-text');
INSERT INTO `chat_model` (`id`, `tenant_id`, `category`, `model_name`, `model_describe`, `model_price`, `model_type`, `model_show`, `system_prompt`, `api_host`, `api_key`, `create_dept`, `create_by`, `create_time`, `update_by`, `update_time`, `remark`) VALUES (1907577073490161665, '000000', 'vector', 'snowflake-arctic-embed', 'snowflake-arctic-embed', 0, '2', '0', NULL, 'http://127.0.0.1:11434/', 'snowflake-arctic-embed', 103, 1, '2025-04-03 07:33:10', 1, '2025-04-03 07:33:10', 'snowflake-arctic-embed');

View File

@@ -0,0 +1,42 @@
/*
Navicat MySQL Data Transfer
Source Server : 129.211.24.7
Source Server Type : MySQL
Source Server Version : 50744
Source Host : 129.211.24.7:3306
Source Schema : ry-vue
Target Server Type : MySQL
Target Server Version : 50744
File Encoding : 65001
Date: 05/05/2025 15:01:08
*/
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for chat_session
-- ----------------------------
DROP TABLE IF EXISTS `chat_session`;
CREATE TABLE `chat_session` (
`id` bigint(20) NOT NULL COMMENT '主键',
`user_id` bigint(20) NULL DEFAULT NULL COMMENT '用户id',
`session_title` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '会话标题',
`session_content` text CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL COMMENT '会话内容',
`create_dept` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '部门',
`create_by` bigint(20) NULL DEFAULT NULL COMMENT '创建者',
`create_time` datetime NULL DEFAULT NULL COMMENT '创建时间',
`update_by` bigint(20) NULL DEFAULT NULL COMMENT '更新者',
`update_time` datetime NULL DEFAULT NULL COMMENT '更新时间',
`remark` varchar(500) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL COMMENT '备注',
PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci COMMENT = '会话管理' ROW_FORMAT = Dynamic;
SET FOREIGN_KEY_CHECKS = 1;
ALTER TABLE `chat_message`
ADD COLUMN `session_id` bigint(20) NULL COMMENT '会话id' AFTER `id`;

View File

@@ -0,0 +1,4 @@
ALTER TABLE `chat_model`
ADD COLUMN `api_url` varchar(50) NULL COMMENT '请求后缀' AFTER `api_key`;
INSERT INTO `chat_config` (`id`, `category`, `config_name`, `config_value`, `config_dict`, `create_dept`, `create_time`, `create_by`, `update_by`, `update_time`, `remark`, `version`, `del_flag`, `update_ip`, `tenant_id`) VALUES (1779450794872414211, 'chat', 'apiUrl', 'v1/chat/completions', 'API 请求后缀', 103, '2024-04-14 18:05:05', '1', '1', '2025-04-23 22:29:04', NULL, NULL, '0', NULL, 0);

View File

@@ -0,0 +1,4 @@
#!/bin/bash
rm -rf ruoyi-ai-admin
git clone https://github.com/ageerle/ruoyi-admin
mv ruoyi-admin ruoyi-ai-admin

View File

@@ -0,0 +1,7 @@
#!/bin/bash
rm -rf ruoyi-ai-backend
git clone https://github.com/ageerle/ruoyi-ai
mv ruoyi-ai ruoyi-ai-backend
cd ruoyi-ai-backend
# git checkout v2.0.4
# cd ..

View File

@@ -0,0 +1,4 @@
#!/bin/bash
rm -rf ruoyi-ai-web
git clone https://github.com/ageerle/ruoyi-web
mv ruoyi-web ruoyi-ai-web

View File

@@ -3,6 +3,8 @@ package org.ruoyi;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.metrics.buffering.BufferingApplicationStartup;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
/**
* 启动程序
@@ -10,6 +12,8 @@ import org.springframework.boot.context.metrics.buffering.BufferingApplicationSt
* @author Lion Li
*/
@SpringBootApplication
@EnableScheduling
@EnableAsync
public class RuoYiAIApplication {
public static void main(String[] args) {

View File

@@ -10,6 +10,7 @@ import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandl
import java.util.*;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
/**
* 获取所有Url配置
@@ -19,23 +20,24 @@ import java.util.regex.Pattern;
@Data
public class AllUrlHandler implements InitializingBean {
private static final Pattern PATTERN = Pattern.compile("\\{(.*?)\\}");
private List<String> urls = new ArrayList<>();
private List<String> urls = new ArrayList<>(256);
@Override
public void afterPropertiesSet() {
Set<String> set = new HashSet<>();
RequestMappingHandlerMapping mapping = SpringUtils.getBean("requestMappingHandlerMapping", RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> map = mapping.getHandlerMethods();
map.keySet().forEach(info -> {
// 获取注解上边的 path 替代 path variable 为 *
if(info.getPathPatternsCondition()!=null){
Objects.requireNonNull(info.getPathPatternsCondition().getPatterns())
.forEach(url -> set.add(ReUtil.replaceAll(url.getPatternString(), PATTERN, "*")));
}
});
urls.addAll(set);
String name = "requestMappingHandlerMapping";
RequestMappingHandlerMapping mapping = SpringUtils.getBean(name, RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethods = mapping.getHandlerMethods();
Pattern pattern = Pattern.compile("\\{(.*?)\\}");
Set<String> handlerSet = handlerMethods.keySet().stream()
.flatMap(info -> info.getPatternsCondition().getPatterns().stream())
.collect(Collectors.toSet());
// 获取注解上边的 path 替代 path variable 为 *
handlerSet.stream().map(path -> ReUtil.replaceAll(path, pattern, "*"))
.forEach(item -> urls.add(item));
}
}

View File

@@ -29,13 +29,11 @@ public class ChatSessionBo extends BaseEntity {
/**
* 用户id
*/
@NotNull(message = "用户id不能为空", groups = { AddGroup.class, EditGroup.class })
private Long userId;
/**
* 会话标题
*/
@NotBlank(message = "会话标题不能为空", groups = { AddGroup.class, EditGroup.class })
private String sessionTitle;
/**
@@ -47,7 +45,6 @@ public class ChatSessionBo extends BaseEntity {
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark;

View File

@@ -2,6 +2,7 @@ package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.common.satoken.utils.LoginHelper;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
@@ -45,6 +46,10 @@ public class ChatMessageServiceImpl implements IChatMessageService {
*/
@Override
public TableDataInfo<ChatMessageVo> queryPageList(ChatMessageBo bo, PageQuery pageQuery) {
if(!LoginHelper.isLogin()){
return TableDataInfo.build();
}
bo.setUserId(LoginHelper.getUserId());
LambdaQueryWrapper<ChatMessage> lqw = buildQueryWrapper(bo);
Page<ChatMessageVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
@@ -64,9 +69,8 @@ public class ChatMessageServiceImpl implements IChatMessageService {
LambdaQueryWrapper<ChatMessage> lqw = Wrappers.lambdaQuery();
lqw.eq(bo.getUserId() != null, ChatMessage::getUserId, bo.getUserId());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), ChatMessage::getContent, bo.getContent());
lqw.eq(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole());
lqw.eq(bo.getDeductCost() != null, ChatMessage::getDeductCost, bo.getDeductCost());
lqw.eq(bo.getTotalTokens() != null, ChatMessage::getTotalTokens, bo.getTotalTokens());
lqw.eq(bo.getSessionId() != null, ChatMessage::getSessionId, bo.getSessionId());
lqw.like(StringUtils.isNotBlank(bo.getRole()), ChatMessage::getRole, bo.getRole());
lqw.like(StringUtils.isNotBlank(bo.getModelName()), ChatMessage::getModelName, bo.getModelName());
return lqw;
}

View File

@@ -114,6 +114,10 @@
<artifactId>commons-io</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>org.ruoyi</groupId>
<artifactId>ruoyi-system-api</artifactId>
</dependency>
</dependencies>

View File

@@ -0,0 +1,18 @@
package org.ruoyi.constant;
/**
* @Description:
* @Date: 2025/5/14 下午2:04
*/
public class DealStatus {
//未开始
public static final Integer STATUS_10 = 10;
//进行中
public static final Integer STATUS_20 = 20;
//已结束
public static final Integer STATUS_30 = 30;
//处理失败
public static final Integer STATUS_40 = 40;
}

View File

@@ -18,44 +18,66 @@ import java.io.Serial;
@TableName("knowledge_attach")
public class KnowledgeAttach extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
*
*/
@TableId(value = "id")
private Long id;
/**
* 知识库ID
*/
private String kid;
/**
* 知识库ID
*/
private String kid;
/**
* 文档ID
*/
private String docId;
/**
* 文档ID
*/
private String docId;
/**
* 文档名称
*/
private String docName;
/**
* 文档名称
*/
private String docName;
/**
* 文档类型
*/
private String docType;
/**
* 文档类型
*/
private String docType;
/**
* 文档内容
*/
private String content;
/**
* 文档内容
*/
private String content;
/**
* 备注
*/
private String remark;
/**
* 备注
*/
private String remark;
/**
* 对象存储主键
*/
private Long ossId;
/**
* 拆解图片状态10未开始20进行中30已完成
*/
private Integer picStatus;
/**
* 分析图片状态10未开始20进行中30已完成
*/
private Integer picAnysStatus;
/**
* 写入向量数据库状态10未开始20进行中30已完成
*/
private Integer vectorStatus;
}

View File

@@ -0,0 +1,81 @@
package org.ruoyi.domain;
import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import lombok.EqualsAndHashCode;
import java.io.Serial;
import org.ruoyi.core.domain.BaseEntity;
/**
* 知识库附件图片列对象 knowledge_attach_pic
*
* @author Albert
* @date 2025-05-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@TableName("knowledge_attach_pic")
public class KnowledgeAttachPic extends BaseEntity {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@TableId(value = "id")
private Long id;
/**
* 知识库id
*/
private String kid;
/**
* 附件id
*/
private String aid;
/**
* 文档名称
*/
private String docName;
/**
* 文档类型
*/
private String docType;
/**
* 文档内容
*/
private String content;
/**
* 所在页数
*/
private Integer pageNum;
/**
* 所在页index
*/
private Integer indexNum;
/**
* 分析图片状态10未开始20进行中30已完成
*/
private Integer picAnysStatus;
/**
* 对象存储主键
*/
private Long ossId;
/**
* 备注
*/
private String remark;
}

View File

@@ -20,47 +20,72 @@ import jakarta.validation.constraints.*;
@AutoMapper(target = KnowledgeAttach.class, reverseConvertGenerate = false)
public class KnowledgeAttachBo extends BaseEntity {
/**
*
*/
@NotNull(message = "不能为空", groups = { EditGroup.class })
private Long id;
/**
*
*/
@NotNull(message = "不能为空", groups = {EditGroup.class})
private Long id;
/**
* 知识库ID
*/
@NotBlank(message = "知识库ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String kid;
/**
* 知识库ID
*/
@NotBlank(message = "知识库ID不能为空", groups = {AddGroup.class, EditGroup.class})
private String kid;
/**
* 文档ID
*/
@NotBlank(message = "文档ID不能为空", groups = { AddGroup.class, EditGroup.class })
private String docId;
/**
* 文档ID
*/
@NotBlank(message = "文档ID不能为空", groups = {AddGroup.class, EditGroup.class})
private String docId;
/**
* 文档名称
*/
@NotBlank(message = "文档名称不能为空", groups = { AddGroup.class, EditGroup.class })
private String docName;
/**
* 文档名称
*/
@NotBlank(message = "文档名称不能为空", groups = {AddGroup.class, EditGroup.class})
private String docName;
/**
* 文档类型
*/
@NotBlank(message = "文档类型不能为空", groups = { AddGroup.class, EditGroup.class })
private String docType;
/**
* 文档类型
*/
@NotBlank(message = "文档类型不能为空", groups = {AddGroup.class, EditGroup.class})
private String docType;
/**
* 文档内容
*/
@NotBlank(message = "文档内容不能为空", groups = { AddGroup.class, EditGroup.class })
private String content;
/**
* 文档内容
*/
@NotBlank(message = "文档内容不能为空", groups = {AddGroup.class, EditGroup.class})
private String content;
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = { AddGroup.class, EditGroup.class })
private String remark;
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class})
private String remark;
/**
* 对象存储主键
*/
@NotNull(message = "对象存储主键不能为空", groups = {AddGroup.class, EditGroup.class})
private Long ossId;
/**
* 拆解图片状态10未开始20进行中30已完成
*/
@NotNull(message = "拆解图片状态10未开始20进行中30已完成不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer picStatus;
/**
* 分析图片状态10未开始20进行中30已完成
*/
@NotNull(message = "分析图片状态10未开始20进行中30已完成不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer picAnysStatus;
/**
* 写入向量数据库状态10未开始20进行中30已完成
*/
@NotNull(message = "写入向量数据库状态10未开始20进行中30已完成不能为空", groups = { AddGroup.class, EditGroup.class })
private Integer vectorStatus;
}

View File

@@ -0,0 +1,90 @@
package org.ruoyi.domain.bo;
import org.ruoyi.common.core.validate.AddGroup;
import org.ruoyi.common.core.validate.EditGroup;
import org.ruoyi.core.domain.BaseEntity;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import lombok.EqualsAndHashCode;
import jakarta.validation.constraints.*;
import org.ruoyi.domain.KnowledgeAttachPic;
/**
* 知识库附件图片列业务对象 knowledge_attach_pic
*
* @author Albert
* @date 2025-05-15
*/
@Data
@EqualsAndHashCode(callSuper = true)
@AutoMapper(target = KnowledgeAttachPic.class, reverseConvertGenerate = false)
public class KnowledgeAttachPicBo extends BaseEntity {
/**
* 主键
*/
@NotNull(message = "主键不能为空", groups = {EditGroup.class})
private Long id;
/**
* 知识库id
*/
@NotBlank(message = "知识库id不能为空", groups = {AddGroup.class, EditGroup.class})
private String kid;
/**
* 附件id
*/
@NotBlank(message = "附件id不能为空", groups = {AddGroup.class, EditGroup.class})
private String aid;
/**
* 文档名称
*/
@NotBlank(message = "文档名称不能为空", groups = {AddGroup.class, EditGroup.class})
private String docName;
/**
* 文档类型
*/
@NotBlank(message = "文档类型不能为空", groups = {AddGroup.class, EditGroup.class})
private String docType;
/**
* 文档内容
*/
@NotBlank(message = "文档内容不能为空", groups = {AddGroup.class, EditGroup.class})
private String content;
/**
* 所在页数
*/
@NotNull(message = "所在页数不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer pageNum;
/**
* 所在页index
*/
@NotNull(message = "所在页index不能为空", groups = {AddGroup.class, EditGroup.class})
private Integer indexNum;
/**
* 分析图片状态10未开始20进行中30已完成
*/
@NotNull(message = "分析图片状态10未开始20进行中30已完成不能为空", groups = {AddGroup.class,
EditGroup.class})
private Integer picAnysStatus;
/**
* 对象存储主键
*/
@NotNull(message = "对象存储主键不能为空", groups = {AddGroup.class, EditGroup.class})
private Long ossId;
/**
* 备注
*/
@NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class})
private String remark;
}

View File

@@ -0,0 +1,92 @@
package org.ruoyi.domain.vo;
import com.alibaba.excel.annotation.ExcelIgnoreUnannotated;
import com.alibaba.excel.annotation.ExcelProperty;
import io.github.linpeilie.annotations.AutoMapper;
import lombok.Data;
import java.io.Serial;
import java.io.Serializable;
import org.ruoyi.domain.KnowledgeAttachPic;
/**
* 知识库附件图片列视图对象 knowledge_attach_pic
*
* @author Albert
* @date 2025-05-15
*/
@Data
@ExcelIgnoreUnannotated
@AutoMapper(target = KnowledgeAttachPic.class)
public class KnowledgeAttachPicVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
/**
* 主键
*/
@ExcelProperty(value = "主键")
private Long id;
/**
* 知识库id
*/
@ExcelProperty(value = "知识库id")
private String kid;
/**
* 附件id
*/
@ExcelProperty(value = "附件id")
private String aid;
/**
* 文档名称
*/
@ExcelProperty(value = "文档名称")
private String docName;
/**
* 文档类型
*/
@ExcelProperty(value = "文档类型")
private String docType;
/**
* 文档内容
*/
@ExcelProperty(value = "文档内容")
private String content;
/**
* 所在页数
*/
@ExcelProperty(value = "所在页数")
private Integer pageNum;
/**
* 所在页index
*/
@ExcelProperty(value = "所在页index")
private Integer indexNum;
/**
* 分析图片状态10未开始20进行中30已完成
*/
@ExcelProperty(value = "分析图片状态10未开始20进行中30已完成")
private Integer picAnysStatus;
/**
* 对象存储主键
*/
@ExcelProperty(value = "对象存储主键")
private Long ossId;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
}

View File

@@ -10,8 +10,6 @@ import java.io.Serial;
import java.io.Serializable;
/**
* 知识库附件视图对象 knowledge_attach
*
@@ -23,50 +21,74 @@ import java.io.Serializable;
@AutoMapper(target = KnowledgeAttach.class)
public class KnowledgeAttachVo implements Serializable {
@Serial
private static final long serialVersionUID = 1L;
@Serial
private static final long serialVersionUID = 1L;
/**
*
*/
@ExcelProperty(value = "")
private Long id;
/**
*
*/
@ExcelProperty(value = "")
private Long id;
/**
* 知识库ID
*/
@ExcelProperty(value = "知识库ID")
private String kid;
/**
* 知识库ID
*/
@ExcelProperty(value = "知识库ID")
private String kid;
/**
* 文档ID
*/
@ExcelProperty(value = "文档ID")
private String docId;
/**
* 文档ID
*/
@ExcelProperty(value = "文档ID")
private String docId;
/**
* 文档名称
*/
@ExcelProperty(value = "文档名称")
private String docName;
/**
* 文档名称
*/
@ExcelProperty(value = "文档名称")
private String docName;
/**
* 文档类型
*/
@ExcelProperty(value = "文档类型")
private String docType;
/**
* 文档类型
*/
@ExcelProperty(value = "文档类型")
private String docType;
/**
* 文档内容
*/
@ExcelProperty(value = "文档内容")
private String content;
/**
* 文档内容
*/
@ExcelProperty(value = "文档内容")
private String content;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 备注
*/
@ExcelProperty(value = "备注")
private String remark;
/**
* 对象存储主键
*/
@ExcelProperty(value = "对象存储主键")
private Long ossId;
/**
* 拆解图片状态10未开始20进行中30已完成
*/
@ExcelProperty(value = "拆解图片状态10未开始20进行中30已完成")
private Integer picStatus;
/**
* 分析图片状态10未开始20进行中30已完成
*/
@ExcelProperty(value = "分析图片状态10未开始20进行中30已完成")
private Integer picAnysStatus;
/**
* 写入向量数据库状态10未开始20进行中30已完成
*/
@ExcelProperty(value = "写入向量数据库状态10未开始20进行中30已完成")
private Integer vectorStatus;
}

View File

@@ -0,0 +1,15 @@
package org.ruoyi.mapper;
import org.ruoyi.core.mapper.BaseMapperPlus;
import org.ruoyi.domain.KnowledgeAttachPic;
import org.ruoyi.domain.vo.KnowledgeAttachPicVo;
/**
* 知识库附件图片列Mapper接口
*
* @author Albert
* @date 2025-05-15
*/
public interface KnowledgeAttachPicMapper extends BaseMapperPlus<KnowledgeAttachPic, KnowledgeAttachPicVo> {
}

View File

@@ -0,0 +1,47 @@
package org.ruoyi.service;
import java.util.Collection;
import java.util.List;
import org.ruoyi.core.page.PageQuery;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.domain.bo.KnowledgeAttachPicBo;
import org.ruoyi.domain.vo.KnowledgeAttachPicVo;
/**
* 知识库附件图片列Service接口
*
* @author Albert
* @date 2025-05-15
*/
public interface IKnowledgeAttachPicService {
/**
* 查询知识库附件图片列
*/
KnowledgeAttachPicVo queryById(Long id);
/**
* 查询知识库附件图片列列表
*/
TableDataInfo<KnowledgeAttachPicVo> queryPageList(KnowledgeAttachPicBo bo, PageQuery pageQuery);
/**
* 查询知识库附件图片列列表
*/
List<KnowledgeAttachPicVo> queryList(KnowledgeAttachPicBo bo);
/**
* 新增知识库附件图片列
*/
Boolean insertByBo(KnowledgeAttachPicBo bo);
/**
* 修改知识库附件图片列
*/
Boolean updateByBo(KnowledgeAttachPicBo bo);
/**
* 校验并批量删除知识库附件图片列信息
*/
Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid);
}

View File

@@ -61,5 +61,5 @@ public interface IKnowledgeInfoService {
/**
* 上传附件
*/
void upload(KnowledgeInfoUploadBo bo);
void upload(KnowledgeInfoUploadBo bo) throws Exception;
}

View File

@@ -0,0 +1,123 @@
package org.ruoyi.service.impl;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.KnowledgeAttachPic;
import org.ruoyi.domain.bo.KnowledgeAttachPicBo;
import org.ruoyi.domain.vo.KnowledgeAttachPicVo;
import org.ruoyi.mapper.KnowledgeAttachPicMapper;
import org.ruoyi.service.IKnowledgeAttachPicService;
import org.springframework.stereotype.Service;
import java.util.List;
import java.util.Map;
import java.util.Collection;
/**
* 知识库附件图片列Service业务层处理
*
* @author ageerle
* @date 2025-05-15
*/
@RequiredArgsConstructor
@Service
public class KnowledgeAttachPicServiceImpl implements IKnowledgeAttachPicService {
private final KnowledgeAttachPicMapper baseMapper;
/**
* 查询知识库附件图片列
*/
@Override
public KnowledgeAttachPicVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询知识库附件图片列列表
*/
@Override
public TableDataInfo<KnowledgeAttachPicVo> queryPageList(KnowledgeAttachPicBo bo,
PageQuery pageQuery) {
LambdaQueryWrapper<KnowledgeAttachPic> lqw = buildQueryWrapper(bo);
Page<KnowledgeAttachPicVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询知识库附件图片列列表
*/
@Override
public List<KnowledgeAttachPicVo> queryList(KnowledgeAttachPicBo bo) {
LambdaQueryWrapper<KnowledgeAttachPic> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<KnowledgeAttachPic> buildQueryWrapper(KnowledgeAttachPicBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<KnowledgeAttachPic> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeAttachPic::getKid, bo.getKid());
lqw.eq(StringUtils.isNotBlank(bo.getAid()), KnowledgeAttachPic::getAid, bo.getAid());
lqw.like(StringUtils.isNotBlank(bo.getDocName()), KnowledgeAttachPic::getDocName,
bo.getDocName());
lqw.eq(StringUtils.isNotBlank(bo.getDocType()), KnowledgeAttachPic::getDocType,
bo.getDocType());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeAttachPic::getContent,
bo.getContent());
lqw.eq(bo.getPageNum() != null, KnowledgeAttachPic::getPageNum, bo.getPageNum());
lqw.eq(bo.getIndexNum() != null, KnowledgeAttachPic::getIndexNum, bo.getIndexNum());
lqw.eq(bo.getPicAnysStatus() != null, KnowledgeAttachPic::getPicAnysStatus,
bo.getPicAnysStatus());
lqw.eq(bo.getOssId() != null, KnowledgeAttachPic::getOssId, bo.getOssId());
return lqw;
}
/**
* 新增知识库附件图片列
*/
@Override
public Boolean insertByBo(KnowledgeAttachPicBo bo) {
KnowledgeAttachPic add = MapstructUtils.convert(bo, KnowledgeAttachPic.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改知识库附件图片列
*/
@Override
public Boolean updateByBo(KnowledgeAttachPicBo bo) {
KnowledgeAttachPic update = MapstructUtils.convert(bo, KnowledgeAttachPic.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(KnowledgeAttachPic entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除知识库附件图片列
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
}

View File

@@ -1,5 +1,7 @@
package org.ruoyi.service.impl;
import cn.hutool.core.util.ObjectUtil;
import java.util.stream.Collectors;
import org.ruoyi.common.core.utils.MapstructUtils;
import org.ruoyi.common.core.utils.StringUtils;
import org.ruoyi.core.page.TableDataInfo;
@@ -8,8 +10,11 @@ import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import lombok.RequiredArgsConstructor;
import org.ruoyi.domain.KnowledgeAttachPic;
import org.ruoyi.domain.vo.KnowledgeAttachVo;
import org.ruoyi.mapper.KnowledgeAttachPicMapper;
import org.ruoyi.mapper.KnowledgeFragmentMapper;
import org.ruoyi.system.service.ISysOssService;
import org.springframework.stereotype.Service;
import org.ruoyi.domain.bo.KnowledgeAttachBo;
@@ -33,99 +38,130 @@ import java.util.Collection;
@Service
public class KnowledgeAttachServiceImpl implements IKnowledgeAttachService {
private final KnowledgeAttachMapper baseMapper;
private final KnowledgeFragmentMapper fragmentMapper;
private final KnowledgeAttachMapper baseMapper;
private final KnowledgeFragmentMapper fragmentMapper;
/**
* 查询知识库附件
*/
@Override
public KnowledgeAttachVo queryById(Long id){
return baseMapper.selectVoById(id);
private final ISysOssService ossService;
private final KnowledgeAttachPicMapper picMapper;
/**
* 查询知识库附件
*/
@Override
public KnowledgeAttachVo queryById(Long id) {
return baseMapper.selectVoById(id);
}
/**
* 查询知识库附件列表
*/
@Override
public TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
Page<KnowledgeAttachVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
}
/**
* 查询知识库附件列表
*/
@Override
public List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo) {
LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
}
private LambdaQueryWrapper<KnowledgeAttach> buildQueryWrapper(KnowledgeAttachBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<KnowledgeAttach> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeAttach::getKid, bo.getKid());
lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeAttach::getDocId, bo.getDocId());
lqw.like(StringUtils.isNotBlank(bo.getDocName()), KnowledgeAttach::getDocName, bo.getDocName());
lqw.eq(StringUtils.isNotBlank(bo.getDocType()), KnowledgeAttach::getDocType, bo.getDocType());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeAttach::getContent, bo.getContent());
return lqw;
}
/**
* 新增知识库附件
*/
@Override
public Boolean insertByBo(KnowledgeAttachBo bo) {
KnowledgeAttach add = MapstructUtils.convert(bo, KnowledgeAttach.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 查询知识库附件列表
*/
@Override
public TableDataInfo<KnowledgeAttachVo> queryPageList(KnowledgeAttachBo bo, PageQuery pageQuery) {
LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
Page<KnowledgeAttachVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
return TableDataInfo.build(result);
/**
* 修改知识库附件
*/
@Override
public Boolean updateByBo(KnowledgeAttachBo bo) {
KnowledgeAttach update = MapstructUtils.convert(bo, KnowledgeAttach.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(KnowledgeAttach entity) {
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除知识库附件
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if (isValid) {
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
/**
* 查询知识库附件列表
*/
@Override
public List<KnowledgeAttachVo> queryList(KnowledgeAttachBo bo) {
LambdaQueryWrapper<KnowledgeAttach> lqw = buildQueryWrapper(bo);
return baseMapper.selectVoList(lqw);
@Override
public void removeKnowledgeAttach(String docId) {
Map<String, Object> map = new HashMap<>();
map.put("doc_id", docId);
List<KnowledgeAttachVo> knowledgeAttachVos = baseMapper.selectVoByMap(map);
if (ObjectUtil.isNotEmpty(knowledgeAttachVos)) {
Collection<Long> ossIds = knowledgeAttachVos.stream()
.map(KnowledgeAttachVo::getOssId)
.collect(Collectors.toList());
//删除oss
ossService.deleteWithValidByIds(ossIds, false);
//删除图片oss
List<KnowledgeAttachPic> knowledgeAttachPics = picMapper.selectList(
new LambdaQueryWrapper<KnowledgeAttachPic>()
.in(KnowledgeAttachPic::getKid,
knowledgeAttachVos.stream().map(KnowledgeAttachVo::getKid)
.collect(Collectors.toList()))
.in(KnowledgeAttachPic::getAid,
knowledgeAttachVos.stream().map(KnowledgeAttachVo::getId)
.collect(Collectors.toList()))
);
if (ObjectUtil.isNotEmpty(knowledgeAttachPics)) {
Collection<Long> tossIds = knowledgeAttachPics.stream()
.map(KnowledgeAttachPic::getOssId)
.collect(Collectors.toList());
ossService.deleteWithValidByIds(tossIds, false);
List<Long> collect = knowledgeAttachPics.stream().map(KnowledgeAttachPic::getId)
.collect(Collectors.toList());
picMapper.deleteByIds(collect);
}
}
baseMapper.deleteByMap(map);
fragmentMapper.deleteByMap(map);
}
private LambdaQueryWrapper<KnowledgeAttach> buildQueryWrapper(KnowledgeAttachBo bo) {
Map<String, Object> params = bo.getParams();
LambdaQueryWrapper<KnowledgeAttach> lqw = Wrappers.lambdaQuery();
lqw.eq(StringUtils.isNotBlank(bo.getKid()), KnowledgeAttach::getKid, bo.getKid());
lqw.eq(StringUtils.isNotBlank(bo.getDocId()), KnowledgeAttach::getDocId, bo.getDocId());
lqw.like(StringUtils.isNotBlank(bo.getDocName()), KnowledgeAttach::getDocName, bo.getDocName());
lqw.eq(StringUtils.isNotBlank(bo.getDocType()), KnowledgeAttach::getDocType, bo.getDocType());
lqw.eq(StringUtils.isNotBlank(bo.getContent()), KnowledgeAttach::getContent, bo.getContent());
return lqw;
}
/**
* 新增知识库附件
*/
@Override
public Boolean insertByBo(KnowledgeAttachBo bo) {
KnowledgeAttach add = MapstructUtils.convert(bo, KnowledgeAttach.class);
validEntityBeforeSave(add);
boolean flag = baseMapper.insert(add) > 0;
if (flag) {
bo.setId(add.getId());
}
return flag;
}
/**
* 修改知识库附件
*/
@Override
public Boolean updateByBo(KnowledgeAttachBo bo) {
KnowledgeAttach update = MapstructUtils.convert(bo, KnowledgeAttach.class);
validEntityBeforeSave(update);
return baseMapper.updateById(update) > 0;
}
/**
* 保存前的数据校验
*/
private void validEntityBeforeSave(KnowledgeAttach entity){
//TODO 做一些数据校验,如唯一约束
}
/**
* 批量删除知识库附件
*/
@Override
public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
if(isValid){
//TODO 做一些业务上的校验,判断是否需要校验
}
return baseMapper.deleteBatchIds(ids) > 0;
}
@Override
public void removeKnowledgeAttach(String docId) {
Map<String,Object> map = new HashMap<>();
map.put("doc_id",docId);
baseMapper.deleteByMap(map);
fragmentMapper.deleteByMap(map);
}
@Override
public String translationByFile(MultipartFile file, String targetLanguage) {
@Override
public String translationByFile(MultipartFile file, String targetLanguage) {
/*String fileName = file.getOriginalFilename();
String docType = fileName.substring(fileName.lastIndexOf(".")+1);
String content = "";
@@ -173,6 +209,6 @@ public class KnowledgeAttachServiceImpl implements IKnowledgeAttachService {
throw new BaseException("调用大模型失败,请检查密钥是否正确!");
}
return chatCompletionResponse.getChoices().get(0).getMessage().getContent().toString();*/
return "接口开发中!";
}
return "接口开发中!";
}
}

View File

@@ -4,6 +4,8 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;
import okhttp3.MediaType;
import okhttp3.MultipartBody;
@@ -23,16 +25,19 @@ import org.springframework.web.multipart.MultipartFile;
/**
* PDF图片提取服务实现类
*/
@Service
//@Service
@Slf4j
public class PdfImageExtractServiceImpl implements PdfImageExtractService {
@Data
@AllArgsConstructor
//public class PdfImageExtractServiceImpl implements PdfImageExtractService {
public class PdfImageExtractServiceImpl {
@Value("${pdf.extract.service.url}")
// @Value("${pdf.extract.service.url}")
private String serviceUrl;
@Value("${pdf.extract.ai-api.url}")
// @Value("${pdf.extract.ai-api.url}")
private String aiApiUrl;
@Value("${pdf.extract.ai-api.key}")
private String aiApiKey ;
// @Value("${pdf.extract.ai-api.key}")
private String aiApiKey;
private final OkHttpClient client = new Builder()
.connectTimeout(100, TimeUnit.SECONDS)
@@ -43,7 +48,7 @@ public class PdfImageExtractServiceImpl implements PdfImageExtractService {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
@Override
// @Override
public byte[] extractImages(MultipartFile pdfFile, String imageFormat, boolean allowDuplicates)
throws IOException {
// 构建multipart请求
@@ -77,7 +82,7 @@ public class PdfImageExtractServiceImpl implements PdfImageExtractService {
* @return 文件内容结果列表
* @throws IOException 如果API调用过程中发生错误
*/
@Override
// @Override
public List<PdfFileContentResult> dealFileContent(String[] unzip) throws IOException {
List<PdfFileContentResult> results = new ArrayList<>();
int i = 0;
@@ -110,6 +115,7 @@ public class PdfImageExtractServiceImpl implements PdfImageExtractService {
// 执行请求
try {
log.info("=============call=" + ++i);
Response response = client.newCall(request).execute();
log.info("=============response=" + response);
if (!response.isSuccessful()) {
@@ -126,11 +132,10 @@ public class PdfImageExtractServiceImpl implements PdfImageExtractService {
throw new RuntimeException(e);
}
}
return results;
}
@Override
// @Override
public List<PdfFileContentResult> extractImages(MultipartFile file) throws IOException {
String format = "png";
boolean allowDuplicates = true;

View File

@@ -97,7 +97,7 @@ public class VectorStoreServiceImpl implements VectorStoreService {
for (int i = 0; i < chunkList.size(); i++) {
Map<String, Object> dataSchema = new HashMap<>();
dataSchema.put("kid", storeEmbeddingBo.getKid());
dataSchema.put("docId", storeEmbeddingBo.getKid());
dataSchema.put("docId", storeEmbeddingBo.getDocId());
dataSchema.put("fid", storeEmbeddingBo.getFids().get(i));
Embedding embedding = embeddingModel.embed(chunkList.get(i)).content();
TextSegment segment = TextSegment.from(chunkList.get(i));

View File

@@ -11,6 +11,8 @@ import java.util.Base64;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.web.multipart.MultipartFile;
/**
* ZIP文件处理工具类
@@ -92,4 +94,90 @@ public class ZipUtils {
}
return base64Contents.toArray(new String[0]);
}
/**
* 解压ZIP文件并返回MultipartFile数组
*
* @param zipData ZIP文件的字节数组
* @return MultipartFile数组
* @throws IOException 如果解压过程中发生错误
*/
public static MultipartFile[] unzipToMultipartFiles(byte[] zipData) throws IOException {
List<MultipartFile> multipartFiles = new ArrayList<>();
try (ByteArrayInputStream bis = new ByteArrayInputStream(zipData);
ZipInputStream zis = new ZipInputStream(bis)) {
ZipEntry zipEntry;
while ((zipEntry = zis.getNextEntry()) != null) {
if (!zipEntry.isDirectory()) {
// 读取文件内容到内存
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buffer = new byte[4096];
int read;
while ((read = zis.read(buffer)) != -1) {
baos.write(buffer, 0, read);
}
// 创建MultipartFile对象
String fileName = zipEntry.getName();
byte[] content = baos.toByteArray();
String contentType = determineContentType(fileName);
MultipartFile multipartFile = new MockMultipartFile(
fileName, // 文件名
fileName, // 原始文件名
contentType, // 内容类型
content // 文件内容
);
multipartFiles.add(multipartFile);
}
zis.closeEntry();
}
}
return multipartFiles.toArray(new MultipartFile[0]);
}
/**
* 根据文件名确定内容类型
*
* @param fileName 文件名
* @return 内容类型
*/
private static String determineContentType(String fileName) {
String extension = "";
int i = fileName.lastIndexOf('.');
if (i > 0) {
extension = fileName.substring(i + 1).toLowerCase();
}
switch (extension) {
case "txt":
return "text/plain";
case "html":
case "htm":
return "text/html";
case "pdf":
return "application/pdf";
case "jpg":
case "jpeg":
return "image/jpeg";
case "png":
return "image/png";
case "gif":
return "image/gif";
case "doc":
case "docx":
return "application/msword";
case "xls":
case "xlsx":
return "application/vnd.ms-excel";
case "xml":
return "application/xml";
case "json":
return "application/json";
default:
return "application/octet-stream";
}
}
}

View File

@@ -17,5 +17,11 @@
<maven.compiler.target>17</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
</dependency>
</dependencies>
</project>

View File

@@ -1,5 +1,6 @@
package org.ruoyi.system.service;
import org.ruoyi.common.log.event.LogininforEvent;
import org.ruoyi.core.page.PageQuery;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.system.domain.bo.SysLogininforBo;
@@ -44,4 +45,6 @@ public interface ISysLogininforService {
* 清空系统登录日志
*/
void cleanLogininfor();
void recordLogininfor(LogininforEvent logininforEvent);
}

View File

@@ -1,5 +1,6 @@
package org.ruoyi.system.service;
import org.ruoyi.common.log.event.OperLogEvent;
import org.ruoyi.core.page.PageQuery;
import org.ruoyi.core.page.TableDataInfo;
import org.ruoyi.system.domain.bo.SysOperLogBo;
@@ -51,4 +52,5 @@ public interface ISysOperLogService {
* 清空操作日志
*/
void cleanOperLog();
void recordOper(OperLogEvent operLogEvent);
}

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